diff options
Diffstat (limited to 'src')
m--------- | src/gopkg.in/yaml.v2 | 0 | ||||
m--------- | src/lukeshu.com/git/go/libgnulinux.git | 0 | ||||
m--------- | src/lukeshu.com/git/go/libnslcd.git | 0 | ||||
m--------- | src/lukeshu.com/git/go/libsystemd.git | 0 | ||||
-rw-r--r-- | src/nshd/hackers_git/check_password.go | 50 | ||||
-rw-r--r-- | src/nshd/hackers_git/db_config.go | 44 | ||||
-rw-r--r-- | src/nshd/hackers_git/db_group.go | 144 | ||||
-rw-r--r-- | src/nshd/hackers_git/db_pam.go | 105 | ||||
-rw-r--r-- | src/nshd/hackers_git/db_passwd.go | 86 | ||||
-rw-r--r-- | src/nshd/hackers_git/db_shadow.go | 82 | ||||
-rw-r--r-- | src/nshd/hackers_git/gid.go | 42 | ||||
-rw-r--r-- | src/nshd/hackers_git/hackers.go | 121 | ||||
-rw-r--r-- | src/nshd/hackers_git/hackers_parse.go | 157 | ||||
-rw-r--r-- | src/nshd/hackers_git/set.go | 32 | ||||
-rw-r--r-- | src/nshd/main.go | 37 |
15 files changed, 900 insertions, 0 deletions
diff --git a/src/gopkg.in/yaml.v2 b/src/gopkg.in/yaml.v2 new file mode 160000 +Subproject f7716cbe52baa25d2e9b0d0da546fcf909fc16b diff --git a/src/lukeshu.com/git/go/libgnulinux.git b/src/lukeshu.com/git/go/libgnulinux.git new file mode 160000 +Subproject 58bfc6259f5ced680b5b200687240d2449313b2 diff --git a/src/lukeshu.com/git/go/libnslcd.git b/src/lukeshu.com/git/go/libnslcd.git new file mode 160000 +Subproject dad3de8e9835a11b1df9e718eef3faa50459ccb diff --git a/src/lukeshu.com/git/go/libsystemd.git b/src/lukeshu.com/git/go/libsystemd.git new file mode 160000 +Subproject 89efdfbee5f9a22f9dd1083f7a383daba54d4f1 diff --git a/src/nshd/hackers_git/check_password.go b/src/nshd/hackers_git/check_password.go new file mode 100644 index 0000000..81ad932 --- /dev/null +++ b/src/nshd/hackers_git/check_password.go @@ -0,0 +1,50 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +package hackers_git + +import "unsafe" + +/* +#cgo LDFLAGS: -lcrypt +#define _GNU_SOURCE // for crypt_r(3) in crypt.h +#include <stdlib.h> // for free(3) +#include <crypt.h> // for crypt_r(3) +#include <string.h> // for strcmp(3) and memset(3) +int check_password(const char *password, const char *hash) +{ + int ret; + struct crypt_data data; + data.initialized = 0; + ret = (strcmp(crypt_r(password, hash, &data), hash) == 0); + memset(&data, 0, sizeof(data)); + return ret; +} +*/ +import "C" + +func check_password(password string, hash string) bool { + cpassword := C.CString(password) + defer C.free(unsafe.Pointer(cpassword)) + chash := C.CString(hash) + defer C.free(unsafe.Pointer(chash)) + return C.check_password(cpassword, chash) != 0 +} diff --git a/src/nshd/hackers_git/db_config.go b/src/nshd/hackers_git/db_config.go new file mode 100644 index 0000000..dc3b99e --- /dev/null +++ b/src/nshd/hackers_git/db_config.go @@ -0,0 +1,44 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +package hackers_git + +import ( + p "lukeshu.com/git/go/libnslcd.git/proto" + s "syscall" +) + +func (o *Hackers) Config_Get(cred s.Ucred, req p.Request_Config_Get) <-chan p.Config { + o.lock.RLock() + ret := make(chan p.Config) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + switch req.Key { + case p.NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE: + if o.Cfg.Pam_password_prohibit_message != "" { + ret <- p.Config{Value: o.Cfg.Pam_password_prohibit_message} + } + } + }() + return ret +} diff --git a/src/nshd/hackers_git/db_group.go b/src/nshd/hackers_git/db_group.go new file mode 100644 index 0000000..7e97c05 --- /dev/null +++ b/src/nshd/hackers_git/db_group.go @@ -0,0 +1,144 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +package hackers_git + +import ( + p "lukeshu.com/git/go/libnslcd.git/proto" + s "syscall" +) + +func (o *Hackers) groupByName(name string, users bool) p.Group { + members_set, found := o.groups[name] + if !found { + return p.Group{ID: -1} + } + gid := name2gid(name) + if gid < 0 { + return p.Group{ID: -1} + } + var members_list []string + if users { + members_list = set2list(members_set) + } else { + members_list = make([]string, 0) + } + return p.Group{ + Name: name, + PwHash: "x", + ID: gid, + Members: members_list, + } +} + +func (o *Hackers) groupByGid(gid int32, users bool) p.Group { + name, found := gid2name(gid) + if !found { + return p.Group{ID: -1} + } + members_set, found := o.groups[name] + if !found { + return p.Group{ID: -1} + } + var members_list []string + if users { + members_list = set2list(members_set) + } else { + members_list = make([]string, 0) + } + return p.Group{ + Name: name, + PwHash: "x", + ID: gid, + Members: members_list, + } +} + +func (o *Hackers) Group_ByName(cred s.Ucred, req p.Request_Group_ByName) <-chan p.Group { + o.lock.RLock() + ret := make(chan p.Group) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + group := o.groupByName(req.Name, true) + if group.ID < 0 { + return + } + ret <- group + }() + return ret +} + +func (o *Hackers) Group_ByGid(cred s.Ucred, req p.Request_Group_ByGid) <-chan p.Group { + o.lock.RLock() + ret := make(chan p.Group) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + group := o.groupByGid(req.Gid, true) + if group.ID < 0 { + return + } + ret <- group + }() + return ret +} + +// note that the BYMEMBER call returns an empty members list +func (o *Hackers) Group_ByMember(cred s.Ucred, req p.Request_Group_ByMember) <-chan p.Group { + o.lock.RLock() + ret := make(chan p.Group) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + uid := o.name2uid(req.Member) + if uid < 0 { + return + } + for _, name := range o.users[uid].groups { + group := o.groupByName(name, false) + if group.ID >= 0 { + ret <- group + } + } + }() + return ret +} + +func (o *Hackers) Group_All(cred s.Ucred, req p.Request_Group_All) <-chan p.Group { + o.lock.RLock() + ret := make(chan p.Group) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + for name, _ := range o.groups { + group := o.groupByName(name, true) + if group.ID >= 0 { + ret <- group + } + } + }() + return ret +} diff --git a/src/nshd/hackers_git/db_pam.go b/src/nshd/hackers_git/db_pam.go new file mode 100644 index 0000000..2ef8d9a --- /dev/null +++ b/src/nshd/hackers_git/db_pam.go @@ -0,0 +1,105 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +package hackers_git + +import ( + "crypto/rand" + p "lukeshu.com/git/go/libnslcd.git/proto" + "math/big" + s "syscall" +) + +func (o *Hackers) PAM_Authentication(cred s.Ucred, req p.Request_PAM_Authentication) <-chan p.PAM_Authentication { + o.lock.RLock() + ret := make(chan p.PAM_Authentication) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + uid := o.name2uid(req.UserName) + if uid < 0 { + return + } + + user := o.users[uid] + obj := p.PAM_Authentication{ + AuthenticationResult: p.NSLCD_PAM_AUTH_ERR, + UserName: "", + AuthorizationResult: p.NSLCD_PAM_AUTH_ERR, + AuthorizationError: "", + } + if check_password(req.Password, user.passwd.PwHash) { + obj.AuthenticationResult = p.NSLCD_PAM_SUCCESS + obj.AuthorizationResult = obj.AuthenticationResult + obj.UserName = user.passwd.Name + } + ret <- obj + }() + return ret +} + +func (o *Hackers) PAM_Authorization(cred s.Ucred, req p.Request_PAM_Authorization) <-chan p.PAM_Authorization { + o.lock.RLock() + ret := make(chan p.PAM_Authorization) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + uid := o.name2uid(req.UserName) + if uid < 0 { + return + } + ret <- p.PAM_Authorization{ + Result: p.NSLCD_PAM_SUCCESS, + Error: "", + } + }() + return ret +} + +const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + +var alphabet_len = big.NewInt(int64(len(alphabet))) + +func (o *Hackers) PAM_SessionOpen(cred s.Ucred, req p.Request_PAM_SessionOpen) <-chan p.PAM_SessionOpen { + ret := make(chan p.PAM_SessionOpen) + go func() { + defer close(ret) + + var sessionid [24]byte + for i := 0; i < len(sessionid); i++ { + bigint, err := rand.Int(rand.Reader, alphabet_len) + if err != nil { + return + } + sessionid[i] = alphabet[bigint.Int64()] + } + ret <- p.PAM_SessionOpen{SessionID: string(sessionid[:])} + }() + return ret +} + +func (o *Hackers) PAM_SessionClose(cred s.Ucred, req p.Request_PAM_SessionClose) <-chan p.PAM_SessionClose { + ret := make(chan p.PAM_SessionClose) + go close(ret) + return ret +} diff --git a/src/nshd/hackers_git/db_passwd.go b/src/nshd/hackers_git/db_passwd.go new file mode 100644 index 0000000..0be3910 --- /dev/null +++ b/src/nshd/hackers_git/db_passwd.go @@ -0,0 +1,86 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +package hackers_git + +import ( + p "lukeshu.com/git/go/libnslcd.git/proto" + s "syscall" +) + +/* Note that the output password hash value should be one of: + <empty> - no password set, allow login without password + ! - used to prevent logins + x - "valid" encrypted password that does not match any valid password + often used to indicate that the password is defined elsewhere + other - encrypted password, in crypt(3) format */ + +func (o *Hackers) Passwd_ByName(cred s.Ucred, req p.Request_Passwd_ByName) <-chan p.Passwd { + o.lock.RLock() + ret := make(chan p.Passwd) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + uid := o.name2uid(req.Name) + if uid < 0 { + return + } + passwd := o.users[uid].passwd + passwd.PwHash = "x" // only put actual hashes in the Shadow DB + ret <- passwd + }() + return ret +} + +func (o *Hackers) Passwd_ByUID(cred s.Ucred, req p.Request_Passwd_ByUID) <-chan p.Passwd { + o.lock.RLock() + ret := make(chan p.Passwd) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + user, found := o.users[req.UID] + if !found { + return + } + passwd := user.passwd + passwd.PwHash = "x" // only put actual hashes in the Shadow DB + ret <- passwd + }() + return ret +} + +func (o *Hackers) Passwd_All(cred s.Ucred, req p.Request_Passwd_All) <-chan p.Passwd { + o.lock.RLock() + ret := make(chan p.Passwd) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + for _, user := range o.users { + passwd := user.passwd + passwd.PwHash = "x" // only put actual hashes in the Shadow DB + ret <- passwd + } + }() + return ret +} diff --git a/src/nshd/hackers_git/db_shadow.go b/src/nshd/hackers_git/db_shadow.go new file mode 100644 index 0000000..c2719b3 --- /dev/null +++ b/src/nshd/hackers_git/db_shadow.go @@ -0,0 +1,82 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +package hackers_git + +import ( + p "lukeshu.com/git/go/libnslcd.git/proto" + s "syscall" +) + +func (o *Hackers) Shadow_ByName(cred s.Ucred, req p.Request_Shadow_ByName) <-chan p.Shadow { + o.lock.RLock() + ret := make(chan p.Shadow) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + if cred.Uid != 0 { + return + } + uid := o.name2uid(req.Name) + user := o.users[uid] + ret <- p.Shadow{ + Name: user.passwd.Name, + PwHash: user.passwd.PwHash, + LastChangeDate: -1, + MinDays: -1, + MaxDays: -1, + WarnDays: -1, + InactDays: -1, + ExpireDate: -1, + Flag: -1, + } + }() + return ret +} + +func (o *Hackers) Shadow_All(cred s.Ucred, req p.Request_Shadow_All) <-chan p.Shadow { + o.lock.RLock() + ret := make(chan p.Shadow) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + if cred.Uid != 0 { + return + } + + for _, user := range o.users { + ret <- p.Shadow{ + Name: user.passwd.Name, + PwHash: user.passwd.PwHash, + LastChangeDate: -1, + MinDays: -1, + MaxDays: -1, + WarnDays: -1, + InactDays: -1, + ExpireDate: -1, + Flag: -1, + } + } + }() + return ret +} diff --git a/src/nshd/hackers_git/gid.go b/src/nshd/hackers_git/gid.go new file mode 100644 index 0000000..f7bbac7 --- /dev/null +++ b/src/nshd/hackers_git/gid.go @@ -0,0 +1,42 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +package hackers_git + +import "lukeshu.com/git/go/libgnulinux.git/getgr" + +func name2gid(name string) int32 { + gr, err := getgr.ByName(name) + if gr == nil || err != nil { + return -1 + } else { + return int32(gr.Gid) + } +} + +func gid2name(gid int32) (string, bool) { + gr, err := getgr.ByGid(gid) + if gr == nil || err != nil { + return "", false + } else { + return gr.Name, true + } +} diff --git a/src/nshd/hackers_git/hackers.go b/src/nshd/hackers_git/hackers.go new file mode 100644 index 0000000..b72698f --- /dev/null +++ b/src/nshd/hackers_git/hackers.go @@ -0,0 +1,121 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +// Package hackers_git is an nslcd_server Backend that speaks to +// hackers.git. +package hackers_git + +import ( + "lukeshu.com/git/go/libnslcd.git/proto" + "lukeshu.com/git/go/libnslcd.git/proto/server" + "lukeshu.com/git/go/libnslcd.git/systemd" + "lukeshu.com/git/go/libsystemd.git/sd_daemon/logger" + "path/filepath" + "sync" +) + +type user struct { + passwd nslcd_proto.Passwd + groups []string +} + +type Config struct { + Pam_password_prohibit_message string + Yamldir string +} + +type Hackers struct { + nslcd_server.NilBackend + Cfg Config + lock sync.RWMutex + + users map[int32]user + groups map[string]map[string]bool +} + +var _ nslcd_systemd.Backend = &Hackers{} +var _ nslcd_server.Backend = &Hackers{} + +func (o *Hackers) Init() error { + err := o.Reload() + if err != nil { + logger.Err("hackers.git: Could not initialize: %v", err) + return err + } + return nil +} + +func (o *Hackers) Close() { + logger.Info("hackers.git: Closing session") + o.lock.Lock() + defer o.lock.Unlock() + + o.users = make(map[int32]user, 0) + o.groups = make(map[string]map[string]bool) +} + +func (o *Hackers) Reload() error { + logger.Info("hackers.git: Loading session") + o.lock.Lock() + defer o.lock.Unlock() + + filenames, err := filepath.Glob(o.Cfg.Yamldir + "/*.yml") + if err != nil { + return err + } + o.users = make(map[int32]user, len(filenames)) + o.groups = make(map[string]map[string]bool) + for _, filename := range filenames { + logger.Debug("hackers.git: Loading YAML file: %s", filename) + + user, err := parse_user_yaml(filename) + if err != nil { + logger.Warning("hackers.git: -> File ignored: %v", err) + continue + } + for _, groupname := range user.groups { + o.add_user_to_group(user.passwd.Name, groupname) + } + user.passwd.PwHash = parse_user_password(user.passwd.HomeDir + "/.password") + o.users[user.passwd.UID] = user + logger.Debug("hackers.git: -> User %d(%s) added", user.passwd.UID, user.passwd.Name) + } + + return nil +} + +func (o *Hackers) name2uid(name string) int32 { + for uid, data := range o.users { + if data.passwd.Name == name { + return uid + } + } + return -1 +} + +func (o *Hackers) add_user_to_group(username string, groupname string) { + group, found := o.groups[groupname] + if !found { + group = make(map[string]bool) + o.groups[groupname] = group + } + group[username] = true +} diff --git a/src/nshd/hackers_git/hackers_parse.go b/src/nshd/hackers_git/hackers_parse.go new file mode 100644 index 0000000..d5370eb --- /dev/null +++ b/src/nshd/hackers_git/hackers_parse.go @@ -0,0 +1,157 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +package hackers_git + +import ( + "fmt" + yaml "gopkg.in/yaml.v2" + "io/ioutil" + "lukeshu.com/git/go/libsystemd.git/sd_daemon/logger" + "os" + "path" + "strconv" + "strings" +) + +func filename2uid(filename string) int32 { + basename := path.Base(filename) + parts := strings.SplitN(basename, ".", 2) + if len(parts) != 2 || parts[1] != "yml" { + return -1 + } + uid, err := strconv.ParseInt(parts[0], 10, 32) + if err != nil { + return -1 + } + return int32(uid) +} + +var usersGid = name2gid("users") + +func parse_user_yaml(filename string) (ret user, err error) { + ret.passwd.UID = filename2uid(filename) + + if ret.passwd.UID < 0 { + err = fmt.Errorf("Invalid user filename: %q", filename) + return + } + file, err := os.Open(filename) + if err != nil { + return + } + contents, err := ioutil.ReadAll(file) + if err != nil { + return + } + var _data interface{} + err = yaml.Unmarshal(contents, &_data) + if err != nil { + return + } + data, isMap := _data.(map[interface{}]interface{}) + errs := []string{} + if !isMap { + errs = append(errs, "root node is not a map") + } else { + if iface, isSet := data["username"]; !isSet { + errs = append(errs, "\"username\" is not set") + } else if str, isTyp := iface.(string); !isTyp { + errs = append(errs, "\"username\" is not a string") + } else { + ret.passwd.Name = str + ret.passwd.HomeDir = "/home/" + str + } + + if iface, isSet := data["fullname"]; !isSet { + errs = append(errs, "\"fullname\" is not set") + } else if str, isTyp := iface.(string); !isTyp { + errs = append(errs, "\"fullname\" is not a string") + } else { + ret.passwd.GECOS = str + } + + if iface, isSet := data["shell"]; !isSet { + errs = append(errs, "\"shell\" is not set") + } else if str, isTyp := iface.(string); !isTyp { + errs = append(errs, "\"shell\" is not a string") + } else { + ret.passwd.Shell = str + } + + if iface, isSet := data["groups"]; !isSet { + ret.groups = make([]string, 0) + } else if ary, isTyp := iface.([]interface{}); !isTyp { + errs = append(errs, "\"groups\" is not an array") + } else { + groups := make(map[string]bool, len(ary)) + e := false + for _, iface := range ary { + if str, isTyp := iface.(string); !isTyp { + errs = append(errs, "\"group\" item is not an array") + e = true + break + } else { + groups[str] = true + } + } + if !e { + ret.groups = set2list(groups) + } + } + } + if len(errs) > 0 { + err = &yaml.TypeError{Errors: errs} + } + + ret.passwd.PwHash = "!" + ret.passwd.GID = usersGid + + return +} + +func parse_user_password(filename string) (hash string) { + hash = "!" + file, err := os.Open(filename) + if err != nil { + logger.Debug("hackers.git: %v", err) + return + } + contents, err := ioutil.ReadAll(file) + if err != nil { + logger.Debug("hackers.git: Error while reading: %q: %v", filename, err) + return + } + lines := strings.Split(string(contents), "\n") + switch len(lines) { + case 1: + hash = lines[0] + case 2: + if lines[1] == "" { + hash = lines[0] + } else { + logger.Debug("hackers.git: Invalid password format in file: %q", filename) + } + default: + logger.Debug("hackers.git: Invalid password format in file: %q", filename) + } + return +} diff --git a/src/nshd/hackers_git/set.go b/src/nshd/hackers_git/set.go new file mode 100644 index 0000000..dc1d443 --- /dev/null +++ b/src/nshd/hackers_git/set.go @@ -0,0 +1,32 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +package hackers_git + +func set2list(set map[string]bool) []string { + list := make([]string, len(set)) + i := uint(0) + for item, _ := range set { + list[i] = item + i++ + } + return list +} diff --git a/src/nshd/main.go b/src/nshd/main.go new file mode 100644 index 0000000..6871518 --- /dev/null +++ b/src/nshd/main.go @@ -0,0 +1,37 @@ +// Copyright 2015 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +// Command nshd is an implementation of nslcd that talks to hackers.git instead of LDAP. +package main + +import ( + "lukeshu.com/git/go/libnslcd.git/systemd" + "nshd/hackers_git" + "os" +) + +func main() { + backend := &hackers_git.Hackers{Cfg: hackers_git.Config{ + Pam_password_prohibit_message: "", + Yamldir: "/var/cache/parabola-hackers/users", + }} + os.Exit(int(nslcd_systemd.Main(backend))) +} |