chiark / gitweb /
unit: use weaker dependencies between mount and device units in --user mode
[elogind.git] / src / core / bus-policy.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2014 Daniel Mack
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <stdlib.h>
21
22 #include "kdbus.h"
23 #include "util.h"
24 #include "bus-kernel.h"
25 #include "bus-policy.h"
26
27 int bus_kernel_translate_access(BusPolicyAccess access) {
28         assert(access >= 0);
29         assert(access < _BUS_POLICY_ACCESS_MAX);
30
31         switch (access) {
32
33         case BUS_POLICY_ACCESS_SEE:
34                 return KDBUS_POLICY_SEE;
35
36         case BUS_POLICY_ACCESS_TALK:
37                 return KDBUS_POLICY_TALK;
38
39         case BUS_POLICY_ACCESS_OWN:
40                 return KDBUS_POLICY_OWN;
41
42         default:
43                 assert_not_reached("Unknown policy access");
44         }
45 }
46
47 int bus_kernel_translate_policy(const BusNamePolicy *policy, struct kdbus_item *item) {
48         int r;
49
50         assert(policy);
51         assert(item);
52
53         switch (policy->type) {
54
55         case BUSNAME_POLICY_TYPE_USER: {
56                 const char *user = policy->name;
57                 uid_t uid;
58
59                 r = get_user_creds(&user, &uid, NULL, NULL, NULL);
60                 if (r < 0)
61                         return r;
62
63                 item->policy_access.type = KDBUS_POLICY_ACCESS_USER;
64                 item->policy_access.id = uid;
65                 break;
66         }
67
68         case BUSNAME_POLICY_TYPE_GROUP: {
69                 const char *group = policy->name;
70                 gid_t gid;
71
72                 r = get_group_creds(&group, &gid);
73                 if (r < 0)
74                         return r;
75
76                 item->policy_access.type = KDBUS_POLICY_ACCESS_GROUP;
77                 item->policy_access.id = gid;
78                 break;
79         }
80
81         default:
82                 assert_not_reached("Unknown policy type");
83         }
84
85         item->policy_access.access = bus_kernel_translate_access(policy->access);
86
87         return 0;
88 }
89
90 int bus_kernel_make_starter(
91                 int fd,
92                 const char *name,
93                 bool activating,
94                 bool accept_fd,
95                 BusNamePolicy *policy,
96                 BusPolicyAccess world_policy) {
97
98         struct kdbus_cmd_free cmd_free = { .size = sizeof(cmd_free) };
99         struct kdbus_cmd_hello *hello;
100         struct kdbus_item *n;
101         size_t policy_cnt = 0;
102         BusNamePolicy *po;
103         size_t size;
104         int r;
105
106         assert(fd >= 0);
107         assert(name);
108
109         LIST_FOREACH(policy, po, policy)
110                 policy_cnt++;
111
112         if (world_policy >= 0)
113                 policy_cnt++;
114
115         size = offsetof(struct kdbus_cmd_hello, items) +
116                ALIGN8(offsetof(struct kdbus_item, str) + strlen(name) + 1) +
117                policy_cnt * ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access));
118
119         hello = alloca0_align(size, 8);
120
121         n = hello->items;
122         strcpy(n->str, name);
123         n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
124         n->type = KDBUS_ITEM_NAME;
125         n = KDBUS_ITEM_NEXT(n);
126
127         LIST_FOREACH(policy, po, policy) {
128                 n->type = KDBUS_ITEM_POLICY_ACCESS;
129                 n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
130
131                 r = bus_kernel_translate_policy(po, n);
132                 if (r < 0)
133                         return r;
134
135                 n = KDBUS_ITEM_NEXT(n);
136         }
137
138         if (world_policy >= 0) {
139                 n->type = KDBUS_ITEM_POLICY_ACCESS;
140                 n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
141                 n->policy_access.type = KDBUS_POLICY_ACCESS_WORLD;
142                 n->policy_access.access = bus_kernel_translate_access(world_policy);
143         }
144
145         hello->size = size;
146         hello->flags =
147                 (activating ? KDBUS_HELLO_ACTIVATOR : KDBUS_HELLO_POLICY_HOLDER) |
148                 (accept_fd ? KDBUS_HELLO_ACCEPT_FD : 0);
149         hello->pool_size = KDBUS_POOL_SIZE;
150         hello->attach_flags_send = _KDBUS_ATTACH_ANY;
151         hello->attach_flags_recv = _KDBUS_ATTACH_ANY;
152
153         if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0)
154                 return -errno;
155
156         /* not interested in any output values */
157         cmd_free.offset = hello->offset;
158         (void) ioctl(fd, KDBUS_CMD_FREE, &cmd_free);
159
160         /* The higher 32bit of the bus_flags fields are considered
161          * 'incompatible flags'. Refuse them all for now. */
162         if (hello->bus_flags > 0xFFFFFFFFULL)
163                 return -ENOTSUP;
164
165         return fd;
166 }
167
168 static const char* const bus_policy_access_table[_BUS_POLICY_ACCESS_MAX] = {
169         [BUS_POLICY_ACCESS_SEE] = "see",
170         [BUS_POLICY_ACCESS_TALK] = "talk",
171         [BUS_POLICY_ACCESS_OWN] = "own",
172 };
173
174 DEFINE_STRING_TABLE_LOOKUP(bus_policy_access, BusPolicyAccess);