From b55355121e0ed259097254447f16739b0f3da61d Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Fri, 28 Aug 2015 20:43:12 -0600 Subject: implement hackers_watch --- src/nshd/hackers_git/db_config.go | 4 +- src/nshd/hackers_git/hackers.go | 43 ++++---- src/nshd/hackers_git/hackers_parse.go | 16 +++ src/nshd/hackers_git/hackers_watch.go | 187 ++++++++++++++++++++++++++++++++++ src/nshd/main.go | 11 +- src/nslcd_systemd/nslcd_systemd.go | 8 +- 6 files changed, 244 insertions(+), 25 deletions(-) create mode 100644 src/nshd/hackers_git/hackers_parse.go create mode 100644 src/nshd/hackers_git/hackers_watch.go (limited to 'src') 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") +} diff --git a/src/nshd/main.go b/src/nshd/main.go index d31160f..ac49eaa 100644 --- a/src/nshd/main.go +++ b/src/nshd/main.go @@ -3,9 +3,16 @@ package main import ( "nshd/hackers_git" "nslcd_systemd" + "os" ) func main() { - backend := hackers_git.NewHackers("/var/cache/parabola-hackers/users") - nslcd_systemd.Main(backend) + config := hackers_git.Config{ + Pam_password_prohibit_message: "", + Yamldir: "/var/cache/parabola-hackers/users", + } + backend := hackers_git.NewHackers(config) + ret := nslcd_systemd.Main(backend) + backend.Close() + os.Exit(ret) } diff --git a/src/nslcd_systemd/nslcd_systemd.go b/src/nslcd_systemd/nslcd_systemd.go index 9868581..3d87310 100644 --- a/src/nslcd_systemd/nslcd_systemd.go +++ b/src/nslcd_systemd/nslcd_systemd.go @@ -14,7 +14,7 @@ import ( type Backend interface { nslcd_proto.Backend - Reload() + Reload() error } func get_socket() (socket net.Listener, err error) { @@ -60,7 +60,7 @@ func handler(conn *net.UnixConn, backend nslcd_proto.Backend) { } } -func Main(backend Backend) { +func Main(backend Backend) int { var err error = nil var socket net.Listener = nil defer func() { @@ -73,7 +73,7 @@ func Main(backend Backend) { if err != nil { logger.Err("%s", err.Error()) sd.Notify(false, "STOPPING=1") - os.Exit(1) + return 1 } sigs := make(chan os.Signal, 1) @@ -115,5 +115,5 @@ Loop: } wg.Wait() - os.Exit(0) + return 0 } -- cgit v1.2.2