IdleMonitor (DBus) and unprivileged user

The following piece of code, prints idle time of a user running GNOME. Now I included a very similar code into a patch for BOINC client, to let it detect user idle time. I am afraid it will not work because:

  1. BOINC client runs as systemd service using an unprivileged user and it will have to detect user idle time of users that use GNOME. I haven’t tested it yet on BOINC client running as service because I am getting a crash that does not show debuginfos / symbols;
  2. the IdleMonitor DBus interface runs on session bus, not system bus.

What do you think about? Thank you

/*
 * Compile with:
 *   gcc -Wall print_user_idle_time-gnome.c -o print_user_idle_time-gnome `pkg-config --libs gio-2.0 --cflags`
 */

#include <gio/gio.h>

static void
print_user_idle_time (GDBusProxy *proxy)
{
    guint64 user_idle_time;
    gchar *method = "GetIdletime";
	GError *error = NULL;
	GVariant *ret = NULL;
    
	ret = g_dbus_proxy_call_sync(proxy,
	                              method,
	                              NULL,
	                              G_DBUS_CALL_FLAGS_NONE, -1,
	                              NULL, &error);
	if (!ret) {
		g_dbus_error_strip_remote_error (error);
		g_print ("GetIdletime failed: %s\n", error->message);
		g_error_free (error);
		return;
	}

	g_variant_get(ret, "(t)", &user_idle_time);
    /*
     * In another example
     * g_variant_get (ret, "(^ao)", &user_idle_time);
     * has been replaced with
     * user_idle_time = g_variant_get_uint64 (ret);
	 */
	g_print("%lu\n", user_idle_time);
    g_variant_unref (ret);
}

int
main (int argc, char *argv[])
{
    /*
     * this should be the equivalent of bash command
     * $ sleep 1 && dbus-send --print-reply --dest=org.gnome.Mutter.IdleMonitor /org/gnome/Mutter/IdleMonitor/Core org.gnome.Mutter.IdleMonitor.GetIdletime
     */
	GDBusProxy *proxy = NULL;
    gchar *name = "org.gnome.Mutter.IdleMonitor";
    gchar *object_path = "/org/gnome/Mutter/IdleMonitor/Core";
    gchar *interface_name = "org.gnome.Mutter.IdleMonitor";
	/* Create a D-Bus proxy */
	proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
	                                       G_DBUS_PROXY_FLAGS_NONE,
	                                       NULL,
	                                       name,
	                                       object_path,
	                                       interface_name,
	                                       NULL, NULL);
	g_assert (proxy != NULL);

	print_user_idle_time (proxy);

	g_object_unref (proxy);

	return 0;
}

aaa

Indeed, this cannot work for anything that isn’t your own user.

The compositor (whether X11 or Wayland) runs as your own user, so it exports its interfaces and well known names on the session (user) bus. User services cannot access the session bus of other users by design, because otherwise they could sniff things like passwords or any sensitive data sent over the bus.

A plausible design that separates the BOINC client running as a service exposed on the system bus, would be based on having some form of DBus interface that lets any user notify the BOINC service that a user session is idle; you will need a BOINC user service paired to the BOINC system service:

  • every time a new user session starts, a user service contacts the BOINC system service and registers itself by calling a RegisterSession(out o path) method that returns an object path to be used later by other methods
  • every time the user session goes idle, the user service contacts the BOINC system service and calls a SetIdle(in b is_idle) method on the object path returned by RegisterSession()
  • every time the user session returns from an idle state, the user service contacts the BOINC system service and calls the SetIdle() method on the object path returned by RegisterSession()

The BOINC system service would maintain the association between the object paths it hands out and the idle sessions; when all objects are idle, then it is also idle; as soon as one object is unset as idle, then it’s not idle any more.

You’ll also need a polkit authorisation rule so that the BOINC user service can contact the BOINC system service without necessarily requiring authentication from the user.

You will need to implement the BOINC user session service to listen to the IdleMonitor changes; you will also need to modify the BOINC system service to provide the DBus interface for the session service to call, and the polkit authority for the privilege escalation.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.