From ff729f67553e3406b9f00ec7da73ef24807e44db Mon Sep 17 00:00:00 2001 From: Maycon Santos Date: Thu, 7 Jul 2022 16:13:46 +0200 Subject: [PATCH] Use id command for user lookup on MacOS (#384) When building client without CGO, user.Lookup attempts to get user from /etc/passwd Which doesn't have the user as MacOS uses opendirectoryd as user directory --- client/ssh/lookup.go | 10 ++++++++ client/ssh/lookup_darwin.go | 47 +++++++++++++++++++++++++++++++++++++ client/ssh/server.go | 2 +- 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 client/ssh/lookup.go create mode 100644 client/ssh/lookup_darwin.go diff --git a/client/ssh/lookup.go b/client/ssh/lookup.go new file mode 100644 index 000000000..7acef8f0b --- /dev/null +++ b/client/ssh/lookup.go @@ -0,0 +1,10 @@ +//go:build !darwin +// +build !darwin + +package ssh + +import "os/user" + +func userNameLookup(username string) (*user.User, error) { + return user.Lookup(username) +} diff --git a/client/ssh/lookup_darwin.go b/client/ssh/lookup_darwin.go new file mode 100644 index 000000000..e6f3c3b93 --- /dev/null +++ b/client/ssh/lookup_darwin.go @@ -0,0 +1,47 @@ +//go:build darwin +// +build darwin + +package ssh + +import ( + "bytes" + "fmt" + "os/exec" + "os/user" + "strings" +) + +func userNameLookup(username string) (*user.User, error) { + var userObject *user.User + userObject, err := user.Lookup(username) + if err != nil && err.Error() == user.UnknownUserError(username).Error() { + return idUserNameLookup(username) + } else if err != nil { + return nil, err + } + + return userObject, nil +} + +func idUserNameLookup(username string) (*user.User, error) { + cmd := exec.Command("id", "-P", username) + out, err := cmd.CombinedOutput() + if err != nil { + return nil, fmt.Errorf("error while retrieving user with id -P command, error: %v", err) + } + colon := ":" + + if !bytes.Contains(out, []byte(username+colon)) { + return nil, fmt.Errorf("unable to find user in returned string") + } + // netbird:********:501:20::0:0:netbird:/Users/netbird:/bin/zsh + parts := strings.SplitN(string(out), colon, 10) + userObject := &user.User{ + Username: parts[0], + Uid: parts[2], + Gid: parts[3], + Name: parts[7], + HomeDir: parts[8], + } + return userObject, nil +} diff --git a/client/ssh/server.go b/client/ssh/server.go index 70f13e7c4..5d63362b9 100644 --- a/client/ssh/server.go +++ b/client/ssh/server.go @@ -137,7 +137,7 @@ func (srv *DefaultServer) sessionHandler(session ssh.Session) { } }() - localUser, err := user.Lookup(session.User()) + localUser, err := userNameLookup(session.User()) if err != nil { _, err = fmt.Fprintf(session, "remote SSH server couldn't find local user %s\n", session.User()) //nolint err = session.Exit(1)