func lookupPasswd(uid int, username string, lookupByName bool) (*user.User, error) { f, err := os.Open(UserDatabase) if err != nil { return nil, err } defer f.Close() exist := false p := &PasswdRecord{} scanner := bufio.NewScanner(f) for scanner.Scan() { fields := strings.SplitN(scanner.Text(), ":", 7) if strings.HasPrefix(fields[0], "#") { continue } if len(fields) < 7 { return nil, InvalidUserDatabaseError } p = &PasswdRecord{fields[0], fields[1], fields[2], fields[3], fields[4], fields[5], fields[6]} if lookupByName { if username == p.Name { exist = true break } } else { if strconv.Itoa(uid) == p.Uid { exist = true break } } } if !exist { if lookupByName { return nil, user.UnknownUserError(username) } else { return nil, user.UnknownUserIdError(uid) } } u := &user.User{ Username: p.Name, Uid: p.Uid, Gid: p.Gid, Name: p.Gecos, HomeDir: p.Directory, } // The gecos field isn't quite standardized. Some docs // say: "It is expected to be a comma separated list of // personal data where the first item is the full name of the // user." if i := strings.Index(u.Name, ","); i >= 0 { u.Name = u.Name[:i] } return u, nil }
func Lookup(username string, users []*User) (*User, error) { if users == nil { var err error users, err = AllUsers() if err != nil { return nil, err } } for _, user := range users { if user.Username == username { return user, nil } } return nil, osuser.UnknownUserError(username) }
// EtcPasswdLookup looks up a user by username. If the user cannot be // found, the returned error is of type user.UnknownUserError. This // differs from os/user.Lookup by parsing /etc/password directly, so // it doesn't need cgo support. func EtcPasswdLookup(username string) (*user.User, error) { usernamePrefix := []byte(username) usernamePrefix = append(usernamePrefix, ':') etcPasswd, err := ioutil.ReadFile("/etc/passwd") if err != nil { return nil, err } passwdReader := bufio.NewReader(bytes.NewReader(etcPasswd)) for { l, isPrefix, err := passwdReader.ReadLine() if err != nil { if err == io.EOF { break } return nil, err } if isPrefix { return nil, fmt.Errorf("passwd: line too long: '%s'", l) } if !bytes.HasPrefix(l, usernamePrefix) { continue } fields := strings.Split(string(l), ":") if len(fields) != 7 { log.Printf("/etc/passwd: wrong num fields (%d): %s\n", len(fields), string(l)) continue } // The pw_gecos field isn't standardized. Some docs // say: "It is expected to be a comma separated list // of personal data where the first item is the full // name of the user." fullName := strings.SplitN(fields[fieldGecos], ",", 2)[0] return &user.User{ Uid: fields[fieldUid], Gid: fields[fieldGid], Username: fields[fieldUsername], Name: fullName, HomeDir: fields[fieldHomeDir], }, nil } return nil, user.UnknownUserError(username) }
func lookupDscl(uid int, username string, lookupByName bool) (*user.User, error) { dscl := exec.Command("/usr/bin/dscl", ".", "-list", "users", "uid") dsclbuf, err := dscl.StdoutPipe() if err != nil { return nil, err } if err = dscl.Start(); err != nil { return nil, err } name := "" id := "" exist := false scanner := bufio.NewScanner(dsclbuf) for scanner.Scan() { scannerWord := bufio.NewScanner(bytes.NewReader(scanner.Bytes())) scannerWord.Split(bufio.ScanWords) scannerWord.Scan() name = scannerWord.Text() scannerWord.Scan() id = scannerWord.Text() if lookupByName { if username != name && "_"+username != name { continue } } else { if strconv.Itoa(uid) != id { continue } } dscl = exec.Command("/usr/bin/dscl", "-plist", ".", "-read", "users/"+name) dsclbuf, err = dscl.StdoutPipe() if err != nil { return nil, err } if err = dscl.Start(); err != nil { return nil, err } var uplist userplist buf, err := ioutil.ReadAll(dsclbuf) if err != nil { return nil, err } _, err = plist.Unmarshal(buf, &uplist) if err != nil { return nil, err } exist = true if name[0] == '_' { name = name[1:] } u := &user.User{ Username: name, Uid: id, Gid: uplist.Gid[0], Name: uplist.Name[0], HomeDir: uplist.HomeDir[0], } return u, nil } if !exist { if lookupByName { return nil, user.UnknownUserError(username) } else { return nil, user.UnknownUserIdError(uid) } } return nil, InvalidUserDatabaseError }