mirror of https://github.com/containers/podman.git
				
				
				
			
		
			
				
	
	
		
			145 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
| package systemd
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"strconv"
 | |
| 
 | |
| 	"github.com/containers/podman/v4/pkg/rootless"
 | |
| 	"github.com/coreos/go-systemd/v22/dbus"
 | |
| 	godbus "github.com/godbus/dbus/v5"
 | |
| 	"github.com/sirupsen/logrus"
 | |
| )
 | |
| 
 | |
| // IsSystemdSessionValid checks if sessions is valid for provided rootless uid.
 | |
| func IsSystemdSessionValid(uid int) bool {
 | |
| 	var conn *godbus.Conn
 | |
| 	var err error
 | |
| 	var object godbus.BusObject
 | |
| 	var seat0Path godbus.ObjectPath
 | |
| 	dbusDest := "org.freedesktop.login1"
 | |
| 	dbusInterface := "org.freedesktop.login1.Manager"
 | |
| 	dbusPath := "/org/freedesktop/login1"
 | |
| 
 | |
| 	if rootless.IsRootless() {
 | |
| 		conn, err = GetLogindConnection(rootless.GetRootlessUID())
 | |
| 		if err != nil {
 | |
| 			//unable to fetch systemd object for logind
 | |
| 			logrus.Debugf("systemd-logind: %s", err)
 | |
| 			return false
 | |
| 		}
 | |
| 		object = conn.Object(dbusDest, godbus.ObjectPath(dbusPath))
 | |
| 		if err := object.Call(dbusInterface+".GetSeat", 0, "seat0").Store(&seat0Path); err != nil {
 | |
| 			//unable to get seat0 path.
 | |
| 			logrus.Debugf("systemd-logind: %s", err)
 | |
| 			return false
 | |
| 		}
 | |
| 		seat0Obj := conn.Object(dbusDest, seat0Path)
 | |
| 		activeSession, err := seat0Obj.GetProperty(dbusDest + ".Seat.ActiveSession")
 | |
| 		if err != nil {
 | |
| 			//unable to get active sessions.
 | |
| 			logrus.Debugf("systemd-logind: %s", err)
 | |
| 			return false
 | |
| 		}
 | |
| 		activeSessionMap, ok := activeSession.Value().([]interface{})
 | |
| 		if !ok || len(activeSessionMap) < 2 {
 | |
| 			//unable to get active session map.
 | |
| 			logrus.Debugf("systemd-logind: %s", err)
 | |
| 			return false
 | |
| 		}
 | |
| 		activeSessionPath, ok := activeSessionMap[1].(godbus.ObjectPath)
 | |
| 		if !ok {
 | |
| 			//unable to fetch active session path.
 | |
| 			logrus.Debugf("systemd-logind: %s", err)
 | |
| 			return false
 | |
| 		}
 | |
| 		activeSessionObj := conn.Object(dbusDest, activeSessionPath)
 | |
| 		sessionUser, err := activeSessionObj.GetProperty(dbusDest + ".Session.User")
 | |
| 		if err != nil {
 | |
| 			//unable to fetch session user from activeSession path.
 | |
| 			logrus.Debugf("systemd-logind: %s", err)
 | |
| 			return false
 | |
| 		}
 | |
| 		dbusUser, ok := sessionUser.Value().([]interface{})
 | |
| 		if !ok {
 | |
| 			// not a valid user.
 | |
| 			return false
 | |
| 		}
 | |
| 		if len(dbusUser) < 2 {
 | |
| 			// not a valid session user.
 | |
| 			return false
 | |
| 		}
 | |
| 		activeUID, ok := dbusUser[0].(uint32)
 | |
| 		if !ok {
 | |
| 			return false
 | |
| 		}
 | |
| 		//active session found which belongs to following rootless user
 | |
| 		if activeUID == uint32(uid) {
 | |
| 			return true
 | |
| 		}
 | |
| 		return false
 | |
| 	}
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // GetDbusConnection returns a user connection to D-BUS
 | |
| func GetLogindConnection(uid int) (*godbus.Conn, error) {
 | |
| 	return dbusAuthConnectionLogind(uid)
 | |
| }
 | |
| 
 | |
| func dbusAuthConnectionLogind(uid int) (*godbus.Conn, error) {
 | |
| 	var conn *godbus.Conn
 | |
| 	var err error
 | |
| 	conn, err = godbus.SystemBusPrivate()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	methods := []godbus.Auth{godbus.AuthExternal(strconv.Itoa(uid))}
 | |
| 	if err = conn.Auth(methods); err != nil {
 | |
| 		conn.Close()
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	err = conn.Hello()
 | |
| 	if err != nil {
 | |
| 		conn.Close()
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return conn, nil
 | |
| }
 | |
| 
 | |
| func dbusAuthRootlessConnection(createBus func(opts ...godbus.ConnOption) (*godbus.Conn, error)) (*godbus.Conn, error) {
 | |
| 	conn, err := createBus()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	methods := []godbus.Auth{godbus.AuthExternal(strconv.Itoa(rootless.GetRootlessUID()))}
 | |
| 
 | |
| 	err = conn.Auth(methods)
 | |
| 	if err != nil {
 | |
| 		conn.Close()
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return conn, nil
 | |
| }
 | |
| 
 | |
| func newRootlessConnection() (*dbus.Conn, error) {
 | |
| 	return dbus.NewConnection(func() (*godbus.Conn, error) {
 | |
| 		return dbusAuthRootlessConnection(func(opts ...godbus.ConnOption) (*godbus.Conn, error) {
 | |
| 			path := filepath.Join(os.Getenv("XDG_RUNTIME_DIR"), "systemd/private")
 | |
| 			return godbus.Dial(fmt.Sprintf("unix:path=%s", path))
 | |
| 		})
 | |
| 	})
 | |
| }
 | |
| 
 | |
| // ConnectToDBUS returns a DBUS connection.  It works both as root and non-root
 | |
| // users.
 | |
| func ConnectToDBUS() (*dbus.Conn, error) {
 | |
| 	if rootless.IsRootless() {
 | |
| 		return newRootlessConnection()
 | |
| 	}
 | |
| 	return dbus.NewSystemdConnection()
 | |
| }
 |