From 84dbb723d5bc4119b336ed3444a243063b1e959c Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sat, 4 Feb 2017 17:56:49 -0500 Subject: nshd: Centralize all config-var substitutions into a `paths.go`. I'm tired of accidentally editing the wrong file. --- Makefile | 13 +-- go/src/nshd/.gitignore | 1 - go/src/nshd/main.go | 35 ++++++++ go/src/nshd/main.go.in | 34 -------- go/src/nshd/nshd_files/.gitignore | 3 +- go/src/nshd/nshd_files/passwords.go | 95 ++++++++++++++++++++++ go/src/nshd/nshd_files/passwords.go.in | 97 ---------------------- go/src/nshd/nshd_files/paths.go.in | 7 ++ go/src/nshd/nshd_files/users.go | 143 +++++++++++++++++++++++++++++++++ go/src/nshd/nshd_files/users.go.in | 143 --------------------------------- 10 files changed, 284 insertions(+), 287 deletions(-) delete mode 100644 go/src/nshd/.gitignore create mode 100644 go/src/nshd/main.go delete mode 100644 go/src/nshd/main.go.in create mode 100644 go/src/nshd/nshd_files/passwords.go delete mode 100644 go/src/nshd/nshd_files/passwords.go.in create mode 100644 go/src/nshd/nshd_files/paths.go.in create mode 100644 go/src/nshd/nshd_files/users.go delete mode 100644 go/src/nshd/nshd_files/users.go.in diff --git a/Makefile b/Makefile index f1839b1..670d5ba 100644 --- a/Makefile +++ b/Makefile @@ -85,16 +85,9 @@ $(outdir)/nshd.service: $(var.)user $(var.)bindir $(outdir)/nshd.sysusers: $(var.)user $(outdir)/bin/common.rb: $(var.)conf_file -$(outdir)/go/src/nshd/main.go: $(var.)conf_file -$(outdir)/go/src/nshd/nshd_files/users.go: $(var.)bindir -$(outdir)/go/src/nshd/nshd_files/passwords.go: $(var.)shadow_file - -goconf = \ - $(outdir)/go/src/nshd/main.go \ - $(outdir)/go/src/nshd/nshd_files/users.go \ - $(outdir)/go/src/nshd/nshd_files/passwords.go -$(outdir)/go/bin/nshd: $(goconf) $(outdir)/$(files.generate) -files.out.all += $(goconf) +$(outdir)/go/src/nshd/nshd_files/paths.go: $(var.)bindir $(var.)conf_file $(var.)shadow_file +$(outdir)/go/bin/nshd: go-generate $(outdir)/go/src/nshd/nshd_files/paths.go +files.out.all += $(outdir)/go/src/nshd/nshd_files/paths.go # Install diff --git a/go/src/nshd/.gitignore b/go/src/nshd/.gitignore deleted file mode 100644 index 00870e2..0000000 --- a/go/src/nshd/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/main.go diff --git a/go/src/nshd/main.go b/go/src/nshd/main.go new file mode 100644 index 0000000..2c94382 --- /dev/null +++ b/go/src/nshd/main.go @@ -0,0 +1,35 @@ +// Copyright 2015-2017 Luke Shumaker . +// +// 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. +// +// 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 +// . + +// Command nshd is an implementation of nslcd that talks to +// hackers.git instead of LDAP. +package main + +import ( + "os" + + "nshd/nshd_files" + "nshd/nslcd_backend" + + "git.lukeshu.com/go/libnslcd/nslcd_systemd" +) + +func main() { + backend := &nslcd_backend.Hackers{ + CfgFilename: nshd_files.ConfFile, + } + os.Exit(int(nslcd_systemd.Main(backend))) +} diff --git a/go/src/nshd/main.go.in b/go/src/nshd/main.go.in deleted file mode 100644 index 17e65ca..0000000 --- a/go/src/nshd/main.go.in +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015-2016 Luke Shumaker . -// -// 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. -// -// 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 -// . - -// Command nshd is an implementation of nslcd that talks to -// hackers.git instead of LDAP. -package main - -import ( - "os" - - "nshd/nslcd_backend" - - "git.lukeshu.com/go/libnslcd/nslcd_systemd" -) - -func main() { - backend := &nslcd_backend.Hackers{ - CfgFilename: "@conf_file@", - } - os.Exit(int(nslcd_systemd.Main(backend))) -} diff --git a/go/src/nshd/nshd_files/.gitignore b/go/src/nshd/nshd_files/.gitignore index 3be3f08..12de2b2 100644 --- a/go/src/nshd/nshd_files/.gitignore +++ b/go/src/nshd/nshd_files/.gitignore @@ -1,2 +1 @@ -/users.go -/passwords.go +/paths.go diff --git a/go/src/nshd/nshd_files/passwords.go b/go/src/nshd/nshd_files/passwords.go new file mode 100644 index 0000000..61c9e2b --- /dev/null +++ b/go/src/nshd/nshd_files/passwords.go @@ -0,0 +1,95 @@ +// Copyright 2015-2016 Luke Shumaker . +// +// 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. +// +// 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 +// . + +package nshd_files + +import ( + "fmt" + "io/ioutil" + "os" + "sort" + "strings" + + "git.lukeshu.com/go/libgnulinux/crypt" + "git.lukeshu.com/go/libsystemd/sd_daemon" +) + +/* Note that the password hash value should be one of: + - no password set, allow login without password + ! - used to prevent logins + x - "valid" encrypted password that does not match any valid password + often used to indicate that the password is defined elsewhere + other - encrypted password, in crypt(3) format */ + +func LoadAllPasswords() (map[string]string, error) { + file, err := os.Open(ShadowFile) + if err != nil { + return nil, err + } + contents, err := ioutil.ReadAll(file) + if err != nil { + return nil, err + } + lines := strings.Split(string(contents), "\n") + passwords := make(map[string]string, len(lines)) + for i, line := range lines { + if line == "" { + continue + } + cols := strings.SplitN(line, ":", 2) + if len(cols) != 2 { + sd_daemon.Log.Err(fmt.Sprintf("hackers.git %s:%d: malformed line", ShadowFile, i+1)) + continue + } + username := cols[0] + hash := cols[1] + if hash != "!" && !crypt.SaltOk(hash) { + hash = "!" + sd_daemon.Log.Err(fmt.Sprintf("%s:%d: malformed hash for user: %s", ShadowFile, i+1, username)) + } + passwords[username] = hash + } + return passwords, nil +} + +func SaveAllPasswords(passwords map[string]string) error { + usernames := make([]string, len(passwords)) + i := 0 + for username, _ := range passwords { + usernames[i] = username + i++ + } + sort.Strings(usernames) + + file, err := os.OpenFile(ShadowFile+"-", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) + if err != nil { + return err + } + + for _, username := range usernames { + fmt.Fprintf(file, "%s:%s\n", username, passwords[username]) + } + err = file.Sync() + if err != nil { + return err + } + err = file.Close() + if err != nil { + return err + } + + return os.Rename(ShadowFile+"-", ShadowFile) +} diff --git a/go/src/nshd/nshd_files/passwords.go.in b/go/src/nshd/nshd_files/passwords.go.in deleted file mode 100644 index 679f7c0..0000000 --- a/go/src/nshd/nshd_files/passwords.go.in +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015-2016 Luke Shumaker . -// -// 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. -// -// 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 -// . - -package nshd_files - -import ( - "fmt" - "io/ioutil" - "os" - "sort" - "strings" - - "git.lukeshu.com/go/libgnulinux/crypt" - "git.lukeshu.com/go/libsystemd/sd_daemon" -) - -/* Note that the password hash value should be one of: - - no password set, allow login without password - ! - used to prevent logins - x - "valid" encrypted password that does not match any valid password - often used to indicate that the password is defined elsewhere - other - encrypted password, in crypt(3) format */ - -const shadow_file = "@shadow_file@" - -func LoadAllPasswords() (map[string]string, error) { - file, err := os.Open(shadow_file) - if err != nil { - return nil, err - } - contents, err := ioutil.ReadAll(file) - if err != nil { - return nil, err - } - lines := strings.Split(string(contents), "\n") - passwords := make(map[string]string, len(lines)) - for i, line := range lines { - if line == "" { - continue - } - cols := strings.SplitN(line, ":", 2) - if len(cols) != 2 { - sd_daemon.Log.Err(fmt.Sprintf("hackers.git %s:%d: malformed line", shadow_file, i+1)) - continue - } - username := cols[0] - hash := cols[1] - if hash != "!" && !crypt.SaltOk(hash) { - hash = "!" - sd_daemon.Log.Err(fmt.Sprintf("%s:%d: malformed hash for user: %s", shadow_file, i+1, username)) - } - passwords[username] = hash - } - return passwords, nil -} - -func SaveAllPasswords(passwords map[string]string) error { - usernames := make([]string, len(passwords)) - i := 0 - for username, _ := range passwords { - usernames[i] = username - i++ - } - sort.Strings(usernames) - - file, err := os.OpenFile(shadow_file+"-", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) - if err != nil { - return err - } - - for _, username := range usernames { - fmt.Fprintf(file, "%s:%s\n", username, passwords[username]) - } - err = file.Sync() - if err != nil { - return err - } - err = file.Close() - if err != nil { - return err - } - - return os.Rename(shadow_file+"-", shadow_file) -} diff --git a/go/src/nshd/nshd_files/paths.go.in b/go/src/nshd/nshd_files/paths.go.in new file mode 100644 index 0000000..652a37b --- /dev/null +++ b/go/src/nshd/nshd_files/paths.go.in @@ -0,0 +1,7 @@ +package nshd_files + +const ( + ConfFile = "@conf_file@" + ShadowFile = "@shadow_file@" + BinDir = "@bindir@" +) diff --git a/go/src/nshd/nshd_files/users.go b/go/src/nshd/nshd_files/users.go new file mode 100644 index 0000000..4fd3cd1 --- /dev/null +++ b/go/src/nshd/nshd_files/users.go @@ -0,0 +1,143 @@ +// Copyright 2015-2016 Luke Shumaker . +// +// 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. +// +// 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 +// . + +package nshd_files + +import ( + "fmt" + "os/exec" + + "nshd/util" + + yaml "gopkg.in/yaml.v2" + p "git.lukeshu.com/go/libnslcd/nslcd_proto" + "git.lukeshu.com/go/libsystemd/sd_daemon" +) + +/* Note that the password hash value should be one of: + - no password set, allow login without password + ! - used to prevent logins + x - "valid" encrypted password that does not match any valid password + often used to indicate that the password is defined elsewhere + other - encrypted password, in crypt(3) format */ + +type User struct { + Passwd p.Passwd + Groups []string +} + +func LoadAllUsers() (users map[int32]User, err error) { + contents, err := exec.Command(BinDir + "/meta-cat").Output() + if err != nil { + return + } + + var _data interface{} + err = yaml.Unmarshal(contents, &_data) + if err != nil { + return + } + + data, isMap := _data.(map[interface{}]interface{}) + errs := []string{} + if !isMap { + errs = append(errs, "root node is not a map") + } else { + users = make(map[int32]User, len(data)) + for _uid, _user := range data { + uid, isInt := _uid.(int) + if !isInt { + errs = append(errs, fmt.Sprintf("UID is not an int: %T ( %#v )", _uid, _uid)) + continue + } + user, _err := parseUser(_user) + if _err != nil { + errs = append(errs, fmt.Sprintf("Could not parse data for UID %d: %v", uid, _err)) + continue + } + user.Passwd.UID = int32(uid) + sd_daemon.Log.Debug(fmt.Sprintf("hackers.git: -> User %d(%s) parsed", user.Passwd.UID, user.Passwd.Name)) + users[user.Passwd.UID] = user + } + } + if len(errs) > 0 { + users = nil + err = &yaml.TypeError{Errors: errs} + } + return +} + +func parseUser(_data interface{}) (ret User, err error) { + data, isMap := _data.(map[interface{}]interface{}) + errs := []string{} + if !isMap { + errs = append(errs, "root node is not a map") + } else { + if iface, isSet := data["username"]; !isSet { + errs = append(errs, "\"username\" is not set") + } else if str, isTyp := iface.(string); !isTyp { + errs = append(errs, "\"username\" is not a string") + } else { + ret.Passwd.Name = str + ret.Passwd.HomeDir = "/home/" + str + } + + if iface, isSet := data["fullname"]; !isSet { + errs = append(errs, "\"fullname\" is not set") + } else if str, isTyp := iface.(string); !isTyp { + errs = append(errs, "\"fullname\" is not a string") + } else { + ret.Passwd.GECOS = str + } + + if iface, isSet := data["shell"]; !isSet { + errs = append(errs, "\"shell\" is not set") + } else if str, isTyp := iface.(string); !isTyp { + errs = append(errs, "\"shell\" is not a string") + } else { + ret.Passwd.Shell = str + } + + if iface, isSet := data["groups"]; !isSet { + ret.Groups = make([]string, 0) + } else if ary, isTyp := iface.([]interface{}); !isTyp { + errs = append(errs, "\"groups\" is not an array") + } else { + groups := make(map[string]bool, len(ary)) + e := false + for _, iface := range ary { + if str, isTyp := iface.(string); !isTyp { + errs = append(errs, "\"group\" item is not an array") + e = true + break + } else { + groups[str] = true + } + } + if !e { + ret.Groups = util.Set2list(groups) + } + } + } + if len(errs) > 0 { + err = &yaml.TypeError{Errors: errs} + } + + ret.Passwd.PwHash = string("x") // look in shadow for the password hash + ret.Passwd.GID = -1 + + return +} diff --git a/go/src/nshd/nshd_files/users.go.in b/go/src/nshd/nshd_files/users.go.in deleted file mode 100644 index 51703fd..0000000 --- a/go/src/nshd/nshd_files/users.go.in +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2015-2016 Luke Shumaker . -// -// 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. -// -// 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 -// . - -package nshd_files - -import ( - "fmt" - "os/exec" - - "nshd/util" - - yaml "gopkg.in/yaml.v2" - p "git.lukeshu.com/go/libnslcd/nslcd_proto" - "git.lukeshu.com/go/libsystemd/sd_daemon" -) - -/* Note that the password hash value should be one of: - - no password set, allow login without password - ! - used to prevent logins - x - "valid" encrypted password that does not match any valid password - often used to indicate that the password is defined elsewhere - other - encrypted password, in crypt(3) format */ - -type User struct { - Passwd p.Passwd - Groups []string -} - -func LoadAllUsers() (users map[int32]User, err error) { - contents, err := exec.Command("@bindir@/meta-cat").Output() - if err != nil { - return - } - - var _data interface{} - err = yaml.Unmarshal(contents, &_data) - if err != nil { - return - } - - data, isMap := _data.(map[interface{}]interface{}) - errs := []string{} - if !isMap { - errs = append(errs, "root node is not a map") - } else { - users = make(map[int32]User, len(data)) - for _uid, _user := range data { - uid, isInt := _uid.(int) - if !isInt { - errs = append(errs, fmt.Sprintf("UID is not an int: %T ( %#v )", _uid, _uid)) - continue - } - user, _err := parseUser(_user) - if _err != nil { - errs = append(errs, fmt.Sprintf("Could not parse data for UID %d: %v", uid, _err)) - continue - } - user.Passwd.UID = int32(uid) - sd_daemon.Log.Debug(fmt.Sprintf("hackers.git: -> User %d(%s) parsed", user.Passwd.UID, user.Passwd.Name)) - users[user.Passwd.UID] = user - } - } - if len(errs) > 0 { - users = nil - err = &yaml.TypeError{Errors: errs} - } - return -} - -func parseUser(_data interface{}) (ret User, err error) { - data, isMap := _data.(map[interface{}]interface{}) - errs := []string{} - if !isMap { - errs = append(errs, "root node is not a map") - } else { - if iface, isSet := data["username"]; !isSet { - errs = append(errs, "\"username\" is not set") - } else if str, isTyp := iface.(string); !isTyp { - errs = append(errs, "\"username\" is not a string") - } else { - ret.Passwd.Name = str - ret.Passwd.HomeDir = "/home/" + str - } - - if iface, isSet := data["fullname"]; !isSet { - errs = append(errs, "\"fullname\" is not set") - } else if str, isTyp := iface.(string); !isTyp { - errs = append(errs, "\"fullname\" is not a string") - } else { - ret.Passwd.GECOS = str - } - - if iface, isSet := data["shell"]; !isSet { - errs = append(errs, "\"shell\" is not set") - } else if str, isTyp := iface.(string); !isTyp { - errs = append(errs, "\"shell\" is not a string") - } else { - ret.Passwd.Shell = str - } - - if iface, isSet := data["groups"]; !isSet { - ret.Groups = make([]string, 0) - } else if ary, isTyp := iface.([]interface{}); !isTyp { - errs = append(errs, "\"groups\" is not an array") - } else { - groups := make(map[string]bool, len(ary)) - e := false - for _, iface := range ary { - if str, isTyp := iface.(string); !isTyp { - errs = append(errs, "\"group\" item is not an array") - e = true - break - } else { - groups[str] = true - } - } - if !e { - ret.Groups = util.Set2list(groups) - } - } - } - if len(errs) > 0 { - err = &yaml.TypeError{Errors: errs} - } - - ret.Passwd.PwHash = string("x") // look in shadow for the password hash - ret.Passwd.GID = -1 - - return -} -- cgit v1.2.2