chiark / gitweb /
bus: add new sd_bus_creds object to encapsulate process credentials
authorLennart Poettering <lennart@poettering.net>
Thu, 28 Nov 2013 16:50:02 +0000 (17:50 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 28 Nov 2013 17:42:18 +0000 (18:42 +0100)
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.

33 files changed:
.gitignore
Makefile.am
src/core/dbus-manager.c
src/core/dbus.c
src/core/selinux-access.c
src/core/service.c
src/libsystemd-bus/bus-control.c
src/libsystemd-bus/bus-convenience.c
src/libsystemd-bus/bus-creds.c [new file with mode: 0644]
src/libsystemd-bus/bus-creds.h [new file with mode: 0644]
src/libsystemd-bus/bus-dump.c
src/libsystemd-bus/bus-dump.h
src/libsystemd-bus/bus-internal.h
src/libsystemd-bus/bus-kernel.c
src/libsystemd-bus/bus-message.c
src/libsystemd-bus/bus-message.h
src/libsystemd-bus/bus-util.c
src/libsystemd-bus/bus-util.h
src/libsystemd-bus/busctl.c
src/libsystemd-bus/libsystemd-bus.sym
src/libsystemd-bus/sd-bus.c
src/libsystemd-bus/test-bus-chat.c
src/libsystemd-bus/test-bus-creds.c [new file with mode: 0644]
src/libsystemd-bus/test-bus-kernel.c
src/login/logind-dbus.c
src/login/logind-seat-dbus.c
src/login/logind-session-dbus.c
src/login/logind-user-dbus.c
src/machine/machine-dbus.c
src/machine/machined-dbus.c
src/shared/audit.c
src/shared/util.c
src/systemd/sd-bus.h

index f8f6c8a..84c83a5 100644 (file)
@@ -90,6 +90,7 @@
 /tags
 /test-boot-timestamp
 /test-bus-chat
+/test-bus-creds
 /test-bus-error
 /test-bus-introspect
 /test-bus-kernel
index 47b864c..90874df 100644 (file)
@@ -769,7 +769,9 @@ libsystemd_shared_la_SOURCES = \
        src/shared/errno-list.c \
        src/shared/errno-list.h \
        src/shared/syscall-list.c \
-       src/shared/syscall-list.h
+       src/shared/syscall-list.h \
+       src/shared/audit.c \
+       src/shared/audit.h
 
 nodist_libsystemd_shared_la_SOURCES = \
        src/shared/errno-from-name.h \
@@ -843,14 +845,6 @@ libsystemd_capability_la_LIBADD = \
        $(CAP_LIBS)
 
 # ------------------------------------------------------------------------------
-noinst_LTLIBRARIES += \
-       libsystemd-audit.la
-
-libsystemd_audit_la_SOURCES = \
-       src/shared/audit.c \
-       src/shared/audit.h
-
-# ------------------------------------------------------------------------------
 if HAVE_ACL
 noinst_LTLIBRARIES += \
        libsystemd-acl.la
@@ -1013,7 +1007,6 @@ libsystemd_core_la_LIBADD = \
        libsystemd-capability.la \
        libsystemd-units.la \
        libsystemd-label.la \
-       libsystemd-audit.la \
        libsystemd-id128-internal.la \
        libsystemd-daemon-internal.la \
        libudev-internal.la \
@@ -1957,6 +1950,8 @@ libsystemd_bus_la_SOURCES = \
        src/libsystemd-bus/bus-container.h \
        src/libsystemd-bus/bus-message.c \
        src/libsystemd-bus/bus-message.h \
+       src/libsystemd-bus/bus-creds.c \
+       src/libsystemd-bus/bus-creds.h \
        src/libsystemd-bus/bus-signature.c \
        src/libsystemd-bus/bus-signature.h \
        src/libsystemd-bus/bus-type.c \
@@ -2035,6 +2030,7 @@ tests += \
        test-bus-introspect \
        test-bus-objects \
        test-bus-error \
+       test-bus-creds \
        test-event
 
 bin_PROGRAMS += \
@@ -2119,6 +2115,17 @@ test_bus_error_LDADD = \
        libsystemd-daemon-internal.la \
        libsystemd-shared.la
 
+test_bus_creds_SOURCES = \
+       src/libsystemd-bus/test-bus-creds.c
+
+test_bus_creds_LDADD = \
+       libsystemd-bus-internal.la \
+       libsystemd-id128-internal.la \
+       libsystemd-daemon-internal.la \
+       libsystemd-shared.la \
+       libsystemd-bus-dump.la \
+       libsystemd-capability.la
+
 test_bus_match_SOURCES = \
        src/libsystemd-bus/test-bus-match.c
 
@@ -3086,7 +3093,6 @@ nodist_libsystemd_journal_core_la_SOURCES = \
 libsystemd_journal_core_la_LIBADD = \
        libsystemd-journal-internal.la \
        libudev-internal.la \
-       libsystemd-audit.la \
        libsystemd-capability.la \
        libsystemd-label.la \
        libsystemd-daemon-internal.la \
@@ -3778,7 +3784,6 @@ libsystemd_machine_core_la_SOURCES = \
 
 libsystemd_machine_core_la_LIBADD = \
        libsystemd-label.la \
-       libsystemd-audit.la \
        libsystemd-daemon-internal.la \
        libsystemd-bus-internal.la \
        libsystemd-id128-internal.la \
@@ -3933,7 +3938,6 @@ libsystemd_logind_core_la_SOURCES = \
 libsystemd_logind_core_la_LIBADD = \
        libsystemd-label.la \
        libsystemd-capability.la \
-       libsystemd-audit.la \
        libsystemd-daemon-internal.la \
        libsystemd-id128-internal.la \
        libsystemd-bus-internal.la \
@@ -4073,7 +4077,6 @@ pam_systemd_la_LDFLAGS = \
 
 pam_systemd_la_LIBADD = \
        libsystemd-capability.la \
-       libsystemd-audit.la \
        libsystemd-bus-internal.la \
        libsystemd-id128-internal.la \
        libsystemd-daemon-internal.la \
index b934624..8f63721 100644 (file)
@@ -338,7 +338,13 @@ static int method_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *us
                 return r;
 
         if (pid == 0) {
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
                 if (r < 0)
                         return r;
         }
index d130e09..7d7c6cb 100644 (file)
@@ -247,9 +247,14 @@ static int selinux_filter(sd_bus *bus, sd_bus_message *message, void *userdata,
         }
 
         if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 pid_t pid;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return 0;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
                 if (r < 0)
                         return 0;
 
@@ -300,6 +305,7 @@ static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_
         assert(path);
 
         if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 sd_bus_message *message;
                 pid_t pid;
 
@@ -307,9 +313,13 @@ static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_
                 if (!message)
                         return 0;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
                 if (r < 0)
-                        return 0;
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
 
                 u = manager_get_unit_by_pid(m, pid);
         } else {
index cca3df6..21c7a8c 100644 (file)
 #include "audit.h"
 #include "selinux-util.h"
 #include "audit-fd.h"
+#include "strv.h"
 
 static bool initialized = false;
 
-struct auditstruct {
+struct audit_info {
+        sd_bus_creds *creds;
         const char *path;
-        char *cmdline;
-        uid_t loginuid;
-        uid_t uid;
-        gid_t gid;
+        const char *cmdline;
 };
 
-static int bus_get_selinux_security_context(
-                sd_bus *bus,
-                const char *name,
-                sd_bus_error *error,
-                char **ret) {
-
-        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        const void *p;
-        size_t sz;
-        char *b;
-        int r;
-
-        assert(bus);
-        assert(name);
-        assert(ret);
-
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.DBus",
-                        "/org/freedesktop/DBus",
-                        "org.freedesktop.DBus",
-                        "GetConnectionSELinuxSecurityContext",
-                        error, &m,
-                        "s", name);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read_array(m, 'y', &p, &sz);
-        if (r < 0)
-                return r;
-
-        b = strndup(p, sz);
-        if (!b)
-                return -ENOMEM;
-
-        *ret = b;
-        return 0;
-}
-
-static int bus_get_audit_data(
-                sd_bus *bus,
-                const char *name,
-                struct auditstruct *audit) {
-
-        pid_t pid;
-        int r;
-
-        assert(bus);
-        assert(name);
-        assert(audit);
-
-        r = sd_bus_get_owner_pid(bus, name, &pid);
-        if (r < 0)
-                return r;
-
-        r = audit_loginuid_from_pid(pid, &audit->loginuid);
-        if (r < 0)
-                return r;
-
-        r = get_process_uid(pid, &audit->uid);
-        if (r < 0)
-                return r;
-
-        r = get_process_gid(pid, &audit->gid);
-        if (r < 0)
-                return r;
-
-        r = get_process_cmdline(pid, 0, true, &audit->cmdline);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
 /*
    Any time an access gets denied this callback will be called
    with the aduit data.  We then need to just copy the audit data into the msgbuf.
@@ -136,19 +61,19 @@ static int audit_callback(
                 char *msgbuf,
                 size_t msgbufsize) {
 
-        struct auditstruct *audit = (struct auditstruct *) auditdata;
+        const struct audit_info *audit = auditdata;
+        uid_t uid = 0, login_uid = 0;
+        gid_t gid = 0;
+
+        sd_bus_creds_get_audit_login_uid(audit->creds, &login_uid);
+        sd_bus_creds_get_uid(audit->creds, &uid);
+        sd_bus_creds_get_gid(audit->creds, &gid);
 
         snprintf(msgbuf, msgbufsize,
                  "auid=%d uid=%d gid=%d%s%s%s%s%s%s",
-                 audit->loginuid,
-                 audit->uid,
-                 audit->gid,
-                 (audit->path ? " path=\"" : ""),
-                 strempty(audit->path),
-                 (audit->path ? "\"" : ""),
-                 (audit->cmdline ? " cmdline=\"" : ""),
-                 strempty(audit->cmdline),
-                 (audit->cmdline ? "\"" : ""));
+                 login_uid, uid, gid,
+                 audit->path ? " path=\"" : "", strempty(audit->path), audit->path ? "\"" : "",
+                 audit->cmdline ? " cmdline=\"" : "", strempty(audit->cmdline), audit->cmdline ? "\"" : "");
 
         msgbuf[msgbufsize-1] = 0;
 
@@ -164,13 +89,12 @@ static int audit_callback(
 _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
         va_list ap;
 
-        va_start(ap, fmt);
-
 #ifdef HAVE_AUDIT
         if (get_audit_fd() >= 0) {
                 _cleanup_free_ char *buf = NULL;
                 int r;
 
+                va_start(ap, fmt);
                 r = vasprintf(&buf, fmt, ap);
                 va_end(ap);
 
@@ -178,10 +102,10 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
                         audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
                         return 0;
                 }
-
-                va_start(ap, fmt);
         }
 #endif
+
+        va_start(ap, fmt);
         log_metav(LOG_USER | LOG_INFO, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
         va_end(ap);
 
@@ -238,76 +162,6 @@ void selinux_access_free(void) {
         initialized = false;
 }
 
-static int get_audit_data(
-                sd_bus *bus,
-                sd_bus_message *message,
-                struct auditstruct *audit) {
-
-        struct ucred ucred;
-        const char *sender;
-        socklen_t len;
-        int r, fd;
-
-        sender = sd_bus_message_get_sender(message);
-        if (sender)
-                return bus_get_audit_data(bus, sender, audit);
-
-        fd = sd_bus_get_fd(bus);
-        if (fd < 0)
-                return fd;
-
-        len = sizeof(ucred);
-        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len);
-        if (r < 0)
-                return -errno;
-
-        audit->uid = ucred.uid;
-        audit->gid = ucred.gid;
-
-        r = audit_loginuid_from_pid(ucred.pid, &audit->loginuid);
-        if (r < 0)
-                return r;
-
-        r = get_process_cmdline(ucred.pid, 0, true, &audit->cmdline);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-/*
-   This function returns the security context of the remote end of the dbus
-   connections.  Whether it is on the bus or a local connection.
-*/
-static int get_calling_context(
-                sd_bus *bus,
-                sd_bus_message *message,
-                sd_bus_error *error,
-                security_context_t *ret) {
-
-        const char *sender;
-        int r, fd;
-
-        /*
-           If sender exists then
-           if sender is NULL this indicates a local connection.  Grab the fd
-           from dbus and do an getpeercon to peers process context
-        */
-        sender = sd_bus_message_get_sender(message);
-        if (sender)
-                return bus_get_selinux_security_context(bus, sender, error, ret);
-
-        fd = sd_bus_get_fd(bus);
-        if (fd < 0)
-                return fd;
-
-        r = getpeercon(fd, ret);
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
 /*
    This function communicates with the kernel to check whether or not it should
    allow the access.
@@ -321,9 +175,12 @@ int selinux_generic_access_check(
                 const char *permission,
                 sd_bus_error *error) {
 
-        security_context_t scon = NULL, fcon = NULL;
-        const char *tclass = NULL;
-        struct auditstruct audit;
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+        const char *tclass = NULL, *scon = NULL;
+        struct audit_info audit_info = {};
+        _cleanup_free_ char *cl = NULL;
+        security_context_t fcon = NULL;
+        char **cmdline = NULL;
         int r = 0;
 
         assert(bus);
@@ -338,12 +195,16 @@ int selinux_generic_access_check(
         if (r < 0)
                 return r;
 
-        audit.uid = audit.loginuid = (uid_t) -1;
-        audit.gid = (gid_t) -1;
-        audit.cmdline = NULL;
-        audit.path = path;
+        r = sd_bus_query_sender_creds(
+                        message,
+                        SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|
+                        SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_AUDIT_LOGIN_UID|
+                        SD_BUS_CREDS_SELINUX_CONTEXT,
+                        &creds);
+        if (r < 0)
+                goto finish;
 
-        r = get_calling_context(bus, message, error, &scon);
+        r = sd_bus_creds_get_selinux_context(creds, &scon);
         if (r < 0)
                 goto finish;
 
@@ -367,21 +228,23 @@ int selinux_generic_access_check(
                 tclass = "system";
         }
 
-        get_audit_data(bus, message, &audit);
+        sd_bus_creds_get_cmdline(creds, &cmdline);
+        cl = strv_join(cmdline, " ");
+
+        audit_info.creds = creds;
+        audit_info.path = path;
+        audit_info.cmdline = cl;
 
-        errno = 0;
-        r = selinux_check_access(scon, fcon, tclass, permission, &audit);
+        r = selinux_check_access((security_context_t) scon, fcon, tclass, permission, &audit_info);
         if (r < 0)
                 r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
 
-        log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, audit.cmdline, r);
+        log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, cl, r);
 
 finish:
-        free(audit.cmdline);
-        freecon(scon);
         freecon(fcon);
 
-        if (r && security_getenforce() != 1) {
+        if (r < 0 && security_getenforce() != 1) {
                 sd_bus_error_free(error);
                 r = 0;
         }
index 5b41c36..cdbe4c8 100644 (file)
@@ -3673,11 +3673,14 @@ static void service_bus_name_owner_change(
                     s->state == SERVICE_RUNNING ||
                     s->state == SERVICE_RELOAD)) {
 
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 pid_t pid;
 
                 /* Try to acquire PID from bus service */
 
-                r = sd_bus_get_owner_pid(u->manager->api_bus, name, &pid);
+                r = sd_bus_get_owner_creds(u->manager->api_bus, name, SD_BUS_CREDS_PID, &creds);
+                if (r >= 0)
+                        r = sd_bus_creds_get_pid(creds, &pid);
                 if (r >= 0) {
                         log_debug_unit(u->id, "%s's D-Bus name %s is now owned by process %u", u->id, name, (unsigned) pid);
 
index f217269..43e2848 100644 (file)
@@ -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;
 }
 
index e765ddb..e57b26b 100644 (file)
@@ -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 (file)
index 0000000..5ca70cc
--- /dev/null
@@ -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 (file)
index 0000000..e2416aa
--- /dev/null
@@ -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);
index 8231cfa..9545e18 100644 (file)
@@ -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;
+}
index 51aa6aa..bb1d25d 100644 (file)
@@ -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);
index 7a695c7..accb838 100644 (file)
@@ -213,6 +213,8 @@ struct sd_bus {
         struct ucred ucred;
         char label[NAME_MAX];
 
+        uint64_t creds_mask;
+
         int *fds;
         unsigned n_fds;
 
index da9474d..84d84df 100644 (file)
@@ -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 &&
index 132426f..dd058e7 100644 (file)
@@ -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,
index 8c0ba86..72a79f7 100644 (file)
@@ -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)
index 7a21975..5069aaa 100644 (file)
@@ -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)
index 38d468e..9d49237 100644 (file)
@@ -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)              \
index 4204adb..24db48a 100644 (file)
@@ -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)
index 9cf06c4..435c794 100644 (file)
@@ -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;
index 49a2abc..97a8c68 100644 (file)
@@ -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;
+}
index 66a5df9..021379f 100644 (file)
@@ -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 (file)
index 0000000..0a9b2ca
--- /dev/null
@@ -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;
+}
index 44d2fa7..f970ca5 100644 (file)
@@ -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);
index a4bdf5f..0461d18 100644 (file)
@@ -172,7 +172,13 @@ static int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void
                 return r;
 
         if (pid == 0) {
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
                 if (r < 0)
                         return r;
         }
