From aaf263957b09953ffd3ca7277bd61705e15e1c9b Mon Sep 17 00:00:00 2001 From: state-plumber <273540141+state-plumber@users.noreply.github.com> Date: Tue, 12 May 2026 20:39:55 +0000 Subject: [PATCH] Change ownership of admin socket before dropping permissions (#1336) This is to allow access to the socket by members of the group that permissions are dropped to. --- cmd/yggdrasil/chuser_other.go | 2 +- cmd/yggdrasil/chuser_unix.go | 14 +++++++++++++- cmd/yggdrasil/chuser_unix_test.go | 14 +++++++------- cmd/yggdrasil/main.go | 2 +- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/cmd/yggdrasil/chuser_other.go b/cmd/yggdrasil/chuser_other.go index 9d331c3b..889a09dc 100644 --- a/cmd/yggdrasil/chuser_other.go +++ b/cmd/yggdrasil/chuser_other.go @@ -4,6 +4,6 @@ package main import "errors" -func chuser(user string) error { +func chuser(user, adminSockUrl string) error { return errors.New("setting uid/gid is not supported on this platform") } diff --git a/cmd/yggdrasil/chuser_unix.go b/cmd/yggdrasil/chuser_unix.go index fdb290d2..0eb57c20 100644 --- a/cmd/yggdrasil/chuser_unix.go +++ b/cmd/yggdrasil/chuser_unix.go @@ -4,6 +4,8 @@ package main import ( "fmt" + "net/url" + "os" "os/user" "strconv" "strings" @@ -11,7 +13,7 @@ import ( "golang.org/x/sys/unix" ) -func chuser(input string) error { +func chuser(input, adminSockUrl string) error { givenUser, givenGroup, _ := strings.Cut(input, ":") if givenUser == "" { return fmt.Errorf("user is empty") @@ -48,6 +50,16 @@ func chuser(input string) error { gid, _ = strconv.Atoi(usr.Gid) } + if adminSockUrl != "" { + u, err := url.Parse(adminSockUrl) + if err == nil && u.Scheme == "unix" { + err = os.Chown(u.Path, uid, gid) + } + if err != nil { + return fmt.Errorf("chown %s %d:%d: %v", adminSockUrl, uid, gid, err) + } + } + if err := unix.Setgroups([]int{gid}); err != nil { return fmt.Errorf("setgroups: %d: %v", gid, err) } diff --git a/cmd/yggdrasil/chuser_unix_test.go b/cmd/yggdrasil/chuser_unix_test.go index 5d9720f7..96af9a5d 100644 --- a/cmd/yggdrasil/chuser_unix_test.go +++ b/cmd/yggdrasil/chuser_unix_test.go @@ -9,21 +9,21 @@ import ( // Usernames must not contain a number sign. func TestEmptyString(t *testing.T) { - if chuser("") == nil { + if chuser("", "") == nil { t.Fatal("the empty string is not a valid user") } } // Either omit delimiter and group, or omit both. func TestEmptyGroup(t *testing.T) { - if chuser("0:") == nil { + if chuser("0:", "") == nil { t.Fatal("the empty group is not allowed") } } // Either user only or user and group. func TestGroupOnly(t *testing.T) { - if chuser(":0") == nil { + if chuser(":0", "") == nil { t.Fatal("group only is not allowed") } } @@ -31,14 +31,14 @@ func TestGroupOnly(t *testing.T) { // Usenames must not contain the number sign. func TestInvalidUsername(t *testing.T) { const username = "#user" - if chuser(username) == nil { + if chuser(username, "") == nil { t.Fatalf("'%s' is not a valid username", username) } } // User IDs must be non-negative. func TestInvalidUserid(t *testing.T) { - if chuser("-1") == nil { + if chuser("-1", "") == nil { t.Fatal("User ID cannot be negative") } } @@ -54,7 +54,7 @@ func TestCurrentUserid(t *testing.T) { t.Skip("setgroups(2): Only the superuser may set new groups.") } - if err = chuser(usr.Uid); err != nil { + if err = chuser(usr.Uid, ""); err != nil { t.Fatal(err) } } @@ -70,7 +70,7 @@ func TestCommonUsername(t *testing.T) { t.Skip("setgroups(2): Only the superuser may set new groups.") } - if err := chuser("nobody"); err != nil { + if err := chuser("nobody", ""); err != nil { if _, ok := err.(user.UnknownUserError); ok { t.Skip(err) } diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 51893dad..e19579b5 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -293,7 +293,7 @@ func main() { // Change user if requested if *chuserto != "" { - err = chuser(*chuserto) + err = chuser(*chuserto, cfg.AdminListen) if err != nil { panic(err) }