/*** 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);