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/sd-bus/bus-convenience.c | |
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/sd-bus/bus-convenience.c')
-rw-r--r-- | src/libsystemd/sd-bus/bus-convenience.c | 53 |
1 files changed, 53 insertions, 0 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; +} |