diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-08-15 20:08:51 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-08-15 20:08:51 +0200 |
commit | def9a7aa0182e5ecca3ac61b26f75136a5c4f103 (patch) | |
tree | cb9da3fa3ad63f8c9e62c883cf821f23295c74d3 /src/libsystemd | |
parent | 4311fa08fe7f3e702a2adb569fe20fb023a4b746 (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/libsystemd')
-rw-r--r-- | src/libsystemd/sd-bus/bus-convenience.c | 53 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-objects.c | 25 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-util.c | 24 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-util.h | 4 |
4 files changed, 65 insertions, 41 deletions
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); |