diff options
Diffstat (limited to 'src')
l--------- | src/bus-proxyd/Makefile | 1 | ||||
-rw-r--r-- | src/bus-proxyd/bus-proxyd.c | 332 | ||||
-rw-r--r-- | src/bus-proxyd/bus-xml-policy.c | 1324 | ||||
-rw-r--r-- | src/bus-proxyd/bus-xml-policy.h | 149 | ||||
-rw-r--r-- | src/bus-proxyd/driver.c | 680 | ||||
-rw-r--r-- | src/bus-proxyd/driver.h | 27 | ||||
-rw-r--r-- | src/bus-proxyd/proxy.c | 854 | ||||
-rw-r--r-- | src/bus-proxyd/proxy.h | 51 | ||||
-rw-r--r-- | src/bus-proxyd/stdio-bridge.c | 249 | ||||
-rw-r--r-- | src/bus-proxyd/synthesize.c | 220 | ||||
-rw-r--r-- | src/bus-proxyd/synthesize.h | 36 | ||||
-rw-r--r-- | src/bus-proxyd/test-bus-xml-policy.c | 169 |
12 files changed, 0 insertions, 4092 deletions
diff --git a/src/bus-proxyd/Makefile b/src/bus-proxyd/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/bus-proxyd/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile
\ No newline at end of file diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c deleted file mode 100644 index d612816851..0000000000 --- a/src/bus-proxyd/bus-proxyd.c +++ /dev/null @@ -1,332 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Daniel Mack - Copyright 2014 Kay Sievers - Copyright 2015 David Herrmann - - 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 <sys/socket.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <sys/prctl.h> -#include <stddef.h> -#include <getopt.h> -#include <pthread.h> - -#include "log.h" -#include "util.h" -#include "sd-daemon.h" -#include "bus-internal.h" -#include "build.h" -#include "strv.h" -#include "def.h" -#include "capability.h" -#include "bus-xml-policy.h" -#include "proxy.h" - -static char *arg_address = NULL; -static char **arg_configuration = NULL; - -typedef struct { - int fd; - SharedPolicy *policy; - uid_t bus_uid; -} ClientContext; - -static ClientContext *client_context_free(ClientContext *c) { - if (!c) - return NULL; - - safe_close(c->fd); - free(c); - - return NULL; -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free); - -static int client_context_new(ClientContext **out) { - _cleanup_(client_context_freep) ClientContext *c = NULL; - - c = new0(ClientContext, 1); - if (!c) - return -ENOMEM; - - c->fd = -1; - - *out = c; - c = NULL; - return 0; -} - -static void *run_client(void *userdata) { - _cleanup_(client_context_freep) ClientContext *c = userdata; - _cleanup_(proxy_freep) Proxy *p = NULL; - char comm[16]; - int r; - - r = proxy_new(&p, c->fd, c->fd, arg_address); - if (r < 0) - goto exit; - - c->fd = -1; - - /* set comm to "p$PIDu$UID" and suffix with '*' if truncated */ - r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid); - if (r >= (ssize_t)sizeof(comm)) - comm[sizeof(comm) - 2] = '*'; - (void) prctl(PR_SET_NAME, comm); - - r = proxy_set_policy(p, c->policy, arg_configuration); - if (r < 0) - goto exit; - - r = proxy_hello_policy(p, c->bus_uid); - if (r < 0) - goto exit; - - r = proxy_run(p); - -exit: - return NULL; -} - -static int loop_clients(int accept_fd, uid_t bus_uid) { - _cleanup_(shared_policy_freep) SharedPolicy *sp = NULL; - pthread_attr_t attr; - int r; - - r = pthread_attr_init(&attr); - if (r < 0) { - return log_error_errno(errno, "Cannot initialize pthread attributes: %m"); - } - - r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (r < 0) { - r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m"); - goto finish; - } - - r = shared_policy_new(&sp); - if (r < 0) - goto finish; - - for (;;) { - ClientContext *c; - pthread_t tid; - int fd; - - fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC); - if (fd < 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - - r = log_error_errno(errno, "accept4() failed: %m"); - goto finish; - } - - r = client_context_new(&c); - if (r < 0) { - log_oom(); - close(fd); - continue; - } - - c->fd = fd; - c->policy = sp; - c->bus_uid = bus_uid; - - r = pthread_create(&tid, &attr, run_client, c); - if (r < 0) { - log_error("Cannot spawn thread: %m"); - client_context_free(c); - continue; - } - } - -finish: - pthread_attr_destroy(&attr); - return r; -} - -static int help(void) { - - printf("%s [OPTIONS...]\n\n" - "DBus proxy server.\n\n" - " -h --help Show this help\n" - " --version Show package version\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_ADDRESS ")\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_ADDRESS, - 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 }, - { "configuration", required_argument, NULL, ARG_CONFIGURATION }, - { "machine", required_argument, NULL, ARG_MACHINE }, - {}, - }; - - int c, r; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; - - case ARG_ADDRESS: - r = free_and_strdup(&arg_address, optarg); - if (r < 0) - return log_oom(); - 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-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL); -#else - a = strjoin("x-machine-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 (argc > optind) { - log_error("Too many arguments"); - return -EINVAL; - } - - if (!arg_address) { - arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS); - if (!arg_address) - return log_oom(); - } - - return 1; -} - -int main(int argc, char *argv[]) { - int r, accept_fd; - uid_t uid, bus_uid; - gid_t gid; - - log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); - log_parse_environment(); - log_open(); - - bus_uid = getuid(); - - if (geteuid() == 0) { - const char *user = "systemd-bus-proxy"; - - r = get_user_creds(&user, &uid, &gid, NULL, NULL); - if (r < 0) { - log_error_errno(r, "Cannot resolve user name %s: %m", user); - goto finish; - } - - r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER); - if (r < 0) { - log_error_errno(r, "Cannot drop privileges: %m"); - goto finish; - } - } - - r = parse_argv(argc, argv); - if (r <= 0) - goto finish; - - r = sd_listen_fds(0); - if (r != 1) { - log_error("Illegal number of file descriptors passed"); - goto finish; - } - - accept_fd = SD_LISTEN_FDS_START; - - r = fd_nonblock(accept_fd, false); - if (r < 0) { - log_error_errno(r, "Cannot mark accept-fd non-blocking: %m"); - goto finish; - } - - r = loop_clients(accept_fd, bus_uid); - -finish: - sd_notify(false, - "STOPPING=1\n" - "STATUS=Shutting down."); - - strv_free(arg_configuration); - free(arg_address); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c deleted file mode 100644 index 497bce7b56..0000000000 --- a/src/bus-proxyd/bus-xml-policy.c +++ /dev/null @@ -1,1324 +0,0 @@ -/*-*- 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 "xml.h" -#include "fileio.h" -#include "strv.h" -#include "set.h" -#include "conf-files.h" -#include "bus-internal.h" -#include "bus-xml-policy.h" -#include "sd-login.h" - -static void policy_item_free(PolicyItem *i) { - assert(i); - - free(i->interface); - free(i->member); - free(i->error); - free(i->name); - free(i->path); - free(i); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free); - -static void item_append(PolicyItem *i, PolicyItem **list) { - - PolicyItem *tail; - - LIST_FIND_TAIL(items, *list, tail); - LIST_INSERT_AFTER(items, *list, tail, i); -} - -static int file_load(Policy *p, const char *path) { - - _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL; - _cleanup_(policy_item_freep) PolicyItem *i = NULL; - void *xml_state = NULL; - unsigned n_other = 0; - const char *q; - int r; - - enum { - STATE_OUTSIDE, - STATE_BUSCONFIG, - STATE_POLICY, - STATE_POLICY_CONTEXT, - STATE_POLICY_CONSOLE, - STATE_POLICY_USER, - STATE_POLICY_GROUP, - STATE_POLICY_OTHER_ATTRIBUTE, - STATE_ALLOW_DENY, - STATE_ALLOW_DENY_INTERFACE, - STATE_ALLOW_DENY_MEMBER, - STATE_ALLOW_DENY_ERROR, - STATE_ALLOW_DENY_PATH, - STATE_ALLOW_DENY_MESSAGE_TYPE, - STATE_ALLOW_DENY_NAME, - STATE_ALLOW_DENY_OTHER_ATTRIBUTE, - STATE_OTHER, - } state = STATE_OUTSIDE; - - enum { - POLICY_CATEGORY_NONE, - POLICY_CATEGORY_DEFAULT, - POLICY_CATEGORY_MANDATORY, - POLICY_CATEGORY_ON_CONSOLE, - POLICY_CATEGORY_NO_CONSOLE, - POLICY_CATEGORY_USER, - POLICY_CATEGORY_GROUP - } policy_category = POLICY_CATEGORY_NONE; - - unsigned line = 0; - - assert(p); - - r = read_full_file(path, &c, NULL); - if (r < 0) { - if (r == -ENOENT) - return 0; - if (r == -EISDIR) - return r; - - return log_error_errno(r, "Failed to load %s: %m", path); - } - - q = c; - for (;;) { - _cleanup_free_ char *name = NULL; - int t; - - t = xml_tokenize(&q, &name, &xml_state, &line); - if (t < 0) - return log_error_errno(t, "XML parse failure in %s: %m", path); - - switch (state) { - - case STATE_OUTSIDE: - - if (t == XML_TAG_OPEN) { - if (streq(name, "busconfig")) - state = STATE_BUSCONFIG; - else { - log_error("Unexpected tag %s at %s:%u.", name, path, line); - return -EINVAL; - } - - } else if (t == XML_END) - return 0; - else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (1) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_BUSCONFIG: - - if (t == XML_TAG_OPEN) { - if (streq(name, "policy")) { - state = STATE_POLICY; - policy_category = POLICY_CATEGORY_NONE; - free(policy_user); - free(policy_group); - policy_user = policy_group = NULL; - } else { - state = STATE_OTHER; - n_other = 0; - } - } else if (t == XML_TAG_CLOSE_EMPTY || - (t == XML_TAG_CLOSE && streq(name, "busconfig"))) - state = STATE_OUTSIDE; - else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (2) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY: - - if (t == XML_ATTRIBUTE_NAME) { - if (streq(name, "context")) - state = STATE_POLICY_CONTEXT; - else if (streq(name, "at_console")) - state = STATE_POLICY_CONSOLE; - else if (streq(name, "user")) - state = STATE_POLICY_USER; - else if (streq(name, "group")) - state = STATE_POLICY_GROUP; - else { - log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line); - state = STATE_POLICY_OTHER_ATTRIBUTE; - } - } else if (t == XML_TAG_CLOSE_EMPTY || - (t == XML_TAG_CLOSE && streq(name, "policy"))) - state = STATE_BUSCONFIG; - else if (t == XML_TAG_OPEN) { - PolicyItemType it; - - if (streq(name, "allow")) - it = POLICY_ITEM_ALLOW; - else if (streq(name, "deny")) - it = POLICY_ITEM_DENY; - else { - log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line); - return -EINVAL; - } - - assert(!i); - i = new0(PolicyItem, 1); - if (!i) - return log_oom(); - - i->type = it; - state = STATE_ALLOW_DENY; - - } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (3) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_CONTEXT: - - if (t == XML_ATTRIBUTE_VALUE) { - if (streq(name, "default")) { - policy_category = POLICY_CATEGORY_DEFAULT; - state = STATE_POLICY; - } else if (streq(name, "mandatory")) { - policy_category = POLICY_CATEGORY_MANDATORY; - state = STATE_POLICY; - } else { - log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line); - return -EINVAL; - } - } else { - log_error("Unexpected token (4) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_CONSOLE: - - if (t == XML_ATTRIBUTE_VALUE) { - if (streq(name, "true")) { - policy_category = POLICY_CATEGORY_ON_CONSOLE; - state = STATE_POLICY; - } else if (streq(name, "false")) { - policy_category = POLICY_CATEGORY_NO_CONSOLE; - state = STATE_POLICY; - } else { - log_error("at_console= parameter %s unknown for <policy> at %s:%u.", name, path, line); - return -EINVAL; - } - } else { - log_error("Unexpected token (4.1) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_USER: - - if (t == XML_ATTRIBUTE_VALUE) { - free(policy_user); - policy_user = name; - name = NULL; - policy_category = POLICY_CATEGORY_USER; - state = STATE_POLICY; - } else { - log_error("Unexpected token (5) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_GROUP: - - if (t == XML_ATTRIBUTE_VALUE) { - free(policy_group); - policy_group = name; - name = NULL; - policy_category = POLICY_CATEGORY_GROUP; - state = STATE_POLICY; - } else { - log_error("Unexpected token (6) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_OTHER_ATTRIBUTE: - - if (t == XML_ATTRIBUTE_VALUE) - state = STATE_POLICY; - else { - log_error("Unexpected token (7) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY: - - assert(i); - - if (t == XML_ATTRIBUTE_NAME) { - PolicyItemClass ic; - - if (startswith(name, "send_")) - ic = POLICY_ITEM_SEND; - else if (startswith(name, "receive_")) - ic = POLICY_ITEM_RECV; - else if (streq(name, "own")) - ic = POLICY_ITEM_OWN; - else if (streq(name, "own_prefix")) - ic = POLICY_ITEM_OWN_PREFIX; - else if (streq(name, "user")) - ic = POLICY_ITEM_USER; - else if (streq(name, "group")) - ic = POLICY_ITEM_GROUP; - else if (streq(name, "eavesdrop")) { - log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line); - state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; - break; - } else { - log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line); - state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; - break; - } - - if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) { - log_error("send_, receive_/eavesdrop fields mixed on same tag at %s:%u.", path, line); - return -EINVAL; - } - - i->class = ic; - - if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) { - const char *u; - - u = strchr(name, '_'); - assert(u); - - u++; - - if (streq(u, "interface")) - state = STATE_ALLOW_DENY_INTERFACE; - else if (streq(u, "member")) - state = STATE_ALLOW_DENY_MEMBER; - else if (streq(u, "error")) - state = STATE_ALLOW_DENY_ERROR; - else if (streq(u, "path")) - state = STATE_ALLOW_DENY_PATH; - else if (streq(u, "type")) - state = STATE_ALLOW_DENY_MESSAGE_TYPE; - else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) || - (streq(u, "sender") && ic == POLICY_ITEM_RECV)) - state = STATE_ALLOW_DENY_NAME; - else { - if (streq(u, "requested_reply")) - log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line); - else - log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line); - state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; - break; - } - } else - state = STATE_ALLOW_DENY_NAME; - - } else if (t == XML_TAG_CLOSE_EMPTY || - (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) { - - /* If the tag is fully empty so far, we consider it a recv */ - if (i->class == _POLICY_ITEM_CLASS_UNSET) - i->class = POLICY_ITEM_RECV; - - if (policy_category == POLICY_CATEGORY_DEFAULT) - item_append(i, &p->default_items); - else if (policy_category == POLICY_CATEGORY_MANDATORY) - item_append(i, &p->mandatory_items); - else if (policy_category == POLICY_CATEGORY_ON_CONSOLE) - item_append(i, &p->on_console_items); - else if (policy_category == POLICY_CATEGORY_NO_CONSOLE) - item_append(i, &p->no_console_items); - else if (policy_category == POLICY_CATEGORY_USER) { - const char *u = policy_user; - - assert_cc(sizeof(uid_t) == sizeof(uint32_t)); - - r = hashmap_ensure_allocated(&p->user_items, NULL); - if (r < 0) - return log_oom(); - - if (!u) { - log_error("User policy without name"); - return -EINVAL; - } - - r = get_user_creds(&u, &i->uid, NULL, NULL, NULL); - if (r < 0) { - log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u); - free(i); - } else { - PolicyItem *first; - - first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid)); - item_append(i, &first); - i->uid_valid = true; - - r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first); - if (r < 0) { - LIST_REMOVE(items, first, i); - return log_oom(); - } - } - - } else if (policy_category == POLICY_CATEGORY_GROUP) { - const char *g = policy_group; - - assert_cc(sizeof(gid_t) == sizeof(uint32_t)); - - r = hashmap_ensure_allocated(&p->group_items, NULL); - if (r < 0) - return log_oom(); - - if (!g) { - log_error("Group policy without name"); - return -EINVAL; - } - - r = get_group_creds(&g, &i->gid); - if (r < 0) { - log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g); - free(i); - } else { - PolicyItem *first; - - first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid)); - item_append(i, &first); - i->gid_valid = true; - - r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first); - if (r < 0) { - LIST_REMOVE(items, first, i); - return log_oom(); - } - } - } - - state = STATE_POLICY; - i = NULL; - - } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (8) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_INTERFACE: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->interface) { - log_error("Duplicate interface at %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->interface = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (9) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_MEMBER: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->member) { - log_error("Duplicate member in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->member = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (10) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_ERROR: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->error) { - log_error("Duplicate error in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->error = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (11) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_PATH: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->path) { - log_error("Duplicate path in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->path = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (12) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_MESSAGE_TYPE: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - - if (i->message_type != 0) { - log_error("Duplicate message type in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - r = bus_message_type_from_string(name, &i->message_type); - if (r < 0) { - log_error("Invalid message type in %s:%u.", path, line); - return -EINVAL; - } - } - - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (13) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_NAME: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->name) { - log_error("Duplicate name in %s:%u.", path, line); - return -EINVAL; - } - - switch (i->class) { - case POLICY_ITEM_USER: - if (!streq(name, "*")) { - const char *u = name; - - r = get_user_creds(&u, &i->uid, NULL, NULL, NULL); - if (r < 0) - log_error_errno(r, "Failed to resolve user %s: %m", name); - else - i->uid_valid = true; - } - break; - case POLICY_ITEM_GROUP: - if (!streq(name, "*")) { - const char *g = name; - - r = get_group_creds(&g, &i->gid); - if (r < 0) - log_error_errno(r, "Failed to resolve group %s: %m", name); - else - i->gid_valid = true; - } - break; - - case POLICY_ITEM_SEND: - case POLICY_ITEM_RECV: - - if (streq(name, "*")) { - free(name); - name = NULL; - } - break; - - - default: - break; - } - - i->name = name; - name = NULL; - - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (14) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_OTHER_ATTRIBUTE: - - if (t == XML_ATTRIBUTE_VALUE) - state = STATE_ALLOW_DENY; - else { - log_error("Unexpected token (15) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_OTHER: - - if (t == XML_TAG_OPEN) - n_other++; - else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) { - - if (n_other == 0) - state = STATE_BUSCONFIG; - else - n_other--; - } - - break; - } - } -} - -enum { - DENY, - ALLOW, - DUNNO, -}; - -static const char *verdict_to_string(int v) { - switch (v) { - - case DENY: - return "DENY"; - case ALLOW: - return "ALLOW"; - case DUNNO: - return "DUNNO"; - } - - return NULL; -} - -struct policy_check_filter { - PolicyItemClass class; - uid_t uid; - gid_t gid; - int message_type; - const char *name; - const char *interface; - const char *path; - const char *member; -}; - -static int is_permissive(PolicyItem *i) { - - assert(i); - - return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY; -} - -static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) { - - assert(i); - assert(filter); - - switch (i->class) { - case POLICY_ITEM_SEND: - case POLICY_ITEM_RECV: - - if (i->name && !streq_ptr(i->name, filter->name)) - break; - - if ((i->message_type != 0) && (i->message_type != filter->message_type)) - break; - - if (i->path && !streq_ptr(i->path, filter->path)) - break; - - if (i->member && !streq_ptr(i->member, filter->member)) - break; - - if (i->interface && !streq_ptr(i->interface, filter->interface)) - break; - - return is_permissive(i); - - case POLICY_ITEM_OWN: - assert(filter->name); - - if (streq(i->name, "*") || streq(i->name, filter->name)) - return is_permissive(i); - break; - - case POLICY_ITEM_OWN_PREFIX: - assert(filter->name); - - if (streq(i->name, "*") || service_name_startswith(filter->name, i->name)) - return is_permissive(i); - break; - - case POLICY_ITEM_USER: - if (filter->uid != UID_INVALID) - if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid))) - return is_permissive(i); - break; - - case POLICY_ITEM_GROUP: - if (filter->gid != GID_INVALID) - if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid))) - return is_permissive(i); - break; - - case POLICY_ITEM_IGNORE: - default: - break; - } - - return DUNNO; -} - -static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) { - - PolicyItem *i; - int verdict = DUNNO; - - assert(filter); - - /* Check all policies in a set - a broader one might be followed by a more specific one, - * and the order of rules in policy definitions matters */ - LIST_FOREACH(items, i, items) { - int v; - - if (i->class != filter->class && - !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN)) - continue; - - v = check_policy_item(i, filter); - if (v != DUNNO) - verdict = v; - } - - return verdict; -} - -static int policy_check(Policy *p, const struct policy_check_filter *filter) { - - PolicyItem *items; - int verdict, v; - - assert(p); - assert(filter); - - assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP)); - - /* - * The policy check is implemented by the following logic: - * - * 1. Check default items - * 2. Check group items - * 3. Check user items - * 4. Check on/no_console items - * 5. Check mandatory items - * - * Later rules override earlier rules. - */ - - verdict = check_policy_items(p->default_items, filter); - - if (filter->gid != GID_INVALID) { - items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid)); - if (items) { - v = check_policy_items(items, filter); - if (v != DUNNO) - verdict = v; - } - } - - if (filter->uid != UID_INVALID) { - items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid)); - if (items) { - v = check_policy_items(items, filter); - if (v != DUNNO) - verdict = v; - } - } - - if (filter->uid != UID_INVALID && sd_uid_get_seats(filter->uid, -1, NULL) > 0) - v = check_policy_items(p->on_console_items, filter); - else - v = check_policy_items(p->no_console_items, filter); - if (v != DUNNO) - verdict = v; - - v = check_policy_items(p->mandatory_items, filter); - if (v != DUNNO) - verdict = v; - - return verdict; -} - -bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) { - - struct policy_check_filter filter = { - .class = POLICY_ITEM_OWN, - .uid = uid, - .gid = gid, - .name = name, - }; - - int verdict; - - assert(p); - assert(name); - - verdict = policy_check(p, &filter); - - log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG), - "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s", - uid, gid, strna(name), strna(verdict_to_string(verdict))); - - return verdict == ALLOW; -} - -bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) { - - struct policy_check_filter filter = { - .uid = uid, - .gid = gid, - }; - int verdict; - - assert(p); - - filter.class = POLICY_ITEM_USER; - verdict = policy_check(p, &filter); - - if (verdict != DENY) { - int v; - - filter.class = POLICY_ITEM_GROUP; - v = policy_check(p, &filter); - if (v != DUNNO) - verdict = v; - } - - log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG), - "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s", - uid, gid, strna(verdict_to_string(verdict))); - - return verdict == ALLOW; -} - -bool policy_check_one_recv(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - const char *name, - const char *path, - const char *interface, - const char *member) { - - struct policy_check_filter filter = { - .class = POLICY_ITEM_RECV, - .uid = uid, - .gid = gid, - .message_type = message_type, - .name = name, - .interface = interface, - .path = path, - .member = member, - }; - - assert(p); - - return policy_check(p, &filter) == ALLOW; -} - -bool policy_check_recv(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - Set *names, - char **namesv, - const char *path, - const char *interface, - const char *member, - bool dbus_to_kernel) { - - char *n, **nv, *last = NULL; - bool allow = false; - Iterator i; - - assert(p); - - if (set_isempty(names) && strv_isempty(namesv)) { - allow = policy_check_one_recv(p, uid, gid, message_type, NULL, path, interface, member); - } else { - SET_FOREACH(n, names, i) { - last = n; - allow = policy_check_one_recv(p, uid, gid, message_type, n, path, interface, member); - if (allow) - break; - } - if (!allow) { - STRV_FOREACH(nv, namesv) { - last = *nv; - allow = policy_check_one_recv(p, uid, gid, message_type, *nv, path, interface, member); - if (allow) - break; - } - } - } - - log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG), - "Receive permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s", - dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last), - strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY"); - - return allow; -} - -bool policy_check_one_send(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - const char *name, - const char *path, - const char *interface, - const char *member) { - - struct policy_check_filter filter = { - .class = POLICY_ITEM_SEND, - .uid = uid, - .gid = gid, - .message_type = message_type, - .name = name, - .interface = interface, - .path = path, - .member = member, - }; - - assert(p); - - return policy_check(p, &filter) == ALLOW; -} - -bool policy_check_send(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - Set *names, - char **namesv, - const char *path, - const char *interface, - const char *member, - bool dbus_to_kernel, - char **out_used_name) { - - char *n, **nv, *last = NULL; - bool allow = false; - Iterator i; - - assert(p); - - if (set_isempty(names) && strv_isempty(namesv)) { - allow = policy_check_one_send(p, uid, gid, message_type, NULL, path, interface, member); - } else { - SET_FOREACH(n, names, i) { - last = n; - allow = policy_check_one_send(p, uid, gid, message_type, n, path, interface, member); - if (allow) - break; - } - if (!allow) { - STRV_FOREACH(nv, namesv) { - last = *nv; - allow = policy_check_one_send(p, uid, gid, message_type, *nv, path, interface, member); - if (allow) - break; - } - } - } - - if (out_used_name) - *out_used_name = last; - - log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG), - "Send permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s", - dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last), - strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY"); - - return allow; -} - -int policy_load(Policy *p, char **files) { - char **i; - int r; - - assert(p); - - STRV_FOREACH(i, files) { - - r = file_load(p, *i); - if (r == -EISDIR) { - _cleanup_strv_free_ char **l = NULL; - char **j; - - r = conf_files_list(&l, ".conf", NULL, *i, NULL); - if (r < 0) - return log_error_errno(r, "Failed to get configuration file list: %m"); - - STRV_FOREACH(j, l) - file_load(p, *j); - } - - /* We ignore all errors but EISDIR, and just proceed. */ - } - - return 0; -} - -void policy_free(Policy *p) { - PolicyItem *i, *first; - - if (!p) - return; - - while ((i = p->default_items)) { - LIST_REMOVE(items, p->default_items, i); - policy_item_free(i); - } - - while ((i = p->mandatory_items)) { - LIST_REMOVE(items, p->mandatory_items, i); - policy_item_free(i); - } - - while ((i = p->on_console_items)) { - LIST_REMOVE(items, p->on_console_items, i); - policy_item_free(i); - } - - while ((i = p->no_console_items)) { - LIST_REMOVE(items, p->no_console_items, i); - policy_item_free(i); - } - - while ((first = hashmap_steal_first(p->user_items))) { - - while ((i = first)) { - LIST_REMOVE(items, first, i); - policy_item_free(i); - } - } - - while ((first = hashmap_steal_first(p->group_items))) { - - while ((i = first)) { - LIST_REMOVE(items, first, i); - policy_item_free(i); - } - } - - hashmap_free(p->user_items); - hashmap_free(p->group_items); - - p->user_items = p->group_items = NULL; -} - -static void dump_items(PolicyItem *items, const char *prefix) { - - PolicyItem *i; - - if (!items) - return; - - if (!prefix) - prefix = ""; - - LIST_FOREACH(items, i, items) { - - printf("%sType: %s\n" - "%sClass: %s\n", - prefix, policy_item_type_to_string(i->type), - prefix, policy_item_class_to_string(i->class)); - - if (i->interface) - printf("%sInterface: %s\n", - prefix, i->interface); - - if (i->member) - printf("%sMember: %s\n", - prefix, i->member); - - if (i->error) - printf("%sError: %s\n", - prefix, i->error); - - if (i->path) - printf("%sPath: %s\n", - prefix, i->path); - - if (i->name) - printf("%sName: %s\n", - prefix, i->name); - - if (i->message_type != 0) - printf("%sMessage Type: %s\n", - prefix, bus_message_type_to_string(i->message_type)); - - if (i->uid_valid) { - _cleanup_free_ char *user; - - user = uid_to_name(i->uid); - - printf("%sUser: %s ("UID_FMT")\n", - prefix, strna(user), i->uid); - } - - if (i->gid_valid) { - _cleanup_free_ char *group; - - group = gid_to_name(i->gid); - - printf("%sGroup: %s ("GID_FMT")\n", - prefix, strna(group), i->gid); - } - printf("%s-\n", prefix); - } -} - -static void dump_hashmap_items(Hashmap *h) { - PolicyItem *i; - Iterator j; - void *k; - - HASHMAP_FOREACH_KEY(i, k, h, j) { - printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k)); - dump_items(i, "\t\t"); - } -} - -void policy_dump(Policy *p) { - - printf("%s Default Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->default_items, "\t"); - - printf("%s Group Items:\n", draw_special_char(DRAW_ARROW)); - dump_hashmap_items(p->group_items); - - printf("%s User Items:\n", draw_special_char(DRAW_ARROW)); - dump_hashmap_items(p->user_items); - - printf("%s On-Console Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->on_console_items, "\t"); - - printf("%s No-Console Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->no_console_items, "\t"); - - printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->mandatory_items, "\t"); - - fflush(stdout); -} - -int shared_policy_new(SharedPolicy **out) { - SharedPolicy *sp; - int r; - - sp = new0(SharedPolicy, 1); - if (!sp) - return log_oom(); - - r = pthread_mutex_init(&sp->lock, NULL); - if (r < 0) { - log_error_errno(r, "Cannot initialize shared policy mutex: %m"); - goto exit_free; - } - - r = pthread_rwlock_init(&sp->rwlock, NULL); - if (r < 0) { - log_error_errno(r, "Cannot initialize shared policy rwlock: %m"); - goto exit_mutex; - } - - *out = sp; - sp = NULL; - return 0; - - /* pthread lock destruction is not fail-safe... meh! */ -exit_mutex: - pthread_mutex_destroy(&sp->lock); -exit_free: - free(sp); - return r; -} - -SharedPolicy *shared_policy_free(SharedPolicy *sp) { - if (!sp) - return NULL; - - policy_free(sp->policy); - pthread_rwlock_destroy(&sp->rwlock); - pthread_mutex_destroy(&sp->lock); - strv_free(sp->configuration); - free(sp); - - return NULL; -} - -static int shared_policy_reload_unlocked(SharedPolicy *sp, char **configuration) { - Policy old, buffer = {}; - bool free_old; - int r; - - assert(sp); - - r = policy_load(&buffer, configuration); - if (r < 0) - return log_error_errno(r, "Failed to load policy: %m"); - - log_debug("Reloading configuration"); - /* policy_dump(&buffer); */ - - pthread_rwlock_wrlock(&sp->rwlock); - memcpy(&old, &sp->buffer, sizeof(old)); - memcpy(&sp->buffer, &buffer, sizeof(buffer)); - free_old = !!sp->policy; - sp->policy = &sp->buffer; - pthread_rwlock_unlock(&sp->rwlock); - - if (free_old) - policy_free(&old); - - return 0; -} - -int shared_policy_reload(SharedPolicy *sp) { - int r; - - assert(sp); - - pthread_mutex_lock(&sp->lock); - r = shared_policy_reload_unlocked(sp, sp->configuration); - pthread_mutex_unlock(&sp->lock); - - return r; -} - -int shared_policy_preload(SharedPolicy *sp, char **configuration) { - _cleanup_strv_free_ char **conf = NULL; - int r = 0; - - assert(sp); - - conf = strv_copy(configuration); - if (!conf) - return log_oom(); - - pthread_mutex_lock(&sp->lock); - if (!sp->policy) { - r = shared_policy_reload_unlocked(sp, conf); - if (r >= 0) { - sp->configuration = conf; - conf = NULL; - } - } - pthread_mutex_unlock(&sp->lock); - - return r; -} - -Policy *shared_policy_acquire(SharedPolicy *sp) { - assert(sp); - - pthread_rwlock_rdlock(&sp->rwlock); - if (sp->policy) - return sp->policy; - pthread_rwlock_unlock(&sp->rwlock); - - return NULL; -} - -void shared_policy_release(SharedPolicy *sp, Policy *p) { - assert(sp); - assert(!p || sp->policy == p); - - if (p) - pthread_rwlock_unlock(&sp->rwlock); -} - -static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = { - [_POLICY_ITEM_TYPE_UNSET] = "unset", - [POLICY_ITEM_ALLOW] = "allow", - [POLICY_ITEM_DENY] = "deny", -}; -DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType); - -static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = { - [_POLICY_ITEM_CLASS_UNSET] = "unset", - [POLICY_ITEM_SEND] = "send", - [POLICY_ITEM_RECV] = "recv", - [POLICY_ITEM_OWN] = "own", - [POLICY_ITEM_OWN_PREFIX] = "own-prefix", - [POLICY_ITEM_USER] = "user", - [POLICY_ITEM_GROUP] = "group", - [POLICY_ITEM_IGNORE] = "ignore", -}; -DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass); diff --git a/src/bus-proxyd/bus-xml-policy.h b/src/bus-proxyd/bus-xml-policy.h deleted file mode 100644 index 8f0ab8f17f..0000000000 --- a/src/bus-proxyd/bus-xml-policy.h +++ /dev/null @@ -1,149 +0,0 @@ -/*-*- 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 <pthread.h> - -#include "list.h" -#include "hashmap.h" - -typedef enum PolicyItemType { - _POLICY_ITEM_TYPE_UNSET = 0, - POLICY_ITEM_ALLOW, - POLICY_ITEM_DENY, - _POLICY_ITEM_TYPE_MAX, - _POLICY_ITEM_TYPE_INVALID = -1, -} PolicyItemType; - -typedef enum PolicyItemClass { - _POLICY_ITEM_CLASS_UNSET = 0, - POLICY_ITEM_SEND, - POLICY_ITEM_RECV, - POLICY_ITEM_OWN, - POLICY_ITEM_OWN_PREFIX, - POLICY_ITEM_USER, - POLICY_ITEM_GROUP, - POLICY_ITEM_IGNORE, - _POLICY_ITEM_CLASS_MAX, - _POLICY_ITEM_CLASS_INVALID = -1, -} PolicyItemClass; - -typedef struct PolicyItem PolicyItem; - -struct PolicyItem { - PolicyItemType type; - PolicyItemClass class; - char *interface; - char *member; - char *error; - char *path; - char *name; - uint8_t message_type; - uid_t uid; - gid_t gid; - - bool uid_valid, gid_valid; - - LIST_FIELDS(PolicyItem, items); -}; - -typedef struct Policy { - LIST_HEAD(PolicyItem, default_items); - LIST_HEAD(PolicyItem, mandatory_items); - LIST_HEAD(PolicyItem, on_console_items); - LIST_HEAD(PolicyItem, no_console_items); - Hashmap *user_items; - Hashmap *group_items; -} Policy; - -typedef struct SharedPolicy { - char **configuration; - pthread_mutex_t lock; - pthread_rwlock_t rwlock; - Policy buffer; - Policy *policy; -} SharedPolicy; - -/* policy */ - -int policy_load(Policy *p, char **files); -void policy_free(Policy *p); - -bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name); -bool policy_check_hello(Policy *p, uid_t uid, gid_t gid); -bool policy_check_one_recv(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - const char *name, - const char *path, - const char *interface, - const char *member); -bool policy_check_recv(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - Set *names, - char **namesv, - const char *path, - const char *interface, - const char *member, - bool dbus_to_kernel); -bool policy_check_one_send(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - const char *name, - const char *path, - const char *interface, - const char *member); -bool policy_check_send(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - Set *names, - char **namesv, - const char *path, - const char *interface, - const char *member, - bool dbus_to_kernel, - char **out_used_name); - -void policy_dump(Policy *p); - -const char* policy_item_type_to_string(PolicyItemType t) _const_; -PolicyItemType policy_item_type_from_string(const char *s) _pure_; - -const char* policy_item_class_to_string(PolicyItemClass t) _const_; -PolicyItemClass policy_item_class_from_string(const char *s) _pure_; - -/* shared policy */ - -int shared_policy_new(SharedPolicy **out); -SharedPolicy *shared_policy_free(SharedPolicy *sp); - -int shared_policy_reload(SharedPolicy *sp); -int shared_policy_preload(SharedPolicy *sp, char **configuration); -Policy *shared_policy_acquire(SharedPolicy *sp); -void shared_policy_release(SharedPolicy *sp, Policy *p); - -DEFINE_TRIVIAL_CLEANUP_FUNC(SharedPolicy*, shared_policy_free); diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c deleted file mode 100644 index 90ddd735dc..0000000000 --- a/src/bus-proxyd/driver.c +++ /dev/null @@ -1,680 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Daniel Mack - Copyright 2014 Kay Sievers - - 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 <string.h> -#include <errno.h> -#include <stddef.h> - -#include "util.h" -#include "sd-bus.h" -#include "bus-internal.h" -#include "bus-message.h" -#include "bus-util.h" -#include "strv.h" -#include "set.h" -#include "driver.h" -#include "synthesize.h" - -static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; - int r; - - assert(bus); - assert(name); - assert(_creds); - - r = sd_bus_get_name_creds(bus, name, mask, &c); - if (r == -ESRCH || r == -ENXIO) - return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name); - if (r < 0) - return r; - - *_creds = c; - c = NULL; - - return 0; -} - -static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { - const char *name; - int r; - - assert(bus); - assert(m); - assert(_creds); - - r = sd_bus_message_read(m, "s", &name); - if (r < 0) - return r; - - return get_creds_by_name(bus, name, mask, _creds, error); -} - -int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) { - int r; - - assert(a); - assert(b); - assert(m); - - if (!a->is_kernel) - return 0; - - if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus")) - return 0; - - /* The "Hello()" call is is handled in process_hello() */ - - if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) { - - if (!sd_bus_message_has_signature(m, "")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - return synthetic_reply_method_return(m, "s", - "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" " - "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" - "<node>\n" - " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" - " <method name=\"Introspect\">\n" - " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" - " </method>\n" - " </interface>\n" - " <interface name=\"org.freedesktop.DBus\">\n" - " <method name=\"AddMatch\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " </method>\n" - " <method name=\"RemoveMatch\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " </method>\n" - " <method name=\"GetConnectionCredentials\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " <arg type=\"a{sv}\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"GetConnectionSELinuxSecurityContext\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " <arg type=\"ay\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"GetConnectionUnixProcessID\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " <arg type=\"u\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"GetConnectionUnixUser\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " <arg type=\"u\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"GetId\">\n" - " <arg type=\"s\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"GetNameOwner\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " <arg type=\"s\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"Hello\">\n" - " <arg type=\"s\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"ListActivatableNames\">\n" - " <arg type=\"as\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"ListNames\">\n" - " <arg type=\"as\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"ListQueuedOwners\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " <arg type=\"as\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"NameHasOwner\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " <arg type=\"b\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"ReleaseName\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " <arg type=\"u\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"ReloadConfig\">\n" - " </method>\n" - " <method name=\"RequestName\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " <arg type=\"u\" direction=\"in\"/>\n" - " <arg type=\"u\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"StartServiceByName\">\n" - " <arg type=\"s\" direction=\"in\"/>\n" - " <arg type=\"u\" direction=\"in\"/>\n" - " <arg type=\"u\" direction=\"out\"/>\n" - " </method>\n" - " <method name=\"UpdateActivationEnvironment\">\n" - " <arg type=\"a{ss}\" direction=\"in\"/>\n" - " </method>\n" - " <signal name=\"NameAcquired\">\n" - " <arg type=\"s\"/>\n" - " </signal>\n" - " <signal name=\"NameLost\">\n" - " <arg type=\"s\"/>\n" - " </signal>\n" - " <signal name=\"NameOwnerChanged\">\n" - " <arg type=\"s\"/>\n" - " <arg type=\"s\"/>\n" - " <arg type=\"s\"/>\n" - " </signal>\n" - " </interface>\n" - "</node>\n"); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) { - const char *match; - - if (!sd_bus_message_has_signature(m, "s")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_read(m, "s", &match); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_add_match(a, NULL, match, NULL, NULL); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, NULL); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) { - const char *match; - - if (!sd_bus_message_has_signature(m, "s")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_read(m, "s", &match); - if (r < 0) - return synthetic_reply_method_errno(m, r, 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); - - return synthetic_reply_method_return(m, NULL); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionCredentials")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - - if (!sd_bus_message_has_signature(m, "s")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = get_creds_by_message(a, m, SD_BUS_CREDS_PID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error); - if (r < 0) - return synthetic_reply_method_errno(m, r, &error); - - r = sd_bus_message_new_method_return(m, &reply); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_open_container(reply, 'a', "{sv}"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - /* Due to i.e. namespace translations some data might be missing */ - - if (creds->mask & SD_BUS_CREDS_PID) { - r = sd_bus_message_append(reply, "{sv}", "ProcessID", "u", (uint32_t) creds->pid); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - } - - if (creds->mask & SD_BUS_CREDS_EUID) { - r = sd_bus_message_append(reply, "{sv}", "UnixUserID", "u", (uint32_t) creds->euid); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - } - - if (creds->mask & SD_BUS_CREDS_SELINUX_CONTEXT) { - r = sd_bus_message_open_container(reply, 'e', "sv"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_append(reply, "s", "LinuxSecurityLabel"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_open_container(reply, 'v', "ay"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label)); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_close_container(reply); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_close_container(reply); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - } - - r = sd_bus_message_close_container(reply); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_driver_send(m->bus, reply); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - - if (!sd_bus_message_has_signature(m, "s")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error); - if (r < 0) - return synthetic_reply_method_errno(m, r, &error); - - if (!(creds->mask & SD_BUS_CREDS_SELINUX_CONTEXT)) - return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL); - - return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label)); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - - if (!sd_bus_message_has_signature(m, "s")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error); - if (r < 0) - return synthetic_reply_method_errno(m, r, &error); - - if (!(creds->mask & SD_BUS_CREDS_PID)) - return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL); - - return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - - if (!sd_bus_message_has_signature(m, "s")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = get_creds_by_message(a, m, SD_BUS_CREDS_EUID, &creds, &error); - if (r < 0) - return synthetic_reply_method_errno(m, r, &error); - - if (!(creds->mask & SD_BUS_CREDS_EUID)) - return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL); - - return synthetic_reply_method_return(m, "u", (uint32_t) creds->euid); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) { - sd_id128_t server_id; - char buf[SD_ID128_STRING_MAX]; - - if (!sd_bus_message_has_signature(m, "")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_get_bus_id(a, &server_id); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf)); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) { - const char *name; - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - - if (!sd_bus_message_has_signature(m, "s")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_read(m, "s", &name); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (streq(name, "org.freedesktop.DBus")) - return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus"); - - r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error); - if (r < 0) - return synthetic_reply_method_errno(m, r, &error); - - if (!(creds->mask & SD_BUS_CREDS_UNIQUE_NAME)) - return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL); - - return synthetic_reply_method_return(m, "s", creds->unique_name); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) { - _cleanup_strv_free_ char **names = NULL; - - if (!sd_bus_message_has_signature(m, "")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_list_names(a, NULL, &names); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - /* Let's sort the names list to make it stable */ - strv_sort(names); - - return synthetic_reply_method_return_strv(m, names); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) { - _cleanup_strv_free_ char **names = NULL; - - if (!sd_bus_message_has_signature(m, "")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_list_names(a, &names, NULL); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = strv_extend(&names, "org.freedesktop.DBus"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - /* Let's sort the names list to make it stable */ - strv_sort(names); - - return synthetic_reply_method_return_strv(m, names); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) { - struct kdbus_cmd_list cmd = { - .flags = KDBUS_LIST_QUEUED, - .size = sizeof(cmd), - }; - struct kdbus_info *name_list, *name; - _cleanup_strv_free_ char **owners = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - char *arg0; - int err = 0; - - if (!sd_bus_message_has_signature(m, "s")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_read(m, "s", &arg0); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_get_name_creds(a, arg0, 0, NULL); - if (r == -ESRCH || r == -ENXIO) { - sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0); - return synthetic_reply_method_errno(m, r, &error); - } - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = ioctl(a->input_fd, KDBUS_CMD_LIST, &cmd); - if (r < 0) - return synthetic_reply_method_errno(m, -errno, NULL); - - name_list = (struct kdbus_info *) ((uint8_t *) a->kdbus_buffer + cmd.offset); - - KDBUS_FOREACH(name, name_list, cmd.list_size) { - const char *entry_name = NULL; - struct kdbus_item *item; - char *n; - - KDBUS_ITEM_FOREACH(item, name, items) - if (item->type == KDBUS_ITEM_OWNED_NAME) - entry_name = item->name.name; - - if (!streq_ptr(entry_name, arg0)) - continue; - - if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) { - err = -ENOMEM; - break; - } - - r = strv_consume(&owners, n); - if (r < 0) { - err = r; - break; - } - } - - r = bus_kernel_cmd_free(a, cmd.offset); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (err < 0) - return synthetic_reply_method_errno(m, err, NULL); - - return synthetic_reply_method_return_strv(m, owners); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) { - const char *name; - - if (!sd_bus_message_has_signature(m, "s")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_read(m, "s", &name); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (streq(name, "org.freedesktop.DBus")) - return synthetic_reply_method_return(m, "b", true); - - r = sd_bus_get_name_creds(a, name, 0, NULL); - if (r < 0 && r != -ESRCH && r != -ENXIO) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, "b", r >= 0); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) { - const char *name; - - if (!sd_bus_message_has_signature(m, "s")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_read(m, "s", &name); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_release_name(a, name); - if (r < 0) { - if (r == -ESRCH) - return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT); - if (r == -EADDRINUSE) - return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER); - - return synthetic_reply_method_errno(m, r, NULL); - } - - set_remove(owned_names, (char*) name); - - return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) { - if (!sd_bus_message_has_signature(m, "")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = shared_policy_reload(sp); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, NULL); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) { - const char *name; - uint32_t flags, param; - bool in_queue; - - if (!sd_bus_message_has_signature(m, "su")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_read(m, "su", &name, &flags); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (sp) { - Policy *policy; - bool denied; - - policy = shared_policy_acquire(sp); - denied = !policy_check_own(policy, ucred->uid, ucred->gid, name); - shared_policy_release(sp, policy); - if (denied) - return synthetic_reply_method_errno(m, -EPERM, 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); - - param = 0; - if (flags & BUS_NAME_ALLOW_REPLACEMENT) - param |= SD_BUS_NAME_ALLOW_REPLACEMENT; - if (flags & BUS_NAME_REPLACE_EXISTING) - param |= SD_BUS_NAME_REPLACE_EXISTING; - if (!(flags & BUS_NAME_DO_NOT_QUEUE)) - param |= SD_BUS_NAME_QUEUE; - - r = set_put_strdup(owned_names, name); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_request_name(a, name, param); - if (r < 0) { - if (r == -EALREADY) - return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER); - - set_remove(owned_names, (char*) name); - - if (r == -EEXIST) - return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS); - return synthetic_reply_method_errno(m, r, NULL); - } - - in_queue = (r == 0); - - if (in_queue) - return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE); - - return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) { - _cleanup_bus_message_unref_ sd_bus_message *msg = NULL; - const char *name; - uint32_t flags; - - if (!sd_bus_message_has_signature(m, "su")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_read(m, "su", &name, &flags); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (flags != 0) - return synthetic_reply_method_errno(m, -EINVAL, NULL); - - r = sd_bus_get_name_creds(a, name, 0, NULL); - if (r >= 0 || streq(name, "org.freedesktop.DBus")) - return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING); - if (r != -ESRCH) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_new_method_call( - a, - &msg, - name, - "/", - "org.freedesktop.DBus.Peer", - "Ping"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_send(a, msg, NULL); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) { - _cleanup_bus_message_unref_ sd_bus_message *msg = NULL; - _cleanup_strv_free_ char **args = NULL; - - if (!sd_bus_message_has_signature(m, "a{ss}")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) { - _cleanup_free_ char *s = NULL; - const char *key; - const char *value; - - r = sd_bus_message_read(m, "ss", &key, &value); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - s = strjoin(key, "=", value, NULL); - if (!s) - return synthetic_reply_method_errno(m, -ENOMEM, NULL); - - r = strv_extend(&args, s); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_exit_container(m); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - } - - r = sd_bus_message_exit_container(m); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (!args) - return synthetic_reply_method_errno(m, -EINVAL, NULL); - - r = sd_bus_message_new_method_call( - a, - &msg, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "SetEnvironment"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_append_strv(msg, args); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_call(a, msg, 0, NULL, NULL); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, NULL); - - } else { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - - r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member); - - return synthetic_reply_method_errno(m, r, &error); - } -} diff --git a/src/bus-proxyd/driver.h b/src/bus-proxyd/driver.h deleted file mode 100644 index b8cedf5ce5..0000000000 --- a/src/bus-proxyd/driver.h +++ /dev/null @@ -1,27 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 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-xml-policy.h" - -int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names); diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c deleted file mode 100644 index c689618853..0000000000 --- a/src/bus-proxyd/proxy.c +++ /dev/null @@ -1,854 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Daniel Mack - Copyright 2014 Kay Sievers - Copyright 2014 David Herrmann - - 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 <sys/socket.h> -#include <sys/types.h> -#include <string.h> -#include <errno.h> -#include <poll.h> - -#include "log.h" -#include "util.h" -#include "sd-daemon.h" -#include "sd-bus.h" -#include "bus-internal.h" -#include "bus-message.h" -#include "bus-util.h" -#include "strv.h" -#include "bus-control.h" -#include "set.h" -#include "bus-xml-policy.h" -#include "driver.h" -#include "proxy.h" -#include "synthesize.h" - -static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) { - _cleanup_bus_close_unref_ sd_bus *b = NULL; - int r; - - r = sd_bus_new(&b); - if (r < 0) - return log_error_errno(r, "Failed to allocate bus: %m"); - - r = sd_bus_set_description(b, "sd-proxy"); - if (r < 0) - return log_error_errno(r, "Failed to set bus name: %m"); - - r = sd_bus_set_address(b, destination); - if (r < 0) - return log_error_errno(r, "Failed to set address to connect to: %m"); - - r = sd_bus_negotiate_fds(b, negotiate_fds); - if (r < 0) - return log_error_errno(r, "Failed to set FD negotiation: %m"); - - r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT); - if (r < 0) - return log_error_errno(r, "Failed to set credential negotiation: %m"); - - if (p->local_creds.pid > 0) { - b->fake_pids.pid = p->local_creds.pid; - b->fake_pids_valid = true; - - b->fake_creds.uid = UID_INVALID; - b->fake_creds.euid = p->local_creds.uid; - b->fake_creds.suid = UID_INVALID; - b->fake_creds.fsuid = UID_INVALID; - b->fake_creds.gid = GID_INVALID; - b->fake_creds.egid = p->local_creds.gid; - b->fake_creds.sgid = GID_INVALID; - b->fake_creds.fsgid = GID_INVALID; - b->fake_creds_valid = true; - } - - if (local_sec) { - b->fake_label = strdup(local_sec); - if (!b->fake_label) - return log_oom(); - } - - b->manual_peer_interface = true; - - r = sd_bus_start(b); - if (r < 0) - return log_error_errno(r, "Failed to start bus client: %m"); - - p->destination_bus = b; - b = NULL; - return 0; -} - -static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) { - _cleanup_bus_close_unref_ sd_bus *b = NULL; - sd_id128_t server_id; - int r; - - r = sd_bus_new(&b); - if (r < 0) - return log_error_errno(r, "Failed to allocate bus: %m"); - - r = sd_bus_set_fd(b, in_fd, out_fd); - if (r < 0) - return log_error_errno(r, "Failed to set fds: %m"); - - r = sd_bus_get_bus_id(p->destination_bus, &server_id); - if (r < 0) - return log_error_errno(r, "Failed to get server ID: %m"); - - r = sd_bus_set_server(b, 1, server_id); - if (r < 0) - return log_error_errno(r, "Failed to set server mode: %m"); - - r = sd_bus_negotiate_fds(b, negotiate_fds); - if (r < 0) - return log_error_errno(r, "Failed to set FD negotiation: %m"); - - r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT); - if (r < 0) - return log_error_errno(r, "Failed to set credential negotiation: %m"); - - r = sd_bus_set_anonymous(b, true); - if (r < 0) - return log_error_errno(r, "Failed to set anonymous authentication: %m"); - - b->manual_peer_interface = true; - - r = sd_bus_start(b); - if (r < 0) - return log_error_errno(r, "Failed to start bus client: %m"); - - p->local_bus = b; - b = NULL; - return 0; -} - -static int proxy_prepare_matches(Proxy *p) { - _cleanup_free_ char *match = NULL; - const char *unique; - int r; - - if (!p->destination_bus->is_kernel) - return 0; - - r = sd_bus_get_unique_name(p->destination_bus, &unique); - if (r < 0) - return log_error_errno(r, "Failed to get unique name: %m"); - - match = strjoin("type='signal'," - "sender='org.freedesktop.DBus'," - "path='/org/freedesktop/DBus'," - "interface='org.freedesktop.DBus'," - "member='NameOwnerChanged'," - "arg1='", - unique, - "'", - NULL); - if (!match) - return log_oom(); - - r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL); - if (r < 0) - return log_error_errno(r, "Failed to add match for NameLost: %m"); - - free(match); - match = strjoin("type='signal'," - "sender='org.freedesktop.DBus'," - "path='/org/freedesktop/DBus'," - "interface='org.freedesktop.DBus'," - "member='NameOwnerChanged'," - "arg2='", - unique, - "'", - NULL); - if (!match) - return log_oom(); - - r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL); - if (r < 0) - return log_error_errno(r, "Failed to add match for NameAcquired: %m"); - - return 0; -} - -int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) { - _cleanup_(proxy_freep) Proxy *p = NULL; - _cleanup_free_ char *local_sec = NULL; - bool is_unix; - int r; - - p = new0(Proxy, 1); - if (!p) - return log_oom(); - - p->local_in = in_fd; - p->local_out = out_fd; - - p->owned_names = set_new(&string_hash_ops); - if (!p->owned_names) - return log_oom(); - - is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 && - sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; - - if (is_unix) { - (void) getpeercred(in_fd, &p->local_creds); - (void) getpeersec(in_fd, &local_sec); - } - - r = proxy_create_destination(p, destination, local_sec, is_unix); - if (r < 0) - return r; - - r = proxy_create_local(p, in_fd, out_fd, is_unix); - if (r < 0) - return r; - - r = proxy_prepare_matches(p); - if (r < 0) - return r; - - *out = p; - p = NULL; - return 0; -} - -Proxy *proxy_free(Proxy *p) { - if (!p) - return NULL; - - sd_bus_close_unrefp(&p->local_bus); - sd_bus_close_unrefp(&p->destination_bus); - set_free_free(p->owned_names); - free(p); - - return NULL; -} - -int proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) { - _cleanup_strv_free_ char **strv = NULL; - Policy *policy; - int r; - - assert(p); - assert(sp); - - /* no need to load legacy policy if destination is not kdbus */ - if (!p->destination_bus->is_kernel) - return 0; - - p->policy = sp; - - policy = shared_policy_acquire(sp); - if (policy) { - /* policy already pre-loaded */ - shared_policy_release(sp, policy); - return 0; - } - - if (!configuration) { - const char *scope; - - r = sd_bus_get_scope(p->destination_bus, &scope); - if (r < 0) - return log_error_errno(r, "Couldn't determine bus scope: %m"); - - if (streq(scope, "system")) - strv = strv_new("/etc/dbus-1/system.conf", - "/etc/dbus-1/system.d/", - "/etc/dbus-1/system-local.conf", - NULL); - else if (streq(scope, "user")) - strv = strv_new("/etc/dbus-1/session.conf", - "/etc/dbus-1/session.d/", - "/etc/dbus-1/session-local.conf", - NULL); - else - return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope); - - if (!strv) - return log_oom(); - - configuration = strv; - } - - return shared_policy_preload(sp, configuration); -} - -int proxy_hello_policy(Proxy *p, uid_t original_uid) { - Policy *policy; - int r = 0; - - assert(p); - - if (!p->policy) - return 0; - - policy = shared_policy_acquire(p->policy); - - if (p->local_creds.uid == original_uid) - log_debug("Permitting access, since bus owner matches bus client."); - else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid)) - log_debug("Permitting access due to XML policy."); - else - r = log_error_errno(EPERM, "Policy denied connection."); - - shared_policy_release(p->policy, policy); - - return r; -} - -static int proxy_wait(Proxy *p) { - uint64_t timeout_destination, timeout_local, t; - int events_destination, events_local, fd; - struct timespec _ts, *ts; - struct pollfd *pollfd; - int r; - - assert(p); - - fd = sd_bus_get_fd(p->destination_bus); - if (fd < 0) - return log_error_errno(fd, "Failed to get fd: %m"); - - events_destination = sd_bus_get_events(p->destination_bus); - if (events_destination < 0) - return log_error_errno(events_destination, "Failed to get events mask: %m"); - - r = sd_bus_get_timeout(p->destination_bus, &timeout_destination); - if (r < 0) - return log_error_errno(r, "Failed to get timeout: %m"); - - events_local = sd_bus_get_events(p->local_bus); - if (events_local < 0) - return log_error_errno(events_local, "Failed to get events mask: %m"); - - r = sd_bus_get_timeout(p->local_bus, &timeout_local); - if (r < 0) - return log_error_errno(r, "Failed to get timeout: %m"); - - t = timeout_destination; - if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination)) - t = timeout_local; - - if (t == (uint64_t) -1) - ts = NULL; - else { - usec_t nw; - - nw = now(CLOCK_MONOTONIC); - if (t > nw) - t -= nw; - else - t = 0; - - ts = timespec_store(&_ts, t); - } - - pollfd = (struct pollfd[3]) { - { .fd = fd, .events = events_destination, }, - { .fd = p->local_in, .events = events_local & POLLIN, }, - { .fd = p->local_out, .events = events_local & POLLOUT, }, - }; - - r = ppoll(pollfd, 3, ts, NULL); - if (r < 0) - return log_error_errno(errno, "ppoll() failed: %m"); - - return 0; -} - -static int handle_policy_error(sd_bus_message *m, int r) { - if (r == -ESRCH || r == -ENXIO) - return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination); - - return r; -} - -static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) { - int r; - - assert(from); - assert(to); - assert(m); - - if (!policy) - return 0; - - /* - * dbus-1 distinguishes expected and non-expected replies by tracking - * method-calls and timeouts. By default, DENY rules are *NEVER* applied - * on expected replies, unless explicitly specified. But we dont track - * method-calls, thus, we cannot know whether a reply is expected. - * Fortunately, the kdbus forbids non-expected replies, so we can safely - * ignore any policy on those and let the kernel deal with it. - * - * TODO: To be correct, we should only ignore policy-tags that are - * applied on non-expected replies. However, so far we don't parse those - * tags so we let everything pass. I haven't seen a DENY policy tag on - * expected-replies, ever, so don't bother.. - */ - if (m->reply_cookie > 0) - return 0; - - if (from->is_kernel) { - uid_t sender_uid = UID_INVALID; - gid_t sender_gid = GID_INVALID; - char **sender_names = NULL; - - /* Driver messages are always OK */ - if (streq_ptr(m->sender, "org.freedesktop.DBus")) - return 0; - - /* The message came from the kernel, and is sent to our legacy client. */ - (void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names); - - (void) sd_bus_creds_get_euid(&m->creds, &sender_uid); - (void) sd_bus_creds_get_egid(&m->creds, &sender_gid); - - if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) { - _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL; - - /* If the message came from another legacy - * client, then the message creds will be - * missing, simply because on legacy clients - * per-message creds were unknown. In this - * case, query the creds of the peer - * instead. */ - - r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds); - if (r < 0) - return handle_policy_error(m, r); - - (void) sd_bus_creds_get_euid(sender_creds, &sender_uid); - (void) sd_bus_creds_get_egid(sender_creds, &sender_gid); - } - - /* First check whether the sender can send the message to our name */ - if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) && - policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false)) - return 0; - - /* Return an error back to the caller */ - if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) - return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy."); - - /* Return 1, indicating that the message shall not be processed any further */ - return 1; - } - - if (to->is_kernel) { - _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL; - uid_t destination_uid = UID_INVALID; - gid_t destination_gid = GID_INVALID; - const char *destination_unique = NULL; - char **destination_names = NULL; - char *n; - - /* Driver messages are always OK */ - if (streq_ptr(m->destination, "org.freedesktop.DBus")) - return 0; - - /* The message came from the legacy client, and is sent to kdbus. */ - if (m->destination) { - r = bus_get_name_creds_kdbus(to, m->destination, - SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME| - SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID, - true, &destination_creds); - if (r < 0) - return handle_policy_error(m, r); - - r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique); - if (r < 0) - return handle_policy_error(m, r); - - (void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names); - - (void) sd_bus_creds_get_euid(destination_creds, &destination_uid); - (void) sd_bus_creds_get_egid(destination_creds, &destination_gid); - } - - /* First check if we (the sender) can send to this name */ - if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, destination_names, m->path, m->interface, m->member, true, &n)) { - if (n) { - /* If we made a receiver decision, then remember which - * name's policy we used, and to which unique ID it - * mapped when we made the decision. Then, let's pass - * this to the kernel when sending the message, so that - * it refuses the operation should the name and unique - * ID not map to each other anymore. */ - - r = free_and_strdup(&m->destination_ptr, n); - if (r < 0) - return r; - - r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id); - if (r < 0) - return r; - } - - if (sd_bus_message_is_signal(m, NULL, NULL)) { - /* If we forward a signal from dbus-1 to kdbus, - * we have no idea who the recipient is. - * Therefore, we cannot apply any dbus-1 - * receiver policies that match on receiver - * credentials. We know sd-bus always sets - * KDBUS_MSG_SIGNAL, so the kernel applies - * receiver policies to the message. Therefore, - * skip policy checks in this case. */ - return 0; - } else if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true)) { - return 0; - } - } - - /* Return an error back to the caller */ - if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) - return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy."); - - /* Return 1, indicating that the message shall not be processed any further */ - return 1; - } - - return 0; -} - -static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) { - Policy *policy; - int r; - - assert(sp); - - policy = shared_policy_acquire(sp); - r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names); - shared_policy_release(sp, policy); - - return r; -} - -static int process_hello(Proxy *p, sd_bus_message *m) { - _cleanup_bus_message_unref_ sd_bus_message *n = NULL; - bool is_hello; - int r; - - assert(p); - assert(m); - - /* As reaction to hello we need to respond with two messages: - * the callback reply and the NameAcquired for the unique - * name, since hello is otherwise obsolete on kdbus. */ - - is_hello = - sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") && - streq_ptr(m->destination, "org.freedesktop.DBus"); - - if (!is_hello) { - if (p->got_hello) - return 0; - - return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member); - } - - if (p->got_hello) - return log_error_errno(EIO, "Got duplicate hello, aborting."); - - p->got_hello = true; - - if (!p->destination_bus->is_kernel) - return 0; - - r = sd_bus_message_new_method_return(m, &n); - if (r < 0) - return log_error_errno(r, "Failed to generate HELLO reply: %m"); - - r = sd_bus_message_append(n, "s", p->destination_bus->unique_name); - if (r < 0) - return log_error_errno(r, "Failed to append unique name to HELLO reply: %m"); - - r = bus_message_append_sender(n, "org.freedesktop.DBus"); - if (r < 0) - return log_error_errno(r, "Failed to append sender to HELLO reply: %m"); - - r = bus_seal_synthetic_message(p->local_bus, n); - if (r < 0) - return log_error_errno(r, "Failed to seal HELLO reply: %m"); - - r = sd_bus_send(p->local_bus, n, NULL); - if (r < 0) - return log_error_errno(r, "Failed to send HELLO reply: %m"); - - n = sd_bus_message_unref(n); - r = sd_bus_message_new_signal( - p->local_bus, - &n, - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "NameAcquired"); - if (r < 0) - return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m"); - - r = sd_bus_message_append(n, "s", p->destination_bus->unique_name); - if (r < 0) - return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m"); - - r = bus_message_append_sender(n, "org.freedesktop.DBus"); - if (r < 0) - return log_error_errno(r, "Failed to append sender to NameAcquired message: %m"); - - r = bus_seal_synthetic_message(p->local_bus, n); - if (r < 0) - return log_error_errno(r, "Failed to seal NameAcquired message: %m"); - - r = sd_bus_send(p->local_bus, n, NULL); - if (r < 0) - return log_error_errno(r, "Failed to send NameAcquired message: %m"); - - return 1; -} - -static int patch_sender(sd_bus *a, sd_bus_message *m) { - char **well_known = NULL; - sd_bus_creds *c; - int r; - - assert(a); - assert(m); - - if (!a->is_kernel) - return 0; - - /* We will change the sender of messages from the bus driver - * so that they originate from the bus driver. This is a - * speciality originating from dbus1, where the bus driver did - * not have a unique id, but only the well-known name. */ - - c = sd_bus_message_get_creds(m); - if (!c) - return 0; - - r = sd_bus_creds_get_well_known_names(c, &well_known); - if (r < 0) - return r; - - if (strv_contains(well_known, "org.freedesktop.DBus")) - m->sender = "org.freedesktop.DBus"; - - return 0; -} - -static int proxy_process_destination_to_local(Proxy *p) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - int r; - - assert(p); - - r = sd_bus_process(p->destination_bus, &m); - if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */ - return r; - if (r < 0) { - log_error_errno(r, "Failed to process destination bus: %m"); - return r; - } - if (r == 0) - return 0; - if (!m) - return 1; - - /* We officially got EOF, let's quit */ - if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) - return -ECONNRESET; - - r = synthesize_name_acquired(p->destination_bus, p->local_bus, m); - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - if (r < 0) - return log_error_errno(r, "Failed to synthesize message: %m"); - - patch_sender(p->destination_bus, m); - - if (p->policy) { - r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names); - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - if (r < 0) - return log_error_errno(r, "Failed to process policy: %m"); - if (r > 0) - return 1; - } - - r = sd_bus_send(p->local_bus, m, NULL); - if (r < 0) { - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - - /* If the peer tries to send a reply and it is - * rejected with EPERM by the kernel, we ignore the - * error. This catches cases where the original - * method-call didn't had EXPECT_REPLY set, but the - * proxy-peer still sends a reply. This is allowed in - * dbus1, but not in kdbus. We don't want to track - * reply-windows in the proxy, so we simply ignore - * EPERM for all replies. The only downside is, that - * callers are no longer notified if their replies are - * dropped. However, this is equivalent to the - * caller's timeout to expire, so this should be - * acceptable. Nobody sane sends replies without a - * matching method-call, so nobody should care. */ - if (r == -EPERM && m->reply_cookie > 0) - return 1; - - /* Return the error to the client, if we can */ - synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m"); - if (r == -ENOBUFS) { - /* if local dbus1 peer does not dispatch its queue, warn only once */ - if (!p->queue_overflow) - log_error("Dropped messages due to queue overflow of local peer (pid: "PID_FMT" uid: "UID_FMT")", p->local_creds.pid, p->local_creds.uid); - p->queue_overflow = true; - } else - log_error_errno(r, - "Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m", - p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type), - strna(m->destination), strna(m->path), strna(m->interface), strna(m->member)); - - return 1; - } - - p->queue_overflow = false; - return 1; -} - -static int proxy_process_local_to_destination(Proxy *p) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - int r; - - assert(p); - - r = sd_bus_process(p->local_bus, &m); - if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */ - return r; - if (r < 0) { - log_error_errno(r, "Failed to process local bus: %m"); - return r; - } - if (r == 0) - return 0; - if (!m) - return 1; - - /* We officially got EOF, let's quit */ - if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) - return -ECONNRESET; - - r = process_hello(p, m); - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - if (r < 0) - return log_error_errno(r, "Failed to process HELLO: %m"); - if (r > 0) - return 1; - - r = bus_proxy_process_driver(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names); - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - if (r < 0) - return log_error_errno(r, "Failed to process driver calls: %m"); - if (r > 0) - return 1; - - for (;;) { - if (p->policy) { - r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names); - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - if (r < 0) - return log_error_errno(r, "Failed to process policy: %m"); - if (r > 0) - return 1; - } - - r = sd_bus_send(p->destination_bus, m, NULL); - if (r < 0) { - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - - /* The name database changed since the policy check, hence let's check again */ - if (r == -EREMCHG) - continue; - - /* see above why EPERM is ignored for replies */ - if (r == -EPERM && m->reply_cookie > 0) - return 1; - - synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m"); - log_error_errno(r, - "Failed to forward message we got from local: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m", - p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type), - strna(m->destination), strna(m->path), strna(m->interface), strna(m->member)); - return 1; - } - - break; - } - - return 1; -} - -int proxy_run(Proxy *p) { - int r; - - assert(p); - - for (;;) { - bool busy = false; - - if (p->got_hello) { - /* Read messages from bus, to pass them on to our client */ - r = proxy_process_destination_to_local(p); - if (r == -ECONNRESET || r == -ENOTCONN) - return 0; - if (r < 0) - return r; - if (r > 0) - busy = true; - } - - /* Read messages from our client, to pass them on to the bus */ - r = proxy_process_local_to_destination(p); - if (r == -ECONNRESET || r == -ENOTCONN) - return 0; - if (r < 0) - return r; - if (r > 0) - busy = true; - - if (!busy) { - r = proxy_wait(p); - if (r == -ECONNRESET || r == -ENOTCONN) - return 0; - if (r < 0) - return r; - } - } - - return 0; -} diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h deleted file mode 100644 index ff278a2465..0000000000 --- a/src/bus-proxyd/proxy.h +++ /dev/null @@ -1,51 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann - - 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-xml-policy.h" - -typedef struct Proxy Proxy; - -struct Proxy { - sd_bus *local_bus; - struct ucred local_creds; - int local_in; - int local_out; - - sd_bus *destination_bus; - - Set *owned_names; - SharedPolicy *policy; - - bool got_hello : 1; - bool queue_overflow : 1; -}; - -int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest); -Proxy *proxy_free(Proxy *p); - -int proxy_set_policy(Proxy *p, SharedPolicy *policy, char **configuration); -int proxy_hello_policy(Proxy *p, uid_t original_uid); -int proxy_run(Proxy *p); - -DEFINE_TRIVIAL_CLEANUP_FUNC(Proxy*, proxy_free); diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c deleted file mode 100644 index 35e69a5c01..0000000000 --- a/src/bus-proxyd/stdio-bridge.c +++ /dev/null @@ -1,249 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Daniel Mack - Copyright 2014 Kay Sievers - - 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 <unistd.h> -#include <string.h> -#include <errno.h> -#include <stddef.h> -#include <getopt.h> - -#include "log.h" -#include "util.h" -#include "sd-daemon.h" -#include "sd-bus.h" -#include "bus-internal.h" -#include "bus-util.h" -#include "build.h" -#include "strv.h" -#include "def.h" -#include "proxy.h" - -static char *arg_address = NULL; -static char *arg_command_line_buffer = NULL; - -static int help(void) { - - printf("%s [OPTIONS...]\n\n" - "Connect STDIO to a given bus address.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --machine=MACHINE Connect to specified machine\n" - " --address=ADDRESS Connect to the bus specified by ADDRESS\n" - " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_ADDRESS, - ARG_MACHINE, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "address", required_argument, NULL, ARG_ADDRESS }, - { "machine", required_argument, NULL, ARG_MACHINE }, - {}, - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; - - case ARG_ADDRESS: { - char *a; - - a = strdup(optarg); - if (!a) - return log_oom(); - - free(arg_address); - arg_address = a; - 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-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL); -#else - a = strjoin("x-machine-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 && !in_charset(arg_command_line_buffer, "x"))) { - log_error("Too many arguments"); - return -EINVAL; - } - - if (!arg_address) { - arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS); - if (!arg_address) - return log_oom(); - } - - return 1; -} - -static int rename_service(sd_bus *a, sd_bus *b) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_free_ char *p = NULL, *name = NULL; - const char *comm; - char **cmdline; - uid_t uid; - pid_t pid; - int r; - - assert(a); - assert(b); - - r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds); - if (r < 0) - return r; - - r = sd_bus_creds_get_euid(creds, &uid); - if (r < 0) - return r; - - r = sd_bus_creds_get_pid(creds, &pid); - if (r < 0) - return r; - - r = sd_bus_creds_get_cmdline(creds, &cmdline); - if (r < 0) - return r; - - r = sd_bus_creds_get_comm(creds, &comm); - if (r < 0) - return r; - - name = uid_to_name(uid); - if (!name) - return -ENOMEM; - - p = strv_join(cmdline, " "); - if (!p) - return -ENOMEM; - - /* The status string gets the full command line ... */ - sd_notifyf(false, - "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)", - pid, p, - uid, name); - - /* ... and the argv line only the short comm */ - if (arg_command_line_buffer) { - size_t m, w; - - m = strlen(arg_command_line_buffer); - w = snprintf(arg_command_line_buffer, m, - "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]", - pid, comm, - uid, name); - - if (m > w) - memzero(arg_command_line_buffer + w, m - w); - } - - log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s", - pid, p, - uid, name, - a->unique_name); - - return 0; -} - -int main(int argc, char *argv[]) { - _cleanup_(proxy_freep) Proxy *p = NULL; - int r; - - log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); - log_parse_environment(); - log_open(); - - r = parse_argv(argc, argv); - if (r <= 0) - goto finish; - - r = proxy_new(&p, STDIN_FILENO, STDOUT_FILENO, arg_address); - if (r < 0) - goto finish; - - r = rename_service(p->destination_bus, p->local_bus); - if (r < 0) - log_debug_errno(r, "Failed to rename process: %m"); - - r = proxy_run(p); - -finish: - sd_notify(false, - "STOPPING=1\n" - "STATUS=Shutting down."); - - free(arg_address); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c deleted file mode 100644 index 67bcc7a242..0000000000 --- a/src/bus-proxyd/synthesize.c +++ /dev/null @@ -1,220 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Daniel Mack - Copyright 2014 Kay Sievers - - 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 <stddef.h> - -#include "util.h" -#include "sd-bus.h" -#include "bus-internal.h" -#include "bus-message.h" -#include "bus-util.h" -#include "synthesize.h" - -int synthetic_driver_send(sd_bus *b, sd_bus_message *m) { - int r; - - assert(b); - assert(m); - - r = bus_message_append_sender(m, "org.freedesktop.DBus"); - if (r < 0) - return r; - - r = bus_seal_synthetic_message(b, m); - if (r < 0) - return r; - - return sd_bus_send(b, m, NULL); -} - -int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - int r; - - assert(call); - - if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - return 0; - - r = sd_bus_message_new_method_error(call, &m, e); - if (r < 0) - return r; - - return synthetic_driver_send(call->bus, m); -} - -int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - va_list ap; - - va_start(ap, format); - bus_error_setfv(&error, name, format, ap); - va_end(ap); - - return synthetic_reply_method_error(call, &error); -} - -int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; - - assert(call); - - if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - return 0; - - if (sd_bus_error_is_set(p)) - return synthetic_reply_method_error(call, p); - - sd_bus_error_set_errno(&berror, error); - - return synthetic_reply_method_error(call, &berror); -} - -int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; - va_list ap; - - assert(call); - - if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - return 0; - - va_start(ap, format); - sd_bus_error_set_errnofv(&berror, error, format, ap); - va_end(ap); - - return synthetic_reply_method_error(call, &berror); -} - -int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - int r; - - assert(call); - - if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - return 0; - - r = sd_bus_message_new_method_return(call, &m); - if (r < 0) - return r; - - if (!isempty(types)) { - va_list ap; - - va_start(ap, types); - r = bus_message_append_ap(m, types, ap); - va_end(ap); - if (r < 0) - return r; - } - - return synthetic_driver_send(call->bus, m); -} - -int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - int r; - - assert(call); - - if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - return 0; - - r = sd_bus_message_new_method_return(call, &m); - if (r < 0) - return synthetic_reply_method_errno(call, r, NULL); - - r = sd_bus_message_append_strv(m, l); - if (r < 0) - return synthetic_reply_method_errno(call, r, NULL); - - return synthetic_driver_send(call->bus, m); -} - -int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) { - _cleanup_bus_message_unref_ sd_bus_message *n = NULL; - const char *name, *old_owner, *new_owner; - int r; - - assert(a); - assert(b); - assert(m); - - /* If we get NameOwnerChanged for our own name, we need to - * synthesize NameLost/NameAcquired, since socket clients need - * that, even though it is obsoleted on kdbus */ - - if (!a->is_kernel) - return 0; - - if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") || - !streq_ptr(m->path, "/org/freedesktop/DBus") || - !streq_ptr(m->sender, "org.freedesktop.DBus")) - return 0; - - r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner); - if (r < 0) - return r; - - r = sd_bus_message_rewind(m, true); - if (r < 0) - return r; - - if (streq(old_owner, a->unique_name)) { - - r = sd_bus_message_new_signal( - b, - &n, - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "NameLost"); - - } else if (streq(new_owner, a->unique_name)) { - - r = sd_bus_message_new_signal( - b, - &n, - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "NameAcquired"); - } else - return 0; - - if (r < 0) - return r; - - r = sd_bus_message_append(n, "s", name); - if (r < 0) - return r; - - r = bus_message_append_sender(n, "org.freedesktop.DBus"); - if (r < 0) - return r; - - r = bus_seal_synthetic_message(b, n); - if (r < 0) - return r; - - return sd_bus_send(b, n, NULL); -} diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h deleted file mode 100644 index e850350bc5..0000000000 --- a/src/bus-proxyd/synthesize.h +++ /dev/null @@ -1,36 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 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" - -int synthetic_driver_send(sd_bus *b, sd_bus_message *m); - -int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...); -int synthetic_reply_method_return_strv(sd_bus_message *call, char **l); - -int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e); -int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) _sd_printf_(3, 4); -int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p); -int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) _sd_printf_(3, 4); - -int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m); diff --git a/src/bus-proxyd/test-bus-xml-policy.c b/src/bus-proxyd/test-bus-xml-policy.c deleted file mode 100644 index d19d0e1b60..0000000000 --- a/src/bus-proxyd/test-bus-xml-policy.c +++ /dev/null @@ -1,169 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 Daniel Mack - - 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 <unistd.h> -#include <errno.h> -#include <stddef.h> - -#include "log.h" -#include "util.h" -#include "sd-bus.h" -#include "strv.h" -#include "bus-xml-policy.h" - -static int test_policy_load(Policy *p, const char *name) { - _cleanup_free_ char *path = NULL; - int r = 0; - - path = strjoin(TEST_DIR, "/bus-policy/", name, NULL); - assert_se(path); - - if (access(path, R_OK) == 0) - r = policy_load(p, STRV_MAKE(path)); - else - r = -ENOENT; - - return r; -} - -static int show_policy(const char *fn) { - Policy p = {}; - int r; - - r = policy_load(&p, STRV_MAKE(fn)); - if (r < 0) { - log_error_errno(r, "Failed to load policy %s: %m", fn); - return r; - } - - policy_dump(&p); - policy_free(&p); - - return 0; -} - -int main(int argc, char *argv[]) { - - Policy p = {}; - - printf("Showing session policy BEGIN\n"); - show_policy("/etc/dbus-1/session.conf"); - printf("Showing session policy END\n"); - - printf("Showing system policy BEGIN\n"); - show_policy("/etc/dbus-1/system.conf"); - printf("Showing system policy END\n"); - - /* Ownership tests */ - assert_se(test_policy_load(&p, "ownerships.conf") == 0); - - assert_se(policy_check_own(&p, 0, 0, "org.test.test1") == true); - assert_se(policy_check_own(&p, 1, 0, "org.test.test1") == true); - - assert_se(policy_check_own(&p, 0, 0, "org.test.test2") == true); - assert_se(policy_check_own(&p, 1, 0, "org.test.test2") == false); - - assert_se(policy_check_own(&p, 0, 0, "org.test.test3") == false); - assert_se(policy_check_own(&p, 1, 0, "org.test.test3") == false); - - assert_se(policy_check_own(&p, 0, 0, "org.test.test4") == false); - assert_se(policy_check_own(&p, 1, 0, "org.test.test4") == true); - - policy_free(&p); - - /* Signaltest */ - assert_se(test_policy_load(&p, "signals.conf") == 0); - - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == true); - assert_se(policy_check_one_send(&p, 1, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == false); - - policy_free(&p); - - /* Method calls */ - assert_se(test_policy_load(&p, "methods.conf") == 0); - policy_dump(&p); - - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false); - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false); - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int1", "Member") == true); - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == true); - - assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test3", "/an/object/path", "org.test.int3", "Member111") == true); - - policy_free(&p); - - /* User and groups */ - assert_se(test_policy_load(&p, "hello.conf") == 0); - policy_dump(&p); - - assert_se(policy_check_hello(&p, 0, 0) == true); - assert_se(policy_check_hello(&p, 1, 0) == false); - assert_se(policy_check_hello(&p, 0, 1) == false); - - policy_free(&p); - - /* dbus1 test file: ownership */ - - assert_se(test_policy_load(&p, "check-own-rules.conf") >= 0); - policy_dump(&p); - - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop") == false); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystem") == false); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems") == true); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo") == true); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo.bar") == true); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2") == false); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo") == false); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo.bar") == false); - - policy_free(&p); - - /* dbus1 test file: many rules */ - - assert_se(test_policy_load(&p, "many-rules.conf") >= 0); - policy_dump(&p); - policy_free(&p); - - /* dbus1 test file: generic test */ - - assert_se(test_policy_load(&p, "test.conf") >= 0); - policy_dump(&p); - - assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService") == true); - assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService2") == false); - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false); - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true); - assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true); - assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false); - assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false); - - assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService") == false); - assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService2") == false); - assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false); - assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false); - assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true); - assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false); - assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false); - - policy_free(&p); - - return EXIT_SUCCESS; -} |