drive/driveimpl: use su instead of sudo

This allows Taildrive to work on systems like Busybox that don't have sudo.

Fixes #12282

Signed-off-by: Percy Wegmann <percy@tailscale.com>
pull/13323/head
Percy Wegmann 3 weeks ago committed by Percy Wegmann
parent 45c97751fb
commit 35423fcf69

@ -333,11 +333,15 @@ func (s *userServer) run() error {
args = append(args, s.Name, s.Path) args = append(args, s.Name, s.Path)
} }
var cmd *exec.Cmd var cmd *exec.Cmd
if s.canSudo() { if su := s.canSU(); su != "" {
s.logf("starting taildrive file server as user %q", s.username) s.logf("starting taildrive file server as user %q", s.username)
allArgs := []string{"-n", "-u", s.username, s.executable} // Quote and escape arguments. Use single quotes to prevent shell substitutions.
allArgs = append(allArgs, args...) for i, arg := range args {
cmd = exec.Command("sudo", allArgs...) args[i] = "'" + strings.ReplaceAll(arg, "'", "'\"'\"'") + "'"
}
cmdString := fmt.Sprintf("%s %s", s.executable, strings.Join(args, " "))
allArgs := []string{s.username, "-c", cmdString}
cmd = exec.Command(su, allArgs...)
} else { } else {
// If we were root, we should have been able to sudo as a specific // If we were root, we should have been able to sudo as a specific
// user, but let's check just to make sure, since we never want to // user, but let's check just to make sure, since we never want to
@ -405,16 +409,28 @@ var writeMethods = map[string]bool{
"DELETE": true, "DELETE": true,
} }
// canSudo checks wether we can sudo -u the configured executable as the // canSU checks whether the current process can run su with the right username.
// configured user by attempting to call the executable with the '-h' flag to // If su can be run, this returns the path to the su command.
// print help. // If not, this returns the empty string "".
func (s *userServer) canSudo() bool { func (s *userServer) canSU() string {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) su, err := exec.LookPath("su")
defer cancel() if err != nil {
if err := exec.CommandContext(ctx, "sudo", "-n", "-u", s.username, s.executable, "-h").Run(); err != nil { s.logf("can't find su command: %v", err)
return false return ""
}
// First try to execute su <user> -c true to make sure we can su.
err = exec.Command(
su,
s.username,
"-c", "true",
).Run()
if err != nil {
s.logf("su check failed: %s", err)
return ""
} }
return true
return su
} }
// assertNotRoot returns an error if the current user has UID 0 or if we cannot // assertNotRoot returns an error if the current user has UID 0 or if we cannot

Loading…
Cancel
Save