X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fbus-proxyd%2Fbus-proxyd.c;h=a5387bb234a27e684cc4532442ddd2d29fa12c6a;hp=c5f9f002feb58ae21b64cefb3a714494e9403654;hb=f8c2425287c8362ae3a3c9acfb9e23a16862b38a;hpb=dc780ecf10c6ca2794c5d1bfe61ca48ef350381f diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c index c5f9f002f..a5387bb23 100644 --- a/src/bus-proxyd/bus-proxyd.c +++ b/src/bus-proxyd/bus-proxyd.c @@ -40,21 +40,29 @@ #include "bus-internal.h" #include "bus-message.h" #include "bus-util.h" +#include "bus-internal.h" #include "build.h" #include "strv.h" #include "def.h" +#include "capability.h" +#include "bus-policy.h" -static const char *arg_address = DEFAULT_SYSTEM_BUS_PATH; +static char *arg_address = NULL; static char *arg_command_line_buffer = NULL; +static bool arg_drop_privileges = false; +static char **arg_configuration = NULL; static int help(void) { printf("%s [OPTIONS...]\n\n" "Connect STDIO or a socket to a given bus address.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --address=ADDRESS Connect to the bus specified by ADDRESS\n" - " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n", + " -h --help Show this help\n" + " --version Show package version\n" + " --drop-privileges Drop privileges\n" + " --configuration=PATH Configuration file or directory\n" + " --machine=MACHINE Connect to specified machine\n" + " --address=ADDRESS Connect to the bus specified by ADDRESS\n" + " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n", program_invocation_short_name); return 0; @@ -65,21 +73,27 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_ADDRESS, + ARG_DROP_PRIVILEGES, + ARG_CONFIGURATION, + ARG_MACHINE, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "address", required_argument, NULL, ARG_ADDRESS }, - { NULL, 0, NULL, 0 } + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "address", required_argument, NULL, ARG_ADDRESS }, + { "drop-privileges", no_argument, NULL, ARG_DROP_PRIVILEGES }, + { "configuration", required_argument, NULL, ARG_CONFIGURATION }, + { "machine", required_argument, NULL, ARG_MACHINE }, + {}, }; - int c; + int c, r; assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) switch (c) { @@ -92,28 +106,72 @@ static int parse_argv(int argc, char *argv[]) { puts(SYSTEMD_FEATURES); return 0; - case ARG_ADDRESS: - arg_address = optarg; + case ARG_ADDRESS: { + char *a; + + a = strdup(optarg); + if (!a) + return log_oom(); + + free(arg_address); + arg_address = a; + break; + } + + case ARG_DROP_PRIVILEGES: + arg_drop_privileges = true; break; + case ARG_CONFIGURATION: + r = strv_extend(&arg_configuration, optarg); + if (r < 0) + return log_oom(); + break; + + case ARG_MACHINE: { + _cleanup_free_ char *e = NULL; + char *a; + + e = bus_address_escape(optarg); + if (!e) + return log_oom(); + +#ifdef ENABLE_KDBUS + a = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL); +#else + a = strjoin("x-container-unix:machine=", e, NULL); +#endif + if (!a) + return log_oom(); + + free(arg_address); + arg_address = a; + + break; + } + case '?': return -EINVAL; default: assert_not_reached("Unhandled option"); } - } /* If the first command line argument is only "x" characters * we'll write who we are talking to into it, so that "ps" is * explanatory */ arg_command_line_buffer = argv[optind]; - if (argc > optind + 1 || - (arg_command_line_buffer && arg_command_line_buffer[strspn(arg_command_line_buffer, "x")] != 0)) { + if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) { log_error("Too many arguments"); return -EINVAL; } + if (!arg_address) { + arg_address = strdup(DEFAULT_SYSTEM_BUS_PATH); + if (!arg_address) + return log_oom(); + } + return 1; } @@ -181,7 +239,7 @@ static int rename_service(sd_bus *a, sd_bus *b) { pid, p, uid, name, a->unique_name); - ; + return 0; } @@ -260,6 +318,9 @@ static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) { assert(b); assert(m); + if (!a->is_kernel) + return 0; + if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll")) return 0; @@ -439,7 +500,6 @@ static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) { return false; } - static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { int r; @@ -447,6 +507,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { assert(b); assert(m); + if (!a->is_kernel) + return 0; + if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus")) return 0; @@ -551,7 +614,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { if (r < 0) return synthetic_reply_method_errno(m, r, NULL); - r = sd_bus_add_match(a, match, NULL, NULL); + r = sd_bus_add_match(a, NULL, match, NULL, NULL); if (r < 0) return synthetic_reply_method_errno(m, r, NULL); @@ -564,7 +627,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { if (r < 0) return synthetic_reply_method_errno(m, r, NULL); - r = sd_bus_remove_match(a, match, NULL, NULL); + r = bus_remove_match_by_string(a, match, NULL, NULL); + if (r == 0) + return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found")); if (r < 0) return synthetic_reply_method_errno(m, r, NULL); @@ -667,7 +732,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { if (r < 0) return synthetic_reply_method_errno(m, r, NULL); - if (service_name_is_valid(arg0) < 0) + if (!service_name_is_valid(arg0)) return synthetic_reply_method_errno(m, -EINVAL, NULL); cmd.flags = KDBUS_NAME_LIST_QUEUED; @@ -678,12 +743,15 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { name_list = (struct kdbus_name_list *) ((uint8_t *) a->kdbus_buffer + cmd.offset); KDBUS_ITEM_FOREACH(name, name_list, names) { + const char *entry_name = NULL; + struct kdbus_item *item; char *n; - if (name->size <= sizeof(*name)) - continue; + KDBUS_ITEM_FOREACH(item, name, items) + if (item->type == KDBUS_ITEM_NAME) + entry_name = item->str; - if (!streq(name->name, arg0)) + if (!streq_ptr(entry_name, arg0)) continue; if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) { @@ -702,7 +770,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { if (r < 0) return synthetic_reply_method_errno(m, r, NULL); - if (err > 0) + if (err < 0) return synthetic_reply_method_errno(m, err, NULL); return synthetic_reply_return_strv(m, owners); @@ -714,7 +782,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { if (r < 0) return synthetic_reply_method_errno(m, r, NULL); - if (service_name_is_valid(name) < 0) + if (!service_name_is_valid(name)) return synthetic_reply_method_errno(m, -EINVAL, NULL); if (streq(name, "org.freedesktop.DBus")) @@ -733,15 +801,16 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { if (r < 0) return synthetic_reply_method_errno(m, r, NULL); - if (service_name_is_valid(name) < 0) + if (!service_name_is_valid(name)) return synthetic_reply_method_errno(m, -EINVAL, NULL); r = sd_bus_release_name(a, name); if (r < 0) { if (r == -ESRCH) - synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT); + return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT); if (r == -EADDRINUSE) - synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER); + return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER); + return synthetic_reply_method_errno(m, r, NULL); } @@ -762,7 +831,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { if (r < 0) return synthetic_reply_method_errno(m, r, NULL); - if (service_name_is_valid(name) < 0) + if (!service_name_is_valid(name)) return synthetic_reply_method_errno(m, -EINVAL, NULL); if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0) return synthetic_reply_method_errno(m, -EINVAL, NULL); @@ -790,7 +859,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) { if (r < 0) return synthetic_reply_method_errno(m, r, NULL); - if (service_name_is_valid(name) < 0) + if (!service_name_is_valid(name)) return synthetic_reply_method_errno(m, -EINVAL, NULL); if (flags != 0) return synthetic_reply_method_errno(m, -EINVAL, NULL); @@ -1024,13 +1093,14 @@ static int patch_sender(sd_bus *a, sd_bus_message *m) { int main(int argc, char *argv[]) { - _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL; + _cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL; sd_id128_t server_id; int r, in_fd, out_fd; bool got_hello = false; bool is_unix; struct ucred ucred = {}; _cleanup_free_ char *peersec = NULL; + Policy policy = {}; log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_parse_environment(); @@ -1040,6 +1110,14 @@ int main(int argc, char *argv[]) { if (r <= 0) goto finish; + r = policy_load(&policy, arg_configuration); + if (r < 0) { + log_error("Failed to load policy: %s", strerror(-r)); + goto finish; + } + + /* policy_dump(&policy); */ + r = sd_listen_fds(0); if (r == 0) { in_fd = STDIN_FILENO; @@ -1061,6 +1139,22 @@ int main(int argc, char *argv[]) { getpeersec(in_fd, &peersec); } + if (arg_drop_privileges) { + const char *user = "systemd-bus-proxy"; + uid_t uid; + gid_t gid; + + r = get_user_creds(&user, &uid, &gid, NULL, NULL); + if (r < 0) { + log_error("Cannot resolve user name %s: %s", user, strerror(-r)); + goto finish; + } + + r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER); + if (r < 0) + goto finish; + } + r = sd_bus_new(&a); if (r < 0) { log_error("Failed to allocate bus: %s", strerror(-r)); @@ -1177,7 +1271,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = sd_bus_add_match(a, match, NULL, NULL); + r = sd_bus_add_match(a, NULL, match, NULL, NULL); if (r < 0) { log_error("Failed to add match for NameLost: %s", strerror(-r)); goto finish; @@ -1198,7 +1292,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = sd_bus_add_match(a, match, NULL, NULL); + r = sd_bus_add_match(a, NULL, match, NULL, NULL); if (r < 0) { log_error("Failed to add match for NameAcquired: %s", strerror(-r)); goto finish; @@ -1305,7 +1399,7 @@ int main(int argc, char *argv[]) { else { k = sd_bus_send(a, m, NULL); if (k < 0) { - if (r == -ECONNRESET) + if (k == -ECONNRESET) r = 0; else { r = k; @@ -1383,8 +1477,13 @@ int main(int argc, char *argv[]) { } finish: - sd_bus_flush(a); - sd_bus_flush(b); + sd_notify(false, + "STOPPING=1\n" + "STATUS=Shutting down."); + + policy_free(&policy); + strv_free(arg_configuration); + free(arg_address); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }