github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/cgroups/systemd/user.go (about) 1 package systemd 2 3 import ( 4 "bufio" 5 "bytes" 6 "errors" 7 "fmt" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "strconv" 12 "strings" 13 14 systemdDbus "github.com/coreos/go-systemd/v22/dbus" 15 dbus "github.com/godbus/dbus/v5" 16 17 "github.com/opencontainers/runc/libcontainer/userns" 18 ) 19 20 // newUserSystemdDbus creates a connection for systemd user-instance. 21 func newUserSystemdDbus() (*systemdDbus.Conn, error) { 22 addr, err := DetectUserDbusSessionBusAddress() 23 if err != nil { 24 return nil, err 25 } 26 uid, err := DetectUID() 27 if err != nil { 28 return nil, err 29 } 30 31 return systemdDbus.NewConnection(func() (*dbus.Conn, error) { 32 conn, err := dbus.Dial(addr) 33 if err != nil { 34 return nil, fmt.Errorf("error while dialing %q: %w", addr, err) 35 } 36 methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(uid))} 37 err = conn.Auth(methods) 38 if err != nil { 39 conn.Close() 40 return nil, fmt.Errorf("error while authenticating connection (address=%q, UID=%d): %w", addr, uid, err) 41 } 42 if err = conn.Hello(); err != nil { 43 conn.Close() 44 return nil, fmt.Errorf("error while sending Hello message (address=%q, UID=%d): %w", addr, uid, err) 45 } 46 return conn, nil 47 }) 48 } 49 50 // DetectUID detects UID from the OwnerUID field of `busctl --user status` 51 // if running in userNS. The value corresponds to sd_bus_creds_get_owner_uid(3) . 52 // 53 // Otherwise returns os.Getuid() . 54 func DetectUID() (int, error) { 55 if !userns.RunningInUserNS() { 56 return os.Getuid(), nil 57 } 58 b, err := exec.Command("busctl", "--user", "--no-pager", "status").CombinedOutput() 59 if err != nil { 60 return -1, fmt.Errorf("could not execute `busctl --user --no-pager status` (output: %q): %w", string(b), err) 61 } 62 scanner := bufio.NewScanner(bytes.NewReader(b)) 63 for scanner.Scan() { 64 s := strings.TrimSpace(scanner.Text()) 65 if strings.HasPrefix(s, "OwnerUID=") { 66 uidStr := strings.TrimPrefix(s, "OwnerUID=") 67 i, err := strconv.Atoi(uidStr) 68 if err != nil { 69 return -1, fmt.Errorf("could not detect the OwnerUID: %w", err) 70 } 71 return i, nil 72 } 73 } 74 if err := scanner.Err(); err != nil { 75 return -1, err 76 } 77 return -1, errors.New("could not detect the OwnerUID") 78 } 79 80 // DetectUserDbusSessionBusAddress returns $DBUS_SESSION_BUS_ADDRESS, if set. 81 // Otherwise it returns "unix:path=$XDG_RUNTIME_DIR/bus", if $XDG_RUNTIME_DIR/bus exists. 82 func DetectUserDbusSessionBusAddress() (string, error) { 83 if env := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); env != "" { 84 return env, nil 85 } 86 if xdr := os.Getenv("XDG_RUNTIME_DIR"); xdr != "" { 87 busPath := filepath.Join(xdr, "bus") 88 if _, err := os.Stat(busPath); err == nil { 89 busAddress := "unix:path=" + dbus.EscapeBusAddressValue(busPath) 90 return busAddress, nil 91 } 92 } 93 return "", errors.New("could not detect DBUS_SESSION_BUS_ADDRESS from the environment; make sure you have installed the dbus-user-session or dbus-daemon package; note you may need to re-login") 94 }