util/osuser: extend id command fallback for group IDs to freebsd

Users on FreeBSD run into a similar problem as has been reported for
Linux #11682 and fixed in #11682: because the tailscaled binaries
that we distribute are static and don't link cgo tailscaled fails to
fetch group IDs that are returned via NSS when spawning an ssh child
process.

This change extends the fallback on the 'id' command that was put in
place as part of #11682 to FreeBSD. More precisely, we try to fetch
the group IDs with the 'id' command first, and only if that fails do
we fall back on the logic in the os/user package.

Updates #14025

Signed-off-by: Gesa Stupperich <gesa@tailscale.com>
main
Gesa Stupperich 1 month ago committed by Gesa Stupperich
parent e400d5aa7b
commit ac74dfa5cd
  1. 17
      util/osuser/group_ids.go
  2. 4
      util/osuser/group_ids_test.go

@ -23,7 +23,7 @@ func GetGroupIds(user *user.User) ([]string, error) {
return nil, nil
}
if runtime.GOOS != "linux" {
if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
return user.GroupIds()
}
@ -46,13 +46,24 @@ func getGroupIdsWithId(usernameOrUID string) ([]string, error) {
defer cancel()
cmd := exec.CommandContext(ctx, "id", "-Gz", usernameOrUID)
out, err := cmd.Output()
if runtime.GOOS == "freebsd" {
cmd = exec.CommandContext(ctx, "id", "-G", usernameOrUID)
}
out, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("running 'id' command: %w", err)
}
return parseGroupIds(out), nil
}
func parseGroupIds(cmdOutput []byte) []string {
return strings.Split(strings.Trim(string(cmdOutput), "\n\x00"), "\x00")
s := strings.TrimSpace(string(cmdOutput))
// Parse NUL-delimited output.
if strings.ContainsRune(s, '\x00') {
return strings.Split(strings.Trim(s, "\x00"), "\x00")
}
// Parse whitespace-delimited output.
return strings.Fields(s)
}

@ -15,7 +15,9 @@ func TestParseGroupIds(t *testing.T) {
}{
{"5000\x005001\n", []string{"5000", "5001"}},
{"5000\n", []string{"5000"}},
{"\n", []string{""}},
{"\n", []string{}},
{"5000 5001 5002\n", []string{"5000", "5001", "5002"}},
{"5000\t5001\n", []string{"5000", "5001"}},
}
for _, test := range tests {
actual := parseGroupIds([]byte(test.in))

Loading…
Cancel
Save