// 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 }