summaryrefslogtreecommitdiffstats
path: root/src/libsystemd/sd-bus
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd/sd-bus')
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.c3
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.h3
-rw-r--r--src/libsystemd/sd-bus/bus-container.c2
-rw-r--r--src/libsystemd/sd-bus/bus-control.c139
-rw-r--r--src/libsystemd/sd-bus/bus-convenience.c38
-rw-r--r--src/libsystemd/sd-bus/bus-creds.c149
-rw-r--r--src/libsystemd/sd-bus/bus-creds.h18
-rw-r--r--src/libsystemd/sd-bus/bus-dump.c2
-rw-r--r--src/libsystemd/sd-bus/bus-internal.h4
-rw-r--r--src/libsystemd/sd-bus/bus-message.c4
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c2
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c112
-rw-r--r--src/libsystemd/sd-bus/bus-track.c2
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c102
-rw-r--r--src/libsystemd/sd-bus/test-bus-chat.c3
-rw-r--r--src/libsystemd/sd-bus/test-bus-cleanup.c2
-rw-r--r--src/libsystemd/sd-bus/test-bus-creds.c24
-rw-r--r--src/libsystemd/sd-bus/test-bus-error.c4
-rw-r--r--src/libsystemd/sd-bus/test-bus-marshal.c4
-rw-r--r--src/libsystemd/sd-bus/test-bus-objects.c3
-rw-r--r--src/libsystemd/sd-bus/test-bus-peersockaddr.c55
21 files changed, 524 insertions, 151 deletions
diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c
index df26fd7..de12ec5 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.c
+++ b/src/libsystemd/sd-bus/bus-common-errors.c
@@ -105,11 +105,13 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_TRANSFER_IN_PROGRESS, EBUSY),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRODUCT_UUID, EOPNOTSUPP),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_HARDWARE_SERIAL, EOPNOTSUPP),
SD_BUS_ERROR_MAP(BUS_ERROR_FILE_IS_PROTECTED, EACCES),
SD_BUS_ERROR_MAP(BUS_ERROR_READ_ONLY_FILESYSTEM, EROFS),
SD_BUS_ERROR_MAP(BUS_ERROR_SPEED_METER_INACTIVE, EOPNOTSUPP),
SD_BUS_ERROR_MAP(BUS_ERROR_UNMANAGED_INTERFACE, EOPNOTSUPP),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NETWORK_ALREADY_RELOADING, EBUSY),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_HOME, EEXIST),
SD_BUS_ERROR_MAP(BUS_ERROR_UID_IN_USE, EEXIST),
@@ -146,6 +148,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_HOME_CANT_AUTHENTICATE, EKEYREVOKED),
SD_BUS_ERROR_MAP(BUS_ERROR_HOME_IN_USE, EADDRINUSE),
SD_BUS_ERROR_MAP(BUS_ERROR_REBALANCE_NOT_NEEDED, EALREADY),
+ SD_BUS_ERROR_MAP(BUS_ERROR_HOME_NOT_REFERENCED, EBADR),
SD_BUS_ERROR_MAP_END
};
diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h
index 3a0eef4..94dc85d 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.h
+++ b/src/libsystemd/sd-bus/bus-common-errors.h
@@ -106,11 +106,13 @@
#define BUS_ERROR_TRANSFER_IN_PROGRESS "org.freedesktop.import1.TransferInProgress"
#define BUS_ERROR_NO_PRODUCT_UUID "org.freedesktop.hostname1.NoProductUUID"
+#define BUS_ERROR_NO_HARDWARE_SERIAL "org.freedesktop.hostname1.NoHardwareSerial"
#define BUS_ERROR_FILE_IS_PROTECTED "org.freedesktop.hostname1.FileIsProtected"
#define BUS_ERROR_READ_ONLY_FILESYSTEM "org.freedesktop.hostname1.ReadOnlyFilesystem"
#define BUS_ERROR_SPEED_METER_INACTIVE "org.freedesktop.network1.SpeedMeterInactive"
#define BUS_ERROR_UNMANAGED_INTERFACE "org.freedesktop.network1.UnmanagedInterface"
+#define BUS_ERROR_NETWORK_ALREADY_RELOADING "org.freedesktop.network1.AlreadyReloading"
#define BUS_ERROR_NO_SUCH_HOME "org.freedesktop.home1.NoSuchHome"
#define BUS_ERROR_UID_IN_USE "org.freedesktop.home1.UIDInUse"
@@ -151,5 +153,6 @@
#define BUS_ERROR_HOME_CANT_AUTHENTICATE "org.freedesktop.home1.HomeCantAuthenticate"
#define BUS_ERROR_HOME_IN_USE "org.freedesktop.home1.HomeInUse"
#define BUS_ERROR_REBALANCE_NOT_NEEDED "org.freedesktop.home1.RebalanceNotNeeded"
+#define BUS_ERROR_HOME_NOT_REFERENCED "org.freedesktop.home1.HomeNotReferenced"
BUS_ERROR_MAP_ELF_USE(bus_common_errors);
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
index 4146a6e..2eca82b 100644
--- a/src/libsystemd/sd-bus/bus-container.c
+++ b/src/libsystemd/sd-bus/bus-container.c
@@ -34,7 +34,7 @@ int bus_container_connect_socket(sd_bus *b) {
log_debug("sd-bus: connecting bus%s%s to namespace of PID "PID_FMT"...",
b->description ? " " : "", strempty(b->description), b->nspid);
- r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+ r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, &usernsfd, &rootfd);
if (r < 0)
return log_debug_errno(r, "Failed to open namespace of PID "PID_FMT": %m", b->nspid);
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index 1355e41..c420584 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -14,6 +14,7 @@
#include "bus-internal.h"
#include "bus-message.h"
#include "capability-util.h"
+#include "fd-util.h"
#include "process-util.h"
#include "stdio-util.h"
#include "string-util.h"
@@ -430,7 +431,6 @@ _public_ int sd_bus_get_name_creds(
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
const char *unique;
- pid_t pid = 0;
int r;
assert_return(bus, -EINVAL);
@@ -483,8 +483,9 @@ _public_ int sd_bus_get_name_creds(
}
if (mask != 0) {
+ bool need_pid, need_uid, need_gids, need_selinux, need_separate_calls, need_pidfd, need_augment;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- bool need_pid, need_uid, need_selinux, need_separate_calls;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
c = bus_creds_new();
if (!c)
@@ -498,20 +499,25 @@ _public_ int sd_bus_get_name_creds(
c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
}
- need_pid = (mask & SD_BUS_CREDS_PID) ||
- ((mask & SD_BUS_CREDS_AUGMENT) &&
- (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
- SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
- SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
- SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
- 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|
- SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
- SD_BUS_CREDS_SELINUX_CONTEXT|
- SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
+ need_augment =
+ (mask & SD_BUS_CREDS_AUGMENT) &&
+ (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
+ SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
+ SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
+ 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|
+ SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
+ SD_BUS_CREDS_SELINUX_CONTEXT|
+ SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID|
+ SD_BUS_CREDS_PIDFD));
+
+ need_pid = (mask & SD_BUS_CREDS_PID) || need_augment;
need_uid = mask & SD_BUS_CREDS_EUID;
+ need_gids = mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
+ need_pidfd = (mask & SD_BUS_CREDS_PIDFD) || need_augment;
- if (need_pid + need_uid + need_selinux > 1) {
+ if (need_pid + need_uid + need_selinux + need_pidfd + need_gids > 1) {
/* If we need more than one of the credentials, then use GetConnectionCredentials() */
@@ -572,7 +578,9 @@ _public_ int sd_bus_get_name_creds(
if (r < 0)
return r;
- pid = p;
+ if (!pidref_is_set(&pidref))
+ pidref = PIDREF_MAKE_FROM_PID(p);
+
if (mask & SD_BUS_CREDS_PID) {
c->pid = p;
c->mask |= SD_BUS_CREDS_PID;
@@ -599,6 +607,69 @@ _public_ int sd_bus_get_name_creds(
r = sd_bus_message_exit_container(reply);
if (r < 0)
return r;
+ } else if (need_pidfd && streq(m, "ProcessFD")) {
+ int fd;
+
+ r = sd_bus_message_read(reply, "v", "h", &fd);
+ if (r < 0)
+ return r;
+
+ pidref_done(&pidref);
+ r = pidref_set_pidfd(&pidref, fd);
+ if (r < 0)
+ return r;
+
+ if (mask & SD_BUS_CREDS_PIDFD) {
+ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (fd < 0)
+ return -errno;
+
+ close_and_replace(c->pidfd, fd);
+ c->mask |= SD_BUS_CREDS_PIDFD;
+ }
+ } else if (need_gids && streq(m, "UnixGroupIDs")) {
+
+ /* Note that D-Bus actually only gives us a combined list of
+ * primary gid and supplementary gids. And we don't know
+ * which one the primary one is. We'll take the whole shebang
+ * hence and use it as the supplementary group list, and not
+ * initialize the primary gid field. This is slightly
+ * incorrect of course, but only slightly, as in effect if
+ * the primary gid is also listed in the supplementary gid
+ * it has zero effect. */
+
+ r = sd_bus_message_enter_container(reply, 'v', "au");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_enter_container(reply, 'a', "u");
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ uint32_t u;
+
+ r = sd_bus_message_read(reply, "u", &u);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ if (!GREEDY_REALLOC(c->supplementary_gids, c->n_supplementary_gids+1))
+ return -ENOMEM;
+
+ c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) u;
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return r;
+
+ c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
} else {
r = sd_bus_message_skip(reply, "v");
if (r < 0)
@@ -614,7 +685,7 @@ _public_ int sd_bus_get_name_creds(
if (r < 0)
return r;
- if (need_pid && pid == 0)
+ if (need_pid && !pidref_is_set(&pidref))
return -EPROTO;
}
@@ -642,7 +713,9 @@ _public_ int sd_bus_get_name_creds(
if (r < 0)
return r;
- pid = u;
+ if (!pidref_is_set(&pidref))
+ pidref = PIDREF_MAKE_FROM_PID(u);
+
if (mask & SD_BUS_CREDS_PID) {
c->pid = u;
c->mask |= SD_BUS_CREDS_PID;
@@ -710,9 +783,11 @@ _public_ int sd_bus_get_name_creds(
}
}
- r = bus_creds_add_more(c, mask, pid, 0);
- if (r < 0 && r != -ESRCH) /* Return the error, but ignore ESRCH which just means the process is already gone */
- return r;
+ if (pidref_is_set(&pidref)) {
+ r = bus_creds_add_more(c, mask, &pidref, 0);
+ if (r < 0 && r != -ESRCH) /* Return the error, but ignore ESRCH which just means the process is already gone */
+ return r;
+ }
}
if (creds)
@@ -765,8 +840,8 @@ not_found:
_public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
- bool do_label, do_groups, do_sockaddr_peer;
- pid_t pid = 0;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ bool do_label, do_groups, do_sockaddr_peer, do_pidfd;
int r;
assert_return(bus, -EINVAL);
@@ -786,9 +861,10 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
do_sockaddr_peer = bus->sockaddr_size_peer >= offsetof(struct sockaddr_un, sun_path) + 1 &&
bus->sockaddr_peer.sa.sa_family == AF_UNIX &&
bus->sockaddr_peer.un.sun_path[0] == 0;
+ do_pidfd = bus->pidfd >= 0 && (mask & SD_BUS_CREDS_PIDFD);
/* Avoid allocating anything if we have no chance of returning useful data */
- if (!bus->ucred_valid && !do_label && !do_groups && !do_sockaddr_peer)
+ if (!bus->ucred_valid && !do_label && !do_groups && !do_sockaddr_peer && !do_pidfd)
return -ENODATA;
c = bus_creds_new();
@@ -797,8 +873,10 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
if (bus->ucred_valid) {
if (pid_is_valid(bus->ucred.pid)) {
- pid = c->pid = bus->ucred.pid;
+ c->pid = bus->ucred.pid;
c->mask |= SD_BUS_CREDS_PID & mask;
+
+ pidref = PIDREF_MAKE_FROM_PID(c->pid);
}
if (uid_is_valid(bus->ucred.uid)) {
@@ -859,7 +937,20 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
}
}
- r = bus_creds_add_more(c, mask, pid, 0);
+ if (do_pidfd) {
+ c->pidfd = fcntl(bus->pidfd, F_DUPFD_CLOEXEC, 3);
+ if (c->pidfd < 0)
+ return -errno;
+
+ pidref_done(&pidref);
+ r = pidref_set_pidfd(&pidref, bus->pidfd);
+ if (r < 0)
+ return r;
+
+ c->mask |= SD_BUS_CREDS_PIDFD;
+ }
+
+ r = bus_creds_add_more(c, mask, &pidref, 0);
if (r < 0 && r != -ESRCH) /* If the process vanished, then don't complain, just return what we got */
return r;
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
index 989e577..14d8073 100644
--- a/src/libsystemd/sd-bus/bus-convenience.c
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -640,8 +640,8 @@ _public_ int sd_bus_set_property(
}
_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **ret) {
+ uint64_t missing;
sd_bus_creds *c;
- int r;
assert_return(call, -EINVAL);
assert_return(call->sealed, -EPERM);
@@ -653,36 +653,22 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
return -ENOTCONN;
c = sd_bus_message_get_creds(call);
-
- /* All data we need? */
- if (c && (mask & ~SD_BUS_CREDS_AUGMENT & ~c->mask) == 0) {
+ if (c)
+ missing = mask & ~SD_BUS_CREDS_AUGMENT & ~c->mask;
+ else
+ missing = mask & ~SD_BUS_CREDS_AUGMENT;
+ if (missing == 0) { /* All data we need? */
*ret = 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)
- /* There's a sender, but the creds are missing. */
- return sd_bus_get_name_creds(call->bus, call->sender, mask, ret);
- else
- /* There's no sender. For direct connections
- * the credentials of the AF_UNIX peer matter,
- * which may be queried via sd_bus_get_owner_creds(). */
- return sd_bus_get_owner_creds(call->bus, mask, ret);
- }
-
- r = bus_creds_extend_by_pid(c, mask, ret);
- if (r == -ESRCH) {
- /* Process doesn't exist anymore? propagate the few things we have */
- *ret = sd_bus_creds_ref(c);
- return 0;
- }
+ /* There's a sender, use that */
+ if (call->sender && call->bus->bus_client)
+ return sd_bus_get_name_creds(call->bus, call->sender, mask, ret);
- return r;
+ /* There's no sender. For direct connections the credentials of the AF_UNIX peer matter, which may be
+ * queried via sd_bus_get_owner_creds(). */
+ return sd_bus_get_owner_creds(call->bus, mask, ret);
}
_public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c
index c6d8caa..adbdeaa 100644
--- a/src/libsystemd/sd-bus/bus-creds.c
+++ b/src/libsystemd/sd-bus/bus-creds.c
@@ -53,6 +53,8 @@ void bus_creds_done(sd_bus_creds *c) {
* below. */
strv_free(c->cmdline_array);
+
+ safe_close(c->pidfd);
}
_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
@@ -129,46 +131,72 @@ _public_ uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c) {
sd_bus_creds* bus_creds_new(void) {
sd_bus_creds *c;
- c = new0(sd_bus_creds, 1);
+ c = new(sd_bus_creds, 1);
if (!c)
return NULL;
- c->allocated = true;
- c->n_ref = 1;
+ *c = (sd_bus_creds) {
+ .allocated = true,
+ .n_ref = 1,
+ SD_BUS_CREDS_INIT_FIELDS,
+ };
+
return c;
}
-_public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
+static int bus_creds_new_from_pidref(sd_bus_creds **ret, PidRef *pidref, uint64_t mask) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
int r;
- assert_return(pid >= 0, -EINVAL);
assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
assert_return(ret, -EINVAL);
- if (pid == 0)
- pid = getpid_cached();
-
c = bus_creds_new();
if (!c)
return -ENOMEM;
- r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
+ r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pidref, 0);
if (r < 0)
return r;
- /* Check if the process existed at all, in case we haven't
- * figured that out already */
- r = pid_is_alive(pid);
+ r = pidref_verify(pidref);
if (r < 0)
return r;
- if (r == 0)
- return -ESRCH;
*ret = TAKE_PTR(c);
return 0;
}
+_public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ int r;
+
+ assert_return(pid >= 0, -EINVAL);
+ assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
+ assert_return(ret, -EINVAL);
+
+ r = pidref_set_pid(&pidref, pid);
+ if (r < 0)
+ return r;
+
+ return bus_creds_new_from_pidref(ret, &pidref, mask);
+}
+
+_public_ int sd_bus_creds_new_from_pidfd(sd_bus_creds **ret, int pidfd, uint64_t mask) {
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ int r;
+
+ assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
+ assert_return(ret, -EINVAL);
+ assert_return(pidfd >= 0, -EBADF);
+
+ r = pidref_set_pidfd(&pidref, pidfd);
+ if (r < 0)
+ return r;
+
+ return bus_creds_new_from_pidref(ret, &pidref, mask);
+}
+
_public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
assert_return(c, -EINVAL);
assert_return(uid, -EINVAL);
@@ -280,6 +308,23 @@ _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
return 0;
}
+_public_ int sd_bus_creds_get_pidfd_dup(sd_bus_creds *c, int *ret_fd) {
+ _cleanup_close_ int copy = -EBADF;
+
+ assert_return(c, -EINVAL);
+ assert_return(ret_fd, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_PIDFD))
+ return -ENODATA;
+
+ copy = fcntl(c->pidfd, F_DUPFD_CLOEXEC, 3);
+ if (copy < 0)
+ return -errno;
+
+ *ret_fd = TAKE_FD(copy);
+ return 0;
+}
+
_public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) {
assert_return(c, -EINVAL);
assert_return(ppid, -EINVAL);
@@ -731,7 +776,7 @@ static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
return -ENOMEM;
}
- for (i = 0; i < sz; i ++) {
+ for (i = 0; i < sz; i++) {
uint32_t v = 0;
for (j = 0; j < 8; ++j) {
@@ -750,7 +795,8 @@ static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
return 0;
}
-int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
+int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, PidRef *pidref, pid_t tid) {
+ _cleanup_(pidref_done) PidRef pidref_buf = PIDREF_NULL;
uint64_t missing;
int r;
@@ -761,12 +807,26 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
return 0;
/* Try to retrieve PID from creds if it wasn't passed to us */
- if (pid > 0) {
- c->pid = pid;
+ if (pidref_is_set(pidref)) {
+ if ((c->mask & SD_BUS_CREDS_PID) && c->pid != pidref->pid) /* Insist that things match if already set */
+ return -EBUSY;
+
+ c->pid = pidref->pid;
c->mask |= SD_BUS_CREDS_PID;
- } else if (c->mask & SD_BUS_CREDS_PID)
- pid = c->pid;
- else
+ } else if (c->mask & SD_BUS_CREDS_PIDFD) {
+ r = pidref_set_pidfd(&pidref_buf, c->pidfd);
+ if (r < 0)
+ return r;
+
+ pidref = &pidref_buf;
+
+ } else if (c->mask & SD_BUS_CREDS_PID) {
+ r = pidref_set_pid(&pidref_buf, c->pid);
+ if (r < 0)
+ return r;
+
+ pidref = &pidref_buf;
+ } else
/* Without pid we cannot do much... */
return 0;
@@ -784,6 +844,14 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
c->mask |= SD_BUS_CREDS_TID;
}
+ if ((missing & SD_BUS_CREDS_PIDFD) && pidref->fd >= 0) {
+ c->pidfd = fcntl(pidref->fd, F_DUPFD_CLOEXEC, 3);
+ if (c->pidfd < 0)
+ return -errno;
+
+ c->mask |= SD_BUS_CREDS_PIDFD;
+ }
+
if (missing & (SD_BUS_CREDS_PPID |
SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
@@ -794,13 +862,13 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
_cleanup_fclose_ FILE *f = NULL;
const char *p;
- p = procfs_file_alloca(pid, "status");
+ p = procfs_file_alloca(pidref->pid, "status");
f = fopen(p, "re");
if (!f) {
if (errno == ENOENT)
return -ESRCH;
- else if (!ERRNO_IS_PRIVILEGE(errno))
+ if (!ERRNO_IS_PRIVILEGE(errno))
return -errno;
} else {
@@ -958,7 +1026,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
const char *p;
- p = procfs_file_alloca(pid, "attr/current");
+ p = procfs_file_alloca(pidref->pid, "attr/current");
r = read_one_line_file(p, &c->label);
if (r < 0) {
if (!IN_SET(r, -ENOENT, -EINVAL, -EPERM, -EACCES))
@@ -968,7 +1036,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
}
if (missing & SD_BUS_CREDS_COMM) {
- r = pid_get_comm(pid, &c->comm);
+ r = pid_get_comm(pidref->pid, &c->comm);
if (r < 0) {
if (!ERRNO_IS_PRIVILEGE(r))
return r;
@@ -977,7 +1045,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
}
if (missing & SD_BUS_CREDS_EXE) {
- r = get_process_exe(pid, &c->exe);
+ r = get_process_exe(pidref->pid, &c->exe);
if (r == -ESRCH) {
/* Unfortunately we cannot really distinguish
* the case here where the process does not
@@ -998,7 +1066,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & SD_BUS_CREDS_CMDLINE) {
const char *p;
- p = procfs_file_alloca(pid, "cmdline");
+ p = procfs_file_alloca(pidref->pid, "cmdline");
r = read_full_virtual_file(p, &c->cmdline, &c->cmdline_size);
if (r == -ENOENT)
return -ESRCH;
@@ -1016,7 +1084,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
_cleanup_free_ char *p = NULL;
- if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
+ if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pidref->pid, tid) < 0)
return -ENOMEM;
r = read_one_line_file(p, &c->tid_comm);
@@ -1032,7 +1100,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
if (!c->cgroup) {
- r = cg_pid_get_path(NULL, pid, &c->cgroup);
+ r = cg_pid_get_path(NULL, pidref->pid, &c->cgroup);
if (r < 0) {
if (!ERRNO_IS_PRIVILEGE(r))
return r;
@@ -1050,7 +1118,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
}
if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
- r = audit_session_from_pid(pid, &c->audit_session_id);
+ r = audit_session_from_pid(pidref->pid, &c->audit_session_id);
if (r == -ENODATA) {
/* ENODATA means: no audit session id assigned */
c->audit_session_id = AUDIT_SESSION_INVALID;
@@ -1063,7 +1131,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
}
if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
- r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
+ r = audit_loginuid_from_pid(pidref->pid, &c->audit_login_uid);
if (r == -ENODATA) {
/* ENODATA means: no audit login uid assigned */
c->audit_login_uid = UID_INVALID;
@@ -1076,7 +1144,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
}
if (missing & SD_BUS_CREDS_TTY) {
- r = get_ctty(pid, NULL, &c->tty);
+ r = get_ctty(pidref->pid, NULL, &c->tty);
if (r == -ENXIO) {
/* ENXIO means: process has no controlling TTY */
c->tty = NULL;
@@ -1088,16 +1156,12 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
c->mask |= SD_BUS_CREDS_TTY;
}
- /* In case only the exe path was to be read we cannot distinguish the case where the exe path was
- * unreadable because the process was a kernel thread, or when the process didn't exist at
- * all. Hence, let's do a final check, to be sure. */
- r = pid_is_alive(pid);
+ r = pidref_verify(pidref);
if (r < 0)
return r;
- if (r == 0)
- return -ESRCH;
- if (tid > 0 && tid != pid && pid_is_unwaited(tid) == 0)
+ /* Validate tid is still valid, too */
+ if (tid > 0 && tid != pidref->pid && pid_is_unwaited(tid) == 0)
return -ESRCH;
c->augmented = missing & c->mask;
@@ -1131,6 +1195,13 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
n->mask |= SD_BUS_CREDS_PID;
}
+ if (c->mask & mask & SD_BUS_CREDS_PIDFD) {
+ n->pidfd = fcntl(c->pidfd, F_DUPFD_CLOEXEC, 3);
+ if (n->pidfd < 0)
+ return -errno;
+ n->mask |= SD_BUS_CREDS_PIDFD;
+ }
+
if (c->mask & mask & SD_BUS_CREDS_TID) {
n->tid = c->tid;
n->mask |= SD_BUS_CREDS_TID;
diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h
index 7806d9e..f45de1c 100644
--- a/src/libsystemd/sd-bus/bus-creds.h
+++ b/src/libsystemd/sd-bus/bus-creds.h
@@ -5,6 +5,9 @@
#include "sd-bus.h"
+#include "pidref.h"
+#include "user-util.h"
+
struct sd_bus_creds {
bool allocated;
unsigned n_ref;
@@ -27,6 +30,7 @@ struct sd_bus_creds {
pid_t ppid;
pid_t pid;
pid_t tid;
+ int pidfd;
char *comm;
char *tid_comm;
@@ -63,10 +67,22 @@ struct sd_bus_creds {
char *description, *unescaped_description;
};
+#define SD_BUS_CREDS_INIT_FIELDS \
+ .uid = UID_INVALID, \
+ .euid = UID_INVALID, \
+ .suid = UID_INVALID, \
+ .fsuid = UID_INVALID, \
+ .gid = GID_INVALID, \
+ .egid = GID_INVALID, \
+ .sgid = GID_INVALID, \
+ .fsgid = GID_INVALID, \
+ .pidfd = -EBADF, \
+ .audit_login_uid = UID_INVALID
+
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);
+int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, PidRef *pidref, pid_t tid);
int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret);
diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c
index 6d24f3b..aa46fec 100644
--- a/src/libsystemd/sd-bus/bus-dump.c
+++ b/src/libsystemd/sd-bus/bus-dump.c
@@ -355,6 +355,8 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
if (c->mask & SD_BUS_CREDS_PID)
fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
+ if (c->mask & SD_BUS_CREDS_PIDFD)
+ fprintf(f, "%sPIDFD=%syes%s", prefix, color, suffix);
if (c->mask & SD_BUS_CREDS_TID)
fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
if (c->mask & SD_BUS_CREDS_PPID) {
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 098a518..e0f4746 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -254,6 +254,9 @@ struct sd_bus {
char *address;
unsigned address_index;
+ uid_t connect_as_uid;
+ gid_t connect_as_gid;
+
int last_connect_error;
enum bus_auth auth;
@@ -269,6 +272,7 @@ struct sd_bus {
size_t n_groups;
union sockaddr_union sockaddr_peer;
socklen_t sockaddr_size_peer;
+ int pidfd;
uint64_t creds_mask;
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index ab8b068..296f450 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -373,6 +373,7 @@ static int message_from_header(
if (!m)
return -ENOMEM;
+ m->creds = (sd_bus_creds) { SD_BUS_CREDS_INIT_FIELDS };
m->sealed = true;
m->header = buffer;
@@ -469,6 +470,7 @@ _public_ int sd_bus_message_new(
return -ENOMEM;
t->n_ref = 1;
+ t->creds = (sd_bus_creds) { SD_BUS_CREDS_INIT_FIELDS };
t->bus = sd_bus_ref(bus);
t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message)));
t->header->endian = BUS_NATIVE_ENDIAN;
@@ -627,7 +629,7 @@ static int message_new_reply(
return r;
}
- t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
+ t->dont_send = FLAGS_SET(call->header->flags, BUS_MESSAGE_NO_REPLY_EXPECTED);
t->enforced_reply_signature = call->enforced_reply_signature;
/* let's copy the sensitive flag over. Let's do that as a safety precaution to keep a transaction
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index c25c40f..e528987 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -1701,7 +1701,7 @@ static bool names_are_valid(const char *signature, const char **names, names_fla
if ((*flags & NAMES_FIRST_PART || *flags & NAMES_SINGLE_PART) && **names != '\0')
*flags |= NAMES_PRESENT;
- for (;*flags & NAMES_PRESENT;) {
+ while (*flags & NAMES_PRESENT) {
size_t l;
if (!*signature)
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index 5ade8e9..07179e0 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -217,7 +217,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
/* And possibly check the third line, too */
if (b->accept_fd) {
l = lines[i++];
- b->can_fds = !!memory_startswith(l, lines[i] - l, "AGREE_UNIX_FD");
+ b->can_fds = memory_startswith(l, lines[i] - l, "AGREE_UNIX_FD");
}
assert(i == n);
@@ -266,7 +266,7 @@ static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) {
if (l % 2 != 0)
return 0;
- r = unhexmem(p, l, (void **) &token, &len);
+ r = unhexmem_full(p, l, /* secure = */ false, (void**) &token, &len);
if (r < 0)
return 0;
@@ -298,7 +298,7 @@ static int verify_external_token(sd_bus *b, const char *p, size_t l) {
if (l % 2 != 0)
return 0;
- r = unhexmem(p, l, (void**) &token, &len);
+ r = unhexmem_full(p, l, /* secure = */ false, (void**) &token, &len);
if (r < 0)
return 0;
@@ -503,11 +503,38 @@ static int bus_socket_write_auth(sd_bus *b) {
if (b->prefer_writev)
k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index);
else {
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control = {};
+
struct msghdr mh = {
.msg_iov = b->auth_iovec + b->auth_index,
.msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index,
};
+ if (uid_is_valid(b->connect_as_uid) || gid_is_valid(b->connect_as_gid)) {
+
+ /* If we shall connect under some specific UID/GID, then synthesize an
+ * SCM_CREDENTIALS record accordingly. After all we want to adopt this UID/GID both
+ * for SO_PEERCRED (where we have to fork()) and SCM_CREDENTIALS (where we can just
+ * fake it via sendmsg()) */
+
+ struct ucred ucred = {
+ .pid = getpid_cached(),
+ .uid = uid_is_valid(b->connect_as_uid) ? b->connect_as_uid : getuid(),
+ .gid = gid_is_valid(b->connect_as_gid) ? b->connect_as_gid : getgid(),
+ };
+
+ mh.msg_control = &control;
+ mh.msg_controllen = sizeof(control);
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
+ *cmsg = (struct cmsghdr) {
+ .cmsg_level = SOL_SOCKET,
+ .cmsg_type = SCM_CREDENTIALS,
+ .cmsg_len = CMSG_LEN(sizeof(struct ucred)),
+ };
+
+ memcpy(CMSG_DATA(cmsg), &ucred, sizeof(struct ucred));
+ }
+
k = sendmsg(b->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
if (k < 0 && errno == ENOTSOCK) {
b->prefer_writev = true;
@@ -643,14 +670,20 @@ static void bus_get_peercred(sd_bus *b) {
/* Get the SELinux context of the peer */
r = getpeersec(b->input_fd, &b->label);
if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT))
- log_debug_errno(r, "Failed to determine peer security context: %m");
+ log_debug_errno(r, "Failed to determine peer security context, ignoring: %m");
/* Get the list of auxiliary groups of the peer */
r = getpeergroups(b->input_fd, &b->groups);
if (r >= 0)
b->n_groups = (size_t) r;
else if (!IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT))
- log_debug_errno(r, "Failed to determine peer's group list: %m");
+ log_debug_errno(r, "Failed to determine peer's group list, ignoring: %m");
+
+ r = getpeerpidfd(b->input_fd);
+ if (r < 0)
+ log_debug_errno(r, "Failed to determine peer pidfd, ignoring: %m");
+ else
+ close_and_replace(b->pidfd, r);
/* Let's query the peers socket address, it might carry information such as the peer's comm or
* description string */
@@ -943,6 +976,66 @@ static int bind_description(sd_bus *b, int fd, int family) {
return 0;
}
+static int connect_as(int fd, const struct sockaddr *sa, socklen_t salen, uid_t uid, gid_t gid) {
+ _cleanup_(close_pairp) int pfd[2] = EBADF_PAIR;
+ ssize_t n;
+ int r;
+
+ /* Shortcut if we are not supposed to drop privileges */
+ if (!uid_is_valid(uid) && !gid_is_valid(gid))
+ return RET_NERRNO(connect(fd, sa, salen));
+
+ /* This changes identity to the specified uid/gid and issues connect() as that. This is useful to
+ * make sure SO_PEERCRED reports the selected UID/GID rather than the usual one of the caller. */
+
+ if (pipe2(pfd, O_CLOEXEC) < 0)
+ return -errno;
+
+ r = safe_fork("(sd-setresuid)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_WAIT, /* ret_pid= */ NULL);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ /* child */
+
+ pfd[0] = safe_close(pfd[0]);
+
+ r = RET_NERRNO(setgroups(0, NULL));
+ if (r < 0)
+ goto child_finish;
+
+ if (gid_is_valid(gid)) {
+ r = RET_NERRNO(setresgid(gid, gid, gid));
+ if (r < 0)
+ goto child_finish;
+ }
+
+ if (uid_is_valid(uid)) {
+ r = RET_NERRNO(setresuid(uid, uid, uid));
+ if (r < 0)
+ goto child_finish;
+ }
+
+ r = RET_NERRNO(connect(fd, sa, salen));
+ if (r < 0)
+ goto child_finish;
+
+ r = 0;
+
+ child_finish:
+ n = write(pfd[1], &r, sizeof(r));
+ if (n != sizeof(r))
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ n = read(pfd[0], &r, sizeof(r));
+ if (n != sizeof(r))
+ return -EIO;
+
+ return r;
+}
+
int bus_socket_connect(sd_bus *b) {
bool inotify_done = false;
int r;
@@ -974,8 +1067,9 @@ int bus_socket_connect(sd_bus *b) {
b->output_fd = b->input_fd;
bus_socket_setup(b);
- if (connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size) < 0) {
- if (errno == EINPROGRESS) {
+ r = connect_as(b->input_fd, &b->sockaddr.sa, b->sockaddr_size, b->connect_as_uid, b->connect_as_gid);
+ if (r < 0) {
+ if (r == -EINPROGRESS) {
/* If we have any inotify watches open, close them now, we don't need them anymore, as
* we have successfully initiated a connection */
@@ -988,7 +1082,7 @@ int bus_socket_connect(sd_bus *b) {
return 1;
}
- if (IN_SET(errno, ENOENT, ECONNREFUSED) && /* ENOENT → unix socket doesn't exist at all; ECONNREFUSED → unix socket stale */
+ if (IN_SET(r, -ENOENT, -ECONNREFUSED) && /* ENOENT → unix socket doesn't exist at all; ECONNREFUSED → unix socket stale */
b->watch_bind &&
b->sockaddr.sa.sa_family == AF_UNIX &&
b->sockaddr.un.sun_path[0] != 0) {
@@ -1016,7 +1110,7 @@ int bus_socket_connect(sd_bus *b) {
inotify_done = true;
} else
- return -errno;
+ return r;
} else
break;
}
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index f9c59a1..6f6fa2d 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -69,7 +69,7 @@ static void bus_track_add_to_queue(sd_bus_track *track) {
return;
/* still referenced? */
- if (hashmap_size(track->names) > 0)
+ if (!hashmap_isempty(track->names))
return;
/* Nothing to call? */
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 8befc97..1a642cb 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -30,6 +30,7 @@
#include "constants.h"
#include "errno-util.h"
#include "fd-util.h"
+#include "format-util.h"
#include "glyph-util.h"
#include "hexdecoct.h"
#include "hostname-util.h"
@@ -151,6 +152,14 @@ void bus_close_inotify_fd(sd_bus *b) {
b->n_inotify_watches = 0;
}
+static void bus_close_fds(sd_bus *b) {
+ assert(b);
+
+ bus_close_io_fds(b);
+ bus_close_inotify_fd(b);
+ b->pidfd = safe_close(b->pidfd);
+}
+
static void bus_reset_queues(sd_bus *b) {
assert(b);
@@ -191,8 +200,7 @@ static sd_bus* bus_free(sd_bus *b) {
if (b->default_bus_ptr)
*b->default_bus_ptr = NULL;
- bus_close_io_fds(b);
- bus_close_inotify_fd(b);
+ bus_close_fds(b);
free(b->label);
free(b->groups);
@@ -256,7 +264,10 @@ _public_ int sd_bus_new(sd_bus **ret) {
.n_groups = SIZE_MAX,
.close_on_exit = true,
.ucred = UCRED_INVALID,
+ .pidfd = -EBADF,
.runtime_scope = _RUNTIME_SCOPE_INVALID,
+ .connect_as_uid = UID_INVALID,
+ .connect_as_gid = GID_INVALID,
};
/* We guarantee that wqueue always has space for at least one entry */
@@ -321,7 +332,7 @@ _public_ int sd_bus_set_bus_client(sd_bus *bus, int b) {
assert_return(!bus->patch_sender, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->bus_client = !!b;
+ bus->bus_client = b;
return 0;
}
@@ -331,7 +342,7 @@ _public_ int sd_bus_set_monitor(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->is_monitor = !!b;
+ bus->is_monitor = b;
return 0;
}
@@ -341,7 +352,7 @@ _public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->accept_fd = !!b;
+ bus->accept_fd = b;
return 0;
}
@@ -353,7 +364,7 @@ _public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) {
/* This is not actually supported by any of our transports these days, but we do honour it for synthetic
* replies, and maybe one day classic D-Bus learns this too */
- bus->attach_timestamp = !!b;
+ bus->attach_timestamp = b;
return 0;
}
@@ -380,7 +391,7 @@ _public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->is_server = !!b;
+ bus->is_server = b;
bus->server_id = server_id;
return 0;
}
@@ -391,7 +402,7 @@ _public_ int sd_bus_set_anonymous(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->anonymous_auth = !!b;
+ bus->anonymous_auth = b;
return 0;
}
@@ -401,7 +412,7 @@ _public_ int sd_bus_set_trusted(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->trusted = !!b;
+ bus->trusted = b;
return 0;
}
@@ -419,7 +430,7 @@ _public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) {
assert_return(bus = bus_resolve(bus), -ENOPKG);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->allow_interactive_authorization = !!b;
+ bus->allow_interactive_authorization = b;
return 0;
}
@@ -437,7 +448,7 @@ _public_ int sd_bus_set_watch_bind(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->watch_bind = !!b;
+ bus->watch_bind = b;
return 0;
}
@@ -455,7 +466,7 @@ _public_ int sd_bus_set_connected_signal(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->connected_signal = !!b;
+ bus->connected_signal = b;
return 0;
}
@@ -640,7 +651,7 @@ int bus_start_running(sd_bus *bus) {
static int parse_address_key(const char **p, const char *key, char **value) {
_cleanup_free_ char *r = NULL;
- size_t l, n = 0;
+ size_t n = 0;
const char *a;
assert(p);
@@ -648,17 +659,14 @@ static int parse_address_key(const char **p, const char *key, char **value) {
assert(value);
if (key) {
- l = strlen(key);
- if (strncmp(*p, key, l) != 0)
- return 0;
-
- if ((*p)[l] != '=')
+ a = startswith(*p, key);
+ if (!a || *a != '=')
return 0;
if (*value)
return -EINVAL;
- a = *p + l + 1;
+ a++;
} else
a = *p;
@@ -717,7 +725,7 @@ static void skip_address_key(const char **p) {
}
static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
- _cleanup_free_ char *path = NULL, *abstract = NULL;
+ _cleanup_free_ char *path = NULL, *abstract = NULL, *uids = NULL, *gids = NULL;
size_t l;
int r;
@@ -745,6 +753,18 @@ static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
else if (r > 0)
continue;
+ r = parse_address_key(p, "uid", &uids);
+ if (r < 0)
+ return r;
+ else if (r > 0)
+ continue;
+
+ r = parse_address_key(p, "gid", &gids);
+ if (r < 0)
+ return r;
+ else if (r > 0)
+ continue;
+
skip_address_key(p);
}
@@ -781,6 +801,17 @@ static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
}
+ if (uids) {
+ r = parse_uid(uids, &b->connect_as_uid);
+ if (r < 0)
+ return r;
+ }
+ if (gids) {
+ r = parse_gid(gids, &b->connect_as_gid);
+ if (r < 0)
+ return r;
+ }
+
b->is_local = true;
return 0;
@@ -1102,8 +1133,7 @@ static int bus_start_address(sd_bus *b) {
assert(b);
for (;;) {
- bus_close_io_fds(b);
- bus_close_inotify_fd(b);
+ bus_close_fds(b);
bus_kill_exec(b);
@@ -1486,9 +1516,15 @@ interpret_port_as_machine_old_syntax:
return -ENOMEM;
}
- a = strjoin("unixexec:path=ssh,argv1=-xT", p ? ",argv2=-p,argv3=" : "", strempty(p),
- ",argv", p ? "4" : "2", "=--,argv", p ? "5" : "3", "=", e,
- ",argv", p ? "6" : "4", "=systemd-stdio-bridge", c);
+ const char *ssh = secure_getenv("SYSTEMD_SSH") ?: "ssh";
+ _cleanup_free_ char *ssh_escaped = bus_address_escape(ssh);
+ if (!ssh_escaped)
+ return -ENOMEM;
+
+ a = strjoin("unixexec:path=", ssh_escaped, ",argv1=-xT",
+ p ? ",argv2=-p,argv3=" : "", strempty(p),
+ ",argv", p ? "4" : "2", "=--,argv", p ? "5" : "3", "=", e,
+ ",argv", p ? "6" : "4", "=systemd-stdio-bridge", c);
if (!a)
return -ENOMEM;
@@ -1668,10 +1704,7 @@ static int user_and_machine_equivalent(const char *user_and_machine) {
return true;
/* Otherwise, we have to figure out our user id and name, and compare things with that. */
- char buf[DECIMAL_STR_MAX(uid_t)];
- xsprintf(buf, UID_FMT, uid);
-
- f = startswith(user_and_machine, buf);
+ f = startswith(user_and_machine, FORMAT_UID(uid));
if (!f) {
un = getusername_malloc();
if (!un)
@@ -1775,8 +1808,7 @@ _public_ void sd_bus_close(sd_bus *bus) {
* the bus object and the bus may be freed */
bus_reset_queues(bus);
- bus_close_io_fds(bus);
- bus_close_inotify_fd(bus);
+ bus_close_fds(bus);
}
_public_ sd_bus *sd_bus_close_unref(sd_bus *bus) {
@@ -4123,13 +4155,13 @@ _public_ int sd_bus_path_decode_many(const char *path, const char *path_template
for (template_pos = path_template; *template_pos; ) {
const char *sep;
- size_t length;
+ size_t length, path_length;
char *label;
/* verify everything until the next '%' matches verbatim */
sep = strchrnul(template_pos, '%');
length = sep - template_pos;
- if (strncmp(path_pos, template_pos, length))
+ if (!strneq(path_pos, template_pos, length))
return 0;
path_pos += length;
@@ -4150,8 +4182,8 @@ _public_ int sd_bus_path_decode_many(const char *path, const char *path_template
/* verify the suffixes match */
sep = strchrnul(path_pos, '/');
- if (sep - path_pos < (ssize_t)length ||
- strncmp(sep - length, template_pos, length))
+ path_length = sep - path_pos;
+ if (length > path_length || !strneq(sep - length, template_pos, length))
return 0;
template_pos += length; /* skip over matched label */
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index da1340f..d06853b 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -432,8 +432,7 @@ static void* client2(void *p) {
if (r < 0)
log_debug("Failed to issue method call: %s", bus_error_message(&error, r));
else {
- log_error("Slow call unexpectedly succeed.");
- r = -ENOANO;
+ r = log_error_errno(SYNTHETIC_ERRNO(ENOANO), "Slow call unexpectedly succeeded.");
goto finish;
}
diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c
index 3e14627..b569986 100644
--- a/src/libsystemd/sd-bus/test-bus-cleanup.c
+++ b/src/libsystemd/sd-bus/test-bus-cleanup.c
@@ -30,7 +30,7 @@ static void test_bus_fork(void) {
r = safe_fork("(bus-fork-test)", FORK_WAIT|FORK_LOG, NULL);
if (r == 0) {
assert_se(bus);
- assert_se(sd_bus_is_ready(bus) == -ECHILD);
+ ASSERT_RETURN_EXPECTED_SE(sd_bus_is_ready(bus) == -ECHILD);
assert_se(sd_bus_flush_close_unref(bus) == NULL);
assert_se(sd_bus_close_unref(bus) == NULL);
assert_se(sd_bus_unref(bus) == NULL);
diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c
index 13801be..7eb7a38 100644
--- a/src/libsystemd/sd-bus/test-bus-creds.c
+++ b/src/libsystemd/sd-bus/test-bus-creds.c
@@ -4,6 +4,7 @@
#include "bus-dump.h"
#include "cgroup-util.h"
+#include "errno-util.h"
#include "tests.h"
int main(int argc, char *argv[]) {
@@ -12,7 +13,7 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
- if (cg_unified() == -ENOMEDIUM)
+ if (IN_SET(cg_unified(), -ENOMEDIUM, -ENOENT))
return log_tests_skipped("/sys/fs/cgroup/ not available");
r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL);
@@ -24,11 +25,30 @@ int main(int argc, char *argv[]) {
creds = sd_bus_creds_unref(creds);
r = sd_bus_creds_new_from_pid(&creds, 1, _SD_BUS_CREDS_ALL);
- if (r != -EACCES) {
+ if (!ERRNO_IS_NEG_PRIVILEGE(r)) {
assert_se(r >= 0);
putchar('\n');
bus_creds_dump(creds, NULL, true);
}
+ creds = sd_bus_creds_unref(creds);
+
+ _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
+ r = sd_bus_default_system(&bus);
+ if (r < 0)
+ log_warning_errno(r, "Unable to connect to system bus, skipping rest of test.");
+ else {
+ const char *unique;
+
+ assert_se(sd_bus_get_unique_name(bus, &unique) >= 0);
+
+ r = sd_bus_get_name_creds(bus, unique, _SD_BUS_CREDS_ALL, &creds);
+ log_full_errno(r < 0 ? LOG_ERR : LOG_DEBUG, r, "sd_bus_get_name_creds: %m");
+ assert_se(r >= 0);
+
+ putchar('\n');
+ bus_creds_dump(creds, NULL, true);
+ }
+
return 0;
}
diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c
index a55f3f9..91045c0 100644
--- a/src/libsystemd/sd-bus/test-bus-error.c
+++ b/src/libsystemd/sd-bus/test-bus-error.c
@@ -213,8 +213,8 @@ TEST(errno_mapping_custom) {
assert_se(sd_bus_error_set(NULL, BUS_ERROR_NO_SUCH_UNIT, NULL) == -ENOENT);
- assert_se(sd_bus_error_add_map(test_errors_bad1) == -EINVAL);
- assert_se(sd_bus_error_add_map(test_errors_bad2) == -EINVAL);
+ ASSERT_RETURN_EXPECTED_SE(sd_bus_error_add_map(test_errors_bad1) == -EINVAL);
+ ASSERT_RETURN_EXPECTED_SE(sd_bus_error_add_map(test_errors_bad2) == -EINVAL);
}
TEST(sd_bus_error_set_errnof) {
diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c
index 0044d33..92da627 100644
--- a/src/libsystemd/sd-bus/test-bus-marshal.c
+++ b/src/libsystemd/sd-bus/test-bus-marshal.c
@@ -42,8 +42,8 @@ static void test_bus_path_encode(void) {
assert_se(sd_bus_path_decode(a, "/waldo", &b) == 0 && b == NULL);
assert_se(sd_bus_path_decode(a, "/foo/bar", &b) > 0 && streq(b, "waldo"));
- assert_se(sd_bus_path_encode("xxxx", "waldo", &c) < 0);
- assert_se(sd_bus_path_encode("/foo/", "waldo", &c) < 0);
+ ASSERT_RETURN_EXPECTED_SE(sd_bus_path_encode("xxxx", "waldo", &c) < 0);
+ ASSERT_RETURN_EXPECTED_SE(sd_bus_path_encode("/foo/", "waldo", &c) < 0);
assert_se(sd_bus_path_encode("/foo/bar", "", &c) >= 0 && streq(c, "/foo/bar/_"));
assert_se(sd_bus_path_decode(c, "/foo/bar", &d) > 0 && streq(d, ""));
diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c
index ccdd0d5..2847ba8 100644
--- a/src/libsystemd/sd-bus/test-bus-objects.c
+++ b/src/libsystemd/sd-bus/test-bus-objects.c
@@ -494,10 +494,9 @@ static int client(struct context *c) {
}
assert_se(sd_bus_message_exit_container(reply) >= 0);
- if (streq(path, "/value/a")) {
+ if (streq(path, "/value/a"))
/* ObjectManager must be here */
assert_se(found_object_manager_interface);
- }
} else
assert_se(sd_bus_message_skip(reply, "a{sa{sv}}") >= 0);
diff --git a/src/libsystemd/sd-bus/test-bus-peersockaddr.c b/src/libsystemd/sd-bus/test-bus-peersockaddr.c
index 79556e8..a7bba17 100644
--- a/src/libsystemd/sd-bus/test-bus-peersockaddr.c
+++ b/src/libsystemd/sd-bus/test-bus-peersockaddr.c
@@ -5,10 +5,39 @@
#include "sd-bus.h"
+#include "bus-dump.h"
+#include "bus-util.h"
#include "fd-util.h"
#include "process-util.h"
#include "socket-util.h"
+#include "sort-util.h"
#include "tests.h"
+#include "user-util.h"
+
+static bool gid_list_contained(const gid_t *a, size_t n, const gid_t *b, size_t m) {
+ assert_se(a || n == 0);
+ assert_se(b || m == 0);
+
+ /* Checks if every entry in a[] is also in b[] */
+
+ for (size_t i = 0; i < n; i++) {
+ size_t j;
+
+ for (j = 0; j < m; j++)
+ if (a[i] == b[j])
+ break;
+
+ if (j >= m)
+ return false;
+ }
+
+ return true;
+}
+
+static bool gid_list_same(const gid_t *a, size_t n, const gid_t *b, size_t m) {
+ return gid_list_contained(a, n, b, m) &&
+ gid_list_contained(b, m, a, n);
+}
static void *server(void *p) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
@@ -27,11 +56,13 @@ static void *server(void *p) {
assert_se(sd_bus_set_fd(bus, fd, fd) >= 0);
TAKE_FD(fd);
assert_se(sd_bus_set_server(bus, true, id) >= 0);
- assert_se(sd_bus_negotiate_creds(bus, 1, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION) >= 0);
+ assert_se(sd_bus_negotiate_creds(bus, 1, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_PIDFD|SD_BUS_CREDS_SUPPLEMENTARY_GIDS) >= 0);
assert_se(sd_bus_start(bus) >= 0);
- assert_se(sd_bus_get_owner_creds(bus, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION, &c) >= 0);
+ assert_se(sd_bus_get_owner_creds(bus, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_PIDFD|SD_BUS_CREDS_SUPPLEMENTARY_GIDS, &c) >= 0);
+
+ bus_creds_dump(c, /* f= */ NULL, /* terse= */ false);
uid_t u;
assert_se(sd_bus_creds_get_euid(c, &u) >= 0);
@@ -45,6 +76,26 @@ static void *server(void *p) {
assert_se(sd_bus_creds_get_pid(c, &pid) >= 0);
assert_se(pid == getpid_cached());
+ int pidfd = -EBADF;
+ if (sd_bus_creds_get_pidfd_dup(c, &pidfd) >= 0) {
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+
+ assert_se(pidref_set_pidfd_take(&pidref, pidfd) >= 0);
+ assert_se(pidref.pid == getpid_cached());
+ }
+
+ const gid_t *gl = NULL;
+ int n;
+ n = sd_bus_creds_get_supplementary_gids(c, &gl);
+
+ if (n >= 0) {
+ _cleanup_free_ gid_t *gg = NULL;
+ r = getgroups_alloc(&gg);
+ assert_se(r >= 0);
+
+ assert_se(gid_list_same(gl, n, gg, r));
+ }
+
const char *comm;
assert_se(sd_bus_creds_get_comm(c, &comm) >= 0);
assert_se(pid_get_comm(0, &our_comm) >= 0);