X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibelogind%2Fsd-bus%2Fbus-control.c;h=c6403d3bae2b4ce8cf05d63114c58ff35ab128f5;hp=3cdce6600387e99e1cc8774dc25f69dca85b0e20;hb=8b5aa329e08b4f9e5ce8262e2edaa60455f5524f;hpb=1cfc78c91965df340cdde100ad6cb3ed50b28927 diff --git a/src/libelogind/sd-bus/bus-control.c b/src/libelogind/sd-bus/bus-control.c index 3cdce6600..c6403d3ba 100644 --- a/src/libelogind/sd-bus/bus-control.c +++ b/src/libelogind/sd-bus/bus-control.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,17 +21,22 @@ #include #endif -#include #include +#include -#include "strv.h" #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-bloom.h" +#include "bus-control.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-control.h" -#include "bus-bloom.h" #include "bus-util.h" -#include "capability.h" +#include "capability-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { int r; @@ -86,7 +89,7 @@ static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags } static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; uint32_t ret, param = 0; int r; @@ -182,7 +185,7 @@ static int bus_release_name_kernel(sd_bus *bus, const char *name) { } static int bus_release_name_dbus1(sd_bus *bus, const char *name) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; uint32_t ret; int r; @@ -258,13 +261,16 @@ static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { KDBUS_FOREACH(name, name_list, cmd.list_size) { struct kdbus_item *item; - if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id) { + if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id && !(name->flags & KDBUS_HELLO_ACTIVATOR)) { char *n; - if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + if (asprintf(&n, ":1.%llu", name->id) < 0) { r = -ENOMEM; goto fail; } +#pragma GCC diagnostic pop r = strv_consume(x, n); if (r < 0) @@ -321,7 +327,7 @@ static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activata } static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_strv_free_ char **x = NULL, **y = NULL; int r; @@ -642,7 +648,7 @@ int bus_get_name_creds_kdbus( bool allow_activator, sd_bus_creds **creds) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; struct kdbus_cmd_info *cmd; struct kdbus_info *conn_info; size_t size, l; @@ -675,6 +681,7 @@ int bus_get_name_creds_kdbus( (mask & (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| + SD_BUS_CREDS_SUPPLEMENTARY_GIDS| SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_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| @@ -707,10 +714,13 @@ int bus_get_name_creds_kdbus( } if (mask & SD_BUS_CREDS_UNIQUE_NAME) { - if (asprintf(&c->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + if (asprintf(&c->unique_name, ":1.%llu", conn_info->id) < 0) { r = -ENOMEM; goto fail; } +#pragma GCC diagnostic pop c->mask |= SD_BUS_CREDS_UNIQUE_NAME; } @@ -748,8 +758,8 @@ static int bus_get_name_creds_dbus1( uint64_t mask, sd_bus_creds **creds) { - _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL; - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _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 = NULL; pid_t pid = 0; int r; @@ -776,6 +786,8 @@ static int bus_get_name_creds_dbus1( } if (mask != 0) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + bool need_pid, need_uid, need_selinux, need_separate_calls; c = bus_creds_new(); if (!c) return -ENOMEM; @@ -788,98 +800,216 @@ static int bus_get_name_creds_dbus1( c->mask |= SD_BUS_CREDS_UNIQUE_NAME; } - if ((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_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_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_uid = mask & SD_BUS_CREDS_EUID; + need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT; + + if (need_pid + need_uid + need_selinux > 1) { - uint32_t u; + /* If we need more than one of the credentials, then use GetConnectionCredentials() */ r = sd_bus_call_method( bus, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", - "GetConnectionUnixProcessID", - NULL, + "GetConnectionCredentials", + &error, &reply, "s", - unique ? unique : name); - if (r < 0) - return r; + unique ?: name); - r = sd_bus_message_read(reply, "u", &u); - if (r < 0) - return r; + if (r < 0) { - pid = u; - if (mask & SD_BUS_CREDS_PID) { - c->pid = u; - c->mask |= SD_BUS_CREDS_PID; - } + if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) + return r; - reply = sd_bus_message_unref(reply); - } + /* If we got an unknown method error, fall back to the invidual calls... */ + need_separate_calls = true; + sd_bus_error_free(&error); - if (mask & SD_BUS_CREDS_EUID) { - uint32_t u; + } else { + need_separate_calls = false; - r = sd_bus_call_method( - bus, - "org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "GetConnectionUnixUser", - NULL, - &reply, - "s", - unique ? unique : name); - if (r < 0) - return r; + r = sd_bus_message_enter_container(reply, 'a', "{sv}"); + if (r < 0) + return r; - r = sd_bus_message_read(reply, "u", &u); - if (r < 0) - return r; + for (;;) { + const char *m; - c->euid = u; - c->mask |= SD_BUS_CREDS_EUID; + r = sd_bus_message_enter_container(reply, 'e', "sv"); + if (r < 0) + return r; + if (r == 0) + break; - reply = sd_bus_message_unref(reply); - } + r = sd_bus_message_read(reply, "s", &m); + if (r < 0) + return r; - if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - const void *p = NULL; - size_t sz = 0; + if (need_uid && streq(m, "UnixUserID")) { + uint32_t u; - r = sd_bus_call_method( - bus, - "org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "GetConnectionSELinuxSecurityContext", - &error, - &reply, - "s", - unique ? unique : name); - if (r < 0) { - if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown")) + r = sd_bus_message_read(reply, "v", "u", &u); + if (r < 0) + return r; + + c->euid = u; + c->mask |= SD_BUS_CREDS_EUID; + + } else if (need_pid && streq(m, "ProcessID")) { + uint32_t p; + + r = sd_bus_message_read(reply, "v", "u", &p); + if (r < 0) + return r; + + pid = p; + if (mask & SD_BUS_CREDS_PID) { + c->pid = p; + c->mask |= SD_BUS_CREDS_PID; + } + + } else if (need_selinux && streq(m, "LinuxSecurityLabel")) { + const void *p = NULL; + size_t sz = 0; + + r = sd_bus_message_enter_container(reply, 'v', "ay"); + if (r < 0) + return r; + + r = sd_bus_message_read_array(reply, 'y', &p, &sz); + if (r < 0) + return r; + + free(c->label); + c->label = strndup(p, sz); + if (!c->label) + return -ENOMEM; + + c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + } else { + r = sd_bus_message_skip(reply, "v"); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) return r; - } else { - r = sd_bus_message_read_array(reply, 'y', &p, &sz); + + if (need_pid && pid == 0) + return -EPROTO; + } + + } else /* When we only need a single field, then let's use separate calls */ + need_separate_calls = true; + + if (need_separate_calls) { + if (need_pid) { + uint32_t u; + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionUnixProcessID", + NULL, + &reply, + "s", + unique ?: name); if (r < 0) return r; - c->label = strndup(p, sz); - if (!c->label) - return -ENOMEM; + r = sd_bus_message_read(reply, "u", &u); + if (r < 0) + return r; - c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT; + pid = u; + if (mask & SD_BUS_CREDS_PID) { + c->pid = u; + c->mask |= SD_BUS_CREDS_PID; + } + + reply = sd_bus_message_unref(reply); + } + + if (need_uid) { + uint32_t u; + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionUnixUser", + NULL, + &reply, + "s", + unique ? unique : name); + if (r < 0) + return r; + + r = sd_bus_message_read(reply, "u", &u); + if (r < 0) + return r; + + c->euid = u; + c->mask |= SD_BUS_CREDS_EUID; + + reply = sd_bus_message_unref(reply); + } + + if (need_selinux) { + const void *p = NULL; + size_t sz = 0; + + r = sd_bus_call_method( + bus, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetConnectionSELinuxSecurityContext", + &error, + &reply, + "s", + unique ? unique : name); + if (r < 0) { + if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown")) + return r; + + /* no data is fine */ + } else { + 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; + } } } @@ -915,6 +1045,9 @@ _public_ int sd_bus_get_name_creds( if (streq(name, "org.freedesktop.DBus.Local")) return -EINVAL; + if (streq(name, "org.freedesktop.DBus")) + return sd_bus_get_owner_creds(bus, mask, creds); + if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; @@ -925,7 +1058,7 @@ _public_ int sd_bus_get_name_creds( } static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; struct kdbus_cmd_info cmd = { .size = sizeof(struct kdbus_cmd_info), }; @@ -944,6 +1077,7 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds ** (mask & (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| + SD_BUS_CREDS_SUPPLEMENTARY_GIDS| SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_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| @@ -974,10 +1108,14 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds ** } static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; pid_t pid = 0; + bool do_label; int r; - bool do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); + + assert(bus); + + do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); /* Avoid allocating anything if we have no chance of returning useful data */ if (!bus->ucred_valid && !do_label) @@ -1124,12 +1262,11 @@ static int add_name_change_match(sd_bus *bus, item->name_change.old_id.id = old_owner_id; item->name_change.new_id.id = new_owner_id; - if (name) - memcpy(item->name_change.name, name, l); + memcpy_safe(item->name_change.name, name, l); /* If the old name is unset or empty, then * this can match against added names */ - if (!old_owner || old_owner[0] == 0) { + if (isempty(old_owner)) { item->type = KDBUS_ITEM_NAME_ADD; r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); @@ -1139,7 +1276,7 @@ static int add_name_change_match(sd_bus *bus, /* If the new name is unset or empty, then * this can match against removed names */ - if (!new_owner || new_owner[0] == 0) { + if (isempty(new_owner)) { item->type = KDBUS_ITEM_NAME_REMOVE; r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); @@ -1183,7 +1320,7 @@ static int add_name_change_match(sd_bus *bus, /* If the old name is unset or empty, then this can * match against added ids */ - if (!old_owner || old_owner[0] == 0) { + if (isempty(old_owner)) { item->type = KDBUS_ITEM_ID_ADD; if (!isempty(new_owner)) item->id_change.id = new_owner_id; @@ -1195,7 +1332,7 @@ static int add_name_change_match(sd_bus *bus, /* If thew new name is unset or empty, then this can * match against removed ids */ - if (!new_owner || new_owner[0] == 0) { + if (isempty(new_owner)) { item->type = KDBUS_ITEM_ID_REMOVE; if (!isempty(old_owner)) item->id_change.id = old_owner_id; @@ -1309,7 +1446,16 @@ int bus_add_match_internal_kernel( break; } - case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: { + case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: { + char buf[sizeof("arg")-1 + 2 + sizeof("-has")]; + + xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS); + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); + using_bloom = true; + break; + } + + case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: /* * XXX: DBus spec defines arg[0..63]path= matching to be * a two-way glob. That is, if either string is a prefix @@ -1323,7 +1469,6 @@ int bus_add_match_internal_kernel( * to properly support multiple-matches here. */ break; - } case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: { char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")]; @@ -1334,7 +1479,7 @@ int bus_add_match_internal_kernel( break; } - case BUS_MATCH_DESTINATION: { + case BUS_MATCH_DESTINATION: /* * Kernel only supports matching on destination IDs, but * not on destination names. So just skip the @@ -1352,7 +1497,6 @@ int bus_add_match_internal_kernel( matches_name_change = false; break; - } case BUS_MATCH_ROOT: case BUS_MATCH_VALUE: @@ -1526,10 +1670,9 @@ int bus_remove_match_internal( return bus_remove_match_internal_dbus1(bus, match); } -/// UNNEEDED by elogind -#if 0 +#if 0 /// UNNEEDED by elogind _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; const char *mid; int r;