diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-11-28 17:50:02 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-11-28 18:42:18 +0100 |
commit | 5b12334d35eadf1f45cc3d631fd1a2e72ffaea0a (patch) | |
tree | 55682fbecfeb705adfaf0f78fd76f5c8dc219b1b /src/libsystemd-bus | |
parent | 70f75a523b16ad495a7791d595ee3eececf75953 (diff) |
bus: add new sd_bus_creds object to encapsulate process credentials
This way we can unify handling of credentials that are attached to
messages, or can be queried for bus name owners or connection peers.
This also adds the ability to extend incomplete credential information
with data from /proc,
Also, provide a convenience call that will automatically determine the
most appropriate credential object for an incoming message, by using the
the attached information if possible, the sending name information if
available and otherwise the peer's credentials.
Diffstat (limited to 'src/libsystemd-bus')
-rw-r--r-- | src/libsystemd-bus/bus-control.c | 154 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-convenience.c | 30 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-creds.c | 796 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-creds.h | 67 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-dump.c | 227 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-dump.h | 2 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-internal.h | 2 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-kernel.c | 61 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-message.c | 234 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-message.h | 30 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-util.c | 31 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-util.h | 2 | ||||
-rw-r--r-- | src/libsystemd-bus/busctl.c | 44 | ||||
-rw-r--r-- | src/libsystemd-bus/libsystemd-bus.sym | 76 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-bus.c | 120 | ||||
-rw-r--r-- | src/libsystemd-bus/test-bus-chat.c | 4 | ||||
-rw-r--r-- | src/libsystemd-bus/test-bus-creds.c | 46 | ||||
-rw-r--r-- | src/libsystemd-bus/test-bus-kernel.c | 18 |
18 files changed, 1393 insertions, 551 deletions
diff --git a/src/libsystemd-bus/bus-control.c b/src/libsystemd-bus/bus-control.c index f217269f79..43e2848ecc 100644 --- a/src/libsystemd-bus/bus-control.c +++ b/src/libsystemd-bus/bus-control.c @@ -260,80 +260,114 @@ _public_ int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner) { return 0; } -_public_ int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid) { +_public_ int sd_bus_get_owner_creds(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **creds) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - uint32_t u; + _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + pid_t pid = 0; int r; - if (!bus) - return -EINVAL; - if (!name) - return -EINVAL; - if (!uid) - return -EINVAL; - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; - if (bus_pid_changed(bus)) - return -ECHILD; + assert_return(bus, -EINVAL); + assert_return(name, -EINVAL); + assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP); + assert_return(creds, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); - r = sd_bus_call_method( - bus, - "org.freedesktop.DBus", - "/", - "org.freedesktop.DBus", - "GetConnectionUnixUser", - NULL, - &reply, - "s", - name); - if (r < 0) - return r; + c = bus_creds_new(); + if (!c) + return -ENOMEM; - r = sd_bus_message_read(reply, "u", &u); - if (r < 0) - return r; + if ((mask & SD_BUS_CREDS_PID) || + mask & ~(SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_SELINUX_CONTEXT)) { + uint32_t u; - *uid = (uid_t) u; - return 0; -} + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/", + "org.freedesktop.DBus", + "GetConnectionUnixProcessID", + NULL, + &reply, + "s", + name); + if (r < 0) + return r; -_public_ int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - uint32_t u; - int r; + r = sd_bus_message_read(reply, "u", &u); + if (r < 0) + return r; - if (!bus) - return -EINVAL; - if (!name) - return -EINVAL; - if (!pid) - return -EINVAL; - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; - if (bus_pid_changed(bus)) - return -ECHILD; + pid = u; + if (mask & SD_BUS_CREDS_PID) { + c->pid = u; + c->mask |= SD_BUS_CREDS_PID; + } - r = sd_bus_call_method( - bus, - "org.freedesktop.DBus", - "/", - "org.freedesktop.DBus", - "GetConnectionUnixProcessID", - NULL, - &reply, - "s", - name); - if (r < 0) - return r; + reply = sd_bus_message_unref(reply); + } + + if (mask & SD_BUS_CREDS_UID) { + uint32_t u; + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/", + "org.freedesktop.DBus", + "GetConnectionUnixUser", + NULL, + &reply, + "s", + name); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "u", &u); + if (r < 0) + return r; + + c->uid = u; + c->mask |= SD_BUS_CREDS_UID; + + reply = sd_bus_message_unref(reply); + } + + if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { + const void *p; + size_t sz; + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/", + "org.freedesktop.DBus", + "GetConnectionSELinuxSecurityContext", + NULL, + &reply, + "s", + name); + if (r < 0) + return r; + + r = sd_bus_message_read_array(reply, 'y', &p, &sz); + if (r < 0) + return r; + + c->label = strndup(p, sz); + if (!c->label) + return -ENOMEM; + + c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; + } - r = sd_bus_message_read(reply, "u", &u); + r = bus_creds_add_more(c, mask, pid, 0); if (r < 0) return r; - if (u == 0) - return -EIO; + *creds = c; + c = NULL; - *pid = (uid_t) u; return 0; } diff --git a/src/libsystemd-bus/bus-convenience.c b/src/libsystemd-bus/bus-convenience.c index e765ddb21d..e57b26bf6b 100644 --- a/src/libsystemd-bus/bus-convenience.c +++ b/src/libsystemd-bus/bus-convenience.c @@ -410,3 +410,33 @@ _public_ int sd_bus_set_property( return sd_bus_call(bus, m, 0, error, NULL); } + +_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) { + sd_bus_creds *c; + + assert_return(call, -EINVAL); + assert_return(call->sealed, -EPERM); + assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(call->bus), -ECHILD); + + c = sd_bus_message_get_creds(call); + + /* All data we need? */ + if (c && (mask & ~c->mask) == 0) { + *creds = sd_bus_creds_ref(c); + return 0; + } + + /* No data passed? Or not enough data passed to retrieve the missing bits? */ + if (!c || !(c->mask & SD_BUS_CREDS_PID)) { + /* We couldn't read anything from the call, let's try + * to get it from the sender or peer */ + + if (call->sender) + return sd_bus_get_owner_creds(call->bus, call->sender, mask, creds); + else + return sd_bus_get_peer_creds(call->bus, mask, creds); + } + + return sd_bus_creds_extend(c, mask, creds); +} diff --git a/src/libsystemd-bus/bus-creds.c b/src/libsystemd-bus/bus-creds.c new file mode 100644 index 0000000000..5ca70ccafa --- /dev/null +++ b/src/libsystemd-bus/bus-creds.c @@ -0,0 +1,796 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdlib.h> + +#include "util.h" +#include "cgroup-util.h" +#include "fileio.h" +#include "audit.h" +#include "bus-message.h" +#include "bus-util.h" +#include "time-util.h" +#include "bus-creds.h" + +enum { + CAP_OFFSET_INHERITABLE = 0, + CAP_OFFSET_PERMITTED = 1, + CAP_OFFSET_EFFECTIVE = 2, + CAP_OFFSET_BOUNDING = 3 +}; + +void bus_creds_done(sd_bus_creds *c) { + assert(c); + + /* For internal bus cred structures that are allocated by + * something else */ + + free(c->session); + free(c->unit); + free(c->user_unit); + free(c->slice); + + free(c->cmdline_array); +} + +_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) { + assert_return(c, NULL); + + if (c->allocated) { + assert(c->n_ref > 0); + c->n_ref++; + } else { + sd_bus_message *m; + + /* If this is an embedded creds structure, then + * forward ref counting to the message */ + m = container_of(c, sd_bus_message, creds); + sd_bus_message_ref(m); + } + + return c; +} + +_public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) { + assert_return(c, NULL); + + if (c->allocated) { + assert(c->n_ref > 0); + c->n_ref--; + + if (c->n_ref == 0) { + bus_creds_done(c); + + free(c->comm); + free(c->tid_comm); + free(c->exe); + free(c->cmdline); + free(c->cgroup); + free(c->capability); + free(c->label); + free(c); + } + } else { + sd_bus_message *m; + + m = container_of(c, sd_bus_message, creds); + sd_bus_message_unref(m); + } + + + return NULL; +} + +_public_ uint64_t sd_bus_creds_get_mask(sd_bus_creds *c) { + assert_return(c, 0); + + return c->mask; +} + +sd_bus_creds* bus_creds_new(void) { + sd_bus_creds *c; + + c = new0(sd_bus_creds, 1); + if (!c) + return NULL; + + c->allocated = true; + c->n_ref = 1; + return c; +} + +_public_ int sd_bus_creds_new_from_pid(pid_t pid, uint64_t mask, sd_bus_creds **ret) { + sd_bus_creds *c; + int r; + + assert_return(pid >= 0, -EINVAL); + assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP); + assert_return(ret, -EINVAL); + + if (pid == 0) + pid = getpid(); + + c = bus_creds_new(); + if (!c) + return -ENOMEM; + + r = bus_creds_add_more(c, mask, pid, 0); + if (r < 0) { + free(c); + return r; + } + + /* Check if the process existed at all, in case we haven't + * figured that out already */ + if (kill(pid, 0) < 0 && errno == ESRCH) { + sd_bus_creds_unref(c); + return -ESRCH; + } + + *ret = c; + return 0; +} + +_public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) { + assert_return(c, -EINVAL); + assert_return(uid, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA); + + *uid = c->uid; + return 0; +} + +_public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) { + assert_return(c, -EINVAL); + assert_return(gid, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_UID, -ENODATA); + + *gid = c->gid; + return 0; +} + +_public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) { + assert_return(c, -EINVAL); + assert_return(pid, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_PID, -ENODATA); + + assert(c->pid > 0); + *pid = c->pid; + return 0; +} + +_public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) { + assert_return(c, -EINVAL); + assert_return(tid, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_TID, -ENODATA); + + assert(c->tid > 0); + *tid = c->tid; + return 0; +} + +_public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) { + assert_return(c, -EINVAL); + assert_return(usec, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_PID_STARTTIME, -ENODATA); + + assert(c->pid_starttime > 0); + *usec = c->pid_starttime; + return 0; +} + +_public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT, -ENODATA); + + assert(c->label); + *ret = c->label; + return 0; +} + +_public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_COMM, -ENODATA); + + assert(c->comm); + *ret = c->comm; + return 0; +} + +_public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_TID_COMM, -ENODATA); + + assert(c->tid_comm); + *ret = c->tid_comm; + return 0; +} + +_public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_EXE, -ENODATA); + + assert(c->exe); + *ret = c->exe; + return 0; +} + +_public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) { + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_CGROUP, -ENODATA); + + assert(c->cgroup); + *ret = c->cgroup; + return 0; +} + +_public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) { + int r; + + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_UNIT, -ENODATA); + + assert(c->cgroup); + + if (!c->unit) { + r = cg_path_get_unit(c->cgroup, (char**) &c->unit); + if (r < 0) + return r; + } + + *ret = c->unit; + return 0; +} + +_public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) { + int r; + + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_USER_UNIT, -ENODATA); + + assert(c->cgroup); + + if (!c->user_unit) { + r = cg_path_get_user_unit(c->cgroup, (char**) &c->user_unit); + if (r < 0) + return r; + } + + *ret = c->user_unit; + return 0; +} + +_public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) { + int r; + + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_SLICE, -ENODATA); + + assert(c->cgroup); + + if (!c->slice) { + r = cg_path_get_slice(c->cgroup, (char**) &c->slice); + if (r < 0) + return r; + } + + *ret = c->slice; + return 0; +} + +_public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) { + int r; + + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_SESSION, -ENODATA); + + assert(c->cgroup); + + if (!c->session) { + r = cg_path_get_session(c->cgroup, (char**) &c->session); + if (r < 0) + return r; + } + + *ret = c->session; + return 0; +} + +_public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) { + assert_return(c, -EINVAL); + assert_return(uid, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_OWNER_UID, -ENODATA); + + assert(c->cgroup); + + return cg_path_get_owner_uid(c->cgroup, uid); +} + +_public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) { + size_t n, i; + const char *p; + bool first; + + assert_return(c, -EINVAL); + assert_return(c->cmdline, -ESRCH); + assert_return(c->mask & SD_BUS_CREDS_CMDLINE, -ENODATA); + + assert(c->cmdline); + + for (p = c->cmdline, n = 0; p < c->cmdline + c->cmdline_length; p++) + if (*p == 0) + n++; + + *(char***) &c->cmdline_array = new(char*, n + 1); + if (!c->cmdline_array) + return -ENOMEM; + + for (p = c->cmdline, i = 0, first = true; p < c->cmdline + c->cmdline_length; p++) { + if (first) + c->cmdline_array[i++] = (char*) p; + + first = *p == 0; + } + + c->cmdline_array[i] = NULL; + *cmdline = c->cmdline_array; + + return 0; +} + +_public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) { + assert_return(c, -EINVAL); + assert_return(sessionid, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID, -ENODATA); + + *sessionid = c->audit_session_id; + return 0; +} + +_public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) { + assert_return(c, -EINVAL); + assert_return(uid, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID, -ENODATA); + + *uid = c->audit_login_uid; + return 0; +} + +static int has_cap(sd_bus_creds *c, unsigned offset, int capability) { + size_t sz; + + assert(c); + assert(c->capability); + + sz = c->capability_size / 4; + if ((size_t) capability >= sz*8) + return 0; + + return !!(c->capability[offset * sz + (capability / 8)] & (1 << (capability % 8))); +} + +_public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) { + assert_return(c, -EINVAL); + assert_return(capability >= 0, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS, -ENODATA); + + return has_cap(c, CAP_OFFSET_EFFECTIVE, capability); +} + +_public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) { + assert_return(c, -EINVAL); + assert_return(capability >= 0, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_PERMITTED_CAPS, -ENODATA); + + return has_cap(c, CAP_OFFSET_PERMITTED, capability); +} + +_public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) { + assert_return(c, -EINVAL); + assert_return(capability >= 0, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS, -ENODATA); + + return has_cap(c, CAP_OFFSET_INHERITABLE, capability); +} + +_public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) { + assert_return(c, -EINVAL); + assert_return(capability >= 0, -EINVAL); + assert_return(c->mask & SD_BUS_CREDS_BOUNDING_CAPS, -ENODATA); + + return has_cap(c, CAP_OFFSET_BOUNDING, capability); +} + +static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) { + size_t sz; + unsigned i; + + assert(c); + assert(p); + + p += strspn(p, WHITESPACE); + + sz = strlen(p); + if (sz % 2 != 0) + return -EINVAL; + + sz /= 2; + if (!c->capability) { + c->capability = new0(uint8_t, sz * 4); + if (!c->capability) + return -ENOMEM; + + c->capability_size = sz * 4; + } + + for (i = 0; i < sz; i ++) { + int x, y; + + x = unhexchar(p[i*2]); + y = unhexchar(p[i*2+1]); + + if (x < 0 || y < 0) + return -EINVAL; + + c->capability[offset * sz + (sz - i - 1)] = (uint8_t) x << 4 | (uint8_t) y; + } + + return 0; +} + +int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { + uint64_t missing; + int r; + + assert(c); + assert(c->allocated); + + missing = mask & ~c->mask; + if (missing == 0) + return 0; + + /* Try to retrieve PID from creds if it wasn't passed to us */ + if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID)) + pid = c->pid; + + if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID)) + tid = c->pid; + + /* Without pid we cannot do much... */ + if (pid <= 0) + return 0; + + if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | + SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS | + SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) { + + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX]; + const char *p; + + p = procfs_file_alloca(pid, "status"); + + f = fopen(p, "re"); + if (!f) + return errno == ENOENT ? -ESRCH : -errno; + + FOREACH_LINE(line, f, return -errno) { + truncate_nl(line); + + if (missing & SD_BUS_CREDS_UID) { + p = startswith(line, "Uid:"); + if (p) { + unsigned long uid; + + p += strspn(p, WHITESPACE); + if (sscanf(p, "%lu", &uid) != 1) + return -EIO; + + c->uid = (uid_t) uid; + c->mask |= SD_BUS_CREDS_UID; + continue; + } + } + + if (missing & SD_BUS_CREDS_GID) { + p = startswith(line, "Gid:"); + if (p) { + unsigned long gid; + + p += strspn(p, WHITESPACE); + if (sscanf(p, "%lu", &gid) != 1) + return -EIO; + + c->gid = (uid_t) gid; + c->mask |= SD_BUS_CREDS_GID; + continue; + } + } + + if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) { + p = startswith(line, "CapEff:"); + if (p) { + r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS; + continue; + } + } + + if (missing & SD_BUS_CREDS_PERMITTED_CAPS) { + p = startswith(line, "CapPrm:"); + if (p) { + r = parse_caps(c, CAP_OFFSET_PERMITTED, p); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_PERMITTED_CAPS; + continue; + } + } + + if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) { + p = startswith(line, "CapInh:"); + if (p) { + r = parse_caps(c, CAP_OFFSET_INHERITABLE, p); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS; + continue; + } + } + + if (missing & SD_BUS_CREDS_BOUNDING_CAPS) { + p = startswith(line, "CapBnd:"); + if (p) { + r = parse_caps(c, CAP_OFFSET_BOUNDING, p); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_BOUNDING_CAPS; + continue; + } + } + } + } + + if (missing & (SD_BUS_CREDS_PID_STARTTIME)) { + unsigned long long st; + + r = get_starttime_of_pid(pid, &st); + if (r < 0) + return r; + + c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK); + c->mask |= SD_BUS_CREDS_PID_STARTTIME; + } + + if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) { + const char *p; + + p = procfs_file_alloca(pid, "attr/current"); + r = read_one_line_file(p, &c->label); + if (r < 0 && r != -ENOENT) + return r; + else if (r >= 0) + c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; + } + + if (missing & SD_BUS_CREDS_COMM) { + r = get_process_comm(pid, &c->comm); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_COMM; + } + + if (missing & SD_BUS_CREDS_EXE) { + r = get_process_exe(pid, &c->exe); + if (r < 0) + return r; + + c->mask |= SD_BUS_CREDS_EXE; + } + + if (missing & SD_BUS_CREDS_CMDLINE) { + const char *p; + + p = procfs_file_alloca(pid, "cmdline"); + r = read_full_file(p, &c->cmdline, &c->cmdline_length); + if (r < 0) + return r; + + if (c->cmdline_length == 0) { + free(c->cmdline); + c->cmdline = NULL; + } else + c->mask |= SD_BUS_CREDS_CMDLINE; + } + + if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) { + _cleanup_free_ char *p = NULL; + + if (asprintf(&p, "/proc/%lu/task/%lu/comm", (unsigned long) pid, (unsigned long) tid) < 0) + return -ENOMEM; + + r = read_one_line_file(p, &c->tid_comm); + if (r < 0) + return r == -ENOENT ? -ESRCH : r; + + c->mask |= SD_BUS_CREDS_TID_COMM; + } + + if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) { + + r = cg_pid_get_path(NULL, pid, &c->cgroup); + if (r < 0) + return r; + + c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID); + } + + if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) { + r = audit_session_from_pid(pid, &c->audit_session_id); + if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != ENOENT) + return r; + else if (r >= 0) + c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; + } + + if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) { + r = audit_loginuid_from_pid(pid, &c->audit_login_uid); + if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != ENOENT) + return r; + else if (r >= 0) + c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; + } + + return 0; +} + +_public_ int sd_bus_creds_extend(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) { + _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL; + int r; + + assert_return(c, -EINVAL); + assert_return(ret, -EINVAL); + + if ((mask & ~c->mask) == 0) { + /* There's already all data we need. */ + + *ret = sd_bus_creds_ref(c); + return 0; + } + + n = bus_creds_new(); + if (!n) + return -ENOMEM; + + /* Copy the original data over */ + + if (c->mask & mask & SD_BUS_CREDS_UID) { + n->uid = c->uid; + n->mask |= SD_BUS_CREDS_UID; + } + + if (c->mask & mask & SD_BUS_CREDS_GID) { + n->gid = c->gid; + n->mask |= SD_BUS_CREDS_GID; + } + + if (c->mask & mask & SD_BUS_CREDS_PID) { + n->pid = c->pid; + n->mask |= SD_BUS_CREDS_PID; + } + + if (c->mask & mask & SD_BUS_CREDS_TID) { + n->tid = c->tid; + n->mask |= SD_BUS_CREDS_TID; + } + + if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) { + n->pid_starttime = c->pid_starttime; + n->mask |= SD_BUS_CREDS_PID_STARTTIME; + } + + if (c->mask & mask & SD_BUS_CREDS_COMM) { + n->comm = strdup(c->comm); + if (!n->comm) + return -ENOMEM; + + n->mask |= SD_BUS_CREDS_COMM; + } + + if (c->mask & mask & SD_BUS_CREDS_TID_COMM) { + n->tid_comm = strdup(c->tid_comm); + if (!n->tid_comm) + return -ENOMEM; + + n->mask |= SD_BUS_CREDS_TID_COMM; + } + + if (c->mask & mask & SD_BUS_CREDS_EXE) { + n->exe = strdup(c->exe); + if (!n->exe) + return -ENOMEM; + + n->mask |= SD_BUS_CREDS_EXE; + } + + if (c->mask & mask & SD_BUS_CREDS_CMDLINE) { + n->cmdline = memdup(c->cmdline, c->cmdline_length); + if (!n->cmdline) + return -ENOMEM; + + n->cmdline_length = c->cmdline_length; + n->mask |= SD_BUS_CREDS_CMDLINE; + } + + if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID)) { + n->cgroup = strdup(c->cgroup); + if (!n->cgroup) + return -ENOMEM; + + n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID); + } + + if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) { + n->capability = memdup(c->capability, c->capability_size); + if (!n->capability) + return -ENOMEM; + + n->capability_size = c->capability_size; + n->mask |= c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS); + } + + if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) { + n->audit_session_id = c->audit_session_id; + n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; + } + + if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) { + n->audit_login_uid = c->audit_login_uid; + n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; + } + + /* Get more data */ + + r = bus_creds_add_more(n, mask, + c->mask & SD_BUS_CREDS_PID ? c->pid : 0, + c->mask & SD_BUS_CREDS_TID ? c->tid : 0); + if (r < 0) + return r; + + *ret = n; + n = NULL; + return 0; +} diff --git a/src/libsystemd-bus/bus-creds.h b/src/libsystemd-bus/bus-creds.h new file mode 100644 index 0000000000..e2416aa501 --- /dev/null +++ b/src/libsystemd-bus/bus-creds.h @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> + +#include "sd-bus.h" +#include "time-util.h" + +struct sd_bus_creds { + bool allocated; + unsigned n_ref; + uint64_t mask; + + uid_t uid; + gid_t gid; + pid_t pid; + usec_t pid_starttime; + pid_t tid; + + char *comm; + char *tid_comm; + char *exe; + + char *cmdline; + size_t cmdline_length; + char **cmdline_array; + + char *cgroup; + char *session; + char *unit; + char *user_unit; + char *slice; + + uint8_t *capability; + size_t capability_size; + + uint32_t audit_session_id; + uid_t audit_login_uid; + + char *label; +}; + +sd_bus_creds* bus_creds_new(void); + +void bus_creds_done(sd_bus_creds *c); + +int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid); diff --git a/src/libsystemd-bus/bus-dump.c b/src/libsystemd-bus/bus-dump.c index 8231cfabcd..9545e181d8 100644 --- a/src/libsystemd-bus/bus-dump.c +++ b/src/libsystemd-bus/bus-dump.c @@ -24,6 +24,7 @@ #include "util.h" #include "capability.h" #include "strv.h" +#include "audit.h" #include "bus-message.h" #include "bus-internal.h" @@ -45,13 +46,8 @@ static char *indent(unsigned level) { } int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { - const char *u = NULL, *uu = NULL, *s = NULL; - char **cmdline = NULL; unsigned level = 1; int r; - uid_t owner, audit_loginuid; - uint32_t audit_sessionid; - bool audit_sessionid_is_set = false, audit_loginuid_is_set = false; assert(m); @@ -96,23 +92,6 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(), ansi_highlight_red(), strna(m->error.message), ansi_highlight_off()); - if (m->pid != 0) - fprintf(f, " PID=%lu", (unsigned long) m->pid); - if (m->pid_starttime != 0) - fprintf(f, " PIDStartTime=%llu", (unsigned long long) m->pid_starttime); - if (m->tid != 0) - fprintf(f, " TID=%lu", (unsigned long) m->tid); - if (m->uid_valid) - fprintf(f, " UID=%lu", (unsigned long) m->uid); - r = sd_bus_message_get_owner_uid(m, &owner); - if (r >= 0) - fprintf(f, " OwnerUID=%lu", (unsigned long) owner); - if (m->gid_valid) - fprintf(f, " GID=%lu", (unsigned long) m->gid); - - if (m->pid != 0 || m->pid_starttime != 0 || m->tid != 0 || m->uid_valid || r >= 0 || m->gid_valid) - fputs("\n", f); - if (m->monotonic != 0) fprintf(f, " Monotonic=%llu", (unsigned long long) m->monotonic); if (m->realtime != 0) @@ -121,70 +100,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { if (m->monotonic != 0 || m->realtime != 0) fputs("\n", f); - if (m->exe) - fprintf(f, " Exe=%s", m->exe); - if (m->comm) - fprintf(f, " Comm=%s", m->comm); - if (m->tid_comm) - fprintf(f, " TIDComm=%s", m->tid_comm); - if (m->label) - fprintf(f, " Label=%s", m->label); - - if (m->exe || m->comm || m->tid_comm || m->label) - fputs("\n", f); - - if (sd_bus_message_get_cmdline(m, &cmdline) >= 0) { - char **c; - - fputs(" CommandLine=[", f); - STRV_FOREACH(c, cmdline) { - if (c != cmdline) - fputc(' ', f); - - fputs(*c, f); - } - - fputs("]\n", f); - } - - if (m->cgroup) - fprintf(f, " CGroup=%s\n", m->cgroup); - - sd_bus_message_get_unit(m, &u); - if (u) - fprintf(f, " Unit=%s", u); - sd_bus_message_get_user_unit(m, &uu); - if (uu) - fprintf(f, " UserUnit=%s", uu); - sd_bus_message_get_session(m, &s); - if (s) - fprintf(f, " Session=%s", s); - if (sd_bus_message_get_audit_loginuid(m, &audit_loginuid) >= 0) { - audit_loginuid_is_set = true; - fprintf(f, " AuditLoginUID=%lu", (unsigned long) audit_loginuid); - } - if (sd_bus_message_get_audit_sessionid(m, &audit_sessionid) >= 0) { - audit_sessionid_is_set = true; - fprintf(f, " AuditSessionID=%lu", (unsigned long) audit_sessionid); - } - - if (u || uu || s || audit_loginuid_is_set || audit_sessionid_is_set) - fputs("\n", f); - - r = sd_bus_message_has_effective_cap(m, 0); - if (r >= 0) { - unsigned long c, last_cap; - - fprintf(f, " Capabilities=%s", r ? cap_to_name(0) : ""); - - last_cap = cap_last_cap(); - for (c = 0; c < last_cap; c++) { - r = sd_bus_message_has_effective_cap(m, c); - if (r > 0) - fprintf(f, "|%s", cap_to_name(c)); - } - fputs("\n", f); - } + bus_creds_dump(&m->creds, f); } r = sd_bus_message_rewind(m, true); @@ -333,3 +249,142 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) { fprintf(f, " };\n\n"); return 0; } + +static void dump_capabilities( + sd_bus_creds *c, + FILE *f, + const char *name, + int (*has)(sd_bus_creds *c, int capability)) { + + unsigned long i, last_cap; + unsigned n = 0; + int r; + + assert(c); + assert(f); + assert(name); + assert(has); + + i = 0; + r = has(c, i); + if (r < 0) + return; + + fprintf(f, " %s=", name); + last_cap = cap_last_cap(); + + for (;;) { + if (r > 0) { + if (n > 0) + fputc(' ', f); + if (n % 4 == 3) + fputs("\n ", f); + + fputs(cap_to_name(i), f); + n++; + } + + i++; + + if (i > last_cap) + break; + + r = has(c, i); + } + + fputs("\n", f); +} + +int bus_creds_dump(sd_bus_creds *c, FILE *f) { + bool audit_sessionid_is_set = false, audit_loginuid_is_set = false; + const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL; + uid_t owner, audit_loginuid; + uint32_t audit_sessionid; + char **cmdline = NULL; + int r; + + assert(c); + + if (!f) + f = stdout; + + if (c->mask & SD_BUS_CREDS_PID) + fprintf(f, " PID=%lu", (unsigned long) c->pid); + if (c->mask & SD_BUS_CREDS_PID_STARTTIME) + fprintf(f, " PIDStartTime=%llu", (unsigned long long) c->pid_starttime); + if (c->mask & SD_BUS_CREDS_TID) + fprintf(f, " TID=%lu", (unsigned long) c->tid); + if (c->mask & SD_BUS_CREDS_UID) + fprintf(f, " UID=%lu", (unsigned long) c->uid); + r = sd_bus_creds_get_owner_uid(c, &owner); + if (r >= 0) + fprintf(f, " OwnerUID=%lu", (unsigned long) owner); + if (c->mask & SD_BUS_CREDS_GID) + fprintf(f, " GID=%lu", (unsigned long) c->gid); + + if ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID)) || r >= 0) + fputs("\n", f); + + if (c->mask & SD_BUS_CREDS_EXE) + fprintf(f, " Exe=%s", c->exe); + if (c->mask & SD_BUS_CREDS_COMM) + fprintf(f, " Comm=%s", c->comm); + if (c->mask & SD_BUS_CREDS_TID_COMM) + fprintf(f, " TIDComm=%s", c->tid_comm); + if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT) + fprintf(f, " Label=%s", c->label); + + if (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_SELINUX_CONTEXT)) + fputs("\n", f); + + if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) { + char **i; + + fputs(" CommandLine=", f); + STRV_FOREACH(i, cmdline) { + if (i != cmdline) + fputc(' ', f); + + fputs(*i, f); + } + + fputs("\n", f); + } + + if (c->mask & SD_BUS_CREDS_CGROUP) + fprintf(f, " CGroup=%s", c->cgroup); + sd_bus_creds_get_unit(c, &u); + if (u) + fprintf(f, " Unit=%s", u); + sd_bus_creds_get_user_unit(c, &uu); + if (uu) + fprintf(f, " UserUnit=%s", uu); + sd_bus_creds_get_slice(c, &sl); + if (sl) + fprintf(f, " Slice=%s", sl); + sd_bus_creds_get_session(c, &s); + if (s) + fprintf(f, " Session=%s", s); + + if ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s) + fputs("\n", f); + + if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) { + audit_loginuid_is_set = true; + fprintf(f, " AuditLoginUID=%lu", (unsigned long) audit_loginuid); + } + if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) { + audit_sessionid_is_set = true; + fprintf(f, " AuditSessionID=%lu", (unsigned long) audit_sessionid); + } + + if (audit_loginuid_is_set || audit_sessionid_is_set) + fputs("\n", f); + + dump_capabilities(c, f, "EffectiveCapabilities", sd_bus_creds_has_effective_cap); + dump_capabilities(c, f, "PermittedCapabilities", sd_bus_creds_has_permitted_cap); + dump_capabilities(c, f, "InheritableCapabilities", sd_bus_creds_has_inheritable_cap); + dump_capabilities(c, f, "BoundingCapabilities", sd_bus_creds_has_bounding_cap); + + return 0; +} diff --git a/src/libsystemd-bus/bus-dump.h b/src/libsystemd-bus/bus-dump.h index 51aa6aad4a..bb1d25dc42 100644 --- a/src/libsystemd-bus/bus-dump.h +++ b/src/libsystemd-bus/bus-dump.h @@ -27,3 +27,5 @@ #include "sd-bus.h" int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header); + +int bus_creds_dump(sd_bus_creds *c, FILE *f); diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h index 7a695c7b93..accb83849b 100644 --- a/src/libsystemd-bus/bus-internal.h +++ b/src/libsystemd-bus/bus-internal.h @@ -213,6 +213,8 @@ struct sd_bus { struct ucred ucred; char label[NAME_MAX]; + uint64_t creds_mask; + int *fds; unsigned n_fds; diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c index da9474dc51..84d84df59d 100644 --- a/src/libsystemd-bus/bus-kernel.c +++ b/src/libsystemd-bus/bus-kernel.c @@ -548,31 +548,48 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_mess idx += d->memfd.size; } else if (d->type == KDBUS_MSG_SRC_CREDS) { - m->pid_starttime = d->creds.starttime / NSEC_PER_USEC; - m->uid = d->creds.uid; - m->gid = d->creds.gid; - m->pid = d->creds.pid; - m->tid = d->creds.tid; - m->uid_valid = m->gid_valid = true; + m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC; + m->creds.uid = d->creds.uid; + m->creds.gid = d->creds.gid; + m->creds.pid = d->creds.pid; + m->creds.tid = d->creds.tid; + m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID) & bus->creds_mask; + } else if (d->type == KDBUS_MSG_TIMESTAMP) { m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC; m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC; - } else if (d->type == KDBUS_MSG_SRC_PID_COMM) - m->comm = d->str; - else if (d->type == KDBUS_MSG_SRC_TID_COMM) - m->tid_comm = d->str; - else if (d->type == KDBUS_MSG_SRC_EXE) - m->exe = d->str; - else if (d->type == KDBUS_MSG_SRC_CMDLINE) { - m->cmdline = d->str; - m->cmdline_length = l; - } else if (d->type == KDBUS_MSG_SRC_CGROUP) - m->cgroup = d->str; - else if (d->type == KDBUS_MSG_SRC_AUDIT) - m->audit = &d->audit; - else if (d->type == KDBUS_MSG_SRC_CAPS) { - m->capability = d->data; - m->capability_size = l; + + } else if (d->type == KDBUS_MSG_SRC_PID_COMM) { + m->creds.comm = d->str; + m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask; + + } else if (d->type == KDBUS_MSG_SRC_TID_COMM) { + m->creds.tid_comm = d->str; + m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask; + + } else if (d->type == KDBUS_MSG_SRC_EXE) { + m->creds.exe = d->str; + m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask; + + } else if (d->type == KDBUS_MSG_SRC_CMDLINE) { + m->creds.cmdline = d->str; + m->creds.cmdline_length = l; + m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask; + + } else if (d->type == KDBUS_MSG_SRC_CGROUP) { + m->creds.cgroup = d->str; + m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask; + + } else if (d->type == KDBUS_MSG_SRC_AUDIT) { + m->creds.audit_session_id = d->audit.sessionid; + m->creds.audit_login_uid = d->audit.loginuid; + m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask; + + } else if (d->type == KDBUS_MSG_SRC_CAPS) { + m->creds.capability = d->data; + m->creds.capability_size = l; + m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask; + } else if (d->type == KDBUS_MSG_DST_NAME) destination = d->str; else if (d->type != KDBUS_MSG_FDS && diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index 132426f6fd..dd058e72c4 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -143,16 +143,12 @@ static void message_free(sd_bus_message *m) { if (m->iovec != m->iovec_fixed) free(m->iovec); - free(m->cmdline_array); - message_reset_containers(m); free(m->root_container.signature); free(m->peeked_signature); - free(m->unit); - free(m->user_unit); - free(m->session); + bus_creds_done(&m->creds); free(m); } @@ -358,15 +354,17 @@ int bus_message_from_header( m->n_fds = n_fds; if (ucred) { - m->uid = ucred->uid; - m->pid = ucred->pid; - m->gid = ucred->gid; - m->uid_valid = m->gid_valid = true; + m->creds.uid = ucred->uid; + m->creds.pid = ucred->pid; + m->creds.gid = ucred->gid; + m->creds.mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID; } if (label) { - m->label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra); - memcpy(m->label, label, label_sz + 1); + m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra); + memcpy(m->creds.label, label, label_sz + 1); + + m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT; } if (bus) @@ -811,63 +809,10 @@ _public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) { return &m->error; } -_public_ int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid) { - assert_return(m, -EINVAL); - assert_return(uid, -EINVAL); - assert_return(m->uid_valid, -ESRCH); - - *uid = m->uid; - return 0; -} - -_public_ int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid) { - assert_return(m, -EINVAL); - assert_return(gid, -EINVAL); - assert_return(m->gid_valid, -ESRCH); - - *gid = m->gid; - return 0; -} - -_public_ int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid) { - assert_return(m, -EINVAL); - assert_return(pid, -EINVAL); - assert_return(m->pid > 0, -ESRCH); - - *pid = m->pid; - return 0; -} - -_public_ int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid) { - assert_return(m, -EINVAL); - assert_return(tid, -EINVAL); - assert_return(m->tid > 0, -ESRCH); - - *tid = m->tid; - return 0; -} - -_public_ int sd_bus_message_get_pid_starttime(sd_bus_message *m, uint64_t *usec) { - assert_return(m, -EINVAL); - assert_return(usec, -EINVAL); - assert_return(m->pid_starttime > 0, -ESRCH); - - *usec = m->pid_starttime; - return 0; -} - -_public_ int sd_bus_message_get_selinux_context(sd_bus_message *m, const char **ret) { - assert_return(m, -EINVAL); - assert_return(m->label, -ESRCH); - - *ret = m->label; - return 0; -} - _public_ int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec) { assert_return(m, -EINVAL); assert_return(usec, -EINVAL); - assert_return(m->monotonic > 0, -ESRCH); + assert_return(m->monotonic > 0, -ENODATA); *usec = m->monotonic; return 0; @@ -876,166 +821,19 @@ _public_ int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t _public_ int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec) { assert_return(m, -EINVAL); assert_return(usec, -EINVAL); - assert_return(m->realtime > 0, -ESRCH); + assert_return(m->realtime > 0, -ENODATA); *usec = m->realtime; return 0; } -_public_ int sd_bus_message_get_comm(sd_bus_message *m, const char **ret) { - assert_return(m, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(m->comm, -ESRCH); - - *ret = m->comm; - return 0; -} - -_public_ int sd_bus_message_get_tid_comm(sd_bus_message *m, const char **ret) { - assert_return(m, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(m->tid_comm, -ESRCH); - - *ret = m->tid_comm; - return 0; -} - -_public_ int sd_bus_message_get_exe(sd_bus_message *m, const char **ret) { - assert_return(m, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(m->exe, -ESRCH); - - *ret = m->exe; - return 0; -} - -_public_ int sd_bus_message_get_cgroup(sd_bus_message *m, const char **ret) { - assert_return(m, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(m->cgroup, -ESRCH); - - *ret = m->cgroup; - return 0; -} - -_public_ int sd_bus_message_get_unit(sd_bus_message *m, const char **ret) { - int r; - - assert_return(m, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(m->cgroup, -ESRCH); - - if (!m->unit) { - r = cg_path_get_unit(m->cgroup, &m->unit); - if (r < 0) - return r; - } - - *ret = m->unit; - return 0; -} - -_public_ int sd_bus_message_get_user_unit(sd_bus_message *m, const char **ret) { - int r; - - assert_return(m, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(m->cgroup, -ESRCH); - - if (!m->user_unit) { - r = cg_path_get_user_unit(m->cgroup, &m->user_unit); - if (r < 0) - return r; - } - - *ret = m->user_unit; - return 0; -} - -_public_ int sd_bus_message_get_session(sd_bus_message *m, const char **ret) { - int r; - - assert_return(m, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(m->cgroup, -ESRCH); - - if (!m->session) { - r = cg_path_get_session(m->cgroup, &m->session); - if (r < 0) - return r; - } - - *ret = m->session; - return 0; -} - -_public_ int sd_bus_message_get_owner_uid(sd_bus_message *m, uid_t *uid) { - assert_return(m, -EINVAL); - assert_return(uid, -EINVAL); - assert_return(m->cgroup, -ESRCH); - - return cg_path_get_owner_uid(m->cgroup, uid); -} - -_public_ int sd_bus_message_get_cmdline(sd_bus_message *m, char ***cmdline) { - size_t n, i; - const char *p; - bool first; - - assert_return(m, -EINVAL); - assert_return(m->cmdline, -ESRCH); - - for (p = m->cmdline, n = 0; p < m->cmdline + m->cmdline_length; p++) - if (*p == 0) - n++; - - m->cmdline_array = new(char*, n + 1); - if (!m->cmdline_array) - return -ENOMEM; - - for (p = m->cmdline, i = 0, first = true; p < m->cmdline + m->cmdline_length; p++) { - if (first) - m->cmdline_array[i++] = (char*) p; - - first = *p == 0; - } - - m->cmdline_array[i] = NULL; - *cmdline = m->cmdline_array; - - return 0; -} - -_public_ int sd_bus_message_get_audit_sessionid(sd_bus_message *m, uint32_t *sessionid) { - assert_return(m, -EINVAL); - assert_return(sessionid, -EINVAL); - assert_return(m->audit, -ESRCH); - - *sessionid = m->audit->sessionid; - return 0; -} - -_public_ int sd_bus_message_get_audit_loginuid(sd_bus_message *m, uid_t *uid) { - assert_return(m, -EINVAL); - assert_return(uid, -EINVAL); - assert_return(m->audit, -ESRCH); - - *uid = m->audit->loginuid; - return 0; -} - -_public_ int sd_bus_message_has_effective_cap(sd_bus_message *m, int capability) { - unsigned sz; - - assert_return(m, -EINVAL); - assert_return(capability < 0, -EINVAL); - assert_return(!m->capability, -ESRCH); +_public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) { + assert_return(m, NULL); - sz = m->capability_size / 4; - if ((unsigned) capability >= sz*8) - return 0; + if (m->creds.mask == 0) + return NULL; - return !!(m->capability[2 * sz + (capability / 8)] & (1 << (capability % 8))); + return &m->creds; } _public_ int sd_bus_message_is_signal(sd_bus_message *m, diff --git a/src/libsystemd-bus/bus-message.h b/src/libsystemd-bus/bus-message.h index 8c0ba86213..72a79f792b 100644 --- a/src/libsystemd-bus/bus-message.h +++ b/src/libsystemd-bus/bus-message.h @@ -29,6 +29,7 @@ #include "sd-bus.h" #include "kdbus.h" #include "time-util.h" +#include "bus-creds.h" struct bus_container { char enclosing; @@ -78,19 +79,14 @@ struct sd_bus_message { sd_bus_error error; - uid_t uid; - gid_t gid; - pid_t pid; - pid_t tid; - usec_t pid_starttime; + sd_bus_creds creds; + usec_t monotonic; usec_t realtime; bool sealed:1; bool dont_send:1; bool allow_fds:1; - bool uid_valid:1; - bool gid_valid:1; bool free_header:1; bool free_kdbus:1; bool free_fds:1; @@ -102,8 +98,6 @@ struct sd_bus_message { struct bus_body_part *body_end; unsigned n_body_parts; - char *label; - size_t rindex; struct bus_body_part *cached_rindex_part; size_t cached_rindex_part_begin; @@ -126,24 +120,6 @@ struct sd_bus_message { char sender_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1]; char destination_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1]; - - const char *exe; - const char *comm; - const char *tid_comm; - const char *cgroup; - - const char *cmdline; - size_t cmdline_length; - char **cmdline_array; - - char *session; - char *unit; - char *user_unit; - - struct kdbus_audit *audit; - - uint8_t *capability; - size_t capability_size; }; #define BUS_MESSAGE_NEED_BSWAP(m) ((m)->header->endian != SD_BUS_NATIVE_ENDIAN) diff --git a/src/libsystemd-bus/bus-util.c b/src/libsystemd-bus/bus-util.c index 7a21975092..5069aaaaba 100644 --- a/src/libsystemd-bus/bus-util.c +++ b/src/libsystemd-bus/bus-util.c @@ -20,6 +20,7 @@ ***/ #include <sys/socket.h> +#include <sys/capability.h> #include "util.h" #include "strv.h" @@ -137,7 +138,7 @@ int bus_verify_polkit( bool *_challenge, sd_bus_error *e) { - const char *sender; + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; uid_t uid; int r; @@ -145,11 +146,11 @@ int bus_verify_polkit( assert(m); assert(action); - sender = sd_bus_message_get_sender(m); - if (!sender) - return -EBADMSG; + r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; - r = sd_bus_get_owner_uid(bus, sender, &uid); + r = sd_bus_creds_get_uid(creds, &uid); if (r < 0) return r; @@ -160,6 +161,11 @@ int bus_verify_polkit( else { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; int authorized = false, challenge = false; + const char *sender; + + sender = sd_bus_message_get_sender(m); + if (!sender) + return -EBADMSG; r = sd_bus_call_method( bus, @@ -271,8 +277,9 @@ int bus_verify_polkit_async( #ifdef ENABLE_POLKIT _cleanup_bus_message_unref_ sd_bus_message *pk = NULL; AsyncPolkitQuery *q; -#endif const char *sender; +#endif + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; uid_t uid; int r; @@ -319,17 +326,21 @@ int bus_verify_polkit_async( } #endif - sender = sd_bus_message_get_sender(m); - if (!sender) - return -EBADMSG; + r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds); + if (r < 0) + return r; - r = sd_bus_get_owner_uid(bus, sender, &uid); + r = sd_bus_creds_get_uid(creds, &uid); if (r < 0) return r; if (uid == 0) return 1; + #ifdef ENABLE_POLKIT + sender = sd_bus_message_get_sender(m); + if (!sender) + return -EBADMSG; r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func); if (r < 0) diff --git a/src/libsystemd-bus/bus-util.h b/src/libsystemd-bus/bus-util.h index 38d468edad..9d4923794d 100644 --- a/src/libsystemd-bus/bus-util.h +++ b/src/libsystemd-bus/bus-util.h @@ -137,9 +137,11 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref); #define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp) #define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp) +#define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp) #define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free) #define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type) \ diff --git a/src/libsystemd-bus/busctl.c b/src/libsystemd-bus/busctl.c index 4204adb5bc..24db48a7e6 100644 --- a/src/libsystemd-bus/busctl.c +++ b/src/libsystemd-bus/busctl.c @@ -75,41 +75,47 @@ static int list_bus_names(sd_bus *bus, char **argv) { (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 20, "CONNECTION"); STRV_FOREACH(i, l) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; _cleanup_free_ char *owner = NULL; sd_id128_t mid; - pid_t pid; - uid_t uid; if (arg_no_unique && (*i)[0] == ':') continue; printf("%-*s", (int) max_i, *i); - r = sd_bus_get_owner_pid(bus, *i, &pid); + r = sd_bus_get_owner_creds(bus, *i, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM, &creds); if (r >= 0) { - _cleanup_free_ char *comm = NULL; + pid_t pid; + uid_t uid; - printf(" %10lu", (unsigned long) pid); + r = sd_bus_creds_get_pid(creds, &pid); + if (r >= 0) { + const char *comm = NULL; - get_process_comm(pid, &comm); - printf(" %-15s", strna(comm)); - } else - printf(" - - "); + sd_bus_creds_get_comm(creds, &comm); - r = sd_bus_get_owner_uid(bus, *i, &uid); - if (r >= 0) { - _cleanup_free_ char *u = NULL; + printf(" %10lu %-15s", (unsigned long) pid, strna(comm)); + } else + printf(" - - "); - u = uid_to_name(uid); - if (!u) - return log_oom(); + r = sd_bus_creds_get_uid(creds, &uid); + if (r >= 0) { + _cleanup_free_ char *u = NULL; - if (strlen(u) > 16) - u[16] = 0; + u = uid_to_name(uid); + if (!u) + return log_oom(); - printf(" %-16s", u); + if (strlen(u) > 16) + u[16] = 0; + + printf(" %-16s", u); + } else + printf(" - "); } else - printf(" - "); + printf(" - - - "); + r = sd_bus_get_owner(bus, *i, &owner); if (r >= 0) diff --git a/src/libsystemd-bus/libsystemd-bus.sym b/src/libsystemd-bus/libsystemd-bus.sym index 9cf06c44dd..435c794b14 100644 --- a/src/libsystemd-bus/libsystemd-bus.sym +++ b/src/libsystemd-bus/libsystemd-bus.sym @@ -28,13 +28,6 @@ global: sd_bus_negotiate_fds; sd_bus_negotiate_attach_timestamp; sd_bus_negotiate_attach_creds; - sd_bus_negotiate_attach_comm; - sd_bus_negotiate_attach_exe; - sd_bus_negotiate_attach_cmdline; - sd_bus_negotiate_attach_cgroup; - sd_bus_negotiate_attach_caps; - sd_bus_negotiate_attach_selinux_context; - sd_bus_negotiate_attach_audit; sd_bus_start; sd_bus_close; sd_bus_ref; @@ -42,6 +35,7 @@ global: sd_bus_is_open; sd_bus_can_send; sd_bus_get_server_id; + sd_bus_get_peer_creds; sd_bus_send; sd_bus_send_to; sd_bus_get_fd; @@ -82,6 +76,7 @@ global: sd_bus_message_new_method_errnof; sd_bus_message_ref; sd_bus_message_unref; + sd_bus_message_get_bus; sd_bus_message_get_type; sd_bus_message_get_serial; sd_bus_message_get_reply_serial; @@ -95,27 +90,9 @@ global: sd_bus_message_get_sender; sd_bus_message_get_error; sd_bus_message_get_errno; - sd_bus_message_get_bus; sd_bus_message_get_monotonic_timestamp; sd_bus_message_get_realtime_timestamp; - sd_bus_message_get_uid; - sd_bus_message_get_gid; - sd_bus_message_get_pid; - sd_bus_message_get_tid; - sd_bus_message_get_pid_starttime; - sd_bus_message_get_selinux_context; - sd_bus_message_get_comm; - sd_bus_message_get_tid_comm; - sd_bus_message_get_exe; - sd_bus_message_get_cgroup; - sd_bus_message_get_cmdline; - sd_bus_message_get_unit; - sd_bus_message_get_user_unit; - sd_bus_message_get_session; - sd_bus_message_get_owner_uid; - sd_bus_message_get_audit_sessionid; - sd_bus_message_get_audit_loginuid; - sd_bus_message_has_effective_cap; + sd_bus_message_get_creds; sd_bus_message_is_signal; sd_bus_message_is_method_call; sd_bus_message_is_method_error; @@ -147,6 +124,15 @@ global: sd_bus_message_at_end; sd_bus_message_rewind; + /* Bus management */ + sd_bus_get_unique_name; + sd_bus_request_name; + sd_bus_release_name; + sd_bus_list_names; + sd_bus_get_owner; + sd_bus_get_owner_creds; + sd_bus_get_owner_machine_id; + /* Convenience calls */ sd_bus_call_method; sd_bus_get_property; @@ -166,16 +152,36 @@ global: sd_bus_emit_interfaces_added; sd_bus_emit_interfaces_removed_strv; sd_bus_emit_interfaces_removed; + sd_bus_query_sender_creds; - /* Bus management */ - sd_bus_get_unique_name; - sd_bus_request_name; - sd_bus_release_name; - sd_bus_list_names; - sd_bus_get_owner; - sd_bus_get_owner_uid; - sd_bus_get_owner_pid; - sd_bus_get_owner_machine_id; + /* Credentials */ + sd_bus_creds_new_from_pid; + sd_bus_creds_ref; + sd_bus_creds_unref; + sd_bus_creds_extend; + sd_bus_creds_get_mask; + sd_bus_creds_get_uid; + sd_bus_creds_get_gid; + sd_bus_creds_get_pid; + sd_bus_creds_get_pid_starttime; + sd_bus_creds_get_tid; + sd_bus_creds_get_comm; + sd_bus_creds_get_tid_comm; + sd_bus_creds_get_exe; + sd_bus_creds_get_cmdline; + sd_bus_creds_get_cgroup; + sd_bus_creds_get_unit; + sd_bus_creds_get_user_unit; + sd_bus_creds_get_slice; + sd_bus_creds_get_session; + sd_bus_creds_get_owner_uid; + sd_bus_creds_has_effective_cap; + sd_bus_creds_has_permitted_cap; + sd_bus_creds_has_inheritable_cap; + sd_bus_creds_has_bounding_cap; + sd_bus_creds_get_selinux_context; + sd_bus_creds_get_audit_session_id; + sd_bus_creds_get_audit_login_uid; /* Error structures */ sd_bus_error_free; diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index 49a2abc73b..97a8c683bb 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -283,75 +283,38 @@ _public_ int sd_bus_negotiate_attach_timestamp(sd_bus *bus, int b) { return 0; } -_public_ int sd_bus_negotiate_attach_creds(sd_bus *bus, int b) { +_public_ int sd_bus_negotiate_attach_creds(sd_bus *bus, uint64_t mask) { assert_return(bus, -EINVAL); + assert_return(mask <= _SD_BUS_CREDS_MAX, -EINVAL); assert_return(bus->state == BUS_UNSET, -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); - SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CREDS, b); - return 0; -} + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CREDS, + !!(mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID))); -_public_ int sd_bus_negotiate_attach_comm(sd_bus *bus, int b) { - assert_return(bus, -EINVAL); - assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_COMM, + !!(mask & (SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM))); - SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_COMM, b); - return 0; -} + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_EXE, + !!(mask & SD_BUS_CREDS_EXE)); -_public_ int sd_bus_negotiate_attach_exe(sd_bus *bus, int b) { - assert_return(bus, -EINVAL); - assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CMDLINE, + !!(mask & SD_BUS_CREDS_CMDLINE)); - SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_EXE, b); - return 0; -} + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CGROUP, + !!(mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID))); -_public_ int sd_bus_negotiate_attach_cmdline(sd_bus *bus, int b) { - assert_return(bus, -EINVAL); - assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CAPS, + !!(mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS))); - SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CMDLINE, b); - return 0; -} + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_SECLABEL, + !!(mask & SD_BUS_CREDS_SELINUX_CONTEXT)); -_public_ int sd_bus_negotiate_attach_cgroup(sd_bus *bus, int b) { - assert_return(bus, -EINVAL); - assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); - - SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CGROUP, b); - return 0; -} - -_public_ int sd_bus_negotiate_attach_caps(sd_bus *bus, int b) { - assert_return(bus, -EINVAL); - assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); - - SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_CAPS, b); - return 0; -} + SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_AUDIT, + !!(mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))); -_public_ int sd_bus_negotiate_attach_selinux_context(sd_bus *bus, int b) { - assert_return(bus, -EINVAL); - assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus->creds_mask = mask; - SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_SECLABEL, b); - return 0; -} - -_public_ int sd_bus_negotiate_attach_audit(sd_bus *bus, int b) { - assert_return(bus, -EINVAL); - assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(!bus_pid_changed(bus), -ECHILD); - - SET_FLAG(bus->hello_flags, KDBUS_HELLO_ATTACH_AUDIT, b); return 0; } @@ -2812,3 +2775,48 @@ _public_ char *sd_bus_label_unescape(const char *f) { return r; } + +_public_ int sd_bus_get_peer_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { + sd_bus_creds *c; + pid_t pid = 0; + int r; + + assert_return(bus, -EINVAL); + assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP); + assert_return(ret, -EINVAL); + assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); + assert_return(!bus_pid_changed(bus), -ECHILD); + assert_return(!bus->is_kernel, -ENOTSUP); + + if (!bus->ucred_valid && !isempty(bus->label)) + return -ENODATA; + + c = bus_creds_new(); + if (!c) + return -ENOMEM; + + if (bus->ucred_valid) { + pid = c->pid = bus->ucred.pid; + c->uid = bus->ucred.uid; + c->gid = bus->ucred.gid; + + c->mask |= ((SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask) & bus->creds_mask; + } + + if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) { + c->label = strdup(bus->label); + if (!c->label) { + sd_bus_creds_unref(c); + return -ENOMEM; + } + + c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT | bus->creds_mask; + } + + r = bus_creds_add_more(c, mask, pid, 0); + if (r < 0) + return r; + + *ret = c; + return 0; +} diff --git a/src/libsystemd-bus/test-bus-chat.c b/src/libsystemd-bus/test-bus-chat.c index 66a5df9b57..021379f0b0 100644 --- a/src/libsystemd-bus/test-bus-chat.c +++ b/src/libsystemd-bus/test-bus-chat.c @@ -158,8 +158,8 @@ static int server(sd_bus *bus) { if (!m) continue; - sd_bus_message_get_pid(m, &pid); - sd_bus_message_get_selinux_context(m, &label); + sd_bus_creds_get_pid(sd_bus_message_get_creds(m), &pid); + sd_bus_creds_get_selinux_context(sd_bus_message_get_creds(m), &label); log_info("Got message! member=%s pid=%lu label=%s", strna(sd_bus_message_get_member(m)), (unsigned long) pid, diff --git a/src/libsystemd-bus/test-bus-creds.c b/src/libsystemd-bus/test-bus-creds.c new file mode 100644 index 0000000000..0a9b2ca466 --- /dev/null +++ b/src/libsystemd-bus/test-bus-creds.c @@ -0,0 +1,46 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "sd-bus.h" +#include "bus-dump.h" +#include "bus-util.h" +#include "util.h" + +int main(int argc, char *argv[]) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + int r; + + r = sd_bus_creds_new_from_pid(0, _SD_BUS_CREDS_MAX, &creds); + assert_se(r >= 0); + + bus_creds_dump(creds, NULL); + + creds = sd_bus_creds_unref(creds); + + r = sd_bus_creds_new_from_pid(1, _SD_BUS_CREDS_MAX, &creds); + if (r != -EACCES) { + assert_se(r >= 0); + putchar('\n'); + bus_creds_dump(creds, NULL); + } + + return 0; +} diff --git a/src/libsystemd-bus/test-bus-kernel.c b/src/libsystemd-bus/test-bus-kernel.c index 44d2fa7247..f970ca5ca4 100644 --- a/src/libsystemd-bus/test-bus-kernel.c +++ b/src/libsystemd-bus/test-bus-kernel.c @@ -63,24 +63,10 @@ int main(int argc, char *argv[]) { assert_se(r >= 0); assert_se(sd_bus_negotiate_attach_timestamp(a, 1) >= 0); - assert_se(sd_bus_negotiate_attach_creds(a, 1) >= 0); - assert_se(sd_bus_negotiate_attach_comm(a, 1) >= 0); - assert_se(sd_bus_negotiate_attach_exe(a, 1) >= 0); - assert_se(sd_bus_negotiate_attach_cmdline(a, 1) >= 0); - assert_se(sd_bus_negotiate_attach_cgroup(a, 1) >= 0); - assert_se(sd_bus_negotiate_attach_caps(a, 1) >= 0); - assert_se(sd_bus_negotiate_attach_selinux_context(a, 1) >= 0); - assert_se(sd_bus_negotiate_attach_audit(a, 1) >= 0); + assert_se(sd_bus_negotiate_attach_creds(a, _SD_BUS_CREDS_MAX) >= 0); assert_se(sd_bus_negotiate_attach_timestamp(b, 1) >= 0); - assert_se(sd_bus_negotiate_attach_creds(b, 1) >= 0); - assert_se(sd_bus_negotiate_attach_comm(b, 1) >= 0); - assert_se(sd_bus_negotiate_attach_exe(b, 1) >= 0); - assert_se(sd_bus_negotiate_attach_cmdline(b, 1) >= 0); - assert_se(sd_bus_negotiate_attach_cgroup(b, 1) >= 0); - assert_se(sd_bus_negotiate_attach_caps(b, 1) >= 0); - assert_se(sd_bus_negotiate_attach_selinux_context(b, 1) >= 0); - assert_se(sd_bus_negotiate_attach_audit(b, 1) >= 0); + assert_se(sd_bus_negotiate_attach_creds(b, _SD_BUS_CREDS_MAX) >= 0); r = sd_bus_start(a); assert_se(r >= 0); |