summaryrefslogtreecommitdiff
path: root/src/dbus-common.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2011-03-12 01:03:13 +0100
committerLennart Poettering <lennart@poettering.net>2011-03-12 01:07:17 +0100
commita8f11321c209830a35edd0357e8def5d4437d854 (patch)
tree6624318fbfc07042729a69ad29b4e0ffc2402263 /src/dbus-common.c
parente75c058023a7e130599f5a3ae2981540d8e397c8 (diff)
systemctl: support remote and privileged systemctl access via SSH and pkexec
This adds support for executing systemctl operations remotely or as privileged user while still running systemctl itself unprivileged and locally. This currently requires a D-Bus patch to work properly. https://bugs.freedesktop.org/show_bug.cgi?id=35230
Diffstat (limited to 'src/dbus-common.c')
-rw-r--r--src/dbus-common.c159
1 files changed, 123 insertions, 36 deletions
diff --git a/src/dbus-common.c b/src/dbus-common.c
index 809ea0f67a..25b718ec02 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -23,6 +23,8 @@
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <dbus/dbus.h>
#include "log.h"
@@ -55,59 +57,63 @@ int bus_check_peercred(DBusConnection *c) {
return 1;
}
-int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private, DBusError *error) {
- DBusConnection *bus;
+#define TIMEOUT_USEC (60*USEC_PER_SEC)
- assert(_bus);
+static int sync_auth(DBusConnection *bus, DBusError *error) {
+ usec_t begin, tstamp;
-#define TIMEOUT_USEC (60*USEC_PER_SEC)
+ assert(bus);
- /* If we are root, then let's not go via the bus */
- if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
- usec_t begin, tstamp;
+ /* This complexity should probably move into D-Bus itself:
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
- if (!(bus = dbus_connection_open_private("unix:abstract=/org/freedesktop/systemd1/private", error)))
- return -EIO;
+ begin = tstamp = now(CLOCK_MONOTONIC);
+ for (;;) {
- if (bus_check_peercred(bus) < 0) {
- dbus_connection_close(bus);
- dbus_connection_unref(bus);
+ if (tstamp > begin + TIMEOUT_USEC)
+ break;
- dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
- return -EACCES;
- }
+ if (dbus_connection_get_is_authenticated(bus))
+ break;
- /* This complexity should probably move into D-Bus itself:
- *
- * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
- begin = tstamp = now(CLOCK_MONOTONIC);
- for (;;) {
+ if (!dbus_connection_read_write_dispatch(bus, ((begin + TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
+ break;
- if (tstamp > begin + TIMEOUT_USEC)
- break;
+ tstamp = now(CLOCK_MONOTONIC);
+ }
- if (dbus_connection_get_is_authenticated(bus))
- break;
+ if (!dbus_connection_get_is_connected(bus)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
+ return -ECONNREFUSED;
+ }
- if (!dbus_connection_read_write_dispatch(bus, ((begin + TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
- break;
+ if (!dbus_connection_get_is_authenticated(bus)) {
+ dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
+ return -EACCES;
+ }
- tstamp = now(CLOCK_MONOTONIC);
- }
+ return 0;
+}
- if (!dbus_connection_get_is_connected(bus)) {
- dbus_connection_close(bus);
- dbus_connection_unref(bus);
+int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private, DBusError *error) {
+ DBusConnection *bus;
+ int r;
- dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
- return -ECONNREFUSED;
- }
+ assert(_bus);
- if (!dbus_connection_get_is_authenticated(bus)) {
+ /* If we are root, then let's not go via the bus */
+ if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
+ if (!(bus = dbus_connection_open_private("unix:abstract=/org/freedesktop/systemd1/private", error)))
+ return -EIO;
+
+ dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+ if (bus_check_peercred(bus) < 0) {
dbus_connection_close(bus);
dbus_connection_unref(bus);
- dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
+ dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
return -EACCES;
}
@@ -118,12 +124,93 @@ int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private, DBusError *
if (!(bus = dbus_bus_get_private(t, error)))
return -EIO;
+ dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
if (private)
*private = false;
}
+ if ((r = sync_auth(bus, error)) < 0) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ return r;
+ }
+
+ *_bus = bus;
+ return 0;
+}
+
+int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
+ DBusConnection *bus;
+ char *p = NULL;
+ int r;
+
+ assert(_bus);
+ assert(user || host);
+
+ if (user && host)
+ asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
+ else if (user)
+ asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user);
+ else if (host)
+ asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
+
+ if (!p) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
+ return -ENOMEM;
+ }
+
+ bus = dbus_connection_open_private(p, error);
+ free(p);
+
+ if (!bus)
+ return -EIO;
+
+ dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+ if ((r = sync_auth(bus, error)) < 0) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ return r;
+ }
+
+ if (!dbus_bus_register(bus, error)) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ return r;
+ }
+
+ *_bus = bus;
+ return 0;
+}
+
+int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
+ DBusConnection *bus;
+ int r;
+
+ assert(_bus);
+
+ /* Don't bother with PolicyKit if we are root */
+ if (geteuid() == 0)
+ return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
+
+ if (!(bus = dbus_connection_open_private("exec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error)))
+ return -EIO;
+
dbus_connection_set_exit_on_disconnect(bus, FALSE);
+ if ((r = sync_auth(bus, error)) < 0) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ return r;
+ }
+
+ if (!dbus_bus_register(bus, error)) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ return r;
+ }
+
*_bus = bus;
return 0;
}