@@ -234,7 +240,13 @@ static int method_get_user_by_pid(sd_bus *bus, sd_bus_message *message, void *us
                 return r;
 
         if (pid == 0) {
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
                 if (r < 0)
                         return r;
         }
@@ -543,9 +555,15 @@ static int method_create_session(sd_bus *bus, sd_bus_message *message, void *use
         }
 
         if (leader <= 0) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
                 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), (pid_t*) &leader);
+                r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
                 if (r < 0)
                         return r;
         }
@@ -1424,6 +1442,7 @@ static int method_do_shutdown_or_sleep(
                 sd_bus_message_handler_t method,
                 sd_bus_error *error) {
 
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         bool multiple_sessions, blocked;
         int interactive, r;
         uid_t uid;
@@ -1455,7 +1474,11 @@ static int method_do_shutdown_or_sleep(
                         return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
         }
 
-        r = sd_bus_get_owner_uid(m->bus, sd_bus_message_get_sender(message), &uid);
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
@@ -1579,6 +1602,7 @@ static int method_can_shutdown_or_sleep(
                 const char *sleep_verb,
                 sd_bus_error *error) {
 
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         bool multiple_sessions, challenge, blocked;
         const char *result = NULL;
         uid_t uid;
@@ -1600,7 +1624,11 @@ static int method_can_shutdown_or_sleep(
                         return sd_bus_reply_method_return(message, "s", "na");
         }
 
-        r = sd_bus_get_owner_uid(m->bus, sd_bus_message_get_sender(message), &uid);
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
@@ -1722,6 +1750,7 @@ static int method_can_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *u
 }
 
 static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         const char *who, *why, *what, *mode;
         _cleanup_free_ char *id = NULL;
         _cleanup_close_ int fifo_fd = -1;
@@ -1774,11 +1803,15 @@ static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata,
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        r = sd_bus_get_owner_uid(m->bus, sd_bus_message_get_sender(message), &uid);
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
-        r = sd_bus_get_owner_pid(m->bus, sd_bus_message_get_sender(message), &pid);
+        r = sd_bus_creds_get_pid(creds, &pid);
         if (r < 0)
                 return r;
 
index f274c0d..76158e5 100644 (file)
@@ -266,6 +266,7 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void
         assert(m);
 
         if (streq(path, "/org/freedesktop/login1/seat/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 sd_bus_message *message;
                 Session *session;
                 pid_t pid;
@@ -274,9 +275,13 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void
                 if (!message)
                         return 0;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
                 if (r < 0)
-                        return 0;
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
 
                 r = manager_get_session_by_pid(m, pid, &session);
                 if (r <= 0)
index bb62b26..4bbe75e 100644 (file)
@@ -225,6 +225,7 @@ static int method_lock(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
 }
 
 static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         Session *s = userdata;
         uid_t uid;
         int r, b;
@@ -237,7 +238,11 @@ static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *user
         if (r < 0)
                 return r;
 
-        r = sd_bus_get_owner_uid(bus, sd_bus_message_get_sender(message), &uid);
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
@@ -283,6 +288,7 @@ static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
 }
 
 static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
         Session *s = userdata;
         int r, force;
         uid_t uid;
@@ -295,7 +301,11 @@ static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userd
         if (r < 0)
                 return r;
 
-        r = sd_bus_get_owner_uid(bus, sd_bus_message_get_sender(message), &uid);
+        r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_UID, &creds);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_creds_get_uid(creds, &uid);
         if (r < 0)
                 return r;
 
@@ -477,6 +487,7 @@ int session_object_find(sd_bus *bus, const char *path, const char *interface, vo
         assert(m);
 
         if (streq(path, "/org/freedesktop/login1/session/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 sd_bus_message *message;
                 pid_t pid;
 
@@ -484,9 +495,13 @@ int session_object_find(sd_bus *bus, const char *path, const char *interface, vo
                 if (!message)
                         return 0;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
                 if (r < 0)
-                        return 0;
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
 
                 r = manager_get_session_by_pid(m, pid, &session);
                 if (r <= 0)
index 6a77e33..b034515 100644 (file)
@@ -247,6 +247,7 @@ int user_object_find(sd_bus *bus, const char *path, const char *interface, void
         assert(m);
 
         if (streq(path, "/org/freedesktop/login1/user/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 sd_bus_message *message;
                 pid_t pid;
 
@@ -254,9 +255,13 @@ int user_object_find(sd_bus *bus, const char *path, const char *interface, void
                 if (!message)
                         return 0;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
                 if (r < 0)
-                        return 0;
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
 
                 r = manager_get_user_by_pid(m, pid, &user);
                 if (r <= 0)
index c6a794b..1f24b11 100644 (file)
@@ -154,6 +154,7 @@ int machine_object_find(sd_bus *bus, const char *path, const char *interface, vo
         assert(m);
 
         if (streq(path, "/org/freedesktop/machine1/machine/self")) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
                 sd_bus_message *message;
                 pid_t pid;
 
@@ -161,9 +162,13 @@ int machine_object_find(sd_bus *bus, const char *path, const char *interface, vo
                 if (!message)
                         return 0;
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
                 if (r < 0)
-                        return 0;
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
+                if (r < 0)
+                        return r;
 
                 r = manager_get_machine_by_pid(m, pid, &machine);
                 if (r <= 0)
index 34cd61d..726cc4c 100644 (file)
@@ -102,7 +102,13 @@ static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void
                 return r;
 
         if (pid == 0) {
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_creds_get_pid(creds, &pid);
                 if (r < 0)
                         return r;
         }
@@ -216,9 +222,15 @@ static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *use
                 return r;
 
         if (leader == 0) {
+                _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+
+                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+                if (r < 0)
+                        return r;
+
                 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
 
-                r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), (pid_t*) &leader);
+                r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
                 if (r < 0)
                         return r;
         }
index 97560cc..9ab4640 100644 (file)
@@ -26,8 +26,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
-#include <sys/prctl.h>
-#include <sys/capability.h>
 
 #include "macro.h"
 #include "audit.h"
 #include "virt.h"
 
 int audit_session_from_pid(pid_t pid, uint32_t *id) {
-        char *s;
+        _cleanup_free_ char *s = NULL;
+        const char *p;
         uint32_t u;
         int r;
 
         assert(id);
 
-        if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0)
-                return -ENOENT;
-
         /* Audit doesn't support containers right now */
         if (detect_container(NULL) > 0)
                 return -ENOTSUP;
 
         if (pid == 0)
-                r = read_one_line_file("/proc/self/sessionid", &s);
-        else {
-                char *p;
-
-                if (asprintf(&p, "/proc/%lu/sessionid", (unsigned long) pid) < 0)
-                        return -ENOMEM;
-
-                r = read_one_line_file(p, &s);
-                free(p);
-        }
+                p = "/proc/self/sessionid";
+        else
+                p = procfs_file_alloca(pid, "sessionid");
 
+        r = read_one_line_file(p, &s);
         if (r < 0)
                 return r;
 
         r = safe_atou32(s, &u);
-        free(s);
-
         if (r < 0)
                 return r;
 
         if (u == (uint32_t) -1 || u <= 0)
-                return -ENOENT;
+                return -ENXIO;
 
         *id = u;
         return 0;
 }
 
 int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
-        char *s;
+        _cleanup_free_ char *s = NULL;
+        const char *p;
         uid_t u;
         int r;
 
         assert(uid);
 
-        /* Only use audit login uid if we are executed with sufficient
-         * capabilities so that pam_loginuid could do its job. If we
-         * are lacking the CAP_AUDIT_CONTROL capabality we most likely
-         * are being run in a container and /proc/self/loginuid is
-         * useless since it probably contains a uid of the host
-         * system. */
-
-        if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0)
-                return -ENOENT;
-
         /* Audit doesn't support containers right now */
         if (detect_container(NULL) > 0)
                 return -ENOTSUP;
 
         if (pid == 0)
-                r = read_one_line_file("/proc/self/loginuid", &s);
-        else {
-                char *p;
-
-                if (asprintf(&p, "/proc/%lu/loginuid", (unsigned long) pid) < 0)
-                        return -ENOMEM;
-
-                r = read_one_line_file(p, &s);
-                free(p);
-        }
+                p = "/proc/self/loginuid";
+        else
+                p = procfs_file_alloca(pid, "loginuid");
 
+        r = read_one_line_file(p, &s);
         if (r < 0)
                 return r;
 
         r = parse_uid(s, &u);
-        free(s);
-
         if (r < 0)
                 return r;
 
         if (u == (uid_t) -1)
-                return -ENOENT;
+                return -ENXIO;
 
         *uid = (uid_t) u;
         return 0;
index 0fce253..38134ae 100644 (file)
@@ -430,7 +430,7 @@ char *split_quoted(const char *c, size_t *l, char **state) {
                 *state = (char*) e;
         }
 
-        return current;
+        return (char*) current;
 }
 
 int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
@@ -497,7 +497,7 @@ int get_starttime_of_pid(pid_t pid, unsigned long long *st) {
 
         f = fopen(p, "re");
         if (!f)
-                return -errno;
+                return errno == ENOENT ? -ESRCH : -errno;
 
         if (!fgets(line, sizeof(line), f)) {
                 if (ferror(f))
@@ -563,6 +563,7 @@ char *truncate_nl(char *s) {
 
 int get_process_comm(pid_t pid, char **name) {
         const char *p;
+        int r;
 
         assert(name);
         assert(pid >= 0);
@@ -572,7 +573,11 @@ int get_process_comm(pid_t pid, char **name) {
         else
                 p = procfs_file_alloca(pid, "comm");
 
-        return read_one_line_file(p, name);
+        r = read_one_line_file(p, name);
+        if (r == -ENOENT)
+                return -ESRCH;
+
+        return r;
 }
 
 int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
@@ -729,7 +734,7 @@ int get_process_exe(pid_t pid, char **name) {
 
         r = readlink_malloc(p, name);
         if (r < 0)
-                return r;
+                return r == -ENOENT ? -ESRCH : r;
 
         d = endswith(*name, " (deleted)");
         if (d)
index 9c001b1..202fdb8 100644 (file)
@@ -37,6 +37,7 @@ _SD_BEGIN_DECLARATIONS;
 
 typedef struct sd_bus sd_bus;
 typedef struct sd_bus_message sd_bus_message;
+typedef struct sd_bus_creds sd_bus_creds;
 
 typedef struct {
         const char *name;
@@ -44,6 +45,34 @@ typedef struct {
         int need_free;
 } sd_bus_error;
 
+/* Flags */
+
+enum {
+        SD_BUS_CREDS_UID              = 1ULL << 0,
+        SD_BUS_CREDS_GID              = 1ULL << 1,
+        SD_BUS_CREDS_PID              = 1ULL << 2,
+        SD_BUS_CREDS_PID_STARTTIME    = 1ULL << 3,
+        SD_BUS_CREDS_TID              = 1ULL << 4,
+        SD_BUS_CREDS_COMM             = 1ULL << 5,
+        SD_BUS_CREDS_TID_COMM         = 1ULL << 6,
+        SD_BUS_CREDS_EXE              = 1ULL << 7,
+        SD_BUS_CREDS_CMDLINE          = 1ULL << 8,
+        SD_BUS_CREDS_CGROUP           = 1ULL << 9,
+        SD_BUS_CREDS_UNIT             = 1ULL << 10,
+        SD_BUS_CREDS_USER_UNIT        = 1ULL << 11,
+        SD_BUS_CREDS_SLICE            = 1ULL << 12,
+        SD_BUS_CREDS_SESSION          = 1ULL << 13,
+        SD_BUS_CREDS_OWNER_UID        = 1ULL << 14,
+        SD_BUS_CREDS_EFFECTIVE_CAPS   = 1ULL << 15,
+        SD_BUS_CREDS_PERMITTED_CAPS   = 1ULL << 16,
+        SD_BUS_CREDS_INHERITABLE_CAPS = 1ULL << 17,
+        SD_BUS_CREDS_BOUNDING_CAPS    = 1ULL << 18,
+        SD_BUS_CREDS_SELINUX_CONTEXT  = 1ULL << 19,
+        SD_BUS_CREDS_AUDIT_SESSION_ID = 1ULL << 20,
+        SD_BUS_CREDS_AUDIT_LOGIN_UID  = 1ULL << 21,
+        _SD_BUS_CREDS_MAX             = (1ULL << 22) -1,
+};
+
 /* Callbacks */
 
 typedef int (*sd_bus_message_handler_t)(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
@@ -74,14 +103,7 @@ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id);
 int sd_bus_set_anonymous(sd_bus *bus, int b);
 int sd_bus_negotiate_fds(sd_bus *bus, int b);
 int sd_bus_negotiate_attach_timestamp(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_creds(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_comm(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_exe(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_cmdline(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_cgroup(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_caps(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_selinux_context(sd_bus *bus, int b);
-int sd_bus_negotiate_attach_audit(sd_bus *bus, int b);
+int sd_bus_negotiate_attach_creds(sd_bus *bus, uint64_t creds_mask);
 int sd_bus_start(sd_bus *ret);
 
 void sd_bus_close(sd_bus *bus);
@@ -92,6 +114,7 @@ sd_bus *sd_bus_unref(sd_bus *bus);
 int sd_bus_is_open(sd_bus *bus);
 int sd_bus_can_send(sd_bus *bus, char type);
 int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *peer);
+int sd_bus_get_peer_creds(sd_bus *bus, uint64_t creds_mask, sd_bus_creds **ret);
 
 int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial);
 int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *serial);
@@ -149,6 +172,8 @@ int sd_bus_message_new_method_errnof(sd_bus_message *call, sd_bus_message **m, i
 sd_bus_message* sd_bus_message_ref(sd_bus_message *m);
 sd_bus_message* sd_bus_message_unref(sd_bus_message *m);
 
+sd_bus* sd_bus_message_get_bus(sd_bus_message *m);
+
 int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type);
 int sd_bus_message_get_serial(sd_bus_message *m, uint64_t *serial);
 int sd_bus_message_get_reply_serial(sd_bus_message *m, uint64_t *serial);
@@ -164,28 +189,9 @@ const char *sd_bus_message_get_sender(sd_bus_message *m);
 const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m);
 int sd_bus_message_get_errno(sd_bus_message *m);
 
-sd_bus* sd_bus_message_get_bus(sd_bus_message *m);
-
 int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec);
 int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec);
-int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid);
-int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid);
-int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid);
-int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid);
-int sd_bus_message_get_pid_starttime(sd_bus_message *m, uint64_t *usec);
-int sd_bus_message_get_selinux_context(sd_bus_message *m, const char **r);
-int sd_bus_message_get_comm(sd_bus_message *m, const char **r);
-int sd_bus_message_get_tid_comm(sd_bus_message *m, const char **r);
-int sd_bus_message_get_exe(sd_bus_message *m, const char **r);
-int sd_bus_message_get_cgroup(sd_bus_message *m, const char **r);
-int sd_bus_message_get_cmdline(sd_bus_message *m, char ***cmdline);
-int sd_bus_message_get_unit(sd_bus_message *m, const char **unit);
-int sd_bus_message_get_user_unit(sd_bus_message *m, const char **unit);
-int sd_bus_message_get_session(sd_bus_message *m, const char **session);
-int sd_bus_message_get_owner_uid(sd_bus_message *m, uid_t *uid);
-int sd_bus_message_get_audit_sessionid(sd_bus_message *m, uint32_t *sessionid);
-int sd_bus_message_get_audit_loginuid(sd_bus_message *m, uid_t *loginuid);
-int sd_bus_message_has_effective_cap(sd_bus_message *m, int capability);
+sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m); /* do not unref the result */
 
 int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member);
 int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, const char *member);
@@ -221,6 +227,16 @@ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *content
 int sd_bus_message_at_end(sd_bus_message *m, int complete);
 int sd_bus_message_rewind(sd_bus_message *m, int complete);
 
+/* Bus management */
+
+int sd_bus_get_unique_name(sd_bus *bus, const char **unique);
+int sd_bus_request_name(sd_bus *bus, const char *name, int flags);
+int sd_bus_release_name(sd_bus *bus, const char *name);
+int sd_bus_list_names(sd_bus *bus, char ***l);
+int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner); /* free the result! */
+int sd_bus_get_owner_creds(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **creds); /* unref the result! */
+int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine);
+
 /* Convenience calls */
 
 int sd_bus_call_method(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, sd_bus_message **reply, const char *types, ...);
@@ -246,16 +262,39 @@ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *inte
 int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces);
 int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) _sd_sentinel_;
 
-/* Bus management */
-
-int sd_bus_get_unique_name(sd_bus *bus, const char **unique);
-int sd_bus_request_name(sd_bus *bus, const char *name, int flags);
-int sd_bus_release_name(sd_bus *bus, const char *name);
-int sd_bus_list_names(sd_bus *bus, char ***l);
-int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner); /* free the result! */
-int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid);
-int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid);
-int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine);
+int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds);
+
+/* Credential handling */
+
+int sd_bus_creds_new_from_pid(pid_t pid, uint64_t creds_mask, sd_bus_creds **ret);
+sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c);
+sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c);
+uint64_t sd_bus_creds_get_mask(sd_bus_creds *c);
+
+int sd_bus_creds_extend(sd_bus_creds *c, uint64_t creds_mask, sd_bus_creds **ret); /* unref the result */
+
+int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid);
+int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid);
+int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid);
+int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec);
+int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid);
+int sd_bus_creds_get_comm(sd_bus_creds *c, const char **r);
+int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **r);
+int sd_bus_creds_get_exe(sd_bus_creds *c, const char **r);
+int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline);
+int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **r);
+int sd_bus_creds_get_unit(sd_bus_creds *c, const char **unit);
+int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **unit);
+int sd_bus_creds_get_slice(sd_bus_creds *c, const char **slice);
+int sd_bus_creds_get_session(sd_bus_creds *c, const char **session);
+int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid);
+int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability);
+int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability);
+int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability);
+int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability);
+int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **r);
+int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid);
+int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *loginuid);
 
 /* Error structures */
 
@@ -273,6 +312,8 @@ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e);
 int sd_bus_error_is_set(const sd_bus_error *e);
 int sd_bus_error_has_name(const sd_bus_error *e, const char *name);
 
+/* Auxiliary macros */
+
 #define SD_BUS_MESSAGE_APPEND_ID128(x) 16,                              \
                 (x).bytes[0],  (x).bytes[1],  (x).bytes[2],  (x).bytes[3], \
                 (x).bytes[4],  (x).bytes[5],  (x).bytes[6],  (x).bytes[7], \
@@ -285,6 +326,8 @@ int sd_bus_error_has_name(const sd_bus_error *e, const char *name);
                 &(x).bytes[8],  &(x).bytes[9],  &(x).bytes[10], &(x).bytes[11], \
                 &(x).bytes[12], &(x).bytes[13], &(x).bytes[14], &(x).bytes[15]
 
+/* Label escaping */
+
 char *sd_bus_label_escape(const char *s);
 char *sd_bus_label_unescape(const char *f);