summaryrefslogtreecommitdiff
path: root/src/nshd/hackers_git/hackers_watch.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2015-08-28 20:43:12 -0600
committerLuke Shumaker <lukeshu@sbcglobal.net>2015-08-28 20:43:12 -0600
commitb55355121e0ed259097254447f16739b0f3da61d (patch)
tree3149a5cfe50952e9a3ea6c9a9e888b3da72dbfff /src/nshd/hackers_git/hackers_watch.go
parent3c237531f5067340e34b01c7f7ea45fa55c39657 (diff)
implement hackers_watch
Diffstat (limited to 'src/nshd/hackers_git/hackers_watch.go')
-rw-r--r--src/nshd/hackers_git/hackers_watch.go187
1 files changed, 187 insertions, 0 deletions
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")
+}