summaryrefslogtreecommitdiff
path: root/src/libcore/bus-policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcore/bus-policy.c')
-rw-r--r--src/libcore/bus-policy.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/libcore/bus-policy.c b/src/libcore/bus-policy.c
new file mode 100644
index 0000000000..4907c268e8
--- /dev/null
+++ b/src/libcore/bus-policy.c
@@ -0,0 +1,180 @@
+/***
+ 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 <stdlib.h>
+
+#include "alloc-util.h"
+#include "bus-kernel.h"
+#include "bus-policy.h"
+#include "kdbus.h"
+#include "string-table.h"
+#include "user-util.h"
+#include "util.h"
+
+int bus_kernel_translate_access(BusPolicyAccess access) {
+ assert(access >= 0);
+ assert(access < _BUS_POLICY_ACCESS_MAX);
+
+ switch (access) {
+
+ case BUS_POLICY_ACCESS_SEE:
+ return KDBUS_POLICY_SEE;
+
+ case BUS_POLICY_ACCESS_TALK:
+ return KDBUS_POLICY_TALK;
+
+ case BUS_POLICY_ACCESS_OWN:
+ return KDBUS_POLICY_OWN;
+
+ default:
+ assert_not_reached("Unknown policy access");
+ }
+}
+
+int bus_kernel_translate_policy(const BusNamePolicy *policy, struct kdbus_item *item) {
+ int r;
+
+ assert(policy);
+ assert(item);
+
+ switch (policy->type) {
+
+ case BUSNAME_POLICY_TYPE_USER: {
+ const char *user = policy->name;
+ uid_t uid;
+
+ r = get_user_creds(&user, &uid, NULL, NULL, NULL);
+ if (r < 0)
+ return r;
+
+ item->policy_access.type = KDBUS_POLICY_ACCESS_USER;
+ item->policy_access.id = uid;
+ break;
+ }
+
+ case BUSNAME_POLICY_TYPE_GROUP: {
+ const char *group = policy->name;
+ gid_t gid;
+
+ r = get_group_creds(&group, &gid);
+ if (r < 0)
+ return r;
+
+ item->policy_access.type = KDBUS_POLICY_ACCESS_GROUP;
+ item->policy_access.id = gid;
+ break;
+ }
+
+ default:
+ assert_not_reached("Unknown policy type");
+ }
+
+ item->policy_access.access = bus_kernel_translate_access(policy->access);
+
+ return 0;
+}
+
+int bus_kernel_make_starter(
+ int fd,
+ const char *name,
+ bool activating,
+ bool accept_fd,
+ BusNamePolicy *policy,
+ BusPolicyAccess world_policy) {
+
+ struct kdbus_cmd_free cmd_free = { .size = sizeof(cmd_free) };
+ struct kdbus_cmd_hello *hello;
+ struct kdbus_item *n;
+ size_t policy_cnt = 0;
+ BusNamePolicy *po;
+ size_t size;
+ int r;
+
+ assert(fd >= 0);
+ assert(name);
+
+ LIST_FOREACH(policy, po, policy)
+ policy_cnt++;
+
+ if (world_policy >= 0)
+ policy_cnt++;
+
+ size = offsetof(struct kdbus_cmd_hello, items) +
+ ALIGN8(offsetof(struct kdbus_item, str) + strlen(name) + 1) +
+ policy_cnt * ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access));
+
+ hello = alloca0_align(size, 8);
+
+ n = hello->items;
+ strcpy(n->str, name);
+ n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
+ n->type = KDBUS_ITEM_NAME;
+ n = KDBUS_ITEM_NEXT(n);
+
+ LIST_FOREACH(policy, po, policy) {
+ n->type = KDBUS_ITEM_POLICY_ACCESS;
+ n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
+
+ r = bus_kernel_translate_policy(po, n);
+ if (r < 0)
+ return r;
+
+ n = KDBUS_ITEM_NEXT(n);
+ }
+
+ if (world_policy >= 0) {
+ n->type = KDBUS_ITEM_POLICY_ACCESS;
+ n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
+ n->policy_access.type = KDBUS_POLICY_ACCESS_WORLD;
+ n->policy_access.access = bus_kernel_translate_access(world_policy);
+ }
+
+ hello->size = size;
+ hello->flags =
+ (activating ? KDBUS_HELLO_ACTIVATOR : KDBUS_HELLO_POLICY_HOLDER) |
+ (accept_fd ? KDBUS_HELLO_ACCEPT_FD : 0);
+ hello->pool_size = KDBUS_POOL_SIZE;
+ hello->attach_flags_send = _KDBUS_ATTACH_ANY;
+ hello->attach_flags_recv = _KDBUS_ATTACH_ANY;
+
+ if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) {
+ if (errno == ENOTTY) /* Major API change */
+ return -ESOCKTNOSUPPORT;
+ return -errno;
+ }
+
+ /* not interested in any output values */
+ cmd_free.offset = hello->offset;
+ (void) ioctl(fd, KDBUS_CMD_FREE, &cmd_free);
+
+ /* The higher 32bit of the bus_flags fields are considered
+ * 'incompatible flags'. Refuse them all for now. */
+ if (hello->bus_flags > 0xFFFFFFFFULL)
+ return -ESOCKTNOSUPPORT;
+
+ return fd;
+}
+
+static const char* const bus_policy_access_table[_BUS_POLICY_ACCESS_MAX] = {
+ [BUS_POLICY_ACCESS_SEE] = "see",
+ [BUS_POLICY_ACCESS_TALK] = "talk",
+ [BUS_POLICY_ACCESS_OWN] = "own",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bus_policy_access, BusPolicyAccess);