From aa6a2d1e56a58c9e800b81701fa4636f85c9982a Mon Sep 17 00:00:00 2001 From: Percy Wegmann Date: Tue, 29 Jul 2025 09:11:36 -0500 Subject: [PATCH] drive/driveimpl: use sudo or su to run file server Some systems have `sudo`, some have `su`. This tries both, increasing the chance that we can run the file server as an unprivileged user. Updates #14629 Signed-off-by: Percy Wegmann --- drive/driveimpl/remote_impl.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drive/driveimpl/remote_impl.go b/drive/driveimpl/remote_impl.go index 7fd5d3325..2ff98075e 100644 --- a/drive/driveimpl/remote_impl.go +++ b/drive/driveimpl/remote_impl.go @@ -333,8 +333,14 @@ func (s *userServer) run() error { args = append(args, s.Name, s.Path) } var cmd *exec.Cmd - if su := s.canSU(); su != "" { - s.logf("starting taildrive file server as user %q", s.username) + + if s.canSudo() { + s.logf("starting taildrive file server with sudo as user %q", s.username) + allArgs := []string{"-n", "-u", s.username, s.executable} + allArgs = append(allArgs, args...) + cmd = exec.Command("sudo", allArgs...) + } else if su := s.canSU(); su != "" { + s.logf("starting taildrive file server with su as user %q", s.username) // Quote and escape arguments. Use single quotes to prevent shell substitutions. for i, arg := range args { args[i] = "'" + strings.ReplaceAll(arg, "'", "'\"'\"'") + "'" @@ -343,7 +349,7 @@ func (s *userServer) run() error { allArgs := []string{s.username, "-c", cmdString} cmd = exec.Command(su, allArgs...) } 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 or su as a specific // user, but let's check just to make sure, since we never want to // access shared folders as root. err := s.assertNotRoot() @@ -409,6 +415,18 @@ func (s *userServer) run() error { "DELETE": true, } +// canSudo checks wether we can sudo -u the configured executable as the +// configured user by attempting to call the executable with the '-h' flag to +// print help. +func (s *userServer) canSudo() bool { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + if err := exec.CommandContext(ctx, "sudo", "-n", "-u", s.username, s.executable, "-h").Run(); err != nil { + return false + } + return true +} + // canSU checks whether the current process can run su with the right username. // If su can be run, this returns the path to the su command. // If not, this returns the empty string "".