summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-08-15 20:08:51 +0200
committerLennart Poettering <lennart@poettering.net>2014-08-15 20:08:51 +0200
commitdef9a7aa0182e5ecca3ac61b26f75136a5c4f103 (patch)
treecb9da3fa3ad63f8c9e62c883cf821f23295c74d3 /src
parent4311fa08fe7f3e702a2adb569fe20fb023a4b746 (diff)
sd-bus: add API to check if a client has privileges
This is a generalization of the vtable privilege check we already have, but exported, and hence useful when preparing for a polkit change. This will deal with the complexity that on dbus1 one cannot trust the capability field we retrieve via the bus, since it is read via /proc/$$/stat (and thus might be out-of-date) rather than directly from the message (like on kdbus) or bus connection (as for uid creds on dbus1). Also, port over all code to this new API.
Diffstat (limited to 'src')
-rw-r--r--src/hostname/hostnamed.c12
-rw-r--r--src/libsystemd/sd-bus/bus-convenience.c53
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c25
-rw-r--r--src/libsystemd/sd-bus/bus-util.c24
-rw-r--r--src/libsystemd/sd-bus/bus-util.h4
-rw-r--r--src/locale/localed.c7
-rw-r--r--src/login/logind-dbus.c17
-rw-r--r--src/systemd/sd-bus.h1
-rw-r--r--src/timedate/timedated.c8
9 files changed, 91 insertions, 60 deletions
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index 4acdb72b12..dae73b390f 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/utsname.h>
+#include <sys/capability.h>
#include "util.h"
#include "strv.h"
@@ -425,7 +426,7 @@ static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, s
if (streq_ptr(name, c->data[PROP_HOSTNAME]))
return sd_bus_reply_method_return(m, NULL);
- r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-hostname", interactive, error, method_set_hostname, c);
+ r = bus_verify_polkit_async(bus, &c->polkit_registry, m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-hostname", interactive, error, method_set_hostname, c);
if (r < 0)
return r;
if (r == 0)
@@ -467,7 +468,7 @@ static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *user
if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
return sd_bus_reply_method_return(m, NULL);
- r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-static-hostname", interactive, error, method_set_static_hostname, c);
+ r = bus_verify_polkit_async(bus, &c->polkit_registry, m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-static-hostname", interactive, error, method_set_static_hostname, c);
if (r < 0)
return r;
if (r == 0)
@@ -532,9 +533,10 @@ static int set_machine_info(Context *c, sd_bus *bus, sd_bus_message *m, int prop
* same time as the static one, use the same policy action for
* both... */
- r = bus_verify_polkit_async(bus, &c->polkit_registry, m, prop == PROP_PRETTY_HOSTNAME ?
- "org.freedesktop.hostname1.set-static-hostname" :
- "org.freedesktop.hostname1.set-machine-info", interactive, error, cb, c);
+ r = bus_verify_polkit_async(bus, &c->polkit_registry, m, CAP_SYS_ADMIN,
+ prop == PROP_PRETTY_HOSTNAME ?
+ "org.freedesktop.hostname1.set-static-hostname" :
+ "org.freedesktop.hostname1.set-machine-info", interactive, error, cb, c);
if (r < 0)
return r;
if (r == 0)
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
index c5b9cd4caa..f88836b884 100644
--- a/src/libsystemd/sd-bus/bus-convenience.c
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -472,3 +472,56 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
return bus_creds_extend_by_pid(c, mask, creds);
}
+
+_public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
+ _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ uid_t our_uid;
+ int r;
+
+ assert_return(call, -EINVAL);
+ assert_return(call->sealed, -EPERM);
+ assert_return(call->bus, -EINVAL);
+ assert_return(!bus_pid_changed(call->bus), -ECHILD);
+
+ if (!BUS_IS_OPEN(call->bus->state))
+ return -ENOTCONN;
+
+ /* We only trust the effective capability set if this is
+ * kdbus. On classic dbus1 we cannot retrieve the value
+ * without races. Since this function is supposed to be useful
+ * for authentication decision we hence avoid requesting and
+ * using that information. */
+ if (call->bus->is_kernel && capability >= 0) {
+ r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_creds_has_effective_cap(creds, capability);
+ if (r > 0)
+ return 1;
+ } else {
+ r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID, &creds);
+ if (r < 0)
+ return r;
+ }
+
+ /* Now, check the UID, but only if the capability check wasn't
+ * sufficient */
+ our_uid = getuid();
+ if (our_uid != 0 || !call->bus->is_kernel || capability < 0) {
+ uid_t sender_uid;
+
+ r = sd_bus_creds_get_uid(creds, &sender_uid);
+ if (r >= 0) {
+ /* Sender has same UID as us, then let's grant access */
+ if (sender_uid == our_uid)
+ return 1;
+
+ /* Sender is root, we are not root. */
+ if (our_uid != 0 && sender_uid == 0)
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index dbb04e5ec6..78dab8048d 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -289,7 +289,6 @@ static int node_callbacks_run(
static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c, sd_bus_error *error) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
uint64_t cap;
- uid_t uid;
int r;
assert(bus);
@@ -304,17 +303,6 @@ static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c,
if (c->vtable->flags & SD_BUS_VTABLE_UNPRIVILEGED)
return 0;
- /* If we are not connected to kdbus we cannot retrieve the
- * effective capability set without race. Since we need this
- * for a security decision we cannot use racy data, hence
- * don't request it. */
- if (bus->is_kernel)
- r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
- else
- r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
- if (r < 0)
- return r;
-
/* Check have the caller has the requested capability
* set. Note that the flags value contains the capability
* number plus one, which we need to subtract here. We do this
@@ -328,16 +316,11 @@ static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c,
else
cap --;
- r = sd_bus_creds_has_effective_cap(creds, cap);
+ r = sd_bus_query_sender_privilege(m, cap);
+ if (r < 0)
+ return r;
if (r > 0)
- return 1;
-
- /* Caller has same UID as us, then let's grant access */
- r = sd_bus_creds_get_uid(creds, &uid);
- if (r >= 0) {
- if (uid == getuid())
- return 1;
- }
+ return 0;
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Access to %s.%s() not permitted.", c->interface, c->member);
}
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index 32c536813d..0ab11c3905 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -186,28 +186,22 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
int bus_verify_polkit(
sd_bus *bus,
sd_bus_message *m,
+ int capability,
const char *action,
bool interactive,
bool *_challenge,
sd_bus_error *e) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- uid_t uid;
int r;
assert(bus);
assert(m);
assert(action);
- r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
+ r = sd_bus_query_sender_privilege(m, capability);
if (r < 0)
return r;
-
- r = sd_bus_creds_get_uid(creds, &uid);
- if (r < 0)
- return r;
-
- if (uid == 0)
+ if (r > 0)
return 1;
#ifdef ENABLE_POLKIT
@@ -325,6 +319,7 @@ int bus_verify_polkit_async(
sd_bus *bus,
Hashmap **registry,
sd_bus_message *m,
+ int capability,
const char *action,
bool interactive,
sd_bus_error *error,
@@ -336,8 +331,6 @@ int bus_verify_polkit_async(
AsyncPolkitQuery *q;
const char *sender;
#endif
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- uid_t uid;
int r;
assert(bus);
@@ -383,15 +376,10 @@ int bus_verify_polkit_async(
}
#endif
- r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds);
+ r = sd_bus_query_sender_privilege(m, capability);
if (r < 0)
return r;
-
- r = sd_bus_creds_get_uid(creds, &uid);
- if (r < 0)
- return r;
-
- if (uid == 0)
+ if (r > 0)
return 1;
#ifdef ENABLE_POLKIT
diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h
index af50553926..f760a1e80e 100644
--- a/src/libsystemd/sd-bus/bus-util.h
+++ b/src/libsystemd/sd-bus/bus-util.h
@@ -62,9 +62,9 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error);
int bus_check_peercred(sd_bus *c);
-int bus_verify_polkit(sd_bus *bus, sd_bus_message *m, const char *action, bool interactive, bool *_challenge, sd_bus_error *e);
+int bus_verify_polkit(sd_bus *bus, sd_bus_message *m, int capability, const char *action, bool interactive, bool *_challenge, sd_bus_error *e);
-int bus_verify_polkit_async(sd_bus *bus, Hashmap **registry, sd_bus_message *m, const char *action, bool interactive, sd_bus_error *error, sd_bus_message_handler_t callback, void *userdata);
+int bus_verify_polkit_async(sd_bus *bus, Hashmap **registry, sd_bus_message *m, int capability, const char *action, bool interactive, sd_bus_error *error, sd_bus_message_handler_t callback, void *userdata);
void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry);
int bus_open_system_systemd(sd_bus **_bus);
diff --git a/src/locale/localed.c b/src/locale/localed.c
index 3cfc2ea4d3..087066786e 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
+#include <sys/capability.h>
#include "sd-bus.h"
@@ -876,7 +877,7 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
}
if (modified) {
- r = bus_verify_polkit_async(bus, &c->polkit_registry, m,
+ r = bus_verify_polkit_async(bus, &c->polkit_registry, m, CAP_SYS_ADMIN,
"org.freedesktop.locale1.set-locale", interactive,
error, method_set_locale, c);
if (r < 0)
@@ -954,7 +955,7 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata
(keymap_toggle && (!filename_is_safe(keymap_toggle) || !string_is_safe(keymap_toggle))))
return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keymap data");
- r = bus_verify_polkit_async(bus, &c->polkit_registry, m,
+ r = bus_verify_polkit_async(bus, &c->polkit_registry, m, CAP_SYS_ADMIN,
"org.freedesktop.locale1.set-keyboard",
interactive, error, method_set_vc_keyboard, c);
if (r < 0)
@@ -1026,7 +1027,7 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat
(options && !string_is_safe(options)))
return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keyboard data");
- r = bus_verify_polkit_async(bus, &c->polkit_registry, m,
+ r = bus_verify_polkit_async(bus, &c->polkit_registry, m, CAP_SYS_ADMIN,
"org.freedesktop.locale1.set-keyboard",
interactive, error, method_set_x11_keyboard, c);
if (r < 0)
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 1a363c2c59..bcfcba2d07 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -1032,6 +1032,7 @@ static int method_set_user_linger(sd_bus *bus, sd_bus_message *message, void *us
r = bus_verify_polkit_async(bus,
&m->polkit_registry,
message,
+ CAP_SYS_ADMIN,
"org.freedesktop.login1.set-user-linger",
interactive,
error,
@@ -1204,6 +1205,7 @@ static int method_attach_device(sd_bus *bus, sd_bus_message *message, void *user
r = bus_verify_polkit_async(bus,
&m->polkit_registry,
message,
+ CAP_SYS_ADMIN,
"org.freedesktop.login1.attach-device",
interactive,
error,
@@ -1235,6 +1237,7 @@ static int method_flush_devices(sd_bus *bus, sd_bus_message *message, void *user
r = bus_verify_polkit_async(bus,
&m->polkit_registry,
message,
+ CAP_SYS_ADMIN,
"org.freedesktop.login1.flush-devices",
interactive,
error,
@@ -1532,7 +1535,7 @@ static int method_do_shutdown_or_sleep(
blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
if (multiple_sessions) {
- r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message,
+ r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message, CAP_SYS_BOOT,
action_multiple_sessions, interactive, error, method, m);
if (r < 0)
return r;
@@ -1541,7 +1544,7 @@ static int method_do_shutdown_or_sleep(
}
if (blocked) {
- r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message,
+ r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message, CAP_SYS_BOOT,
action_ignore_inhibit, interactive, error, method, m);
if (r < 0)
return r;
@@ -1550,7 +1553,7 @@ static int method_do_shutdown_or_sleep(
}
if (!multiple_sessions && !blocked) {
- r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message,
+ r = bus_verify_polkit_async(m->bus, &m->polkit_registry, message, CAP_SYS_BOOT,
action, interactive, error, method, m);
if (r < 0)
return r;
@@ -1688,7 +1691,7 @@ static int method_can_shutdown_or_sleep(
blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
if (multiple_sessions) {
- r = bus_verify_polkit(m->bus, message, action_multiple_sessions, false, &challenge, error);
+ r = bus_verify_polkit(m->bus, message, CAP_SYS_BOOT, action_multiple_sessions, false, &challenge, error);
if (r < 0)
return r;
@@ -1701,7 +1704,7 @@ static int method_can_shutdown_or_sleep(
}
if (blocked) {
- r = bus_verify_polkit(m->bus, message, action_ignore_inhibit, false, &challenge, error);
+ r = bus_verify_polkit(m->bus, message, CAP_SYS_BOOT, action_ignore_inhibit, false, &challenge, error);
if (r < 0)
return r;
@@ -1717,7 +1720,7 @@ static int method_can_shutdown_or_sleep(
/* If neither inhibit nor multiple sessions
* apply then just check the normal policy */
- r = bus_verify_polkit(m->bus, message, action, false, &challenge, error);
+ r = bus_verify_polkit(m->bus, message, CAP_SYS_BOOT, action, false, &challenge, error);
if (r < 0)
return r;
@@ -1837,7 +1840,7 @@ static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata,
if (m->action_what & w)
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running");
- r = bus_verify_polkit_async(bus, &m->polkit_registry, message,
+ r = bus_verify_polkit_async(bus, &m->polkit_registry, message, CAP_SYS_BOOT,
w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 79566d2109..3eedb4450b 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -282,6 +282,7 @@ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **in
int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_;
int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds);
+int sd_bus_query_sender_privilege(sd_bus_message *call, int capability);
/* Credential handling */
diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c
index 791e2b436f..f0371759a2 100644
--- a/src/timedate/timedated.c
+++ b/src/timedate/timedated.c
@@ -395,7 +395,7 @@ static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata, s
if (streq_ptr(z, c->zone))
return sd_bus_reply_method_return(m, NULL);
- r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-timezone", interactive, error, method_set_timezone, c);
+ r = bus_verify_polkit_async(bus, &c->polkit_registry, m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-timezone", interactive, error, method_set_timezone, c);
if (r < 0)
return r;
if (r == 0)
@@ -456,7 +456,7 @@ static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata,
if (lrtc == c->local_rtc)
return sd_bus_reply_method_return(m, NULL);
- r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-local-rtc", interactive, error, method_set_local_rtc, c);
+ r = bus_verify_polkit_async(bus, &c->polkit_registry, m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-local-rtc", interactive, error, method_set_local_rtc, c);
if (r < 0)
return r;
if (r == 0)
@@ -561,7 +561,7 @@ static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bu
} else
timespec_store(&ts, (usec_t) utc);
- r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-time", interactive, error, method_set_time, c);
+ r = bus_verify_polkit_async(bus, &c->polkit_registry, m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-time", interactive, error, method_set_time, c);
if (r < 0)
return r;
if (r == 0)
@@ -601,7 +601,7 @@ static int method_set_ntp(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus
if ((bool)ntp == c->use_ntp)
return sd_bus_reply_method_return(m, NULL);
- r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.timedate1.set-ntp", interactive, error, method_set_ntp, c);
+ r = bus_verify_polkit_async(bus, &c->polkit_registry, m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-ntp", interactive, error, method_set_ntp, c);
if (r < 0)
return r;
if (r == 0)