mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-12 17:59:06 +02:00
111 lines
2.8 KiB
Go
111 lines
2.8 KiB
Go
//go:build (!cgo || osusergo) && !windows
|
|
|
|
package getent
|
|
|
|
import (
|
|
"os"
|
|
"os/user"
|
|
"strconv"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// Without cgo, os/user only reads /etc/passwd and /etc/group and misses
|
|
// NSS-provided users and groups; the getent and id commands go through the
|
|
// host's NSS stack.
|
|
|
|
// LookupUser looks up a user by name, falling back to getent if os/user fails.
|
|
func LookupUser(username string) (*user.User, error) {
|
|
u, err := user.Lookup(username)
|
|
if err == nil {
|
|
return u, nil
|
|
}
|
|
|
|
stdErr := err
|
|
log.Debugf("os/user.Lookup(%q) failed, trying getent: %v", username, err)
|
|
|
|
u, _, getentErr := passwdLookup(username)
|
|
if getentErr != nil {
|
|
log.Debugf("getent fallback for %q also failed: %v", username, getentErr)
|
|
return nil, stdErr
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
// LookupUserID looks up a user by UID, falling back to getent if os/user fails.
|
|
func LookupUserID(uid string) (*user.User, error) {
|
|
u, err := user.LookupId(uid)
|
|
if err == nil {
|
|
return u, nil
|
|
}
|
|
|
|
stdErr := err
|
|
log.Debugf("os/user.LookupId(%q) failed, trying getent: %v", uid, err)
|
|
|
|
u, _, getentErr := passwdLookup(uid)
|
|
if getentErr != nil {
|
|
log.Debugf("getent fallback for uid %s also failed: %v", uid, getentErr)
|
|
return nil, stdErr
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
// CurrentUser returns the user this process runs as, falling back to getent
|
|
// if os/user fails.
|
|
func CurrentUser() (*user.User, error) {
|
|
u, err := user.Current()
|
|
if err == nil {
|
|
return u, nil
|
|
}
|
|
|
|
stdErr := err
|
|
uid := strconv.Itoa(os.Getuid())
|
|
log.Debugf("os/user.Current() failed, trying getent with UID %s: %v", uid, err)
|
|
|
|
u, _, getentErr := passwdLookup(uid)
|
|
if getentErr != nil {
|
|
return nil, stdErr
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
// LookupGroupID looks up a group by GID, falling back to getent if os/user
|
|
// fails.
|
|
func LookupGroupID(gid string) (*user.Group, error) {
|
|
g, err := user.LookupGroupId(gid)
|
|
if err == nil {
|
|
return g, nil
|
|
}
|
|
|
|
stdErr := err
|
|
log.Debugf("os/user.LookupGroupId(%q) failed, trying getent: %v", gid, err)
|
|
|
|
g, _, getentErr := groupLookup(gid)
|
|
if getentErr != nil {
|
|
log.Debugf("getent fallback for gid %s also failed: %v", gid, getentErr)
|
|
return nil, stdErr
|
|
}
|
|
return g, nil
|
|
}
|
|
|
|
// GroupIDs returns the IDs of the groups the user is a member of.
|
|
// NOTE: unlike the lookups above, which try the standard library first, this
|
|
// intentionally tries `id -G` first because without cgo, user.GroupIds only
|
|
// reads /etc/group and silently returns incomplete results for NSS users
|
|
// (no error, just missing groups). The id command goes through NSS and
|
|
// returns the full set.
|
|
func GroupIDs(u *user.User) ([]string, error) {
|
|
ids, err := idGroups(u.Username)
|
|
if err == nil {
|
|
return ids, nil
|
|
}
|
|
|
|
log.Debugf("id -G %q failed, falling back to user.GroupIds(): %v", u.Username, err)
|
|
|
|
ids, stdErr := u.GroupIds()
|
|
if stdErr != nil {
|
|
return nil, stdErr
|
|
}
|
|
return ids, nil
|
|
}
|