diff options
Diffstat (limited to 'src/nshd/hackers_git')
-rw-r--r-- | src/nshd/hackers_git/hackers.go | 50 | ||||
-rw-r--r-- | src/nshd/hackers_git/hackers_watch.go | 254 |
2 files changed, 38 insertions, 266 deletions
diff --git a/src/nshd/hackers_git/hackers.go b/src/nshd/hackers_git/hackers.go index 2e9edc1..b72698f 100644 --- a/src/nshd/hackers_git/hackers.go +++ b/src/nshd/hackers_git/hackers.go @@ -24,11 +24,11 @@ package hackers_git import ( - "lukeshu.com/git/go/libgnulinux.git/inotify" "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" ) @@ -44,18 +44,11 @@ type Config struct { type Hackers struct { nslcd_server.NilBackend - Cfg Config - lock sync.RWMutex - workers sync.WaitGroup + Cfg Config + lock sync.RWMutex users map[int32]user groups map[string]map[string]bool - - in_fd *inotify.Watcher - in_wd_home inotify.Wd - in_wd_yaml inotify.Wd - in_uid2wd map[int32]inotify.Wd - in_wd2uid map[inotify.Wd]int32 } var _ nslcd_systemd.Backend = &Hackers{} @@ -74,7 +67,9 @@ func (o *Hackers) Close() { logger.Info("hackers.git: Closing session") o.lock.Lock() defer o.lock.Unlock() - o.close() + + o.users = make(map[int32]user, 0) + o.groups = make(map[string]map[string]bool) } func (o *Hackers) Reload() error { @@ -82,7 +77,29 @@ func (o *Hackers) Reload() error { o.lock.Lock() defer o.lock.Unlock() - return o.reload() + 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 { @@ -93,3 +110,12 @@ func (o *Hackers) name2uid(name string) int32 { } 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_watch.go b/src/nshd/hackers_git/hackers_watch.go deleted file mode 100644 index dc5ecf4..0000000 --- a/src/nshd/hackers_git/hackers_watch.go +++ /dev/null @@ -1,254 +0,0 @@ -// 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/inotify" - "lukeshu.com/git/go/libsystemd.git/sd_daemon/logger" - "lukeshu.com/git/go/libsystemd.git/sd_daemon/lsb" - "os" - "path/filepath" -) - -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].passwd.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.Debug("hackers.git: %v", err) - } - o.load_user_password(uid) -} - -func (o *Hackers) unwatchHomedir(wd inotify.Wd) { - err := o.in_fd.RmWatch(wd) - if err != nil { - logger.Warning("hackers.git: %v", err) - return - } - uid := o.in_wd2uid[wd] - delete(o.in_wd2uid, wd) - delete(o.in_uid2wd, uid) - o.load_user_password(uid) -} - -func (o *Hackers) close() { - if o.in_fd != nil { - o.in_fd.Close() - defer o.workers.Wait() - } - o.in_wd_home = -1 - o.in_wd_yaml = -1 - o.users = make(map[int32]user, 0) - o.groups = make(map[string]map[string]bool) - o.in_uid2wd = make(map[int32]inotify.Wd, 0) - o.in_wd2uid = make(map[inotify.Wd]int32, 0) -} - -func (o *Hackers) reload() (err error) { - o.close() - o.in_fd, err = inotify.WatcherInit() ; 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 } - - filenames, err := filepath.Glob(o.Cfg.Yamldir + "/*.yml") - o.users = make(map[int32]user, len(filenames)) - o.groups = make(map[string]map[string]bool) - o.in_uid2wd = make(map[int32]inotify.Wd, len(filenames)) - o.in_wd2uid = make(map[inotify.Wd]int32, len(filenames)) - for _, filename := range filenames { - o.load_yaml_file(filename, false) - } - - go func() { - defer lsb.Recover() - defer o.workers.Done() - o.worker() - }() - - err = nil - return -} - -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 -} - -func (o *Hackers) del_user_from_group(username string, groupname string) { - group, found := o.groups[groupname] - if !found { - return - } - delete(group, username) - if len(group) < 1 { - delete(o.groups, groupname) - } -} - -func (o *Hackers) load_yaml_file(filename string, uselock bool) { - logger.Debug("hackers.git: Loading YAML file: %s", filename) - user, err := parse_user_yaml(filename) - uid := user.passwd.UID - if err == nil { - logger.Debug("hackers.git: -> User %d added/updated", uid) - if uselock { - o.lock.Lock() - defer o.lock.Unlock() - } - if olduser, found := o.users[uid]; found { - for _, groupname := range olduser.groups { - o.del_user_from_group(olduser.passwd.Name, groupname) - } - } - for _, groupname := range user.groups { - o.add_user_to_group(user.passwd.Name, groupname) - } - o.users[uid] = user - o.watchHomedir(uid) - } else if uid >= 0 { - // User became invalid - logger.Debug("hackers.git: -> User %d invalidated: %v", uid, err) - if uselock { - o.lock.Lock() - defer o.lock.Unlock() - } - if wd, found := o.in_uid2wd[uid]; found { - o.unwatchHomedir(wd) - } - if olduser, found := o.users[uid]; found { - for _, groupname := range olduser.groups { - o.del_user_from_group(olduser.passwd.Name, groupname) - } - delete(o.users, uid) - } - } else { - logger.Debug("hackers.git: -> File ignored: %v", err) - } -} - -func (o *Hackers) load_user_password(uid int32) { - user := o.users[uid] - user.passwd.PwHash = parse_user_password(user.passwd.HomeDir + "/.password") - o.users[uid] = user -} - -func (o *Hackers) worker_watch_homedirs() { - for uid, _ := range o.users { - o.watchHomedir(uid) - } -} - -func worker_error(format string, a ...interface{}) { - logger.Err("hackers.git: "+format, a) - os.Exit(int(lsb.EXIT_FAILURE)) -} - -func (o *Hackers) worker() { - err := os.Chdir(o.Cfg.Yamldir) - if err != nil { - worker_error("failed to load %q: %v", o.Cfg.Yamldir, err) - } -Loop: - for { - select { - case event, ok := <-o.in_fd.Events: - if !ok { - break Loop - } - 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 { - if event.Name == nil { - panic("recieved child event from inotify, but no child name") - } - o.load_yaml_file(o.Cfg.Yamldir+"/"+*event.Name, true) - } 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 != nil { - if *event.Name == ".password" { - func() { - o.lock.Lock() - defer o.lock.Unlock() - o.load_user_password(o.in_wd2uid[event.Wd]) - }() - } - } else { - logger.Debug("hackers.git: Event didn't match: %#v", event) - } - } - case err, ok := <-o.in_fd.Errors: - if !ok { - break Loop - } - logger.Warning("hackers.git: Inotify error: %v", err) - } - } - logger.Info("hackers.git: Stopped inotify watcher") -} |