diff options
Diffstat (limited to 'src/nshd/hackers_git')
-rw-r--r-- | src/nshd/hackers_git/db_config.go | 4 | ||||
-rw-r--r-- | src/nshd/hackers_git/hackers.go | 43 | ||||
-rw-r--r-- | src/nshd/hackers_git/hackers_parse.go | 16 | ||||
-rw-r--r-- | src/nshd/hackers_git/hackers_watch.go | 187 |
4 files changed, 231 insertions, 19 deletions
diff --git a/src/nshd/hackers_git/db_config.go b/src/nshd/hackers_git/db_config.go index 9ed978f..5ef4fe6 100644 --- a/src/nshd/hackers_git/db_config.go +++ b/src/nshd/hackers_git/db_config.go @@ -10,7 +10,9 @@ func (o *Hackers) Config_Get(cred p.Ucred, req p.Request_Config_Get) p.Config_En switch req { case p.NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE: - val = &o.pam_password_prohibit_message + if o.cfg.Pam_password_prohibit_message != "" { + val = &o.cfg.Pam_password_prohibit_message + } } if val != nil { diff --git a/src/nshd/hackers_git/hackers.go b/src/nshd/hackers_git/hackers.go index b8ef949..f7c4573 100644 --- a/src/nshd/hackers_git/hackers.go +++ b/src/nshd/hackers_git/hackers.go @@ -2,39 +2,46 @@ package hackers_git import ( "inotify" - _ "gopkg.in/yaml.v2" p "nslcd_proto" "nslcd_systemd" + "sd_daemon/logger" "sync" ) +type Config struct { + Pam_password_prohibit_message string + Yamldir string +} + type Hackers struct { p.NullBackend - lock *sync.RWMutex - pam_password_prohibit_message string + cfg Config + lock sync.RWMutex + users map[int32]p.Passwd + passwords map[int32]string + + in_fd *inotify.Inotify + in_wd_home inotify.Cint + in_wd_yaml inotify.Cint + in_uid2wd map[int32]inotify.Cint + in_wd2uid map[inotify.Cint]int32 } var _ nslcd_systemd.Backend = &Hackers{} var _ p.Backend = &Hackers{} -func (o *Hackers) Reload() { +func (o *Hackers) Close() { + logger.Info("Closing hackers.git session") o.lock.Lock() defer o.lock.Unlock() - // TODO -} - -func NewHackers(yamlDir string) *Hackers { - // TODO - var hackers Hackers - - var lock sync.RWMutex - hackers.lock = &lock - go inotify_watcher(yamlDir) - - return &hackers + o.close() } -func inotify_watcher(yamlDir string) { - // TODO +func (o *Hackers) Reload() error { + logger.Info("Loading hackers.git session") + o.lock.Lock() + defer o.lock.Unlock() + + return o.reload() } diff --git a/src/nshd/hackers_git/hackers_parse.go b/src/nshd/hackers_git/hackers_parse.go new file mode 100644 index 0000000..efc30a5 --- /dev/null +++ b/src/nshd/hackers_git/hackers_parse.go @@ -0,0 +1,16 @@ +package hackers_git + +import ( + _ "gopkg.in/yaml.v2" + "nslcd_proto" +) + +func load_user_yaml(filename string) (nslcd_proto.Passwd, error) { + // TODO + return nslcd_proto.Passwd{}, nil +} + +func load_user_password(filename string) string { + // TODO + return "!" +} diff --git a/src/nshd/hackers_git/hackers_watch.go b/src/nshd/hackers_git/hackers_watch.go new file mode 100644 index 0000000..aec1f65 --- /dev/null +++ b/src/nshd/hackers_git/hackers_watch.go @@ -0,0 +1,187 @@ +package hackers_git + +import ( + "inotify" + p "nslcd_proto" + "os" + "path/filepath" + "sd_daemon/logger" +) + +const ( + in_CHILD_ADD = inotify.IN_CREATE | inotify.IN_MOVED_TO + in_CHILD_DEL = inotify.IN_DELETE | inotify.IN_MOVED_FROM + in_CHILD_MOD = inotify.IN_CLOSE_WRITE | inotify.IN_MOVED_TO + in_CHILD_ANY = in_CHILD_ADD | in_CHILD_DEL | in_CHILD_MOD + + in_DIR_INVALID = inotify.IN_MOVE_SELF | inotify.IN_DELETE_SELF + in_DIR = inotify.IN_ONLYDIR | in_DIR_INVALID +) + +func (o *Hackers) watchHomedir(uid int32) { + wd, err := o.in_fd.AddWatch(o.users[uid].HomeDir, in_DIR|in_CHILD_ANY) + if err == nil { + oldwd, found := o.in_uid2wd[uid] + if found && oldwd != wd { + o.unwatchHomedir(oldwd) + } + o.in_uid2wd[uid] = wd + o.in_wd2uid[wd] = uid + } else { + delete(o.in_uid2wd, uid) + logger.Info("could not watch: %s", o.users[uid].HomeDir) + } +} +func (o *Hackers) unwatchHomedir(wd inotify.Cint) { + err := o.in_fd.RmWatch(wd) + if err != nil { + logger.Warning("could not remove watch: %v", wd) + return + } + uid := o.in_wd2uid[wd] + delete(o.in_wd2uid, wd) + delete(o.in_uid2wd, uid) +} + +func NewHackers(config Config) *Hackers { + o := Hackers{ + cfg: config, + } + err := o.reload() + if err != nil { + return nil + } + go o.worker() + return &o +} + +func (o *Hackers) close() { + if o.in_fd != nil { + o.in_fd.Close() + o.in_fd = nil + } + o.in_wd_home = -1 + o.in_wd_yaml = -1 + o.users = make(map[int32]p.Passwd, 0) + o.in_uid2wd = make(map[int32]inotify.Cint, 0) + o.in_wd2uid = make(map[inotify.Cint]int32, 0) +} + +func (o *Hackers) reload() (err error) { + o.close() + o.in_fd, err = inotify.InotifyInit() ; if err != nil { return } + o.in_wd_home, err = o.in_fd.AddWatch("/home" , in_DIR|in_CHILD_ADD); if err != nil { return } + o.in_wd_yaml, err = o.in_fd.AddWatch(o.cfg.Yamldir, in_DIR|in_CHILD_ANY); if err != nil { return } + + files, err := filepath.Glob(o.cfg.Yamldir + "/*.yml") + o.users = make(map[int32]p.Passwd, len(files)) + o.in_uid2wd = make(map[int32]inotify.Cint, len(files)) + o.in_wd2uid = make(map[inotify.Cint]int32, len(files)) + for _, file := range files { + logger.Debug("Loading yaml file: %s", file) + user, err := load_user_yaml(file) + if err == nil { + o.users[user.UID] = user + logger.Debug("... success") + o.watchHomedir(user.UID) + o.passwords[user.UID] = load_user_password(user.HomeDir + "/.password") + } else { + logger.Debug("... error") + } + } + + err = nil + return +} + +func (o *Hackers) worker_handle_user_add(user p.Passwd) { + o.lock.Lock() + defer o.lock.Unlock() + + o.users[user.UID] = user + o.watchHomedir(user.UID) + o.passwords[user.UID] = load_user_password(user.HomeDir + "/.password") +} + +func (o *Hackers) worker_handle_user_del(uid int32) { + o.lock.Lock() + defer o.lock.Unlock() + + wd, found := o.in_uid2wd[uid] + if found { + o.unwatchHomedir(wd) + } + delete(o.users, uid) +} + +func (o *Hackers) worker_watch_homedirs() { + for uid, _ := range o.users { + o.watchHomedir(uid) + } +} + +func (o *Hackers) worker_handle_passwd(uid int32) { + o.lock.Lock() + defer o.lock.Unlock() + + o.passwords[uid] = load_user_password(o.users[uid].HomeDir + "/.password") +} + +func worker_error(format string, a ...interface{}) { + logger.Err(format, a) + os.Exit(255) +} + +func (o *Hackers) worker() { + err := os.Chdir(o.cfg.Yamldir) + if err != nil { + worker_error("failed to load %q: %v", o.cfg.Yamldir, err) + } + for event, _ := o.in_fd.Read(); event != nil; event, _ = o.in_fd.Read() { + switch event.Wd { + case o.in_wd_yaml: + // handle updates to yaml files + if event.Mask&in_DIR_INVALID != 0 { + err := o.Reload() + if err != nil { + worker_error("failed to reload hackers.git yaml directory: %v", err) + + } + err = os.Chdir(o.cfg.Yamldir) + if err != nil { + worker_error("failed to load %q: %v", o.cfg.Yamldir, err) + } + } else if event.Mask&in_CHILD_ANY != 0 { + user, err := load_user_yaml(*event.Name) + if err == nil { + // User added/updated + o.worker_handle_user_add(user) + } else if user.UID >= 0 { + // User became invalid + o.worker_handle_user_del(user.UID) + } + } else { + panic("recieved non-subscribed inotify event from kernel") + } + case o.in_wd_home: + if event.Mask&in_DIR_INVALID != 0 { + err := o.Reload() + if err != nil { + panic(err) + } + } else if event.Mask&inotify.IN_ISDIR != 0 { + // handle added home directory + o.worker_watch_homedirs() + } + default: + // handle a change to someone's password + if event.Mask&in_DIR_INVALID != 0 { + o.unwatchHomedir(event.Wd) + o.worker_watch_homedirs() + } else if *event.Name == ".password" { + o.worker_handle_passwd(o.in_wd2uid[event.Wd]) + } + } + } + panic("not reached") +} |