mirror of
https://github.com/tailscale/tailscale.git
synced 2026-03-28 19:21:13 -04:00
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>
70 lines
1.7 KiB
Go
70 lines
1.7 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package osuser
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os/exec"
|
|
"os/user"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
|
|
"tailscale.com/version/distro"
|
|
)
|
|
|
|
// GetGroupIds returns the list of group IDs that the user is a member of, or
|
|
// an error. It will first try to use the 'id' command to get the group IDs,
|
|
// and if that fails, it will fall back to the user.GroupIds method.
|
|
func GetGroupIds(user *user.User) ([]string, error) {
|
|
if runtime.GOOS == "plan9" {
|
|
return nil, nil
|
|
}
|
|
|
|
if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
|
|
return user.GroupIds()
|
|
}
|
|
|
|
if distro.Get() == distro.Gokrazy {
|
|
// Gokrazy is a single-user appliance with ~no userspace.
|
|
// There aren't users to look up (no /etc/passwd, etc)
|
|
// so rather than fail below, just hardcode root.
|
|
// TODO(bradfitz): fix os/user upstream instead?
|
|
return []string{"0"}, nil
|
|
}
|
|
|
|
if ids, err := getGroupIdsWithId(user.Username); err == nil {
|
|
return ids, nil
|
|
}
|
|
return user.GroupIds()
|
|
}
|
|
|
|
func getGroupIdsWithId(usernameOrUID string) ([]string, error) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
cmd := exec.CommandContext(ctx, "id", "-Gz", usernameOrUID)
|
|
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 {
|
|
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)
|
|
}
|