Skip to content

Commit

Permalink
feat(login1): add methods to get session/user properties
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyam8 committed Aug 31, 2022
1 parent 1d04472 commit d3e99ab
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 14 deletions.
82 changes: 68 additions & 14 deletions login1/dbus.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ import (
)

const (
dbusDest = "org.freedesktop.login1"
dbusInterface = "org.freedesktop.login1.Manager"
dbusPath = "/org/freedesktop/#1"
dbusDest = "org.freedesktop.login1"
dbusManagerInterface = "org.freedesktop.login1.Manager"
dbusSessionInterface = "org.freedesktop.login1.Session"
dbusUserInterface = "org.freedesktop.login1.User"
dbusPath = "/org/freedesktop/#1"
)

// Conn is a connection to systemds dbus endpoint.
Expand Down Expand Up @@ -166,7 +168,7 @@ func userFromInterfaces(user []interface{}) (*User, error) {
// GetActiveSession may be used to get the session object path for the current active session
func (c *Conn) GetActiveSession() (dbus.ObjectPath, error) {
var seat0Path dbus.ObjectPath
if err := c.object.Call(dbusInterface+".GetSeat", 0, "seat0").Store(&seat0Path); err != nil {
if err := c.object.Call(dbusManagerInterface+".GetSeat", 0, "seat0").Store(&seat0Path); err != nil {
return "", err
}

Expand Down Expand Up @@ -242,7 +244,7 @@ func (c *Conn) GetSessionDisplay(sessionPath dbus.ObjectPath) (string, error) {
// GetSession may be used to get the session object path for the session with the specified ID.
func (c *Conn) GetSession(id string) (dbus.ObjectPath, error) {
var out interface{}
if err := c.object.Call(dbusInterface+".GetSession", 0, id).Store(&out); err != nil {
if err := c.object.Call(dbusManagerInterface+".GetSession", 0, id).Store(&out); err != nil {
return "", err
}

Expand All @@ -262,7 +264,7 @@ func (c *Conn) ListSessions() ([]Session, error) {
// ListSessionsContext returns an array with all current sessions.
func (c *Conn) ListSessionsContext(ctx context.Context) ([]Session, error) {
out := [][]interface{}{}
if err := c.object.CallWithContext(ctx, dbusInterface+".ListSessions", 0).Store(&out); err != nil {
if err := c.object.CallWithContext(ctx, dbusManagerInterface+".ListSessions", 0).Store(&out); err != nil {
return nil, err
}

Expand All @@ -285,7 +287,7 @@ func (c *Conn) ListUsers() ([]User, error) {
// ListUsersContext returns an array with all currently logged-in users.
func (c *Conn) ListUsersContext(ctx context.Context) ([]User, error) {
out := [][]interface{}{}
if err := c.object.CallWithContext(ctx, dbusInterface+".ListUsers", 0).Store(&out); err != nil {
if err := c.object.CallWithContext(ctx, dbusManagerInterface+".ListUsers", 0).Store(&out); err != nil {
return nil, err
}

Expand All @@ -300,36 +302,56 @@ func (c *Conn) ListUsersContext(ctx context.Context) ([]User, error) {
return ret, nil
}

// GetSessionPropertiesContext takes a session path and returns all of its dbus object properties.
func (c *Conn) GetSessionPropertiesContext(ctx context.Context, sessionPath dbus.ObjectPath) (map[string]dbus.Variant, error) {
return c.getProperties(ctx, sessionPath, dbusSessionInterface)
}

// GetSessionPropertyContext takes a session path and a property name and returns the property value.
func (c *Conn) GetSessionPropertyContext(ctx context.Context, sessionPath dbus.ObjectPath, property string) (*dbus.Variant, error) {
return c.getProperty(ctx, sessionPath, dbusSessionInterface, property)
}

// GetUserPropertiesContext takes a user path and returns all of its dbus object properties.
func (c *Conn) GetUserPropertiesContext(ctx context.Context, userPath dbus.ObjectPath) (map[string]dbus.Variant, error) {
return c.getProperties(ctx, userPath, dbusUserInterface)
}

// GetUserPropertyContext takes a user path and a property name and returns the property value.
func (c *Conn) GetUserPropertyContext(ctx context.Context, userPath dbus.ObjectPath, property string) (*dbus.Variant, error) {
return c.getProperty(ctx, userPath, dbusUserInterface, property)
}

// LockSession asks the session with the specified ID to activate the screen lock.
func (c *Conn) LockSession(id string) {
c.object.Call(dbusInterface+".LockSession", 0, id)
c.object.Call(dbusManagerInterface+".LockSession", 0, id)
}

// LockSessions asks all sessions to activate the screen locks. This may be used to lock any access to the machine in one action.
func (c *Conn) LockSessions() {
c.object.Call(dbusInterface+".LockSessions", 0)
c.object.Call(dbusManagerInterface+".LockSessions", 0)
}

// TerminateSession forcibly terminate one specific session.
func (c *Conn) TerminateSession(id string) {
c.object.Call(dbusInterface+".TerminateSession", 0, id)
c.object.Call(dbusManagerInterface+".TerminateSession", 0, id)
}

// TerminateUser forcibly terminates all processes of a user.
func (c *Conn) TerminateUser(uid uint32) {
c.object.Call(dbusInterface+".TerminateUser", 0, uid)
c.object.Call(dbusManagerInterface+".TerminateUser", 0, uid)
}

// Reboot asks logind for a reboot optionally asking for auth.
func (c *Conn) Reboot(askForAuth bool) {
c.object.Call(dbusInterface+".Reboot", 0, askForAuth)
c.object.Call(dbusManagerInterface+".Reboot", 0, askForAuth)
}

// Inhibit takes inhibition lock in logind.
func (c *Conn) Inhibit(what, who, why, mode string) (*os.File, error) {
var fd dbus.UnixFD

err := c.object.Call(dbusInterface+".Inhibit", 0, what, who, why, mode).Store(&fd)
err := c.object.Call(dbusManagerInterface+".Inhibit", 0, what, who, why, mode).Store(&fd)
if err != nil {
return nil, err
}
Expand All @@ -350,5 +372,37 @@ func (c *Conn) Subscribe(members ...string) chan *dbus.Signal {

// PowerOff asks logind for a power off optionally asking for auth.
func (c *Conn) PowerOff(askForAuth bool) {
c.object.Call(dbusInterface+".PowerOff", 0, askForAuth)
c.object.Call(dbusManagerInterface+".PowerOff", 0, askForAuth)
}

func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInterface string) (map[string]dbus.Variant, error) {
if !path.IsValid() {
return nil, fmt.Errorf("invalid object path (%s)", path)
}

obj := c.conn.Object(dbusDest, path)

var props map[string]dbus.Variant
err := obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props)
if err != nil {
return nil, err
}

return props, nil
}

func (c *Conn) getProperty(ctx context.Context, path dbus.ObjectPath, dbusInterface, property string) (*dbus.Variant, error) {
if !path.IsValid() {
return nil, fmt.Errorf("invalid object path (%s)", path)
}

obj := c.conn.Object(dbusDest, path)

var prop dbus.Variant
err := obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, dbusInterface, property).Store(&prop)
if err != nil {
return nil, err
}

return &prop, nil
}
104 changes: 104 additions & 0 deletions login1/dbus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
package login1

import (
"context"
"fmt"
"os/user"
"regexp"
"testing"
"time"
)

// TestNew ensures that New() works without errors.
Expand Down Expand Up @@ -87,3 +89,105 @@ func TestListUsers(t *testing.T) {
}
}
}

func TestConn_GetSessionPropertiesContext(t *testing.T) {
c, err := New()
if err != nil {
t.Fatal(err)
}

sessions, err := c.ListSessions()
if err != nil {
t.Fatal(err)
}

for _, s := range sessions {
func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()

props, err := c.GetSessionPropertiesContext(ctx, s.Path)
if err != nil {
t.Fatal(err)
}
if len(props) == 0 {
t.Fatal("no properties returned")
}
}()
}
}

func TestConn_GetSessionPropertyContext(t *testing.T) {
c, err := New()
if err != nil {
t.Fatal(err)
}

sessions, err := c.ListSessions()
if err != nil {
t.Fatal(err)
}

for _, s := range sessions {
func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()

_, err := c.GetSessionPropertyContext(ctx, s.Path, "Remote")
if err != nil {
t.Fatal(err)
}
}()
}
}

func TestConn_GetUserPropertiesContext(t *testing.T) {
c, err := New()
if err != nil {
t.Fatal(err)
}

users, err := c.ListUsers()
if err != nil {
t.Fatal(err)
}

for _, u := range users {
func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()

props, err := c.GetUserPropertiesContext(ctx, u.Path)
if err != nil {
t.Fatal(err)
}
if len(props) == 0 {
t.Fatal("no properties returned")
}
}()
}
}

func TestConn_GetUserPropertyContext(t *testing.T) {
c, err := New()
if err != nil {
t.Fatal(err)
}

users, err := c.ListUsers()
if err != nil {
t.Fatal(err)
}

for _, u := range users {
func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()

_, err := c.GetUserPropertyContext(ctx, u.Path, "State")
if err != nil {
t.Fatal(err)
}
}()
}
}

0 comments on commit d3e99ab

Please # to comment.