summaryrefslogtreecommitdiff
path: root/src
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
parent3c237531f5067340e34b01c7f7ea45fa55c39657 (diff)
implement hackers_watch
Diffstat (limited to 'src')
-rw-r--r--src/nshd/hackers_git/db_config.go4
-rw-r--r--src/nshd/hackers_git/hackers.go43
-rw-r--r--src/nshd/hackers_git/hackers_parse.go16
-rw-r--r--src/nshd/hackers_git/hackers_watch.go187
-rw-r--r--src/nshd/main.go11
-rw-r--r--src/nslcd_systemd/nslcd_systemd.go8
6 files changed, 244 insertions, 25 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")
+}
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
}