chiark / gitweb /
bus: fill in unique name when using kdbus
[elogind.git] / src / libsystemd-bus / bus-kernel.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <fcntl.h>
23
24 #include "util.h"
25
26 #include "bus-internal.h"
27 #include "bus-message.h"
28 #include "bus-kernel.h"
29
30 #define KDBUS_MSG_FOREACH_DATA(d, k)                                    \
31         for ((d) = (k)->data;                                           \
32              (uint8_t*) (d) < (uint8_t*) (k) + (k)->size;               \
33              (d) = (struct kdbus_msg_data*) ((uint8_t*) (d) + ALIGN8((d)->size)))
34
35
36
37 static int parse_unique_name(const char *s, uint64_t *id) {
38         int r;
39
40         assert(s);
41         assert(id);
42
43         if (!startswith(s, ":1."))
44                 return 0;
45
46         r = safe_atou64(s + 3, id);
47         if (r < 0)
48                 return r;
49
50         return 1;
51 }
52
53 static void append_payload_vec(struct kdbus_msg_data **d, const void *p, size_t sz) {
54         assert(d);
55         assert(p);
56         assert(sz > 0);
57
58         (*d)->size = offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec);
59         (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
60         (*d)->vec.address = (uint64_t) p;
61         (*d)->vec.size = sz;
62
63         *d = (struct kdbus_msg_data*) ((uint8_t*) *d + ALIGN8((*d)->size));
64 }
65
66 static void append_destination(struct kdbus_msg_data **d, const char *s, size_t length) {
67         assert(d);
68         assert(d);
69
70         (*d)->size = offsetof(struct kdbus_msg_data, data) + length + 1;
71         (*d)->type = KDBUS_MSG_DST_NAME;
72         memcpy((*d)->data, s, length + 1);
73
74         *d = (struct kdbus_msg_data*) ((uint8_t*) *d + ALIGN8((*d)->size));
75 }
76
77 static int bus_message_setup_kmsg(sd_bus_message *m) {
78         struct kdbus_msg_data *d;
79         bool well_known;
80         uint64_t unique;
81         size_t sz, dl;
82         int r;
83
84         assert(m);
85         assert(m->sealed);
86         assert(!m->kdbus);
87
88         if (m->destination) {
89                 r = parse_unique_name(m->destination, &unique);
90                 if (r < 0)
91                         return r;
92
93                 well_known = r == 0;
94         } else
95                 well_known = false;
96
97         sz = offsetof(struct kdbus_msg, data);
98
99         /* Add in fixed header, fields header, fields header padding and payload */
100         sz += 4 * ALIGN8(offsetof(struct kdbus_msg_data, vec) + sizeof(struct kdbus_vec));
101
102         /* Add in well-known destination header */
103         if (well_known) {
104                 dl = strlen(m->destination);
105                 sz += ALIGN8(offsetof(struct kdbus_msg, data) + dl + 1);
106         }
107
108         m->kdbus = malloc0(sz);
109         if (!m->kdbus)
110                 return -ENOMEM;
111
112         m->kdbus->flags =
113                 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
114                 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
115         m->kdbus->dst_id =
116                 well_known ? 0 :
117                 m->destination ? unique : (uint64_t) -1;
118         m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
119         m->kdbus->cookie = m->header->serial;
120
121         m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
122
123         d = m->kdbus->data;
124
125         if (well_known)
126                 append_destination(&d, m->destination, dl);
127
128         append_payload_vec(&d, m->header, sizeof(*m->header));
129
130         if (m->fields) {
131                 append_payload_vec(&d, m->fields, m->header->fields_size);
132
133                 if (m->header->fields_size % 8 != 0) {
134                         static const uint8_t padding[7] = {};
135
136                         append_payload_vec(&d, padding, 8 - (m->header->fields_size % 8));
137                 }
138         }
139
140         if (m->body)
141                 append_payload_vec(&d, m->body, m->header->body_size);
142
143         m->kdbus->size = (uint8_t*) m - (uint8_t*) m->kdbus;
144         assert(m->kdbus->size <= sz);
145
146         return 0;
147 }
148
149 int bus_kernel_take_fd(sd_bus *b) {
150         struct kdbus_cmd_hello hello = {};
151         int r;
152
153         assert(b);
154
155         r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
156         if (r < 0)
157                 return -errno;
158
159         if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
160                 return -ENOMEM;
161
162         b->is_kernel = true;
163
164         r = bus_start_running(b);
165         if (r < 0)
166                 return r;
167
168         return 1;
169 }
170
171 int bus_kernel_connect(sd_bus *b) {
172         assert(b);
173         assert(b->input_fd < 0);
174         assert(b->output_fd < 0);
175         assert(b->kernel);
176
177         b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
178         if (b->input_fd)
179                 return -errno;
180
181         b->output_fd = b->input_fd;
182
183         return bus_kernel_take_fd(b);
184 }
185
186 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
187         int r;
188
189         assert(bus);
190         assert(m);
191         assert(bus->state == BUS_RUNNING);
192
193         r = bus_message_setup_kmsg(m);
194         if (r < 0)
195                 return r;
196
197         r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
198         if (r < 0)
199                 return errno == EAGAIN ? 0 : -errno;
200
201         return 0;
202 }
203
204 static void close_kdbus_msg(struct kdbus_msg *k) {
205         struct kdbus_msg_data *d;
206
207         KDBUS_MSG_FOREACH_DATA(d, k) {
208
209                 if (d->type != KDBUS_MSG_UNIX_FDS)
210                         continue;
211
212                 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
213         }
214 }
215
216 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
217         sd_bus_message *m = NULL;
218         struct kdbus_msg_data *d;
219         unsigned n_payload = 0, n_fds = 0;
220         _cleanup_free_ int *fds = NULL;
221         struct bus_header *h = NULL;
222         size_t total, n_bytes = 0, idx = 0;
223         int r;
224
225         assert(bus);
226         assert(k);
227         assert(ret);
228
229         if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
230                 return 0;
231
232         KDBUS_MSG_FOREACH_DATA(d, k) {
233                 size_t l;
234
235                 l = d->size - offsetof(struct kdbus_msg_data, data);
236
237                 if (d->type == KDBUS_MSG_PAYLOAD) {
238
239                         if (!h) {
240                                 if (l < sizeof(struct bus_header))
241                                         return -EBADMSG;
242
243                                 h = (struct bus_header*) d->data;
244                         }
245
246                         n_payload++;
247                         n_bytes += l;
248
249                 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
250                         int *f;
251                         unsigned j;
252
253                         j = l / sizeof(int);
254                         f = realloc(fds, sizeof(int) * (n_fds + j));
255                         if (!f)
256                                 return -ENOMEM;
257
258                         fds = f;
259                         memcpy(fds + n_fds, d->fds, j);
260                         n_fds += j;
261                 }
262         }
263
264         if (!h)
265                 return -EBADMSG;
266
267         r = bus_header_size(h, &total);
268         if (r < 0)
269                 return r;
270
271         if (n_bytes != total)
272                 return -EBADMSG;
273
274         r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
275         if (r < 0)
276                 return r;
277
278         KDBUS_MSG_FOREACH_DATA(d, k) {
279                 size_t l;
280
281                 if (d->type != KDBUS_MSG_PAYLOAD)
282                         continue;
283
284                 l = d->size - offsetof(struct kdbus_msg_data, data);
285
286                 if (idx == sizeof(struct bus_header) &&
287                     l == BUS_MESSAGE_FIELDS_SIZE(m))
288                         m->fields = d->data;
289                 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
290                          l == BUS_MESSAGE_BODY_SIZE(m))
291                         m->body = d->data;
292                 else {
293                         sd_bus_message_unref(m);
294                         return -EBADMSG;
295                 }
296
297                 idx += l;
298         }
299
300         r = bus_message_parse_fields(m);
301         if (r < 0) {
302                 sd_bus_message_unref(m);
303                 return r;
304         }
305
306         /* We take possession of the kmsg struct now */
307         m->kdbus = k;
308         m->free_kdbus = true;
309         m->free_fds = true;
310
311         fds = NULL;
312
313         *ret = m;
314         return 1;
315 }
316
317 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
318         struct kdbus_msg *k;
319         size_t sz = 128;
320         int r;
321
322         assert(bus);
323         assert(m);
324
325         for (;;) {
326                 void *q;
327
328                 q = realloc(bus->rbuffer, sz);
329                 if (!q)
330                         return -errno;
331
332                 k = bus->rbuffer = q;
333                 k->size = sz;
334
335                 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
336                 if (r >= 0)
337                         break;
338
339                 if (errno == EAGAIN)
340                         return 0;
341
342                 if (errno != -EMSGSIZE)
343                         return -errno;
344
345                 sz *= 2;
346         }
347
348         r = bus_kernel_make_message(bus, k, m);
349         if (r > 0)
350                 bus->rbuffer = NULL;
351         else
352                 close_kdbus_msg(k);
353
354         return r;
355 }
356
357 int bus_kernel_create(const char *name, char **s) {
358         struct kdbus_cmd_fname *fname;
359         size_t l;
360         int fd;
361         char *p;
362
363         assert(name);
364         assert(s);
365
366         fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
367         if (fd < 0)
368                 return -errno;
369
370         l = strlen(name);
371         fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
372         sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
373         fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
374         fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD;
375         fname->user_flags = 0;
376
377         p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
378         if (!p)
379                 return -ENOMEM;
380
381         if (ioctl(fd, KDBUS_CMD_BUS_MAKE, &fname) < 0) {
382                 close_nointr_nofail(fd);
383                 free(p);
384                 return -errno;
385         }
386
387         if (s)
388                 *s = p;
389
390         return fd;
391 }