]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-message.c
bus: temporarily disable faking of seclabels, as this is broken in kdbus right now
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-message.c
CommitLineData
de1c301e
LP
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 <errno.h>
2c93b4ef 23#include <fcntl.h>
bc7fd8cd 24#include <sys/mman.h>
de1c301e
LP
25
26#include "util.h"
9a17484d 27#include "utf8.h"
89ffcd2a 28#include "strv.h"
6629161f 29#include "time-util.h"
d8d3d8a7 30#include "cgroup-util.h"
de1c301e 31
de1c301e 32#include "sd-bus.h"
9a17484d 33#include "bus-message.h"
de1c301e
LP
34#include "bus-internal.h"
35#include "bus-type.h"
36#include "bus-signature.h"
c1b9d935 37#include "bus-gvariant.h"
e1c433c6 38#include "bus-util.h"
de1c301e 39
80a46c73 40static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
de1c301e 41
bc7fd8cd
LP
42static void *adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) {
43
44 if (p == NULL)
45 return NULL;
46
47 if (old_base == new_base)
48 return (void*) p;
49
50 if ((uint8_t*) p < (uint8_t*) old_base)
51 return (void*) p;
52
53 if ((uint8_t*) p >= (uint8_t*) old_base + sz)
54 return (void*) p;
55
56 return (uint8_t*) new_base + ((uint8_t*) p - (uint8_t*) old_base);
57}
58
59static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
60 assert(m);
61 assert(part);
62
63 if (part->memfd >= 0) {
66b26c5c
LP
64 /* If we can reuse the memfd, try that. For that it
65 * can't be sealed yet. */
bc7fd8cd
LP
66
67 if (!part->sealed)
8e959fbf 68 bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
bc7fd8cd 69 else {
89b4fc46
LP
70 if (part->mapped > 0)
71 assert_se(munmap(part->data, part->mapped) == 0);
bc7fd8cd
LP
72
73 close_nointr_nofail(part->memfd);
74 }
75
453a0c29
LP
76 } else if (part->munmap_this)
77 munmap(part->data, part->mapped);
78 else if (part->free_this)
bc7fd8cd
LP
79 free(part->data);
80
81 if (part != &m->body)
82 free(part);
83}
84
85static void message_reset_parts(sd_bus_message *m) {
86 struct bus_body_part *part;
87
88 assert(m);
89
90 part = &m->body;
91 while (m->n_body_parts > 0) {
92 struct bus_body_part *next = part->next;
93 message_free_part(m, part);
94 part = next;
95 m->n_body_parts--;
96 }
97
98 m->body_end = NULL;
99
100 m->cached_rindex_part = NULL;
101 m->cached_rindex_part_begin = 0;
102}
103
104static void message_reset_containers(sd_bus_message *m) {
9a17484d
LP
105 unsigned i;
106
107 assert(m);
108
6647dc66 109 for (i = 0; i < m->n_containers; i++) {
9a17484d 110 free(m->containers[i].signature);
6647dc66
LP
111 free(m->containers[i].offsets);
112 }
9a17484d
LP
113
114 free(m->containers);
115 m->containers = NULL;
116
306f07be 117 m->n_containers = m->containers_allocated = 0;
9a17484d
LP
118 m->root_container.index = 0;
119}
120
de1c301e 121static void message_free(sd_bus_message *m) {
de1c301e
LP
122 assert(m);
123
124 if (m->free_header)
125 free(m->header);
126
bc7fd8cd 127 message_reset_parts(m);
de1c301e 128
6629161f
LP
129 if (m->free_kdbus)
130 free(m->kdbus);
131
62b3e928
KS
132 if (m->release_kdbus) {
133 uint64_t off;
134
135 off = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer;
1d0e3c98 136 ioctl(m->bus->input_fd, KDBUS_CMD_FREE, &off);
62b3e928 137 }
fd8d62d9 138
f54514f3
LP
139 if (m->bus)
140 sd_bus_unref(m->bus);
141
2c93b4ef
LP
142 if (m->free_fds) {
143 close_many(m->fds, m->n_fds);
144 free(m->fds);
145 }
de1c301e 146
bc7fd8cd
LP
147 if (m->iovec != m->iovec_fixed)
148 free(m->iovec);
149
bc7fd8cd 150 message_reset_containers(m);
9a17484d 151 free(m->root_container.signature);
6647dc66 152 free(m->root_container.offsets);
de1c301e 153
3798fd4c 154 free(m->root_container.peeked_signature);
d8d3d8a7 155
5b12334d 156 bus_creds_done(&m->creds);
de1c301e
LP
157 free(m);
158}
159
c1b9d935 160static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
c91cb83c
LP
161 void *op, *np;
162 size_t old_size, new_size, start;
de1c301e 163
c91cb83c 164 assert(m);
35460afc
LP
165
166 if (m->poisoned)
167 return NULL;
de1c301e 168
c91cb83c
LP
169 old_size = sizeof(struct bus_header) + m->header->fields_size;
170 start = ALIGN_TO(old_size, align);
171 new_size = start + sz;
de1c301e 172
c91cb83c
LP
173 if (old_size == new_size)
174 return (uint8_t*) m->header + old_size;
de1c301e 175
c91cb83c
LP
176 if (new_size > (size_t) ((uint32_t) -1))
177 goto poison;
de1c301e 178
c91cb83c
LP
179 if (m->free_header) {
180 np = realloc(m->header, ALIGN8(new_size));
181 if (!np)
182 goto poison;
183 } else {
184 /* Initially, the header is allocated as part of of
185 * the sd_bus_message itself, let's replace it by
186 * dynamic data */
de1c301e 187
c91cb83c
LP
188 np = malloc(ALIGN8(new_size));
189 if (!np)
190 goto poison;
de1c301e 191
c91cb83c
LP
192 memcpy(np, m->header, sizeof(struct bus_header));
193 }
de1c301e 194
c91cb83c
LP
195 /* Zero out padding */
196 if (start > old_size)
197 memset((uint8_t*) np + old_size, 0, start - old_size);
bc7fd8cd 198
c91cb83c
LP
199 op = m->header;
200 m->header = np;
201 m->header->fields_size = new_size - sizeof(struct bus_header);
de1c301e 202
bc7fd8cd 203 /* Adjust quick access pointers */
c91cb83c
LP
204 m->path = adjust_pointer(m->path, op, old_size, m->header);
205 m->interface = adjust_pointer(m->interface, op, old_size, m->header);
206 m->member = adjust_pointer(m->member, op, old_size, m->header);
207 m->destination = adjust_pointer(m->destination, op, old_size, m->header);
208 m->sender = adjust_pointer(m->sender, op, old_size, m->header);
209 m->error.name = adjust_pointer(m->error.name, op, old_size, m->header);
bc7fd8cd 210
c91cb83c 211 m->free_header = true;
de1c301e 212
c1b9d935
LP
213 if (add_offset) {
214 if (m->n_header_offsets >= ELEMENTSOF(m->header_offsets))
215 goto poison;
216
217 m->header_offsets[m->n_header_offsets++] = new_size - sizeof(struct bus_header);
218 }
219
c91cb83c
LP
220 return (uint8_t*) np + start;
221
222poison:
223 m->poisoned = true;
224 return NULL;
de1c301e
LP
225}
226
227static int message_append_field_string(
228 sd_bus_message *m,
229 uint8_t h,
230 char type,
231 const char *s,
232 const char **ret) {
233
234 size_t l;
235 uint8_t *p;
236
237 assert(m);
238
c1b9d935
LP
239 /* dbus1 doesn't allow strings over 32bit, let's enforce this
240 * globally, to not risk convertability */
de1c301e
LP
241 l = strlen(s);
242 if (l > (size_t) (uint32_t) -1)
243 return -EINVAL;
244
c1b9d935
LP
245 /* Signature "(yv)" where the variant contains "s" */
246
6647dc66 247 if (BUS_MESSAGE_IS_GVARIANT(m)) {
de1c301e 248
c1b9d935
LP
249 /* (field id byte + 7x padding, ((string + NUL) + NUL + signature string 's') */
250 p = message_extend_fields(m, 8, 1 + 7 + l + 1 + 1 + 1, true);
251 if (!p)
252 return -ENOMEM;
de1c301e 253
c1b9d935
LP
254 p[0] = h;
255 memset(p+1, 0, 7);
256 memcpy(p+8, s, l);
257 p[8+l] = 0;
258 p[8+l+1] = 0;
259 p[8+l+2] = type;
de1c301e 260
c1b9d935 261 if (ret)
6647dc66 262 *ret = (char*) p + 8;
c1b9d935
LP
263
264 } else {
265 /* (field id byte + (signature length + signature 's' + NUL) + (string length + string + NUL)) */
266 p = message_extend_fields(m, 8, 4 + 4 + l + 1, false);
267 if (!p)
268 return -ENOMEM;
269
270 p[0] = h;
271 p[1] = 1;
272 p[2] = type;
273 p[3] = 0;
274
275 ((uint32_t*) p)[1] = l;
276 memcpy(p + 8, s, l + 1);
277
278 if (ret)
279 *ret = (char*) p + 8;
280 }
de1c301e
LP
281
282 return 0;
283}
284
285static int message_append_field_signature(
286 sd_bus_message *m,
287 uint8_t h,
288 const char *s,
289 const char **ret) {
290
291 size_t l;
292 uint8_t *p;
293
294 assert(m);
295
c1b9d935
LP
296 /* dbus1 doesn't allow signatures over 32bit, let's enforce
297 * this globally, to not risk convertability */
de1c301e
LP
298 l = strlen(s);
299 if (l > 255)
300 return -EINVAL;
301
c1b9d935
LP
302 /* Signature "(yv)" where the variant contains "g" */
303
6647dc66 304 if (BUS_MESSAGE_IS_GVARIANT(m))
c1b9d935
LP
305 /* For gvariant the serialization is the same as for normal strings */
306 return message_append_field_string(m, h, 'g', s, ret);
307 else {
308 /* (field id byte + (signature length + signature 'g' + NUL) + (string length + string + NUL)) */
309 p = message_extend_fields(m, 8, 4 + 1 + l + 1, false);
310 if (!p)
311 return -ENOMEM;
de1c301e 312
c1b9d935
LP
313 p[0] = h;
314 p[1] = 1;
315 p[2] = SD_BUS_TYPE_SIGNATURE;
316 p[3] = 0;
317 p[4] = l;
318 memcpy(p + 5, s, l + 1);
de1c301e 319
c1b9d935
LP
320 if (ret)
321 *ret = (const char*) p + 5;
322 }
de1c301e
LP
323
324 return 0;
325}
326
327static int message_append_field_uint32(sd_bus_message *m, uint8_t h, uint32_t x) {
328 uint8_t *p;
329
330 assert(m);
331
6647dc66 332 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
333 /* (field id byte + 7x padding + ((value + NUL + signature string 'u') */
334
335 p = message_extend_fields(m, 8, 1 + 7 + 4 + 1 + 1, true);
336 if (!p)
337 return -ENOMEM;
de1c301e 338
c1b9d935
LP
339 p[0] = h;
340 memset(p+1, 0, 7);
341 *((uint32_t*) (p + 8)) = x;
342 p[12] = 0;
343 p[13] = 'u';
344 } else {
345 /* (field id byte + (signature length + signature 'u' + NUL) + value) */
346 p = message_extend_fields(m, 8, 4 + 4, false);
347 if (!p)
348 return -ENOMEM;
349
350 p[0] = h;
351 p[1] = 1;
352 p[2] = SD_BUS_TYPE_UINT32;
353 p[3] = 0;
de1c301e 354
c1b9d935
LP
355 ((uint32_t*) p)[1] = x;
356 }
de1c301e
LP
357
358 return 0;
359}
360
6629161f 361int bus_message_from_header(
df2d202e 362 sd_bus *bus,
2571ead1
LP
363 void *buffer,
364 size_t length,
2c93b4ef
LP
365 int *fds,
366 unsigned n_fds,
367 const struct ucred *ucred,
2571ead1 368 const char *label,
6629161f 369 size_t extra,
2571ead1
LP
370 sd_bus_message **ret) {
371
80a46c73
LP
372 sd_bus_message *m;
373 struct bus_header *h;
6629161f 374 size_t a, label_sz;
80a46c73
LP
375
376 assert(buffer || length <= 0);
2c93b4ef 377 assert(fds || n_fds <= 0);
80a46c73
LP
378 assert(ret);
379
380 if (length < sizeof(struct bus_header))
381 return -EBADMSG;
382
383 h = buffer;
6647dc66
LP
384 if (h->version != 1 &&
385 h->version != 2)
80a46c73
LP
386 return -EBADMSG;
387
388 if (h->serial == 0)
389 return -EBADMSG;
390
391 if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
392 return -EBADMSG;
393
0461f8cd
LP
394 if (h->endian != BUS_LITTLE_ENDIAN &&
395 h->endian != BUS_BIG_ENDIAN)
80a46c73
LP
396 return -EBADMSG;
397
6629161f 398 a = ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
80a46c73 399
2571ead1
LP
400 if (label) {
401 label_sz = strlen(label);
6629161f
LP
402 a += label_sz + 1;
403 }
2571ead1
LP
404
405 m = malloc0(a);
80a46c73
LP
406 if (!m)
407 return -ENOMEM;
408
409 m->n_ref = 1;
2c93b4ef 410 m->sealed = true;
80a46c73 411 m->header = h;
2c93b4ef
LP
412 m->fds = fds;
413 m->n_fds = n_fds;
80a46c73 414
2571ead1 415 if (ucred) {
5b12334d
LP
416 m->creds.uid = ucred->uid;
417 m->creds.pid = ucred->pid;
418 m->creds.gid = ucred->gid;
419 m->creds.mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID;
2571ead1
LP
420 }
421
422 if (label) {
5b12334d
LP
423 m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
424 memcpy(m->creds.label, label, label_sz + 1);
425
426 m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
2571ead1
LP
427 }
428
df2d202e
LP
429 if (bus)
430 m->bus = sd_bus_ref(bus);
431
6629161f
LP
432 *ret = m;
433 return 0;
434}
435
436int bus_message_from_malloc(
df2d202e 437 sd_bus *bus,
6629161f
LP
438 void *buffer,
439 size_t length,
440 int *fds,
441 unsigned n_fds,
442 const struct ucred *ucred,
443 const char *label,
444 sd_bus_message **ret) {
445
446 sd_bus_message *m;
5461f53f 447 size_t sz;
6629161f
LP
448 int r;
449
df2d202e 450 r = bus_message_from_header(bus, buffer, length, fds, n_fds, ucred, label, 0, &m);
6629161f
LP
451 if (r < 0)
452 return r;
453
454 if (length != BUS_MESSAGE_SIZE(m)) {
455 r = -EBADMSG;
456 goto fail;
457 }
458
5461f53f
LP
459 sz = length - sizeof(struct bus_header) - ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
460 if (sz > 0) {
461 m->n_body_parts = 1;
462 m->body.data = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
463 m->body.size = sz;
464 m->body.sealed = true;
465 m->body.memfd = -1;
466 }
6629161f 467
80a46c73 468 m->n_iovec = 1;
bc7fd8cd 469 m->iovec = m->iovec_fixed;
80a46c73
LP
470 m->iovec[0].iov_base = buffer;
471 m->iovec[0].iov_len = length;
472
6629161f 473 r = bus_message_parse_fields(m);
2c93b4ef
LP
474 if (r < 0)
475 goto fail;
476
477 /* We take possession of the memory and fds now */
478 m->free_header = true;
479 m->free_fds = true;
80a46c73
LP
480
481 *ret = m;
482 return 0;
2c93b4ef
LP
483
484fail:
485 message_free(m);
486 return r;
80a46c73
LP
487}
488
de1c301e
LP
489static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
490 sd_bus_message *m;
491
80a46c73 492 m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
de1c301e
LP
493 if (!m)
494 return NULL;
495
496 m->n_ref = 1;
497 m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message)));
0461f8cd 498 m->header->endian = BUS_NATIVE_ENDIAN;
de1c301e
LP
499 m->header->type = type;
500 m->header->version = bus ? bus->message_version : 1;
021a1e78 501 m->allow_fds = !bus || bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING);
6647dc66 502 m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m);
de1c301e 503
9b05bc48
LP
504 if (bus)
505 m->bus = sd_bus_ref(bus);
506
de1c301e
LP
507 return m;
508}
509
d9f644e2 510_public_ int sd_bus_message_new_signal(
de1c301e
LP
511 sd_bus *bus,
512 const char *path,
513 const char *interface,
514 const char *member,
515 sd_bus_message **m) {
516
517 sd_bus_message *t;
518 int r;
519
9d6c7c82
LP
520 assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
521 assert_return(object_path_is_valid(path), -EINVAL);
522 assert_return(interface_name_is_valid(interface), -EINVAL);
523 assert_return(member_name_is_valid(member), -EINVAL);
524 assert_return(m, -EINVAL);
de1c301e 525
40ca29a1 526 t = message_new(bus, SD_BUS_MESSAGE_SIGNAL);
de1c301e
LP
527 if (!t)
528 return -ENOMEM;
529
0461f8cd 530 t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
89ffcd2a 531
0461f8cd 532 r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
de1c301e
LP
533 if (r < 0)
534 goto fail;
0461f8cd 535 r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
de1c301e
LP
536 if (r < 0)
537 goto fail;
0461f8cd 538 r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
de1c301e
LP
539 if (r < 0)
540 goto fail;
541
542 *m = t;
543 return 0;
544
545fail:
546 sd_bus_message_unref(t);
547 return r;
548}
549
d9f644e2 550_public_ int sd_bus_message_new_method_call(
de1c301e
LP
551 sd_bus *bus,
552 const char *destination,
553 const char *path,
554 const char *interface,
555 const char *member,
556 sd_bus_message **m) {
557
558 sd_bus_message *t;
559 int r;
560
9d6c7c82
LP
561 assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
562 assert_return(!destination || service_name_is_valid(destination), -EINVAL);
563 assert_return(object_path_is_valid(path), -EINVAL);
564 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
565 assert_return(member_name_is_valid(member), -EINVAL);
566 assert_return(m, -EINVAL);
de1c301e 567
40ca29a1 568 t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL);
de1c301e
LP
569 if (!t)
570 return -ENOMEM;
571
0461f8cd 572 r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
de1c301e
LP
573 if (r < 0)
574 goto fail;
0461f8cd 575 r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
de1c301e
LP
576 if (r < 0)
577 goto fail;
578
579 if (interface) {
0461f8cd 580 r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
de1c301e
LP
581 if (r < 0)
582 goto fail;
583 }
584
585 if (destination) {
0461f8cd 586 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination);
de1c301e
LP
587 if (r < 0)
588 goto fail;
589 }
590
591 *m = t;
592 return 0;
593
594fail:
595 message_free(t);
596 return r;
597}
598
5407f2de 599static int message_new_reply(
de1c301e 600 sd_bus_message *call,
5407f2de 601 uint8_t type,
de1c301e
LP
602 sd_bus_message **m) {
603
604 sd_bus_message *t;
605 int r;
606
9d6c7c82
LP
607 assert_return(call, -EINVAL);
608 assert_return(call->sealed, -EPERM);
609 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
df2d202e 610 assert_return(!call->bus || call->bus->state != BUS_UNSET, -ENOTCONN);
9d6c7c82 611 assert_return(m, -EINVAL);
de1c301e 612
df2d202e 613 t = message_new(call->bus, type);
de1c301e
LP
614 if (!t)
615 return -ENOMEM;
616
0461f8cd 617 t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
693eb9a2 618 t->reply_cookie = BUS_MESSAGE_COOKIE(call);
5407f2de 619
693eb9a2 620 r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_cookie);
de1c301e
LP
621 if (r < 0)
622 goto fail;
623
624 if (call->sender) {
0461f8cd 625 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination);
de1c301e
LP
626 if (r < 0)
627 goto fail;
628 }
629
0461f8cd 630 t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
6717d473 631 t->enforced_reply_signature = call->enforced_reply_signature;
5407f2de 632
de1c301e 633 *m = t;
89ffcd2a 634 return 0;
de1c301e
LP
635
636fail:
637 message_free(t);
638 return r;
639}
640
d9f644e2 641_public_ int sd_bus_message_new_method_return(
5407f2de
LP
642 sd_bus_message *call,
643 sd_bus_message **m) {
644
df2d202e 645 return message_new_reply(call, SD_BUS_MESSAGE_METHOD_RETURN, m);
5407f2de
LP
646}
647
d9f644e2 648_public_ int sd_bus_message_new_method_error(
de1c301e
LP
649 sd_bus_message *call,
650 const sd_bus_error *e,
651 sd_bus_message **m) {
652
653 sd_bus_message *t;
654 int r;
655
9d6c7c82
LP
656 assert_return(sd_bus_error_is_set(e), -EINVAL);
657 assert_return(m, -EINVAL);
de1c301e 658
df2d202e 659 r = message_new_reply(call, SD_BUS_MESSAGE_METHOD_ERROR, &t);
de1c301e 660 if (r < 0)
5407f2de 661 return r;
de1c301e 662
0461f8cd 663 r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
de1c301e
LP
664 if (r < 0)
665 goto fail;
666
667 if (e->message) {
668 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
669 if (r < 0)
670 goto fail;
671 }
672
79f8d3d2
LP
673 t->error._need_free = -1;
674
de1c301e
LP
675 *m = t;
676 return 0;
677
678fail:
679 message_free(t);
680 return r;
681}
682
d9f644e2 683_public_ int sd_bus_message_new_method_errorf(
29ddb38f
LP
684 sd_bus_message *call,
685 sd_bus_message **m,
686 const char *name,
687 const char *format,
688 ...) {
689
40ca29a1 690 _cleanup_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
29ddb38f 691 va_list ap;
29ddb38f 692
40ca29a1
LP
693 assert_return(name, -EINVAL);
694 assert_return(m, -EINVAL);
695
696 va_start(ap, format);
780896a4 697 bus_error_setfv(&error, name, format, ap);
40ca29a1 698 va_end(ap);
29ddb38f 699
df2d202e 700 return sd_bus_message_new_method_error(call, &error, m);
40ca29a1 701}
29ddb38f 702
d9f644e2 703_public_ int sd_bus_message_new_method_errno(
40ca29a1
LP
704 sd_bus_message *call,
705 int error,
706 const sd_bus_error *p,
707 sd_bus_message **m) {
29ddb38f 708
40ca29a1 709 _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
29ddb38f 710
40ca29a1 711 if (sd_bus_error_is_set(p))
df2d202e 712 return sd_bus_message_new_method_error(call, p, m);
29ddb38f 713
40ca29a1 714 sd_bus_error_set_errno(&berror, error);
29ddb38f 715
df2d202e 716 return sd_bus_message_new_method_error(call, &berror, m);
40ca29a1 717}
29ddb38f 718
d9f644e2 719_public_ int sd_bus_message_new_method_errnof(
40ca29a1
LP
720 sd_bus_message *call,
721 sd_bus_message **m,
722 int error,
723 const char *format,
724 ...) {
725
726 _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
727 va_list ap;
40ca29a1
LP
728
729 va_start(ap, format);
780896a4 730 bus_error_set_errnofv(&berror, error, format, ap);
40ca29a1
LP
731 va_end(ap);
732
df2d202e 733 return sd_bus_message_new_method_error(call, &berror, m);
29ddb38f
LP
734}
735
eb01ba5d
LP
736int bus_message_new_synthetic_error(
737 sd_bus *bus,
693eb9a2 738 uint64_t cookie,
eb01ba5d
LP
739 const sd_bus_error *e,
740 sd_bus_message **m) {
741
742 sd_bus_message *t;
743 int r;
744
745 assert(sd_bus_error_is_set(e));
746 assert(m);
747
40ca29a1 748 t = message_new(bus, SD_BUS_MESSAGE_METHOD_ERROR);
eb01ba5d
LP
749 if (!t)
750 return -ENOMEM;
751
0461f8cd 752 t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
693eb9a2 753 t->reply_cookie = cookie;
eb01ba5d 754
693eb9a2 755 r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_cookie);
eb01ba5d
LP
756 if (r < 0)
757 goto fail;
758
759 if (bus && bus->unique_name) {
0461f8cd 760 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination);
eb01ba5d
LP
761 if (r < 0)
762 goto fail;
763 }
764
0461f8cd 765 r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
3a7d4f1b
LP
766 if (r < 0)
767 goto fail;
768
769 if (e->message) {
770 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
771 if (r < 0)
772 goto fail;
773 }
774
79f8d3d2
LP
775 t->error._need_free = -1;
776
eb01ba5d
LP
777 *m = t;
778 return 0;
779
780fail:
781 message_free(t);
782 return r;
783}
784
d9f644e2 785_public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
9d6c7c82 786 assert_return(m, NULL);
de1c301e
LP
787
788 assert(m->n_ref > 0);
789 m->n_ref++;
790
791 return m;
792}
793
d9f644e2 794_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
5b1bc83f
LP
795
796 if (!m)
797 return NULL;
de1c301e
LP
798
799 assert(m->n_ref > 0);
800 m->n_ref--;
801
802 if (m->n_ref <= 0)
803 message_free(m);
804
805 return NULL;
806}
807
d9f644e2 808_public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
9d6c7c82
LP
809 assert_return(m, -EINVAL);
810 assert_return(type, -EINVAL);
de1c301e
LP
811
812 *type = m->header->type;
813 return 0;
814}
815
693eb9a2 816_public_ int sd_bus_message_get_cookie(sd_bus_message *m, uint64_t *cookie) {
9d6c7c82 817 assert_return(m, -EINVAL);
693eb9a2 818 assert_return(cookie, -EINVAL);
d9416f8a 819 assert_return(m->header->serial != 0, -ENODATA);
de1c301e 820
693eb9a2 821 *cookie = BUS_MESSAGE_COOKIE(m);
de1c301e
LP
822 return 0;
823}
824
693eb9a2 825_public_ int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie) {
9d6c7c82 826 assert_return(m, -EINVAL);
693eb9a2 827 assert_return(cookie, -EINVAL);
d9416f8a 828 assert_return(m->reply_cookie != 0, -ENODATA);
de1c301e 829
693eb9a2 830 *cookie = m->reply_cookie;
de1c301e
LP
831 return 0;
832}
833
d9f644e2 834_public_ int sd_bus_message_get_no_reply(sd_bus_message *m) {
9d6c7c82 835 assert_return(m, -EINVAL);
de1c301e 836
0461f8cd 837 return m->header->type == SD_BUS_MESSAGE_METHOD_CALL ? !!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) : 0;
de1c301e
LP
838}
839
1fee9de5
LP
840_public_ int sd_bus_message_get_no_auto_start(sd_bus_message *m) {
841 assert_return(m, -EINVAL);
842
0461f8cd 843 return !!(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
1fee9de5
LP
844}
845
d9f644e2 846_public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
9d6c7c82 847 assert_return(m, NULL);
de1c301e
LP
848
849 return m->path;
850}
851
d9f644e2 852_public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
9d6c7c82 853 assert_return(m, NULL);
de1c301e
LP
854
855 return m->interface;
856}
857
d9f644e2 858_public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
9d6c7c82 859 assert_return(m, NULL);
de1c301e
LP
860
861 return m->member;
862}
d9f644e2
ZJS
863
864_public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
9d6c7c82 865 assert_return(m, NULL);
de1c301e
LP
866
867 return m->destination;
868}
869
d9f644e2 870_public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
9d6c7c82 871 assert_return(m, NULL);
de1c301e
LP
872
873 return m->sender;
874}
875
d9f644e2 876_public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
9d6c7c82
LP
877 assert_return(m, NULL);
878 assert_return(sd_bus_error_is_set(&m->error), NULL);
de1c301e
LP
879
880 return &m->error;
881}
882
1fedcf59 883_public_ int sd_bus_message_get_monotonic_usec(sd_bus_message *m, uint64_t *usec) {
9d6c7c82
LP
884 assert_return(m, -EINVAL);
885 assert_return(usec, -EINVAL);
1fedcf59
LP
886
887 if (m->monotonic <= 0)
888 return -ENODATA;
acb5a3cb 889
69aec65c 890 *usec = m->monotonic;
acb5a3cb
LP
891 return 0;
892}
893
1fedcf59 894_public_ int sd_bus_message_get_realtime_usec(sd_bus_message *m, uint64_t *usec) {
9d6c7c82
LP
895 assert_return(m, -EINVAL);
896 assert_return(usec, -EINVAL);
1fedcf59
LP
897
898 if (m->realtime <= 0)
899 return -ENODATA;
69aec65c
LP
900
901 *usec = m->realtime;
902 return 0;
903}
904
6a0e376c
LP
905_public_ int sd_bus_message_get_seqnum(sd_bus_message *m, uint64_t *seqnum) {
906 assert_return(m, -EINVAL);
907 assert_return(seqnum, -EINVAL);
1fedcf59
LP
908
909 if (m->seqnum <= 0)
910 return -ENODATA;
6a0e376c
LP
911
912 *seqnum = m->seqnum;
913 return 0;
914}
915
5b12334d
LP
916_public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) {
917 assert_return(m, NULL);
102ea8e4 918
5b12334d
LP
919 if (m->creds.mask == 0)
920 return NULL;
102ea8e4 921
5b12334d 922 return &m->creds;
102ea8e4
LP
923}
924
d9f644e2
ZJS
925_public_ int sd_bus_message_is_signal(sd_bus_message *m,
926 const char *interface,
927 const char *member) {
9d6c7c82 928 assert_return(m, -EINVAL);
de1c301e 929
40ca29a1 930 if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
de1c301e
LP
931 return 0;
932
933 if (interface && (!m->interface || !streq(m->interface, interface)))
934 return 0;
935
936 if (member && (!m->member || !streq(m->member, member)))
937 return 0;
938
939 return 1;
940}
941
d9f644e2
ZJS
942_public_ int sd_bus_message_is_method_call(sd_bus_message *m,
943 const char *interface,
944 const char *member) {
9d6c7c82 945 assert_return(m, -EINVAL);
de1c301e 946
40ca29a1 947 if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
de1c301e
LP
948 return 0;
949
950 if (interface && (!m->interface || !streq(m->interface, interface)))
951 return 0;
952
953 if (member && (!m->member || !streq(m->member, member)))
954 return 0;
955
956 return 1;
957}
958
d9f644e2 959_public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
9d6c7c82 960 assert_return(m, -EINVAL);
de1c301e 961
40ca29a1 962 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
de1c301e
LP
963 return 0;
964
965 if (name && (!m->error.name || !streq(m->error.name, name)))
966 return 0;
967
968 return 1;
969}
970
d9f644e2 971_public_ int sd_bus_message_set_no_reply(sd_bus_message *m, int b) {
9d6c7c82
LP
972 assert_return(m, -EINVAL);
973 assert_return(!m->sealed, -EPERM);
974 assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
de1c301e
LP
975
976 if (b)
0461f8cd 977 m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
de1c301e 978 else
0461f8cd 979 m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED;
de1c301e
LP
980
981 return 0;
982}
983
1fee9de5
LP
984_public_ int sd_bus_message_set_no_auto_start(sd_bus_message *m, int b) {
985 assert_return(m, -EINVAL);
986 assert_return(!m->sealed, -EPERM);
987
988 if (b)
0461f8cd 989 m->header->flags |= BUS_MESSAGE_NO_AUTO_START;
1fee9de5 990 else
0461f8cd 991 m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START;
1fee9de5
LP
992
993 return 0;
994}
995
de1c301e
LP
996static struct bus_container *message_get_container(sd_bus_message *m) {
997 assert(m);
998
999 if (m->n_containers == 0)
1000 return &m->root_container;
1001
9a17484d
LP
1002 assert(m->containers);
1003 return m->containers + m->n_containers - 1;
de1c301e
LP
1004}
1005
bc7fd8cd
LP
1006struct bus_body_part *message_append_part(sd_bus_message *m) {
1007 struct bus_body_part *part;
1008
1009 assert(m);
35460afc
LP
1010
1011 if (m->poisoned)
1012 return NULL;
bc7fd8cd
LP
1013
1014 if (m->n_body_parts <= 0) {
1015 part = &m->body;
1016 zero(*part);
1017 } else {
1018 assert(m->body_end);
1019
1020 part = new0(struct bus_body_part, 1);
1021 if (!part) {
1022 m->poisoned = true;
1023 return NULL;
1024 }
1025
1026 m->body_end->next = part;
1027 }
1028
1029 part->memfd = -1;
1030 m->body_end = part;
1031 m->n_body_parts ++;
1032
1033 return part;
1034}
1035
1036static void part_zero(struct bus_body_part *part, size_t sz) {
1037 assert(part);
1038 assert(sz > 0);
1039 assert(sz < 8);
1040
453a0c29
LP
1041 /* All other fields can be left in their defaults */
1042 assert(!part->data);
1043 assert(part->memfd < 0);
1044
bc7fd8cd 1045 part->size = sz;
453a0c29
LP
1046 part->is_zero = true;
1047 part->sealed = true;
bc7fd8cd
LP
1048}
1049
1050static int part_make_space(
1051 struct sd_bus_message *m,
1052 struct bus_body_part *part,
1053 size_t sz,
1054 void **q) {
1055
1056 void *n;
1057 int r;
1058
1059 assert(m);
1060 assert(part);
1061 assert(!part->sealed);
1062
1063 if (m->poisoned)
1064 return -ENOMEM;
1065
1066 if (!part->data && part->memfd < 0)
8e959fbf 1067 part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated);
bc7fd8cd
LP
1068
1069 if (part->memfd >= 0) {
bc7fd8cd 1070
8e959fbf
LP
1071 if (part->allocated == 0 || sz > part->allocated) {
1072 uint64_t new_allocated;
1073
1074 new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
1075 r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &new_allocated);
1076 if (r < 0) {
1077 m->poisoned = true;
1078 return -errno;
1079 }
1080
1081 part->allocated = new_allocated;
bc7fd8cd
LP
1082 }
1083
453a0c29 1084 if (!part->data || sz > part->mapped) {
8e959fbf 1085 size_t psz;
bc7fd8cd 1086
8e959fbf 1087 psz = PAGE_ALIGN(sz > 0 ? sz : 1);
bc7fd8cd
LP
1088 if (part->mapped <= 0)
1089 n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
1090 else
1091 n = mremap(part->data, part->mapped, psz, MREMAP_MAYMOVE);
1092
1093 if (n == MAP_FAILED) {
1094 m->poisoned = true;
1095 return -errno;
1096 }
1097
1098 part->mapped = psz;
1099 part->data = n;
1100 }
bf30e48f
KS
1101
1102 part->munmap_this = true;
bc7fd8cd 1103 } else {
8e959fbf
LP
1104 if (part->allocated == 0 || sz > part->allocated) {
1105 size_t new_allocated;
1106
1107 new_allocated = sz > 0 ? 2 * sz : 64;
1108 n = realloc(part->data, new_allocated);
1109 if (!n) {
1110 m->poisoned = true;
1111 return -ENOMEM;
1112 }
bc7fd8cd 1113
8e959fbf
LP
1114 part->data = n;
1115 part->allocated = new_allocated;
1116 part->free_this = true;
1117 }
bc7fd8cd
LP
1118 }
1119
1120 if (q)
1121 *q = part->data ? (uint8_t*) part->data + part->size : NULL;
1122
1123 part->size = sz;
1124 return 0;
1125}
1126
c1b9d935
LP
1127static int message_add_offset(sd_bus_message *m, size_t offset) {
1128 struct bus_container *c;
1129
1130 assert(m);
6647dc66 1131 assert(BUS_MESSAGE_IS_GVARIANT(m));
c1b9d935
LP
1132
1133 /* Add offset to current container, unless this is the first
1134 * item in it, which will have the 0 offset, which we can
1135 * ignore. */
1136 c = message_get_container(m);
1137
1138 if (!c->need_offsets)
1139 return 0;
1140
306f07be 1141 if (!GREEDY_REALLOC(c->offsets, c->offsets_allocated, c->n_offsets + 1))
c1b9d935
LP
1142 return -ENOMEM;
1143
1144 c->offsets[c->n_offsets++] = offset;
1145 return 0;
1146}
1147
453a0c29 1148static void message_extend_containers(sd_bus_message *m, size_t expand) {
de1c301e 1149 struct bus_container *c;
453a0c29
LP
1150
1151 assert(m);
1152
1153 if (expand <= 0)
1154 return;
1155
1156 /* Update counters */
c1b9d935
LP
1157 for (c = m->containers; c < m->containers + m->n_containers; c++) {
1158
453a0c29
LP
1159 if (c->array_size)
1160 *c->array_size += expand;
c1b9d935 1161 }
453a0c29
LP
1162}
1163
c1b9d935 1164static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
f3097697 1165 size_t start_body, end_body, padding, added;
bc7fd8cd
LP
1166 void *p;
1167 int r;
de1c301e
LP
1168
1169 assert(m);
9a17484d 1170 assert(align > 0);
bc7fd8cd 1171 assert(!m->sealed);
35460afc
LP
1172
1173 if (m->poisoned)
1174 return NULL;
de1c301e 1175
bc7fd8cd
LP
1176 start_body = ALIGN_TO((size_t) m->header->body_size, align);
1177 end_body = start_body + sz;
1178
1179 padding = start_body - m->header->body_size;
1180 added = padding + sz;
1181
1182 /* Check for 32bit overflows */
1183 if (end_body > (size_t) ((uint32_t) -1)) {
1184 m->poisoned = true;
de1c301e 1185 return NULL;
bc7fd8cd 1186 }
de1c301e 1187
f3097697
LP
1188 if (added > 0) {
1189 struct bus_body_part *part = NULL;
1190 bool add_new_part;
1191
1192 add_new_part =
1193 m->n_body_parts <= 0 ||
1194 m->body_end->sealed ||
1195 padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
1196
1197 if (add_new_part) {
1198 if (padding > 0) {
1199 part = message_append_part(m);
1200 if (!part)
1201 return NULL;
1202
1203 part_zero(part, padding);
1204 }
de1c301e 1205
bc7fd8cd
LP
1206 part = message_append_part(m);
1207 if (!part)
1208 return NULL;
1209
f3097697
LP
1210 r = part_make_space(m, part, sz, &p);
1211 if (r < 0)
1212 return NULL;
1213 } else {
1214 struct bus_container *c;
1215 void *op;
1216 size_t os, start_part, end_part;
bc7fd8cd 1217
f3097697
LP
1218 part = m->body_end;
1219 op = part->data;
1220 os = part->size;
bc7fd8cd 1221
f3097697
LP
1222 start_part = ALIGN_TO(part->size, align);
1223 end_part = start_part + sz;
bc7fd8cd 1224
f3097697
LP
1225 r = part_make_space(m, part, end_part, &p);
1226 if (r < 0)
1227 return NULL;
bc7fd8cd 1228
f3097697
LP
1229 if (padding > 0) {
1230 memset(p, 0, padding);
1231 p = (uint8_t*) p + padding;
1232 }
bc7fd8cd 1233
f3097697
LP
1234 /* Readjust pointers */
1235 for (c = m->containers; c < m->containers + m->n_containers; c++)
1236 c->array_size = adjust_pointer(c->array_size, op, os, part->data);
bc7fd8cd 1237
f3097697 1238 m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
de1c301e 1239 }
f3097697
LP
1240 } else
1241 /* Return something that is not NULL and is aligned */
1242 p = (uint8_t *) NULL + align;
de1c301e 1243
bc7fd8cd 1244 m->header->body_size = end_body;
453a0c29 1245 message_extend_containers(m, added);
de1c301e 1246
c1b9d935
LP
1247 if (add_offset) {
1248 r = message_add_offset(m, end_body);
1249 if (r < 0) {
1250 m->poisoned = true;
1251 return NULL;
1252 }
1253 }
1254
de1c301e
LP
1255 return p;
1256}
1257
c1b9d935
LP
1258static int message_push_fd(sd_bus_message *m, int fd) {
1259 int *f, copy;
1260
1261 assert(m);
1262
1263 if (fd < 0)
1264 return -EINVAL;
1265
1266 if (!m->allow_fds)
1267 return -ENOTSUP;
1268
1269 copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
1270 if (copy < 0)
1271 return -errno;
1272
1273 f = realloc(m->fds, sizeof(int) * (m->n_fds + 1));
1274 if (!f) {
1275 m->poisoned = true;
1276 close_nointr_nofail(copy);
1277 return -ENOMEM;
1278 }
1279
1280 m->fds = f;
1281 m->fds[m->n_fds] = copy;
1282 m->free_fds = true;
1283
1284 return copy;
1285}
1286
de1c301e 1287int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
c1b9d935 1288 _cleanup_close_ int fd = -1;
de1c301e 1289 struct bus_container *c;
27f6e5c7 1290 ssize_t align, sz;
de1c301e 1291 void *a;
de1c301e 1292
9d6c7c82 1293 assert_return(m, -EINVAL);
9d6c7c82
LP
1294 assert_return(!m->sealed, -EPERM);
1295 assert_return(bus_type_is_basic(type), -EINVAL);
1296 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
1297
1298 c = message_get_container(m);
1299
1300 if (c->signature && c->signature[c->index]) {
1301 /* Container signature is already set */
1302
1303 if (c->signature[c->index] != type)
9a17484d 1304 return -ENXIO;
de1c301e 1305 } else {
5cbe7492
LP
1306 char *e;
1307
de1c301e
LP
1308 /* Maybe we can append to the signature? But only if this is the top-level container*/
1309 if (c->enclosing != 0)
9a17484d 1310 return -ENXIO;
de1c301e
LP
1311
1312 e = strextend(&c->signature, CHAR_TO_STR(type), NULL);
bc7fd8cd
LP
1313 if (!e) {
1314 m->poisoned = true;
de1c301e 1315 return -ENOMEM;
bc7fd8cd 1316 }
de1c301e
LP
1317 }
1318
6647dc66 1319 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
1320 uint8_t u8;
1321 uint32_t u32;
de1c301e 1322
c1b9d935 1323 switch (type) {
cd6f997f 1324
c1b9d935
LP
1325 case SD_BUS_TYPE_SIGNATURE:
1326 case SD_BUS_TYPE_STRING:
1327 p = strempty(p);
b8beb278 1328
c1b9d935
LP
1329 /* Fall through... */
1330 case SD_BUS_TYPE_OBJECT_PATH:
1331 if (!p)
1332 return -EINVAL;
cd6f997f 1333
c1b9d935
LP
1334 align = 1;
1335 sz = strlen(p) + 1;
1336 break;
de1c301e 1337
c1b9d935 1338 case SD_BUS_TYPE_BOOLEAN:
b8beb278 1339
c1b9d935
LP
1340 u8 = p && *(int*) p;
1341 p = &u8;
cd6f997f 1342
c1b9d935
LP
1343 align = sz = 1;
1344 break;
de1c301e 1345
c1b9d935 1346 case SD_BUS_TYPE_UNIX_FD:
b3273daf 1347
c1b9d935
LP
1348 if (!p)
1349 return -EINVAL;
15912917 1350
c1b9d935
LP
1351 fd = message_push_fd(m, *(int*) p);
1352 if (fd < 0)
1353 return fd;
de1c301e 1354
c1b9d935
LP
1355 u32 = m->n_fds;
1356 p = &u32;
de1c301e 1357
c1b9d935
LP
1358 align = sz = 4;
1359 break;
2c93b4ef 1360
c1b9d935
LP
1361 default:
1362 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
6647dc66 1363 sz = bus_gvariant_get_size(CHAR_TO_STR(type));
c1b9d935 1364 break;
15912917
KS
1365 }
1366
c1b9d935
LP
1367 assert(align > 0);
1368 assert(sz > 0);
2c93b4ef 1369
c1b9d935
LP
1370 a = message_extend_body(m, align, sz, true);
1371 if (!a)
1372 return -ENOMEM;
2c93b4ef 1373
c1b9d935 1374 memcpy(a, p, sz);
2c93b4ef 1375
c1b9d935
LP
1376 if (stored)
1377 *stored = (const uint8_t*) a;
2c93b4ef 1378
c1b9d935
LP
1379 } else {
1380 uint32_t u32;
2c93b4ef 1381
c1b9d935 1382 switch (type) {
2c93b4ef 1383
c1b9d935
LP
1384 case SD_BUS_TYPE_STRING:
1385 /* To make things easy we'll serialize a NULL string
1386 * into the empty string */
1387 p = strempty(p);
b3273daf 1388
c1b9d935
LP
1389 /* Fall through... */
1390 case SD_BUS_TYPE_OBJECT_PATH:
de1c301e 1391
c1b9d935
LP
1392 if (!p)
1393 return -EINVAL;
de1c301e 1394
c1b9d935
LP
1395 align = 4;
1396 sz = 4 + strlen(p) + 1;
1397 break;
de1c301e 1398
c1b9d935 1399 case SD_BUS_TYPE_SIGNATURE:
de1c301e 1400
c1b9d935 1401 p = strempty(p);
de1c301e 1402
c1b9d935
LP
1403 align = 1;
1404 sz = 1 + strlen(p) + 1;
1405 break;
de1c301e 1406
c1b9d935 1407 case SD_BUS_TYPE_BOOLEAN:
2c93b4ef 1408
c1b9d935 1409 u32 = p && *(int*) p;
6647dc66
LP
1410 p = &u32;
1411
c1b9d935
LP
1412 align = sz = 4;
1413 break;
2c93b4ef 1414
c1b9d935 1415 case SD_BUS_TYPE_UNIX_FD:
de1c301e 1416
c1b9d935
LP
1417 if (!p)
1418 return -EINVAL;
de1c301e 1419
c1b9d935
LP
1420 fd = message_push_fd(m, *(int*) p);
1421 if (fd < 0)
1422 return fd;
1423
1424 u32 = m->n_fds;
1425 p = &u32;
1426
1427 align = sz = 4;
1428 break;
1429
1430 default:
1431 align = bus_type_get_alignment(type);
1432 sz = bus_type_get_size(type);
1433 break;
1434 }
1435
1436 assert(align > 0);
1437 assert(sz > 0);
1438
1439 a = message_extend_body(m, align, sz, false);
1440 if (!a)
1441 return -ENOMEM;
1442
1443 if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) {
1444 *(uint32_t*) a = sz - 5;
1445 memcpy((uint8_t*) a + 4, p, sz - 4);
1446
1447 if (stored)
1448 *stored = (const uint8_t*) a + 4;
1449
1450 } else if (type == SD_BUS_TYPE_SIGNATURE) {
ec260edc 1451 *(uint8_t*) a = sz - 2;
c1b9d935
LP
1452 memcpy((uint8_t*) a + 1, p, sz - 1);
1453
1454 if (stored)
1455 *stored = (const uint8_t*) a + 1;
1456 } else {
1457 memcpy(a, p, sz);
1458
1459 if (stored)
1460 *stored = a;
1461 }
de1c301e
LP
1462 }
1463
c1b9d935
LP
1464 if (type == SD_BUS_TYPE_UNIX_FD)
1465 m->n_fds ++;
1466
de1c301e 1467 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 1468 c->index++;
de1c301e 1469
c1b9d935 1470 fd = -1;
de1c301e
LP
1471 return 0;
1472}
1473
d9f644e2 1474_public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) {
de1c301e
LP
1475 return message_append_basic(m, type, p, NULL);
1476}
1477
938bcbab
LP
1478_public_ int sd_bus_message_append_string_space(
1479 sd_bus_message *m,
1480 size_t size,
1481 char **s) {
1482
f8e013f8 1483 struct bus_container *c;
f8e013f8 1484 void *a;
f8e013f8 1485
9d6c7c82
LP
1486 assert_return(m, -EINVAL);
1487 assert_return(s, -EINVAL);
1488 assert_return(!m->sealed, -EPERM);
1489 assert_return(!m->poisoned, -ESTALE);
f8e013f8
LP
1490
1491 c = message_get_container(m);
1492
1493 if (c->signature && c->signature[c->index]) {
1494 /* Container signature is already set */
1495
1496 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
1497 return -ENXIO;
1498 } else {
5cbe7492
LP
1499 char *e;
1500
f8e013f8
LP
1501 /* Maybe we can append to the signature? But only if this is the top-level container*/
1502 if (c->enclosing != 0)
1503 return -ENXIO;
1504
1505 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
bc7fd8cd
LP
1506 if (!e) {
1507 m->poisoned = true;
f8e013f8 1508 return -ENOMEM;
bc7fd8cd 1509 }
f8e013f8
LP
1510 }
1511
6647dc66 1512 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
1513 a = message_extend_body(m, 1, size + 1, true);
1514 if (!a)
1515 return -ENOMEM;
1516
1517 *s = a;
1518 } else {
1519 a = message_extend_body(m, 4, 4 + size + 1, false);
1520 if (!a)
1521 return -ENOMEM;
f8e013f8 1522
c1b9d935
LP
1523 *(uint32_t*) a = size;
1524 *s = (char*) a + 4;
1525 }
f8e013f8
LP
1526
1527 (*s)[size] = 0;
1528
1529 if (c->enclosing != SD_BUS_TYPE_ARRAY)
1530 c->index++;
1531
1532 return 0;
f8e013f8
LP
1533}
1534
938bcbab
LP
1535_public_ int sd_bus_message_append_string_iovec(
1536 sd_bus_message *m,
1537 const struct iovec *iov,
1538 unsigned n) {
1539
1540 size_t size;
1541 unsigned i;
1542 char *p;
1543 int r;
1544
1545 assert_return(m, -EINVAL);
1546 assert_return(!m->sealed, -EPERM);
1547 assert_return(iov || n == 0, -EINVAL);
1548 assert_return(!m->poisoned, -ESTALE);
1549
1550 size = IOVEC_TOTAL_SIZE(iov, n);
1551
1552 r = sd_bus_message_append_string_space(m, size, &p);
1553 if (r < 0)
1554 return r;
1555
1556 for (i = 0; i < n; i++) {
1557
1558 if (iov[i].iov_base)
1559 memcpy(p, iov[i].iov_base, iov[i].iov_len);
1560 else
1561 memset(p, ' ', iov[i].iov_len);
1562
1563 p += iov[i].iov_len;
1564 }
1565
1566 return 0;
1567}
1568
de1c301e
LP
1569static int bus_message_open_array(
1570 sd_bus_message *m,
1571 struct bus_container *c,
1572 const char *contents,
c1b9d935
LP
1573 uint32_t **array_size,
1574 size_t *begin,
1575 bool *need_offsets) {
de1c301e 1576
9a17484d 1577 unsigned nindex;
c1b9d935 1578 int alignment, r;
de1c301e
LP
1579
1580 assert(m);
1581 assert(c);
1582 assert(contents);
1583 assert(array_size);
c1b9d935
LP
1584 assert(begin);
1585 assert(need_offsets);
de1c301e 1586
29ddb38f 1587 if (!signature_is_single(contents, true))
de1c301e
LP
1588 return -EINVAL;
1589
de1c301e
LP
1590 if (c->signature && c->signature[c->index]) {
1591
1592 /* Verify the existing signature */
1593
1594 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
9a17484d 1595 return -ENXIO;
de1c301e
LP
1596
1597 if (!startswith(c->signature + c->index + 1, contents))
9a17484d 1598 return -ENXIO;
de1c301e
LP
1599
1600 nindex = c->index + 1 + strlen(contents);
1601 } else {
5cbe7492
LP
1602 char *e;
1603
de1c301e 1604 if (c->enclosing != 0)
9a17484d 1605 return -ENXIO;
de1c301e
LP
1606
1607 /* Extend the existing signature */
1608
1609 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL);
bc7fd8cd
LP
1610 if (!e) {
1611 m->poisoned = true;
de1c301e 1612 return -ENOMEM;
bc7fd8cd 1613 }
de1c301e
LP
1614
1615 nindex = e - c->signature;
1616 }
1617
6647dc66 1618 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
1619 alignment = bus_gvariant_get_alignment(contents);
1620 if (alignment < 0)
1621 return alignment;
de1c301e 1622
c1b9d935
LP
1623 /* Add alignment padding and add to offset list */
1624 if (!message_extend_body(m, alignment, 0, false))
1625 return -ENOMEM;
de1c301e 1626
c1b9d935
LP
1627 r = bus_gvariant_is_fixed_size(contents);
1628 if (r < 0)
1629 return r;
1630
1631 *begin = m->header->body_size;
1632 *need_offsets = r == 0;
1633 } else {
1634 void *a, *op;
1635 size_t os;
1636 struct bus_body_part *o;
1637
1638 alignment = bus_type_get_alignment(contents[0]);
1639 if (alignment < 0)
1640 return alignment;
1641
1642 a = message_extend_body(m, 4, 4, false);
1643 if (!a)
1644 return -ENOMEM;
1645
1646 o = m->body_end;
1647 op = m->body_end->data;
1648 os = m->body_end->size;
1649
1650 /* Add alignment between size and first element */
1651 if (!message_extend_body(m, alignment, 0, false))
1652 return -ENOMEM;
1653
1654 /* location of array size might have changed so let's readjust a */
1655 if (o == m->body_end)
1656 a = adjust_pointer(a, op, os, m->body_end->data);
1657
1658 *(uint32_t*) a = 0;
1659 *array_size = a;
1660 }
de1c301e
LP
1661
1662 if (c->enclosing != SD_BUS_TYPE_ARRAY)
1663 c->index = nindex;
1664
de1c301e
LP
1665 return 0;
1666}
1667
1668static int bus_message_open_variant(
1669 sd_bus_message *m,
1670 struct bus_container *c,
1671 const char *contents) {
1672
de1c301e
LP
1673 assert(m);
1674 assert(c);
1675 assert(contents);
1676
29ddb38f 1677 if (!signature_is_single(contents, false))
de1c301e
LP
1678 return -EINVAL;
1679
1680 if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
1681 return -EINVAL;
1682
1683 if (c->signature && c->signature[c->index]) {
1684
1685 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
9a17484d 1686 return -ENXIO;
de1c301e
LP
1687
1688 } else {
5cbe7492
LP
1689 char *e;
1690
de1c301e 1691 if (c->enclosing != 0)
9a17484d 1692 return -ENXIO;
de1c301e
LP
1693
1694 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL);
bc7fd8cd
LP
1695 if (!e) {
1696 m->poisoned = true;
de1c301e 1697 return -ENOMEM;
bc7fd8cd 1698 }
de1c301e
LP
1699 }
1700
6647dc66 1701 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
1702 /* Variants are always aligned to 8 */
1703
1704 if (!message_extend_body(m, 8, 0, false))
1705 return -ENOMEM;
1706
1707 } else {
1708 size_t l;
1709 void *a;
de1c301e 1710
c1b9d935
LP
1711 l = strlen(contents);
1712 a = message_extend_body(m, 1, 1 + l + 1, false);
1713 if (!a)
1714 return -ENOMEM;
1715
1716 *(uint8_t*) a = l;
1717 memcpy((uint8_t*) a + 1, contents, l + 1);
1718 }
de1c301e
LP
1719
1720 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 1721 c->index++;
de1c301e
LP
1722
1723 return 0;
1724}
1725
1726static int bus_message_open_struct(
1727 sd_bus_message *m,
1728 struct bus_container *c,
c1b9d935
LP
1729 const char *contents,
1730 size_t *begin,
1731 bool *need_offsets) {
de1c301e
LP
1732
1733 size_t nindex;
c1b9d935 1734 int r;
de1c301e
LP
1735
1736 assert(m);
1737 assert(c);
1738 assert(contents);
c1b9d935
LP
1739 assert(begin);
1740 assert(need_offsets);
de1c301e
LP
1741
1742 if (!signature_is_valid(contents, false))
1743 return -EINVAL;
1744
1745 if (c->signature && c->signature[c->index]) {
1746 size_t l;
1747
1748 l = strlen(contents);
1749
1750 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
1751 !startswith(c->signature + c->index + 1, contents) ||
1752 c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
9a17484d 1753 return -ENXIO;
de1c301e
LP
1754
1755 nindex = c->index + 1 + l + 1;
1756 } else {
5cbe7492
LP
1757 char *e;
1758
de1c301e 1759 if (c->enclosing != 0)
9a17484d 1760 return -ENXIO;
de1c301e
LP
1761
1762 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL);
bc7fd8cd
LP
1763 if (!e) {
1764 m->poisoned = true;
de1c301e 1765 return -ENOMEM;
bc7fd8cd 1766 }
de1c301e
LP
1767
1768 nindex = e - c->signature;
1769 }
1770
6647dc66 1771 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
1772 int alignment;
1773
1774 alignment = bus_gvariant_get_alignment(contents);
1775 if (alignment < 0)
1776 return alignment;
1777
1778 if (!message_extend_body(m, alignment, 0, false))
1779 return -ENOMEM;
1780
1781 r = bus_gvariant_is_fixed_size(contents);
1782 if (r < 0)
1783 return r;
1784
1785 *begin = m->header->body_size;
1786 *need_offsets = r == 0;
1787 } else {
1788 /* Align contents to 8 byte boundary */
1789 if (!message_extend_body(m, 8, 0, false))
1790 return -ENOMEM;
1791 }
de1c301e
LP
1792
1793 if (c->enclosing != SD_BUS_TYPE_ARRAY)
1794 c->index = nindex;
1795
1796 return 0;
1797}
1798
1799static int bus_message_open_dict_entry(
1800 sd_bus_message *m,
1801 struct bus_container *c,
c1b9d935
LP
1802 const char *contents,
1803 size_t *begin,
1804 bool *need_offsets) {
de1c301e 1805
c1b9d935 1806 int r;
de1c301e
LP
1807
1808 assert(m);
1809 assert(c);
1810 assert(contents);
c1b9d935
LP
1811 assert(begin);
1812 assert(need_offsets);
de1c301e
LP
1813
1814 if (!signature_is_pair(contents))
1815 return -EINVAL;
1816
1817 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 1818 return -ENXIO;
de1c301e
LP
1819
1820 if (c->signature && c->signature[c->index]) {
1821 size_t l;
1822
1823 l = strlen(contents);
1824
1825 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
1826 !startswith(c->signature + c->index + 1, contents) ||
1827 c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
9a17484d 1828 return -ENXIO;
de1c301e 1829 } else
9a17484d 1830 return -ENXIO;
de1c301e 1831
6647dc66 1832 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935 1833 int alignment;
de1c301e 1834
c1b9d935
LP
1835 alignment = bus_gvariant_get_alignment(contents);
1836 if (alignment < 0)
1837 return alignment;
1838
1839 if (!message_extend_body(m, alignment, 0, false))
1840 return -ENOMEM;
1841
1842 r = bus_gvariant_is_fixed_size(contents);
1843 if (r < 0)
1844 return r;
1845
1846 *begin = m->header->body_size;
1847 *need_offsets = r == 0;
1848 } else {
1849 /* Align contents to 8 byte boundary */
1850 if (!message_extend_body(m, 8, 0, false))
1851 return -ENOMEM;
1852 }
de1c301e
LP
1853
1854 return 0;
1855}
1856
d9f644e2 1857_public_ int sd_bus_message_open_container(
de1c301e
LP
1858 sd_bus_message *m,
1859 char type,
1860 const char *contents) {
1861
9a17484d 1862 struct bus_container *c, *w;
de1c301e 1863 uint32_t *array_size = NULL;
9a17484d 1864 char *signature;
c1b9d935
LP
1865 size_t before, begin;
1866 bool need_offsets = false;
de1c301e
LP
1867 int r;
1868
9d6c7c82
LP
1869 assert_return(m, -EINVAL);
1870 assert_return(!m->sealed, -EPERM);
1871 assert_return(contents, -EINVAL);
1872 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
1873
1874 /* Make sure we have space for one more container */
306f07be 1875 if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1)) {
bc7fd8cd 1876 m->poisoned = true;
de1c301e 1877 return -ENOMEM;
bc7fd8cd
LP
1878 }
1879
de1c301e
LP
1880 c = message_get_container(m);
1881
1882 signature = strdup(contents);
bc7fd8cd
LP
1883 if (!signature) {
1884 m->poisoned = true;
de1c301e 1885 return -ENOMEM;
bc7fd8cd 1886 }
de1c301e 1887
b3af9646
LP
1888 /* Save old index in the parent container, in case we have to
1889 * abort this container */
1890 c->saved_index = c->index;
1891 before = m->header->body_size;
1892
de1c301e 1893 if (type == SD_BUS_TYPE_ARRAY)
c1b9d935 1894 r = bus_message_open_array(m, c, contents, &array_size, &begin, &need_offsets);
de1c301e
LP
1895 else if (type == SD_BUS_TYPE_VARIANT)
1896 r = bus_message_open_variant(m, c, contents);
1897 else if (type == SD_BUS_TYPE_STRUCT)
c1b9d935 1898 r = bus_message_open_struct(m, c, contents, &begin, &need_offsets);
de1c301e 1899 else if (type == SD_BUS_TYPE_DICT_ENTRY)
c1b9d935 1900 r = bus_message_open_dict_entry(m, c, contents, &begin, &need_offsets);
de1c301e
LP
1901 else
1902 r = -EINVAL;
1903
1904 if (r < 0) {
1905 free(signature);
1906 return r;
1907 }
1908
1909 /* OK, let's fill it in */
306f07be 1910 w = m->containers + m->n_containers++;
9a17484d
LP
1911 w->enclosing = type;
1912 w->signature = signature;
1913 w->index = 0;
1914 w->array_size = array_size;
b3af9646 1915 w->before = before;
c1b9d935 1916 w->begin = begin;
306f07be 1917 w->n_offsets = w->offsets_allocated = 0;
c1b9d935
LP
1918 w->offsets = NULL;
1919 w->need_offsets = need_offsets;
1920
1921 return 0;
1922}
1923
6647dc66 1924static size_t determine_word_size(size_t sz, size_t extra) {
224a1ed4 1925 if (sz + extra <= 0xFF)
6647dc66
LP
1926 return 1;
1927 else if (sz + extra*2 <= 0xFFFF)
1928 return 2;
1929 else if (sz + extra*4 <= 0xFFFFFFFF)
1930 return 4;
1931 else
1932 return 8;
1933}
1934
1935static size_t read_word_le(void *p, size_t sz) {
1936 union {
1937 uint16_t u16;
1938 uint32_t u32;
1939 uint64_t u64;
1940 } x;
1941
1942 assert(p);
1943
1944 if (sz == 1)
1945 return *(uint8_t*) p;
1946
1947 memcpy(&x, p, sz);
1948
1949 if (sz == 2)
1950 return le16toh(x.u16);
1951 else if (sz == 4)
1952 return le32toh(x.u32);
1ffee377 1953 else if (sz == 8)
6647dc66
LP
1954 return le64toh(x.u64);
1955
1956 assert_not_reached("unknown word width");
1957}
1958
1959static void write_word_le(void *p, size_t sz, size_t value) {
1960 union {
1961 uint16_t u16;
1962 uint32_t u32;
1963 uint64_t u64;
1964 } x;
1965
1966 assert(p);
1967 assert(sz == 8 || (value < (1ULL << (sz*8))));
1968
1969 if (sz == 1) {
1970 *(uint8_t*) p = value;
1971 return;
1972 } else if (sz == 2)
1973 x.u16 = htole16((uint16_t) value);
1974 else if (sz == 4)
1975 x.u32 = htole32((uint32_t) value);
1976 else if (sz == 8)
1977 x.u64 = htole64((uint64_t) value);
1978 else
1979 assert_not_reached("unknown word width");
1980
1981 memcpy(p, &x, sz);
1982}
1983
c1b9d935
LP
1984static int bus_message_close_array(sd_bus_message *m, struct bus_container *c) {
1985
1986 assert(m);
1987 assert(c);
1988
6647dc66 1989 if (!BUS_MESSAGE_IS_GVARIANT(m))
c1b9d935
LP
1990 return 0;
1991
1992 if (c->need_offsets) {
6647dc66 1993 size_t payload, sz, i;
c1b9d935 1994 uint8_t *a;
c1b9d935
LP
1995
1996 /* Variable-width arrays */
1997
6647dc66
LP
1998 payload = c->n_offsets > 0 ? c->offsets[c->n_offsets-1] - c->begin : 0;
1999 sz = determine_word_size(payload, c->n_offsets);
c1b9d935 2000
6647dc66
LP
2001 a = message_extend_body(m, 1, sz * c->n_offsets, true);
2002 if (!a)
2003 return -ENOMEM;
c1b9d935 2004
6647dc66
LP
2005 for (i = 0; i < c->n_offsets; i++)
2006 write_word_le(a + sz*i, sz, c->offsets[i] - c->begin);
c1b9d935
LP
2007 } else {
2008 void *a;
2009
2010 /* Fixed-width or empty arrays */
2011
2012 a = message_extend_body(m, 1, 0, true); /* let's add offset to parent */
2013 if (!a)
2014 return -ENOMEM;
2015 }
2016
2017 return 0;
2018}
2019
2020static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c) {
2021 uint8_t *a;
2022 size_t l;
2023
2024 assert(m);
2025 assert(c);
2026
6647dc66 2027 if (!BUS_MESSAGE_IS_GVARIANT(m))
c1b9d935
LP
2028 return 0;
2029
2030 l = strlen(c->signature);
2031
2032 a = message_extend_body(m, 1, 1 + l, true);
2033 if (!a)
2034 return -ENOMEM;
2035
2036 a[0] = 0;
2037 memcpy(a+1, c->signature, l);
2038
2039 return 0;
2040}
2041
2042static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, bool add_offset) {
2043 size_t n_variable = 0;
2044 unsigned i = 0;
2045 const char *p;
2046 uint8_t *a;
2047 int r;
2048
2049 assert(m);
2050 assert(c);
2051
6647dc66 2052 if (!BUS_MESSAGE_IS_GVARIANT(m))
c1b9d935
LP
2053 return 0;
2054
d6385068 2055 p = strempty(c->signature);
c1b9d935
LP
2056 while (*p != 0) {
2057 size_t n;
2058
2059 r = signature_element_length(p, &n);
2060 if (r < 0)
2061 return r;
2062 else {
2063 char t[n+1];
2064
2065 memcpy(t, p, n);
2066 t[n] = 0;
2067
2068 r = bus_gvariant_is_fixed_size(t);
2069 if (r < 0)
2070 return r;
2071 }
2072
8f19720d 2073 assert(!c->need_offsets || i <= c->n_offsets);
c1b9d935
LP
2074
2075 /* We need to add an offset for each item that has a
2076 * variable size and that is not the last one in the
2077 * list */
2078 if (r == 0 && p[n] != 0)
2079 n_variable++;
c1b9d935
LP
2080
2081 i++;
2082 p += n;
2083 }
2084
8f19720d
LP
2085 assert(!c->need_offsets || i == c->n_offsets);
2086 assert(c->need_offsets || n_variable == 0);
6647dc66 2087
c1b9d935 2088 if (n_variable <= 0) {
6647dc66 2089 a = message_extend_body(m, 1, 0, add_offset);
c1b9d935
LP
2090 if (!a)
2091 return -ENOMEM;
2092 } else {
6647dc66 2093 size_t sz;
c1b9d935
LP
2094 unsigned j;
2095
6647dc66 2096 assert(c->offsets[c->n_offsets-1] == m->header->body_size);
c1b9d935 2097
6647dc66 2098 sz = determine_word_size(m->header->body_size - c->begin, n_variable);
c1b9d935 2099
6647dc66 2100 a = message_extend_body(m, 1, sz * n_variable, add_offset);
c1b9d935
LP
2101 if (!a)
2102 return -ENOMEM;
2103
d6385068 2104 p = strempty(c->signature);
c1b9d935 2105 for (i = 0, j = 0; i < c->n_offsets; i++) {
c1b9d935 2106 unsigned k;
6647dc66
LP
2107 size_t n;
2108
2109 r = signature_element_length(p, &n);
2110 if (r < 0)
2111 return r;
2112 else {
2113 char t[n+1];
2114
2115 memcpy(t, p, n);
2116 t[n] = 0;
2117
2118 p += n;
c1b9d935 2119
6647dc66
LP
2120 r = bus_gvariant_is_fixed_size(t);
2121 if (r < 0)
2122 return r;
2123 if (r > 0 || p[0] == 0)
2124 continue;
2125 }
c1b9d935 2126
c1b9d935
LP
2127 k = n_variable - 1 - j;
2128
6647dc66 2129 write_word_le(a + k * sz, sz, c->offsets[i] - c->begin);
c1b9d935
LP
2130
2131 j++;
2132 }
2133 }
de1c301e
LP
2134
2135 return 0;
2136}
2137
d9f644e2 2138_public_ int sd_bus_message_close_container(sd_bus_message *m) {
de1c301e 2139 struct bus_container *c;
c1b9d935 2140 int r;
de1c301e 2141
9d6c7c82
LP
2142 assert_return(m, -EINVAL);
2143 assert_return(!m->sealed, -EPERM);
2144 assert_return(m->n_containers > 0, -EINVAL);
2145 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
2146
2147 c = message_get_container(m);
c1b9d935 2148
de1c301e 2149 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 2150 if (c->signature && c->signature[c->index] != 0)
de1c301e
LP
2151 return -EINVAL;
2152
de1c301e
LP
2153 m->n_containers--;
2154
c1b9d935
LP
2155 if (c->enclosing == SD_BUS_TYPE_ARRAY)
2156 r = bus_message_close_array(m, c);
2157 else if (c->enclosing == SD_BUS_TYPE_VARIANT)
2158 r = bus_message_close_variant(m, c);
2159 else if (c->enclosing == SD_BUS_TYPE_STRUCT || c->enclosing == SD_BUS_TYPE_DICT_ENTRY)
2160 r = bus_message_close_struct(m, c, true);
2161 else
2162 assert_not_reached("Unknown container type");
2163
2164 free(c->signature);
6647dc66
LP
2165 free(c->offsets);
2166
c1b9d935 2167 return r;
de1c301e
LP
2168}
2169
1b492614
LP
2170typedef struct {
2171 const char *types;
2172 unsigned n_struct;
2173 unsigned n_array;
2174} TypeStack;
2175
2176static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) {
2177 assert(stack);
2178 assert(max > 0);
2179
2180 if (*i >= max)
2181 return -EINVAL;
2182
2183 stack[*i].types = types;
2184 stack[*i].n_struct = n_struct;
2185 stack[*i].n_array = n_array;
2186 (*i)++;
2187
2188 return 0;
2189}
2190
2191static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) {
2192 assert(stack);
2193 assert(max > 0);
2194 assert(types);
2195 assert(n_struct);
2196 assert(n_array);
2197
2198 if (*i <= 0)
2199 return 0;
2200
2201 (*i)--;
2202 *types = stack[*i].types;
2203 *n_struct = stack[*i].n_struct;
2204 *n_array = stack[*i].n_array;
2205
2206 return 1;
2207}
2208
917b5dc7 2209int bus_message_append_ap(
de1c301e
LP
2210 sd_bus_message *m,
2211 const char *types,
2212 va_list ap) {
2213
1b492614
LP
2214 unsigned n_array, n_struct;
2215 TypeStack stack[BUS_CONTAINER_DEPTH];
2216 unsigned stack_ptr = 0;
de1c301e
LP
2217 int r;
2218
2219 assert(m);
88d331d5
LP
2220
2221 if (!types)
2222 return 0;
de1c301e 2223
1b492614
LP
2224 n_array = (unsigned) -1;
2225 n_struct = strlen(types);
2226
2227 for (;;) {
2228 const char *t;
2229
2230 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
2231 r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
2232 if (r < 0)
2233 return r;
2234 if (r == 0)
2235 break;
2236
2237 r = sd_bus_message_close_container(m);
2238 if (r < 0)
2239 return r;
2240
2241 continue;
2242 }
2243
2244 t = types;
2245 if (n_array != (unsigned) -1)
2246 n_array --;
2247 else {
2248 types ++;
2249 n_struct--;
2250 }
2251
de1c301e
LP
2252 switch (*t) {
2253
2254 case SD_BUS_TYPE_BYTE: {
2255 uint8_t x;
2256
2257 x = (uint8_t) va_arg(ap, int);
2258 r = sd_bus_message_append_basic(m, *t, &x);
2259 break;
2260 }
2261
2262 case SD_BUS_TYPE_BOOLEAN:
2263 case SD_BUS_TYPE_INT32:
9a17484d
LP
2264 case SD_BUS_TYPE_UINT32:
2265 case SD_BUS_TYPE_UNIX_FD: {
de1c301e
LP
2266 uint32_t x;
2267
9a17484d
LP
2268 /* We assume a boolean is the same as int32_t */
2269 assert_cc(sizeof(int32_t) == sizeof(int));
2270
de1c301e
LP
2271 x = va_arg(ap, uint32_t);
2272 r = sd_bus_message_append_basic(m, *t, &x);
2273 break;
2274 }
2275
2276 case SD_BUS_TYPE_INT16:
2277 case SD_BUS_TYPE_UINT16: {
2278 uint16_t x;
2279
2280 x = (uint16_t) va_arg(ap, int);
2281 r = sd_bus_message_append_basic(m, *t, &x);
2282 break;
2283 }
2284
2285 case SD_BUS_TYPE_INT64:
2286 case SD_BUS_TYPE_UINT64:
2287 case SD_BUS_TYPE_DOUBLE: {
2288 uint64_t x;
2289
2290 x = va_arg(ap, uint64_t);
2291 r = sd_bus_message_append_basic(m, *t, &x);
2292 break;
2293 }
2294
2295 case SD_BUS_TYPE_STRING:
2296 case SD_BUS_TYPE_OBJECT_PATH:
2297 case SD_BUS_TYPE_SIGNATURE: {
2298 const char *x;
2299
2300 x = va_arg(ap, const char*);
2301 r = sd_bus_message_append_basic(m, *t, x);
2302 break;
2303 }
2304
de1c301e 2305 case SD_BUS_TYPE_ARRAY: {
de1c301e
LP
2306 size_t k;
2307
2308 r = signature_element_length(t + 1, &k);
2309 if (r < 0)
2310 return r;
2311
2312 {
2313 char s[k + 1];
de1c301e
LP
2314 memcpy(s, t + 1, k);
2315 s[k] = 0;
de1c301e
LP
2316
2317 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
2318 if (r < 0)
2319 return r;
1b492614 2320 }
de1c301e 2321
1b492614
LP
2322 if (n_array == (unsigned) -1) {
2323 types += k;
2324 n_struct -= k;
de1c301e
LP
2325 }
2326
1b492614
LP
2327 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2328 if (r < 0)
2329 return r;
2330
2331 types = t + 1;
2332 n_struct = k;
2333 n_array = va_arg(ap, unsigned);
2334
de1c301e
LP
2335 break;
2336 }
2337
2338 case SD_BUS_TYPE_VARIANT: {
2339 const char *s;
2340
2341 s = va_arg(ap, const char*);
2342 if (!s)
2343 return -EINVAL;
2344
2345 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, s);
2346 if (r < 0)
2347 return r;
2348
1b492614 2349 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
de1c301e
LP
2350 if (r < 0)
2351 return r;
2352
1b492614
LP
2353 types = s;
2354 n_struct = strlen(s);
2355 n_array = (unsigned) -1;
2356
de1c301e
LP
2357 break;
2358 }
2359
2360 case SD_BUS_TYPE_STRUCT_BEGIN:
2361 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
2362 size_t k;
2363
2364 r = signature_element_length(t, &k);
2365 if (r < 0)
2366 return r;
2367
2368 {
2369 char s[k - 1];
2370
2371 memcpy(s, t + 1, k - 2);
2372 s[k - 2] = 0;
2373
2374 r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
2375 if (r < 0)
2376 return r;
1b492614 2377 }
de1c301e 2378
1b492614
LP
2379 if (n_array == (unsigned) -1) {
2380 types += k - 1;
2381 n_struct -= k - 1;
2382 }
de1c301e 2383
1b492614
LP
2384 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2385 if (r < 0)
2386 return r;
de1c301e 2387
1b492614
LP
2388 types = t + 1;
2389 n_struct = k - 2;
2390 n_array = (unsigned) -1;
de1c301e
LP
2391
2392 break;
2393 }
2394
2395 default:
2396 r = -EINVAL;
2397 }
2398
2399 if (r < 0)
2400 return r;
2401 }
2402
ebcf1f97 2403 return 1;
de1c301e
LP
2404}
2405
d9f644e2 2406_public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
de1c301e
LP
2407 va_list ap;
2408 int r;
2409
9d6c7c82
LP
2410 assert_return(m, -EINVAL);
2411 assert_return(types, -EINVAL);
2412 assert_return(!m->sealed, -EPERM);
2413 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
2414
2415 va_start(ap, types);
917b5dc7 2416 r = bus_message_append_ap(m, types, ap);
de1c301e
LP
2417 va_end(ap);
2418
2419 return r;
2420}
2421
c1b9d935
LP
2422_public_ int sd_bus_message_append_array_space(
2423 sd_bus_message *m,
2424 char type,
2425 size_t size,
2426 void **ptr) {
2427
b3af9646
LP
2428 ssize_t align, sz;
2429 void *a;
2430 int r;
2431
9d6c7c82
LP
2432 assert_return(m, -EINVAL);
2433 assert_return(!m->sealed, -EPERM);
0039a203 2434 assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL);
9d6c7c82
LP
2435 assert_return(ptr || size == 0, -EINVAL);
2436 assert_return(!m->poisoned, -ESTALE);
b3af9646 2437
0039a203
LP
2438 /* alignment and size of the trivial types (except bool) is
2439 * identical for gvariant and dbus1 marshalling */
b3af9646
LP
2440 align = bus_type_get_alignment(type);
2441 sz = bus_type_get_size(type);
2442
2443 assert_se(align > 0);
2444 assert_se(sz > 0);
2445
2446 if (size % sz != 0)
2447 return -EINVAL;
2448
2449 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2450 if (r < 0)
2451 return r;
2452
c1b9d935 2453 a = message_extend_body(m, align, size, false);
bc7fd8cd
LP
2454 if (!a)
2455 return -ENOMEM;
b3af9646
LP
2456
2457 r = sd_bus_message_close_container(m);
2458 if (r < 0)
bc7fd8cd 2459 return r;
b3af9646
LP
2460
2461 *ptr = a;
2462 return 0;
b3af9646
LP
2463}
2464
d9f644e2
ZJS
2465_public_ int sd_bus_message_append_array(sd_bus_message *m,
2466 char type,
2467 const void *ptr,
2468 size_t size) {
b3af9646
LP
2469 int r;
2470 void *p;
2471
9d6c7c82
LP
2472 assert_return(m, -EINVAL);
2473 assert_return(!m->sealed, -EPERM);
2474 assert_return(bus_type_is_trivial(type), -EINVAL);
2475 assert_return(ptr || size == 0, -EINVAL);
2476 assert_return(!m->poisoned, -ESTALE);
b3af9646 2477
f8e013f8 2478 r = sd_bus_message_append_array_space(m, type, size, &p);
b3af9646
LP
2479 if (r < 0)
2480 return r;
2481
2482 if (size > 0)
2483 memcpy(p, ptr, size);
2484
2485 return 0;
2486}
2487
938bcbab
LP
2488_public_ int sd_bus_message_append_array_iovec(
2489 sd_bus_message *m,
2490 char type,
2491 const struct iovec *iov,
2492 unsigned n) {
2493
2494 size_t size;
2495 unsigned i;
2496 void *p;
2497 int r;
2498
2499 assert_return(m, -EINVAL);
2500 assert_return(!m->sealed, -EPERM);
2501 assert_return(bus_type_is_trivial(type), -EINVAL);
2502 assert_return(iov || n == 0, -EINVAL);
2503 assert_return(!m->poisoned, -ESTALE);
2504
2505 size = IOVEC_TOTAL_SIZE(iov, n);
2506
2507 r = sd_bus_message_append_array_space(m, type, size, &p);
2508 if (r < 0)
2509 return r;
2510
2511 for (i = 0; i < n; i++) {
2512
2513 if (iov[i].iov_base)
2514 memcpy(p, iov[i].iov_base, iov[i].iov_len);
2515 else
2516 memset(p, 0, iov[i].iov_len);
2517
2518 p = (uint8_t*) p + iov[i].iov_len;
2519 }
2520
2521 return 0;
2522}
2523
d9f644e2
ZJS
2524_public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
2525 char type,
2526 sd_memfd *memfd) {
453a0c29
LP
2527 _cleanup_close_ int copy_fd = -1;
2528 struct bus_body_part *part;
2529 ssize_t align, sz;
2530 uint64_t size;
2531 void *a;
2532 int r;
2533
2534 if (!m)
2535 return -EINVAL;
2536 if (!memfd)
2537 return -EINVAL;
2538 if (m->sealed)
2539 return -EPERM;
2540 if (!bus_type_is_trivial(type))
2541 return -EINVAL;
2542 if (m->poisoned)
2543 return -ESTALE;
2544
2545 r = sd_memfd_set_sealed(memfd, true);
2546 if (r < 0)
2547 return r;
2548
2549 copy_fd = sd_memfd_dup_fd(memfd);
2550 if (copy_fd < 0)
2551 return copy_fd;
2552
2553 r = sd_memfd_get_size(memfd, &size);
2554 if (r < 0)
2555 return r;
2556
2557 align = bus_type_get_alignment(type);
2558 sz = bus_type_get_size(type);
2559
2560 assert_se(align > 0);
2561 assert_se(sz > 0);
2562
2563 if (size % sz != 0)
2564 return -EINVAL;
2565
5cbe7492 2566 if (size > (uint64_t) (uint32_t) -1)
453a0c29
LP
2567 return -EINVAL;
2568
2569 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2570 if (r < 0)
2571 return r;
2572
c1b9d935 2573 a = message_extend_body(m, align, 0, false);
453a0c29
LP
2574 if (!a)
2575 return -ENOMEM;
2576
2577 part = message_append_part(m);
2578 if (!part)
2579 return -ENOMEM;
2580
2581 part->memfd = copy_fd;
2582 part->sealed = true;
2583 part->size = size;
2584 copy_fd = -1;
2585
453a0c29 2586 m->header->body_size += size;
0039a203 2587 message_extend_containers(m, size);
453a0c29
LP
2588
2589 return sd_bus_message_close_container(m);
2590}
2591
d9f644e2 2592_public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) {
5cbe7492
LP
2593 _cleanup_close_ int copy_fd = -1;
2594 struct bus_body_part *part;
2595 struct bus_container *c;
2596 uint64_t size;
2597 void *a;
2598 int r;
2599
55736ed0
LP
2600 assert_return(m, -EINVAL);
2601 assert_return(memfd, -EINVAL);
2602 assert_return(!m->sealed, -EPERM);
2603 assert_return(!m->poisoned, -ESTALE);
5cbe7492
LP
2604
2605 r = sd_memfd_set_sealed(memfd, true);
2606 if (r < 0)
2607 return r;
2608
2609 copy_fd = sd_memfd_dup_fd(memfd);
2610 if (copy_fd < 0)
2611 return copy_fd;
2612
2613 r = sd_memfd_get_size(memfd, &size);
2614 if (r < 0)
2615 return r;
2616
2617 /* We require this to be NUL terminated */
2618 if (size == 0)
2619 return -EINVAL;
2620
2621 if (size > (uint64_t) (uint32_t) -1)
2622 return -EINVAL;
2623
2624 c = message_get_container(m);
2625 if (c->signature && c->signature[c->index]) {
2626 /* Container signature is already set */
2627
2628 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
2629 return -ENXIO;
2630 } else {
2631 char *e;
2632
2633 /* Maybe we can append to the signature? But only if this is the top-level container*/
2634 if (c->enclosing != 0)
2635 return -ENXIO;
2636
2637 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
2638 if (!e) {
2639 m->poisoned = true;
2640 return -ENOMEM;
2641 }
2642 }
2643
6647dc66 2644 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
2645 a = message_extend_body(m, 4, 4, false);
2646 if (!a)
2647 return -ENOMEM;
5cbe7492 2648
c1b9d935
LP
2649 *(uint32_t*) a = size - 1;
2650 }
5cbe7492
LP
2651
2652 part = message_append_part(m);
2653 if (!part)
2654 return -ENOMEM;
2655
2656 part->memfd = copy_fd;
2657 part->sealed = true;
2658 part->size = size;
2659 copy_fd = -1;
2660
5cbe7492 2661 m->header->body_size += size;
c1b9d935
LP
2662 message_extend_containers(m, size);
2663
6647dc66 2664 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
2665 r = message_add_offset(m, m->header->body_size);
2666 if (r < 0) {
2667 m->poisoned = true;
2668 return -ENOMEM;
2669 }
2670 }
5cbe7492
LP
2671
2672 if (c->enclosing != SD_BUS_TYPE_ARRAY)
2673 c->index++;
2674
2675 return 0;
2676}
2677
d9f644e2 2678_public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) {
55736ed0
LP
2679 char **i;
2680 int r;
2681
2682 assert_return(m, -EINVAL);
2683 assert_return(!m->sealed, -EPERM);
2684 assert_return(!m->poisoned, -ESTALE);
2685
2686 r = sd_bus_message_open_container(m, 'a', "s");
2687 if (r < 0)
2688 return r;
2689
2690 STRV_FOREACH(i, l) {
2691 r = sd_bus_message_append_basic(m, 's', *i);
2692 if (r < 0)
2693 return r;
2694 }
2695
2696 return sd_bus_message_close_container(m);
2697}
2698
81389225
LP
2699static int bus_message_close_header(sd_bus_message *m) {
2700 uint8_t *a;
2701 size_t sz, i;
2702
2703 assert(m);
2704
2705 if (!BUS_MESSAGE_IS_GVARIANT(m))
2706 return 0;
2707
2708 if (m->n_header_offsets < 1)
2709 return 0;
2710
2711 assert(m->header->fields_size == m->header_offsets[m->n_header_offsets-1]);
2712
2713 sz = determine_word_size(m->header->fields_size, m->n_header_offsets);
2714
2715 a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
2716 if (!a)
2717 return -ENOMEM;
2718
2719 for (i = 0; i < m->n_header_offsets; i++)
2720 write_word_le(a + sz*i, sz, m->header_offsets[i]);
2721
2722 return 0;
2723}
2724
693eb9a2 2725int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
81389225
LP
2726 struct bus_body_part *part;
2727 size_t l, a;
2728 unsigned i;
2729 int r;
2730
2731 assert(m);
2732
2733 if (m->sealed)
2734 return -EPERM;
2735
2736 if (m->n_containers > 0)
2737 return -EBADMSG;
2738
2739 if (m->poisoned)
2740 return -ESTALE;
2741
2742 /* In vtables the return signature of method calls is listed,
2743 * let's check if they match if this is a response */
2744 if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
2745 m->enforced_reply_signature &&
2746 !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
2747 return -ENOMSG;
2748
2749 /* If gvariant marshalling is used we need to close the body structure */
2750 r = bus_message_close_struct(m, &m->root_container, false);
2751 if (r < 0)
2752 return r;
2753
2754 /* If there's a non-trivial signature set, then add it in here */
2755 if (!isempty(m->root_container.signature)) {
2756 r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
2757 if (r < 0)
2758 return r;
2759 }
2760
2761 if (m->n_fds > 0) {
2762 r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
2763 if (r < 0)
2764 return r;
2765 }
2766
2767 r = bus_message_close_header(m);
2768 if (r < 0)
2769 return r;
2770
693eb9a2 2771 m->header->serial = (uint32_t) cookie;
3df7a7e6 2772 m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout;
81389225
LP
2773
2774 /* Add padding at the end of the fields part, since we know
2775 * the body needs to start at an 8 byte alignment. We made
2776 * sure we allocated enough space for this, so all we need to
2777 * do here is to zero it out. */
2778 l = BUS_MESSAGE_FIELDS_SIZE(m);
2779 a = ALIGN8(l) - l;
2780 if (a > 0)
2781 memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a);
2782
2783 /* If this is something we can send as memfd, then let's seal
2784 the memfd now. Note that we can send memfds as payload only
2785 for directed messages, and not for broadcasts. */
2786 if (m->destination && m->bus && m->bus->use_memfd) {
2787 MESSAGE_FOREACH_PART(part, i, m)
2788 if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) {
8e959fbf
LP
2789 uint64_t sz;
2790
2791 /* Try to seal it if that makes
2792 * sense. First, unmap our own map to
2793 * make sure we don't keep it busy. */
81389225
LP
2794 bus_body_part_unmap(part);
2795
8e959fbf
LP
2796 /* Then, sync up real memfd size */
2797 sz = part->size;
2798 if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &sz) < 0)
2799 return -errno;
2800
2801 /* Finally, try to seal */
81389225
LP
2802 if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
2803 part->sealed = true;
2804 }
2805 }
2806
2807 m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
2808 m->root_container.index = 0;
2809 m->root_container.offset_index = 0;
2810 m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
2811
2812 m->sealed = true;
2813
2814 return 0;
2815}
2816
a392d361 2817int bus_body_part_map(struct bus_body_part *part) {
453a0c29
LP
2818 void *p;
2819 size_t psz;
2820
2821 assert_se(part);
2822
2823 if (part->data)
2824 return 0;
2825
2826 if (part->size <= 0)
2827 return 0;
2828
1307c3ff
LP
2829 /* For smaller zero parts (as used for padding) we don't need to map anything... */
2830 if (part->memfd < 0 && part->is_zero && part->size < 8) {
2831 static const uint8_t zeroes[7] = { };
2832 part->data = (void*) zeroes;
2833 return 0;
2834 }
2835
453a0c29
LP
2836 psz = PAGE_ALIGN(part->size);
2837
2838 if (part->memfd >= 0)
2839 p = mmap(NULL, psz, PROT_READ, MAP_SHARED, part->memfd, 0);
2840 else if (part->is_zero)
2841 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
2842 else
2843 return -EINVAL;
2844
2845 if (p == MAP_FAILED)
2846 return -errno;
2847
2848 part->mapped = psz;
2849 part->data = p;
a392d361
LP
2850 part->munmap_this = true;
2851
453a0c29
LP
2852 return 0;
2853}
2854
a392d361
LP
2855void bus_body_part_unmap(struct bus_body_part *part) {
2856
2857 assert_se(part);
2858
2859 if (part->memfd < 0)
2860 return;
2861
a392d361
LP
2862 if (!part->data)
2863 return;
2864
bf30e48f
KS
2865 if (!part->munmap_this)
2866 return;
a392d361
LP
2867
2868 assert_se(munmap(part->data, part->mapped) == 0);
2869
2870 part->data = NULL;
2871 part->mapped = 0;
2872 part->munmap_this = false;
2873
2874 return;
2875}
2876
9a17484d 2877static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
bc7fd8cd 2878 size_t k, start, end;
de1c301e 2879
9a17484d
LP
2880 assert(rindex);
2881 assert(align > 0);
de1c301e 2882
9a17484d 2883 start = ALIGN_TO((size_t) *rindex, align);
bc7fd8cd 2884 end = start + nbytes;
9a17484d 2885
bc7fd8cd 2886 if (end > sz)
9a17484d
LP
2887 return -EBADMSG;
2888
2889 /* Verify that padding is 0 */
2890 for (k = *rindex; k < start; k++)
2891 if (((const uint8_t*) p)[k] != 0)
2892 return -EBADMSG;
2893
2894 if (r)
2895 *r = (uint8_t*) p + start;
2896
bc7fd8cd 2897 *rindex = end;
9a17484d
LP
2898
2899 return 1;
de1c301e
LP
2900}
2901
7b058942
LP
2902static bool message_end_of_signature(sd_bus_message *m) {
2903 struct bus_container *c;
2904
2905 assert(m);
2906
2907 c = message_get_container(m);
2908 return !c->signature || c->signature[c->index] == 0;
2909}
2910
9a17484d
LP
2911static bool message_end_of_array(sd_bus_message *m, size_t index) {
2912 struct bus_container *c;
de1c301e 2913
9a17484d 2914 assert(m);
de1c301e 2915
9a17484d 2916 c = message_get_container(m);
6647dc66 2917 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 2918 return false;
de1c301e 2919
6647dc66
LP
2920 if (BUS_MESSAGE_IS_GVARIANT(m))
2921 return index >= c->end;
2922 else {
2923 assert(c->array_size);
2924 return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
2925 }
de1c301e
LP
2926}
2927
1405bef3 2928_public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
7b058942
LP
2929 assert_return(m, -EINVAL);
2930 assert_return(m->sealed, -EPERM);
2931
2932 if (complete && m->n_containers > 0)
2933 return false;
2934
2935 if (message_end_of_signature(m))
2936 return true;
2937
2938 if (message_end_of_array(m, m->rindex))
2939 return true;
2940
2941 return false;
2942}
2943
bc7fd8cd
LP
2944static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
2945 struct bus_body_part *part;
2946 size_t begin;
453a0c29
LP
2947 int r;
2948
bc7fd8cd
LP
2949 assert(m);
2950
2951 if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) {
2952 part = m->cached_rindex_part;
2953 begin = m->cached_rindex_part_begin;
2954 } else {
2955 part = &m->body;
2956 begin = 0;
2957 }
2958
2959 while (part) {
2960 if (index < begin)
2961 return NULL;
2962
2963 if (index + sz <= begin + part->size) {
453a0c29 2964
a392d361 2965 r = bus_body_part_map(part);
453a0c29
LP
2966 if (r < 0)
2967 return NULL;
2968
bc7fd8cd 2969 if (p)
453a0c29 2970 *p = (uint8_t*) part->data + index - begin;
bc7fd8cd
LP
2971
2972 m->cached_rindex_part = part;
2973 m->cached_rindex_part_begin = begin;
2974
2975 return part;
2976 }
2977
453a0c29 2978 begin += part->size;
bc7fd8cd
LP
2979 part = part->next;
2980 }
2981
2982 return NULL;
2983}
2984
6647dc66
LP
2985static int container_next_item(sd_bus_message *m, struct bus_container *c, size_t *rindex) {
2986 int r;
2987
2988 assert(m);
2989 assert(c);
2990 assert(rindex);
2991
2992 if (!BUS_MESSAGE_IS_GVARIANT(m))
2993 return 0;
2994
2995 if (c->enclosing == SD_BUS_TYPE_ARRAY) {
2996 int sz;
2997
2998 sz = bus_gvariant_get_size(c->signature);
2999 if (sz < 0) {
3000 int alignment;
3001
3002 if (c->offset_index+1 >= c->n_offsets)
3003 goto end;
3004
3005 /* Variable-size array */
3006
3007 alignment = bus_gvariant_get_alignment(c->signature);
3008 assert(alignment > 0);
3009
3010 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
3011 c->item_size = c->offsets[c->offset_index+1] - *rindex;
3012 } else {
0039a203
LP
3013
3014 if (c->offset_index+1 >= (c->end-c->begin)/sz)
3015 goto end;
3016
6647dc66 3017 /* Fixed-size array */
0039a203 3018 *rindex = c->begin + (c->offset_index+1) * sz;
6647dc66
LP
3019 c->item_size = sz;
3020 }
3021
3022 c->offset_index++;
3023
3024 } else if (c->enclosing == 0 ||
3025 c->enclosing == SD_BUS_TYPE_STRUCT ||
3026 c->enclosing == SD_BUS_TYPE_DICT_ENTRY) {
3027
3028 int alignment;
3029 size_t n, j;
3030
3031 if (c->offset_index+1 >= c->n_offsets)
3032 goto end;
3033
3034 r = signature_element_length(c->signature + c->index, &n);
3035 if (r < 0)
3036 return r;
3037
3038 r = signature_element_length(c->signature + c->index + n, &j);
3039 if (r < 0)
3040 return r;
3041 else {
3042 char t[j+1];
3043 memcpy(t, c->signature + c->index + n, j);
3044 t[j] = 0;
3045
3046 alignment = bus_gvariant_get_alignment(t);
3047 }
3048
3049 assert(alignment > 0);
3050
3051 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
3052 c->item_size = c->offsets[c->offset_index+1] - *rindex;
3053
3054 c->offset_index++;
3055
3056 } else if (c->enclosing == SD_BUS_TYPE_VARIANT)
3057 goto end;
3058 else
3059 assert_not_reached("Unknown container type");
3060
3061 return 0;
3062
3063end:
3064 /* Reached the end */
3065 *rindex = c->end;
3066 c->item_size = 0;
3067 return 0;
3068}
3069
3070
bc7fd8cd
LP
3071static int message_peek_body(
3072 sd_bus_message *m,
3073 size_t *rindex,
3074 size_t align,
3075 size_t nbytes,
3076 void **ret) {
3077
3078 size_t k, start, end, padding;
3079 struct bus_body_part *part;
3080 uint8_t *q;
3081
de1c301e 3082 assert(m);
9a17484d
LP
3083 assert(rindex);
3084 assert(align > 0);
de1c301e 3085
bc7fd8cd
LP
3086 start = ALIGN_TO((size_t) *rindex, align);
3087 padding = start - *rindex;
3088 end = start + nbytes;
3089
3090 if (end > BUS_MESSAGE_BODY_SIZE(m))
3091 return -EBADMSG;
3092
3093 part = find_part(m, *rindex, padding, (void**) &q);
3094 if (!part)
3095 return -EBADMSG;
3096
3097 if (q) {
3098 /* Verify padding */
3099 for (k = 0; k < padding; k++)
3100 if (q[k] != 0)
3101 return -EBADMSG;
3102 }
3103
3104 part = find_part(m, start, nbytes, (void**) &q);
5f7e8903 3105 if (!part || (nbytes > 0 && !q))
bc7fd8cd
LP
3106 return -EBADMSG;
3107
3108 *rindex = end;
3109
3110 if (ret)
3111 *ret = q;
3112
18f5b48f 3113 return 0;
9a17484d 3114}
de1c301e 3115
ac89bf1d 3116static bool validate_nul(const char *s, size_t l) {
de1c301e 3117
9a17484d
LP
3118 /* Check for NUL chars in the string */
3119 if (memchr(s, 0, l))
3120 return false;
de1c301e 3121
9a17484d
LP
3122 /* Check for NUL termination */
3123 if (s[l] != 0)
3124 return false;
de1c301e 3125
ac89bf1d
LP
3126 return true;
3127}
3128
3129static bool validate_string(const char *s, size_t l) {
3130
3131 if (!validate_nul(s, l))
3132 return false;
3133
9a17484d
LP
3134 /* Check if valid UTF8 */
3135 if (!utf8_is_valid(s))
3136 return false;
3137
3138 return true;
de1c301e
LP
3139}
3140
9a17484d 3141static bool validate_signature(const char *s, size_t l) {
de1c301e 3142
ac89bf1d 3143 if (!validate_nul(s, l))
9a17484d 3144 return false;
de1c301e 3145
9a17484d
LP
3146 /* Check if valid signature */
3147 if (!signature_is_valid(s, true))
3148 return false;
3149
3150 return true;
3151}
3152
ac89bf1d
LP
3153static bool validate_object_path(const char *s, size_t l) {
3154
3155 if (!validate_nul(s, l))
3156 return false;
3157
3158 if (!object_path_is_valid(s))
3159 return false;
3160
3161 return true;
3162}
3163
d9f644e2 3164_public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
9a17484d 3165 struct bus_container *c;
6647dc66 3166 size_t rindex;
9a17484d 3167 void *q;
0dcd14b9 3168 int r;
9a17484d 3169
9d6c7c82
LP
3170 assert_return(m, -EINVAL);
3171 assert_return(m->sealed, -EPERM);
3172 assert_return(bus_type_is_basic(type), -EINVAL);
de1c301e 3173
7b058942 3174 if (message_end_of_signature(m))
430fb8fa 3175 return -ENXIO;
9a17484d 3176
1daf8121
LP
3177 if (message_end_of_array(m, m->rindex))
3178 return 0;
3179
7b058942 3180 c = message_get_container(m);
9a17484d
LP
3181 if (c->signature[c->index] != type)
3182 return -ENXIO;
3183
6647dc66 3184 rindex = m->rindex;
9a17484d 3185
6647dc66 3186 if (BUS_MESSAGE_IS_GVARIANT(m)) {
9a17484d 3187
6647dc66
LP
3188 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
3189 bool ok;
9a17484d 3190
6647dc66 3191 r = message_peek_body(m, &rindex, 1, c->item_size, &q);
18f5b48f 3192 if (r < 0)
6647dc66
LP
3193 return r;
3194
3195 if (type == SD_BUS_TYPE_STRING)
3196 ok = validate_string(q, c->item_size-1);
3197 else if (type == SD_BUS_TYPE_OBJECT_PATH)
3198 ok = validate_object_path(q, c->item_size-1);
3199 else
3200 ok = validate_signature(q, c->item_size-1);
9a17484d 3201
6647dc66 3202 if (!ok)
ac89bf1d 3203 return -EBADMSG;
6647dc66
LP
3204
3205 if (p)
3206 *(const char**) p = q;
ac89bf1d 3207 } else {
6647dc66
LP
3208 int sz, align;
3209
3210 sz = bus_gvariant_get_size(CHAR_TO_STR(type));
3211 assert(sz > 0);
3212 if ((size_t) sz != c->item_size)
ac89bf1d 3213 return -EBADMSG;
9a17484d 3214
6647dc66
LP
3215 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
3216 assert(align > 0);
0dcd14b9 3217
6647dc66 3218 r = message_peek_body(m, &rindex, align, c->item_size, &q);
18f5b48f 3219 if (r < 0)
6647dc66 3220 return r;
de1c301e 3221
6647dc66 3222 switch (type) {
9a17484d 3223
6647dc66
LP
3224 case SD_BUS_TYPE_BYTE:
3225 if (p)
3226 *(uint8_t*) p = *(uint8_t*) q;
3227 break;
9a17484d 3228
6647dc66
LP
3229 case SD_BUS_TYPE_BOOLEAN:
3230 if (p)
3231 *(int*) p = !!*(uint8_t*) q;
3232 break;
9a17484d 3233
6647dc66
LP
3234 case SD_BUS_TYPE_INT16:
3235 case SD_BUS_TYPE_UINT16:
3236 if (p)
3237 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3238 break;
3239
3240 case SD_BUS_TYPE_INT32:
3241 case SD_BUS_TYPE_UINT32:
3242 if (p)
3243 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3244 break;
9a17484d 3245
6647dc66
LP
3246 case SD_BUS_TYPE_INT64:
3247 case SD_BUS_TYPE_UINT64:
3248 case SD_BUS_TYPE_DOUBLE:
3249 if (p)
3250 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3251 break;
0dcd14b9 3252
6647dc66
LP
3253 case SD_BUS_TYPE_UNIX_FD: {
3254 uint32_t j;
de1c301e 3255
6647dc66
LP
3256 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3257 if (j >= m->n_fds)
3258 return -EBADMSG;
de1c301e 3259
6647dc66
LP
3260 if (p)
3261 *(int*) p = m->fds[j];
de1c301e 3262
6647dc66
LP
3263 break;
3264 }
3265
3266 default:
3267 assert_not_reached("unexpected type");
3268 }
3269 }
3270
3271 r = container_next_item(m, c, &rindex);
3272 if (r < 0)
9a17484d 3273 return r;
6647dc66 3274 } else {
9a17484d 3275
6647dc66 3276 rindex = m->rindex;
9a17484d 3277
6647dc66
LP
3278 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
3279 uint32_t l;
3280 bool ok;
9a17484d 3281
6647dc66 3282 r = message_peek_body(m, &rindex, 4, 4, &q);
18f5b48f 3283 if (r < 0)
6647dc66 3284 return r;
9a17484d 3285
6647dc66
LP
3286 l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3287 r = message_peek_body(m, &rindex, 1, l+1, &q);
3288 if (r < 0)
3289 return r;
9a17484d 3290
6647dc66
LP
3291 if (type == SD_BUS_TYPE_OBJECT_PATH)
3292 ok = validate_object_path(q, l);
3293 else
3294 ok = validate_string(q, l);
3295 if (!ok)
3296 return -EBADMSG;
9a17484d 3297
0dcd14b9 3298 if (p)
6647dc66 3299 *(const char**) p = q;
9a17484d 3300
6647dc66
LP
3301 } else if (type == SD_BUS_TYPE_SIGNATURE) {
3302 uint8_t l;
3303
3304 r = message_peek_body(m, &rindex, 1, 1, &q);
18f5b48f 3305 if (r < 0)
6647dc66
LP
3306 return r;
3307
3308 l = *(uint8_t*) q;
3309 r = message_peek_body(m, &rindex, 1, l+1, &q);
3310 if (r < 0)
3311 return r;
2c93b4ef 3312
6647dc66 3313 if (!validate_signature(q, l))
2c93b4ef
LP
3314 return -EBADMSG;
3315
0dcd14b9 3316 if (p)
6647dc66 3317 *(const char**) p = q;
2c93b4ef 3318
6647dc66
LP
3319 } else {
3320 ssize_t sz, align;
9a17484d 3321
6647dc66
LP
3322 align = bus_type_get_alignment(type);
3323 assert(align > 0);
2c93b4ef 3324
6647dc66
LP
3325 sz = bus_type_get_size(type);
3326 assert(sz > 0);
3327
3328 r = message_peek_body(m, &rindex, align, sz, &q);
18f5b48f 3329 if (r < 0)
6647dc66
LP
3330 return r;
3331
3332 switch (type) {
3333
3334 case SD_BUS_TYPE_BYTE:
3335 if (p)
3336 *(uint8_t*) p = *(uint8_t*) q;
3337 break;
3338
3339 case SD_BUS_TYPE_BOOLEAN:
3340 if (p)
3341 *(int*) p = !!*(uint32_t*) q;
3342 break;
3343
3344 case SD_BUS_TYPE_INT16:
3345 case SD_BUS_TYPE_UINT16:
3346 if (p)
3347 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3348 break;
3349
3350 case SD_BUS_TYPE_INT32:
3351 case SD_BUS_TYPE_UINT32:
3352 if (p)
3353 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3354 break;
3355
3356 case SD_BUS_TYPE_INT64:
3357 case SD_BUS_TYPE_UINT64:
3358 case SD_BUS_TYPE_DOUBLE:
3359 if (p)
3360 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3361 break;
3362
3363 case SD_BUS_TYPE_UNIX_FD: {
3364 uint32_t j;
3365
3366 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3367 if (j >= m->n_fds)
3368 return -EBADMSG;
3369
3370 if (p)
3371 *(int*) p = m->fds[j];
3372 break;
3373 }
3374
3375 default:
3376 assert_not_reached("Unknown basic type...");
3377 }
3378 }
9a17484d
LP
3379 }
3380
6647dc66
LP
3381 m->rindex = rindex;
3382
9a17484d
LP
3383 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3384 c->index++;
3385
3386 return 1;
de1c301e
LP
3387}
3388
9a17484d
LP
3389static int bus_message_enter_array(
3390 sd_bus_message *m,
3391 struct bus_container *c,
3392 const char *contents,
6647dc66
LP
3393 uint32_t **array_size,
3394 size_t *item_size,
3395 size_t **offsets,
3396 size_t *n_offsets) {
9a17484d
LP
3397
3398 size_t rindex;
3399 void *q;
3400 int r, alignment;
3401
3402 assert(m);
3403 assert(c);
3404 assert(contents);
3405 assert(array_size);
6647dc66
LP
3406 assert(item_size);
3407 assert(offsets);
3408 assert(n_offsets);
9a17484d 3409
29ddb38f 3410 if (!signature_is_single(contents, true))
de1c301e 3411 return -EINVAL;
9a17484d 3412
9a17484d 3413 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3414 return -ENXIO;
9a17484d
LP
3415
3416 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
3417 return -ENXIO;
3418
3419 if (!startswith(c->signature + c->index + 1, contents))
3420 return -ENXIO;
3421
3422 rindex = m->rindex;
9a17484d 3423
6647dc66
LP
3424 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3425 /* dbus1 */
9a17484d 3426
6647dc66 3427 r = message_peek_body(m, &rindex, 4, 4, &q);
18f5b48f 3428 if (r < 0)
6647dc66 3429 return r;
9a17484d 3430
6647dc66
LP
3431 if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE)
3432 return -EBADMSG;
9a17484d 3433
6647dc66
LP
3434 alignment = bus_type_get_alignment(contents[0]);
3435 if (alignment < 0)
3436 return alignment;
3437
3438 r = message_peek_body(m, &rindex, alignment, 0, NULL);
3439 if (r < 0)
3440 return r;
6647dc66
LP
3441
3442 *array_size = (uint32_t*) q;
3443
3444 } else if (c->item_size <= 0) {
3445
3446 /* gvariant: empty array */
3447 *item_size = 0;
3448 *offsets = NULL;
3449 *n_offsets = 0;
3450
3451 } else if (bus_gvariant_is_fixed_size(contents)) {
3452
3453 /* gvariant: fixed length array */
3454 *item_size = bus_gvariant_get_size(contents);
3455 *offsets = NULL;
3456 *n_offsets = 0;
3457
3458 } else {
3459 size_t where, p = 0, framing, sz;
3460 unsigned i;
3461
3462 /* gvariant: variable length array */
3463 sz = determine_word_size(c->item_size, 0);
3464
3465 where = rindex + c->item_size - sz;
3466 r = message_peek_body(m, &where, 1, sz, &q);
3467 if (r < 0)
3468 return r;
6647dc66
LP
3469
3470 framing = read_word_le(q, sz);
3471 if (framing > c->item_size - sz)
3472 return -EBADMSG;
3473 if ((c->item_size - framing) % sz != 0)
3474 return -EBADMSG;
3475
3476 *n_offsets = (c->item_size - framing) / sz;
3477
3478 where = rindex + framing;
3479 r = message_peek_body(m, &where, 1, *n_offsets * sz, &q);
3480 if (r < 0)
3481 return r;
6647dc66
LP
3482
3483 *offsets = new(size_t, *n_offsets);
3484 if (!*offsets)
3485 return -ENOMEM;
3486
3487 for (i = 0; i < *n_offsets; i++) {
3488 size_t x;
3489
3490 x = read_word_le((uint8_t*) q + i * sz, sz);
3491 if (x > c->item_size - sz)
3492 return -EBADMSG;
3493 if (x < p)
3494 return -EBADMSG;
3495
3496 (*offsets)[i] = rindex + x;
3497 p = x;
3498 }
3499
3500 *item_size = (*offsets)[0] - rindex;
3501 }
3502
3503 m->rindex = rindex;
3504
3505 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3506 c->index += 1 + strlen(contents);
9a17484d
LP
3507
3508 return 1;
3509}
3510
3511static int bus_message_enter_variant(
3512 sd_bus_message *m,
3513 struct bus_container *c,
6647dc66
LP
3514 const char *contents,
3515 size_t *item_size) {
9a17484d
LP
3516
3517 size_t rindex;
3518 uint8_t l;
3519 void *q;
3520 int r;
3521
3522 assert(m);
3523 assert(c);
3524 assert(contents);
6647dc66 3525 assert(item_size);
9a17484d 3526
29ddb38f 3527 if (!signature_is_single(contents, false))
de1c301e 3528 return -EINVAL;
de1c301e 3529
9a17484d
LP
3530 if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
3531 return -EINVAL;
3532
3533 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3534 return -ENXIO;
9a17484d
LP
3535
3536 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
3537 return -ENXIO;
3538
3539 rindex = m->rindex;
9a17484d 3540
6647dc66
LP
3541 if (BUS_MESSAGE_IS_GVARIANT(m)) {
3542 size_t k, where;
3543
3544 k = strlen(contents);
3545 if (1+k > c->item_size)
3546 return -EBADMSG;
3547
3548 where = rindex + c->item_size - (1+k);
3549 r = message_peek_body(m, &where, 1, 1+k, &q);
3550 if (r < 0)
3551 return r;
6647dc66
LP
3552
3553 if (*(char*) q != 0)
3554 return -EBADMSG;
3555
3556 if (memcmp((uint8_t*) q+1, contents, k))
3557 return -ENXIO;
3558
3559 *item_size = c->item_size - (1+k);
3560
3561 } else {
3562 r = message_peek_body(m, &rindex, 1, 1, &q);
3563 if (r < 0)
3564 return r;
6647dc66
LP
3565
3566 l = *(uint8_t*) q;
3567 r = message_peek_body(m, &rindex, 1, l+1, &q);
3568 if (r < 0)
3569 return r;
6647dc66
LP
3570
3571 if (!validate_signature(q, l))
3572 return -EBADMSG;
3573
3574 if (!streq(q, contents))
3575 return -ENXIO;
3576 }
3577
3578 m->rindex = rindex;
3579
3580 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3581 c->index++;
3582
3583 return 1;
3584}
3585
3586static int build_struct_offsets(
3587 sd_bus_message *m,
3588 const char *signature,
3589 size_t size,
3590 size_t *item_size,
3591 size_t **offsets,
3592 size_t *n_offsets) {
3593
3594 unsigned n_variable = 0, n_total = 0, v;
3595 size_t previous = 0, where;
3596 const char *p;
3597 size_t sz;
3598 void *q;
3599 int r;
3600
3601 assert(m);
6647dc66
LP
3602 assert(item_size);
3603 assert(offsets);
3604 assert(n_offsets);
3605
d6385068
LP
3606 if (isempty(signature)) {
3607 *item_size = 0;
3608 *offsets = NULL;
3609 *n_offsets = 0;
3610 return 0;
3611 }
3612
6647dc66 3613 sz = determine_word_size(size, 0);
d6385068
LP
3614 if (sz <= 0)
3615 return -EBADMSG;
6647dc66
LP
3616
3617 /* First, loop over signature and count variable elements and
3618 * elements in general. We use this to know how large the
3619 * offset array is at the end of the structure. Note that
3620 * GVariant only stores offsets for all variable size elements
3621 * that are not the last item. */
3622
3623 p = signature;
3624 while (*p != 0) {
3625 size_t n;
3626
3627 r = signature_element_length(p, &n);
3628 if (r < 0)
3629 return r;
3630 else {
3631 char t[n+1];
3632
3633 memcpy(t, p, n);
3634 t[n] = 0;
3635
3636 r = bus_gvariant_is_fixed_size(t);
3637 }
3638
3639 if (r < 0)
3640 return r;
3641 if (r == 0 && p[n] != 0) /* except the last item */
3642 n_variable ++;
3643 n_total++;
3644
3645 p += n;
3646 }
3647
3648 if (size < n_variable * sz)
3649 return -EBADMSG;
3650
3651 where = m->rindex + size - (n_variable * sz);
3652 r = message_peek_body(m, &where, 1, n_variable * sz, &q);
9a17484d
LP
3653 if (r < 0)
3654 return r;
9a17484d 3655
6647dc66 3656 v = n_variable;
9a17484d 3657
6647dc66
LP
3658 *offsets = new(size_t, n_total);
3659 if (!*offsets)
3660 return -ENOMEM;
9a17484d 3661
6647dc66 3662 *n_offsets = 0;
9a17484d 3663
6647dc66
LP
3664 /* Second, loop again and build an offset table */
3665 p = signature;
3666 while (*p != 0) {
3667 size_t n, offset;
3668 int k;
9a17484d 3669
6647dc66
LP
3670 r = signature_element_length(p, &n);
3671 if (r < 0)
3672 return r;
3673 else {
3674 char t[n+1];
3675
3676 memcpy(t, p, n);
3677 t[n] = 0;
3678
3679 k = bus_gvariant_get_size(t);
3680 if (k < 0) {
3681 size_t x;
3682
3683 /* variable size */
3684 if (v > 0) {
3685 v--;
3686
3687 x = read_word_le((uint8_t*) q + v*sz, sz);
3688 if (x >= size)
3689 return -EBADMSG;
3690 if (m->rindex + x < previous)
3691 return -EBADMSG;
3692 } else
3693 /* The last item's end
3694 * is determined from
3695 * the start of the
3696 * offset array */
3697 x = size - (n_variable * sz);
3698
3699 offset = m->rindex + x;
3700
3701 } else {
3702 size_t align;
3703
3704 /* fixed size */
3705 align = bus_gvariant_get_alignment(t);
3706 assert(align > 0);
3707
3708 offset = (*n_offsets == 0 ? m->rindex : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k;
3709 }
3710 }
3711
3712 previous = (*offsets)[(*n_offsets)++] = offset;
3713 p += n;
3714 }
3715
3716 assert(v == 0);
3717 assert(*n_offsets == n_total);
3718
3719 *item_size = (*offsets)[0] - m->rindex;
3720 return 0;
3721}
3722
3723static int enter_struct_or_dict_entry(
3724 sd_bus_message *m,
3725 struct bus_container *c,
3726 const char *contents,
3727 size_t *item_size,
3728 size_t **offsets,
3729 size_t *n_offsets) {
3730
3731 int r;
3732
3733 assert(m);
3734 assert(c);
3735 assert(contents);
3736 assert(item_size);
3737 assert(offsets);
3738 assert(n_offsets);
3739
3740 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3741
3742 /* dbus1 */
3743 r = message_peek_body(m, &m->rindex, 8, 0, NULL);
18f5b48f 3744 if (r < 0)
6647dc66
LP
3745 return r;
3746
3747 } else if (c->item_size <= 0) {
3748
3749 /* gvariant empty struct */
3750 *item_size = 0;
3751 *offsets = NULL;
3752 *n_offsets = 0;
3753 } else
3754 /* gvariant with contents */
3755 return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets);
3756
3757 return 0;
de1c301e
LP
3758}
3759
9a17484d
LP
3760static int bus_message_enter_struct(
3761 sd_bus_message *m,
3762 struct bus_container *c,
6647dc66
LP
3763 const char *contents,
3764 size_t *item_size,
3765 size_t **offsets,
3766 size_t *n_offsets) {
9a17484d
LP
3767
3768 size_t l;
3769 int r;
3770
3771 assert(m);
3772 assert(c);
3773 assert(contents);
6647dc66
LP
3774 assert(item_size);
3775 assert(offsets);
3776 assert(n_offsets);
9a17484d
LP
3777
3778 if (!signature_is_valid(contents, false))
3779 return -EINVAL;
3780
3781 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3782 return -ENXIO;
9a17484d
LP
3783
3784 l = strlen(contents);
3785
3786 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
3787 !startswith(c->signature + c->index + 1, contents) ||
3788 c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
3789 return -ENXIO;
3790
6647dc66
LP
3791 r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
3792 if (r < 0)
9a17484d
LP
3793 return r;
3794
3795 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3796 c->index += 1 + l + 1;
3797
3798 return 1;
3799}
3800
3801static int bus_message_enter_dict_entry(
3802 sd_bus_message *m,
3803 struct bus_container *c,
6647dc66
LP
3804 const char *contents,
3805 size_t *item_size,
3806 size_t **offsets,
3807 size_t *n_offsets) {
9a17484d
LP
3808
3809 size_t l;
3810 int r;
3811
3812 assert(m);
3813 assert(c);
3814 assert(contents);
3815
3816 if (!signature_is_pair(contents))
3817 return -EINVAL;
3818
3819 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3820 return -ENXIO;
3821
3822 if (!c->signature || c->signature[c->index] == 0)
3823 return 0;
3824
3825 l = strlen(contents);
3826
3827 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
3828 !startswith(c->signature + c->index + 1, contents) ||
3829 c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
3830 return -ENXIO;
3831
6647dc66
LP
3832 r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
3833 if (r < 0)
9a17484d
LP
3834 return r;
3835
3836 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3837 c->index += 1 + l + 1;
3838
3839 return 1;
3840}
3841
d9f644e2
ZJS
3842_public_ int sd_bus_message_enter_container(sd_bus_message *m,
3843 char type,
3844 const char *contents) {
9a17484d
LP
3845 struct bus_container *c, *w;
3846 uint32_t *array_size = NULL;
3847 char *signature;
b3af9646 3848 size_t before;
6647dc66
LP
3849 size_t *offsets = NULL;
3850 size_t n_offsets = 0, item_size = 0;
9a17484d
LP
3851 int r;
3852
275b39fe
LP
3853 assert_return(m, -EINVAL);
3854 assert_return(m->sealed, -EPERM);
3855 assert_return(type != 0 || !contents, -EINVAL);
3856
3857 if (type == 0 || !contents) {
3858 const char *cc;
3859 char tt;
3860
3861 /* Allow entering into anonymous containers */
3862 r = sd_bus_message_peek_type(m, &tt, &cc);
18f5b48f 3863 if (r < 0)
275b39fe
LP
3864 return r;
3865
3866 if (type != 0 && type != tt)
3867 return -ENXIO;
3868
3869 if (contents && !streq(contents, cc))
3870 return -ENXIO;
3871
3872 type = tt;
3873 contents = cc;
3874 }
9a17484d 3875
ed205a6b
LP
3876 /*
3877 * We enforce a global limit on container depth, that is much
3878 * higher than the 32 structs and 32 arrays the specification
3879 * mandates. This is simpler to implement for us, and we need
3880 * this only to ensure our container array doesn't grow
3881 * without bounds. We are happy to return any data from a
3882 * message as long as the data itself is valid, even if the
3883 * overall message might be not.
3884 *
3885 * Note that the message signature is validated when
3886 * parsing the headers, and that validation does check the
3887 * 32/32 limit.
3888 *
3889 * Note that the specification defines no limits on the depth
3890 * of stacked variants, but we do.
3891 */
3892 if (m->n_containers >= BUS_CONTAINER_DEPTH)
3893 return -EBADMSG;
3894
306f07be 3895 if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1))
9a17484d 3896 return -ENOMEM;
9a17484d 3897
7b058942 3898 if (message_end_of_signature(m))
430fb8fa 3899 return -ENXIO;
9a17484d 3900
1daf8121
LP
3901 if (message_end_of_array(m, m->rindex))
3902 return 0;
3903
7b058942
LP
3904 c = message_get_container(m);
3905
9a17484d
LP
3906 signature = strdup(contents);
3907 if (!signature)
3908 return -ENOMEM;
3909
b3af9646
LP
3910 c->saved_index = c->index;
3911 before = m->rindex;
3912
9a17484d 3913 if (type == SD_BUS_TYPE_ARRAY)
6647dc66 3914 r = bus_message_enter_array(m, c, contents, &array_size, &item_size, &offsets, &n_offsets);
9a17484d 3915 else if (type == SD_BUS_TYPE_VARIANT)
6647dc66 3916 r = bus_message_enter_variant(m, c, contents, &item_size);
9a17484d 3917 else if (type == SD_BUS_TYPE_STRUCT)
6647dc66 3918 r = bus_message_enter_struct(m, c, contents, &item_size, &offsets, &n_offsets);
9a17484d 3919 else if (type == SD_BUS_TYPE_DICT_ENTRY)
6647dc66 3920 r = bus_message_enter_dict_entry(m, c, contents, &item_size, &offsets, &n_offsets);
9a17484d
LP
3921 else
3922 r = -EINVAL;
3923
3924 if (r <= 0) {
3925 free(signature);
6647dc66 3926 free(offsets);
9a17484d
LP
3927 return r;
3928 }
3929
3930 /* OK, let's fill it in */
306f07be 3931 w = m->containers + m->n_containers++;
9a17484d
LP
3932 w->enclosing = type;
3933 w->signature = signature;
3798fd4c 3934 w->peeked_signature = NULL;
9a17484d 3935 w->index = 0;
6647dc66 3936
b3af9646 3937 w->before = before;
9a17484d 3938 w->begin = m->rindex;
6647dc66
LP
3939 w->end = m->rindex + c->item_size;
3940
3941 w->array_size = array_size;
3942 w->item_size = item_size;
3943 w->offsets = offsets;
3944 w->n_offsets = n_offsets;
3945 w->offset_index = 0;
9a17484d
LP
3946
3947 return 1;
3948}
3949
d9f644e2 3950_public_ int sd_bus_message_exit_container(sd_bus_message *m) {
9a17484d 3951 struct bus_container *c;
5763192a 3952 unsigned saved;
6647dc66 3953 int r;
9a17484d 3954
9d6c7c82
LP
3955 assert_return(m, -EINVAL);
3956 assert_return(m->sealed, -EPERM);
f959af20 3957 assert_return(m->n_containers > 0, -ENXIO);
9a17484d
LP
3958
3959 c = message_get_container(m);
6647dc66
LP
3960
3961 if (c->enclosing != SD_BUS_TYPE_ARRAY) {
3962 if (c->signature && c->signature[c->index] != 0)
3963 return -EBUSY;
3964 }
3965
3966 if (BUS_MESSAGE_IS_GVARIANT(m)) {
3967 if (m->rindex < c->end)
3968 return -EBUSY;
3969
3970 } else if (c->enclosing == SD_BUS_TYPE_ARRAY) {
9a17484d
LP
3971 uint32_t l;
3972
3973 l = BUS_MESSAGE_BSWAP32(m, *c->array_size);
3974 if (c->begin + l != m->rindex)
3975 return -EBUSY;
9a17484d
LP
3976 }
3977
3978 free(c->signature);
3798fd4c 3979 free(c->peeked_signature);
6647dc66 3980 free(c->offsets);
9a17484d
LP
3981 m->n_containers--;
3982
6647dc66
LP
3983 c = message_get_container(m);
3984
5763192a
LP
3985 saved = c->index;
3986 c->index = c->saved_index;
6647dc66 3987 r = container_next_item(m, c, &m->rindex);
5763192a 3988 c->index = saved;
6647dc66
LP
3989 if (r < 0)
3990 return r;
3991
9a17484d
LP
3992 return 1;
3993}
3994
b3af9646
LP
3995static void message_quit_container(sd_bus_message *m) {
3996 struct bus_container *c;
3997
3998 assert(m);
3999 assert(m->sealed);
4000 assert(m->n_containers > 0);
4001
4002 c = message_get_container(m);
4003
4004 /* Undo seeks */
4005 assert(m->rindex >= c->before);
4006 m->rindex = c->before;
4007
4008 /* Free container */
4009 free(c->signature);
6647dc66 4010 free(c->offsets);
b3af9646
LP
4011 m->n_containers--;
4012
4013 /* Correct index of new top-level container */
4014 c = message_get_container(m);
4015 c->index = c->saved_index;
4016}
4017
d9f644e2 4018_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
9a17484d
LP
4019 struct bus_container *c;
4020 int r;
4021
c430fee6
LP
4022 assert_return(m, -EINVAL);
4023 assert_return(m->sealed, -EPERM);
9a17484d 4024
7b058942 4025 if (message_end_of_signature(m))
9a17484d
LP
4026 goto eof;
4027
4028 if (message_end_of_array(m, m->rindex))
4029 goto eof;
4030
7b058942
LP
4031 c = message_get_container(m);
4032
9a17484d
LP
4033 if (bus_type_is_basic(c->signature[c->index])) {
4034 if (contents)
4035 *contents = NULL;
4036 if (type)
4037 *type = c->signature[c->index];
4038 return 1;
4039 }
4040
4041 if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) {
4042
4043 if (contents) {
4044 size_t l;
4045 char *sig;
4046
4047 r = signature_element_length(c->signature+c->index+1, &l);
4048 if (r < 0)
4049 return r;
4050
80a46c73
LP
4051 assert(l >= 1);
4052
9a17484d
LP
4053 sig = strndup(c->signature + c->index + 1, l);
4054 if (!sig)
4055 return -ENOMEM;
4056
3798fd4c
LP
4057 free(c->peeked_signature);
4058 *contents = c->peeked_signature = sig;
9a17484d
LP
4059 }
4060
4061 if (type)
4062 *type = SD_BUS_TYPE_ARRAY;
4063
4064 return 1;
4065 }
4066
4067 if (c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ||
4068 c->signature[c->index] == SD_BUS_TYPE_DICT_ENTRY_BEGIN) {
4069
4070 if (contents) {
4071 size_t l;
4072 char *sig;
4073
4074 r = signature_element_length(c->signature+c->index, &l);
4075 if (r < 0)
4076 return r;
4077
4078 assert(l >= 2);
4079 sig = strndup(c->signature + c->index + 1, l - 2);
4080 if (!sig)
4081 return -ENOMEM;
4082
3798fd4c
LP
4083 free(c->peeked_signature);
4084 *contents = c->peeked_signature = sig;
9a17484d
LP
4085 }
4086
4087 if (type)
4088 *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
4089
4090 return 1;
4091 }
4092
4093 if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) {
4094 if (contents) {
9a17484d
LP
4095 void *q;
4096
6647dc66
LP
4097 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4098 size_t k;
9a17484d 4099
6647dc66
LP
4100 if (c->item_size < 2)
4101 return -EBADMSG;
9a17484d 4102
6647dc66
LP
4103 /* Look for the NUL delimiter that
4104 separates the payload from the
4105 signature. Since the body might be
4106 in a different part that then the
4107 signature we map byte by byte. */
4108
4109 for (k = 2; k <= c->item_size; k++) {
4110 size_t where;
4111
4112 where = m->rindex + c->item_size - k;
4113 r = message_peek_body(m, &where, 1, k, &q);
4114 if (r < 0)
4115 return r;
6647dc66
LP
4116
4117 if (*(char*) q == 0)
4118 break;
4119 }
4120
4121 if (k > c->item_size)
4122 return -EBADMSG;
4123
3798fd4c
LP
4124 free(c->peeked_signature);
4125 c->peeked_signature = strndup((char*) q + 1, k - 1);
4126 if (!c->peeked_signature)
6647dc66
LP
4127 return -ENOMEM;
4128
3798fd4c 4129 if (!signature_is_valid(c->peeked_signature, true))
6647dc66
LP
4130 return -EBADMSG;
4131
3798fd4c 4132 *contents = c->peeked_signature;
6647dc66
LP
4133 } else {
4134 size_t rindex, l;
4135
4136 rindex = m->rindex;
4137 r = message_peek_body(m, &rindex, 1, 1, &q);
4138 if (r < 0)
4139 return r;
9a17484d 4140
6647dc66
LP
4141 l = *(uint8_t*) q;
4142 r = message_peek_body(m, &rindex, 1, l+1, &q);
4143 if (r < 0)
4144 return r;
6647dc66
LP
4145
4146 if (!validate_signature(q, l))
4147 return -EBADMSG;
4148
4149 *contents = q;
4150 }
9a17484d
LP
4151 }
4152
4153 if (type)
4154 *type = SD_BUS_TYPE_VARIANT;
4155
4156 return 1;
4157 }
4158
4159 return -EINVAL;
4160
4161eof:
4162 if (type)
7b058942 4163 *type = 0;
9a17484d
LP
4164 if (contents)
4165 *contents = NULL;
4166 return 0;
4167}
4168
d9f644e2 4169_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
9a17484d
LP
4170 struct bus_container *c;
4171
9d6c7c82
LP
4172 assert_return(m, -EINVAL);
4173 assert_return(m->sealed, -EPERM);
9a17484d
LP
4174
4175 if (complete) {
bc7fd8cd 4176 message_reset_containers(m);
9a17484d 4177 m->rindex = 0;
9a17484d
LP
4178
4179 c = message_get_container(m);
4180 } else {
4181 c = message_get_container(m);
4182
6647dc66 4183 c->offset_index = 0;
9a17484d
LP
4184 c->index = 0;
4185 m->rindex = c->begin;
4186 }
4187
d36b7031 4188 c->offset_index = 0;
e4bb80a0 4189 c->item_size = (c->n_offsets > 0 ? c->offsets[0] : c->end) - c->begin;
d36b7031 4190
9a17484d
LP
4191 return !isempty(c->signature);
4192}
718db961 4193
1b492614
LP
4194static int message_read_ap(
4195 sd_bus_message *m,
4196 const char *types,
4197 va_list ap) {
9a17484d 4198
fe1d424d
LP
4199 unsigned n_array, n_struct;
4200 TypeStack stack[BUS_CONTAINER_DEPTH];
4201 unsigned stack_ptr = 0;
430fb8fa 4202 unsigned n_loop = 0;
9a17484d
LP
4203 int r;
4204
4205 assert(m);
1b492614 4206
430fb8fa 4207 if (isempty(types))
1b492614 4208 return 0;
9a17484d 4209
fe1d424d
LP
4210 /* Ideally, we'd just call ourselves recursively on every
4211 * complex type. However, the state of a va_list that is
4212 * passed to a function is undefined after that function
4213 * returns. This means we need to docode the va_list linearly
4214 * in a single stackframe. We hence implement our own
4215 * home-grown stack in an array. */
4216
430fb8fa
LP
4217 n_array = (unsigned) -1; /* lenght of current array entries */
4218 n_struct = strlen(types); /* length of current struct contents signature */
fe1d424d
LP
4219
4220 for (;;) {
4221 const char *t;
4222
430fb8fa
LP
4223 n_loop++;
4224
1b492614 4225 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
fe1d424d
LP
4226 r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
4227 if (r < 0)
4228 return r;
4229 if (r == 0)
4230 break;
4231
4232 r = sd_bus_message_exit_container(m);
4233 if (r < 0)
4234 return r;
4235
4236 continue;
4237 }
4238
4239 t = types;
4240 if (n_array != (unsigned) -1)
4241 n_array --;
4242 else {
4243 types ++;
4244 n_struct--;
4245 }
4246
9a17484d
LP
4247 switch (*t) {
4248
4249 case SD_BUS_TYPE_BYTE:
4250 case SD_BUS_TYPE_BOOLEAN:
4251 case SD_BUS_TYPE_INT16:
4252 case SD_BUS_TYPE_UINT16:
4253 case SD_BUS_TYPE_INT32:
4254 case SD_BUS_TYPE_UINT32:
4255 case SD_BUS_TYPE_INT64:
4256 case SD_BUS_TYPE_UINT64:
4257 case SD_BUS_TYPE_DOUBLE:
4258 case SD_BUS_TYPE_STRING:
4259 case SD_BUS_TYPE_OBJECT_PATH:
2c93b4ef
LP
4260 case SD_BUS_TYPE_SIGNATURE:
4261 case SD_BUS_TYPE_UNIX_FD: {
9a17484d
LP
4262 void *p;
4263
4264 p = va_arg(ap, void*);
4265 r = sd_bus_message_read_basic(m, *t, p);
fe1d424d
LP
4266 if (r < 0)
4267 return r;
430fb8fa
LP
4268 if (r == 0) {
4269 if (n_loop <= 1)
4270 return 0;
4271
fe1d424d 4272 return -ENXIO;
430fb8fa 4273 }
fe1d424d 4274
9a17484d
LP
4275 break;
4276 }
4277
4278 case SD_BUS_TYPE_ARRAY: {
4279 size_t k;
4280
4281 r = signature_element_length(t + 1, &k);
4282 if (r < 0)
4283 return r;
4284
4285 {
9a17484d 4286 char s[k + 1];
9a17484d
LP
4287 memcpy(s, t + 1, k);
4288 s[k] = 0;
9a17484d
LP
4289
4290 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4291 if (r < 0)
4292 return r;
430fb8fa
LP
4293 if (r == 0) {
4294 if (n_loop <= 1)
4295 return 0;
4296
9a17484d 4297 return -ENXIO;
430fb8fa 4298 }
fe1d424d 4299 }
9a17484d 4300
fe1d424d
LP
4301 if (n_array == (unsigned) -1) {
4302 types += k;
4303 n_struct -= k;
9a17484d
LP
4304 }
4305
fe1d424d
LP
4306 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4307 if (r < 0)
4308 return r;
4309
4310 types = t + 1;
4311 n_struct = k;
4312 n_array = va_arg(ap, unsigned);
4313
9a17484d
LP
4314 break;
4315 }
4316
4317 case SD_BUS_TYPE_VARIANT: {
4318 const char *s;
4319
4320 s = va_arg(ap, const char *);
4321 if (!s)
4322 return -EINVAL;
4323
4324 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s);
4325 if (r < 0)
4326 return r;
430fb8fa
LP
4327 if (r == 0) {
4328 if (n_loop <= 1)
4329 return 0;
4330
9a17484d 4331 return -ENXIO;
430fb8fa 4332 }
9a17484d 4333
fe1d424d 4334 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
9a17484d
LP
4335 if (r < 0)
4336 return r;
9a17484d 4337
fe1d424d
LP
4338 types = s;
4339 n_struct = strlen(s);
4340 n_array = (unsigned) -1;
4341
9a17484d
LP
4342 break;
4343 }
4344
4345 case SD_BUS_TYPE_STRUCT_BEGIN:
4346 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4347 size_t k;
4348
4349 r = signature_element_length(t, &k);
4350 if (r < 0)
4351 return r;
4352
4353 {
4354 char s[k - 1];
4355 memcpy(s, t + 1, k - 2);
4356 s[k - 2] = 0;
4357
4358 r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4359 if (r < 0)
4360 return r;
430fb8fa
LP
4361 if (r == 0) {
4362 if (n_loop <= 1)
4363 return 0;
9a17484d 4364 return -ENXIO;
430fb8fa 4365 }
fe1d424d 4366 }
9a17484d 4367
fe1d424d
LP
4368 if (n_array == (unsigned) -1) {
4369 types += k - 1;
4370 n_struct -= k - 1;
4371 }
9a17484d 4372
fe1d424d
LP
4373 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4374 if (r < 0)
4375 return r;
9a17484d 4376
fe1d424d
LP
4377 types = t + 1;
4378 n_struct = k - 2;
4379 n_array = (unsigned) -1;
9a17484d
LP
4380
4381 break;
4382 }
4383
4384 default:
fe1d424d 4385 return -EINVAL;
9a17484d 4386 }
9a17484d
LP
4387 }
4388
4389 return 1;
4390}
4391
d9f644e2 4392_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
9a17484d
LP
4393 va_list ap;
4394 int r;
4395
9b07511d
LP
4396 assert_return(m, -EINVAL);
4397 assert_return(m->sealed, -EPERM);
4398 assert_return(types, -EINVAL);
9a17484d
LP
4399
4400 va_start(ap, types);
4401 r = message_read_ap(m, types, ap);
4402 va_end(ap);
4403
4404 return r;
4405}
4406
d9f644e2 4407_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
9b07511d
LP
4408 int r;
4409
4410 assert_return(m, -EINVAL);
4411 assert_return(m->sealed, -EPERM);
4412 assert_return(types, -EINVAL);
4413
4414 if (isempty(types))
4415 return 0;
4416
4417 switch (*types) {
4418
4419 case SD_BUS_TYPE_BYTE:
4420 case SD_BUS_TYPE_BOOLEAN:
4421 case SD_BUS_TYPE_INT16:
4422 case SD_BUS_TYPE_UINT16:
4423 case SD_BUS_TYPE_INT32:
4424 case SD_BUS_TYPE_UINT32:
4425 case SD_BUS_TYPE_INT64:
4426 case SD_BUS_TYPE_UINT64:
4427 case SD_BUS_TYPE_DOUBLE:
4428 case SD_BUS_TYPE_STRING:
4429 case SD_BUS_TYPE_OBJECT_PATH:
4430 case SD_BUS_TYPE_SIGNATURE:
4431 case SD_BUS_TYPE_UNIX_FD:
4432
4433 r = sd_bus_message_read_basic(m, *types, NULL);
4434 if (r <= 0)
4435 return r;
4436
4437 r = sd_bus_message_skip(m, types + 1);
4438 if (r < 0)
4439 return r;
4440
4441 return 1;
4442
4443 case SD_BUS_TYPE_ARRAY: {
4444 size_t k;
4445
4446 r = signature_element_length(types + 1, &k);
4447 if (r < 0)
4448 return r;
4449
4450 {
4451 char s[k+1];
4452 memcpy(s, types+1, k);
4453 s[k] = 0;
4454
4455 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4456 if (r <= 0)
4457 return r;
4458
4459 for (;;) {
4460 r = sd_bus_message_skip(m, s);
4461 if (r < 0)
4462 return r;
4463 if (r == 0)
4464 break;
4465 }
4466
4467 r = sd_bus_message_exit_container(m);
4468 if (r < 0)
4469 return r;
4470 }
4471
4472 r = sd_bus_message_skip(m, types + 1 + k);
4473 if (r < 0)
4474 return r;
4475
4476 return 1;
4477 }
4478
4479 case SD_BUS_TYPE_VARIANT: {
4480 const char *contents;
4481 char x;
4482
4483 r = sd_bus_message_peek_type(m, &x, &contents);
4484 if (r <= 0)
4485 return r;
4486
4487 if (x != SD_BUS_TYPE_VARIANT)
4488 return -ENXIO;
4489
4490 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
4491 if (r <= 0)
4492 return r;
4493
4494 r = sd_bus_message_skip(m, contents);
4495 if (r < 0)
4496 return r;
4497 assert(r != 0);
4498
4499 r = sd_bus_message_exit_container(m);
4500 if (r < 0)
4501 return r;
4502
4503 r = sd_bus_message_skip(m, types + 1);
4504 if (r < 0)
4505 return r;
4506
4507 return 1;
4508 }
4509
4510 case SD_BUS_TYPE_STRUCT_BEGIN:
4511 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4512 size_t k;
4513
4514 r = signature_element_length(types, &k);
4515 if (r < 0)
4516 return r;
4517
4518 {
4519 char s[k-1];
4520 memcpy(s, types+1, k-2);
4521 s[k-2] = 0;
4522
4523 r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4524 if (r <= 0)
4525 return r;
4526
4527 r = sd_bus_message_skip(m, s);
4528 if (r < 0)
4529 return r;
4530 assert(r != 0);
4531
4532 r = sd_bus_message_exit_container(m);
4533 if (r < 0)
4534 return r;
4535 }
4536
4537 r = sd_bus_message_skip(m, types + k);
4538 if (r < 0)
4539 return r;
4540
4541 return 1;
4542 }
4543
4544 default:
4545 return -EINVAL;
4546 }
4547}
4548
d9f644e2
ZJS
4549_public_ int sd_bus_message_read_array(sd_bus_message *m,
4550 char type,
4551 const void **ptr,
4552 size_t *size) {
b3af9646
LP
4553 struct bus_container *c;
4554 void *p;
4555 size_t sz;
4556 ssize_t align;
4557 int r;
4558
9d6c7c82
LP
4559 assert_return(m, -EINVAL);
4560 assert_return(m->sealed, -EPERM);
4561 assert_return(bus_type_is_trivial(type), -EINVAL);
4562 assert_return(ptr, -EINVAL);
4563 assert_return(size, -EINVAL);
4564 assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -ENOTSUP);
b3af9646 4565
b3af9646 4566 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
66b26c5c 4567 if (r <= 0)
b3af9646
LP
4568 return r;
4569
4570 c = message_get_container(m);
6647dc66
LP
4571
4572 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4573 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
4574 if (align < 0)
4575 return align;
4576
18f5b48f 4577 sz = c->end - c->begin;
6647dc66
LP
4578 } else {
4579 align = bus_type_get_alignment(type);
4580 if (align < 0)
4581 return align;
4582
4583 sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
4584 }
b3af9646 4585
5e86fd7b
LP
4586 if (sz == 0)
4587 /* Zero length array, let's return some aligned
4588 * pointer that is not NULL */
4589 p = (uint8_t*) NULL + align;
4590 else {
4591 r = message_peek_body(m, &m->rindex, align, sz, &p);
4592 if (r < 0)
4593 goto fail;
b3af9646
LP
4594 }
4595
4596 r = sd_bus_message_exit_container(m);
4597 if (r < 0)
4598 goto fail;
4599
4600 *ptr = (const void*) p;
4601 *size = sz;
4602
4603 return 1;
4604
4605fail:
4606 message_quit_container(m);
4607 return r;
4608}
4609
80a46c73
LP
4610static int message_peek_fields(
4611 sd_bus_message *m,
4612 size_t *rindex,
4613 size_t align,
4614 size_t nbytes,
4615 void **ret) {
4616
4617 assert(m);
4618 assert(rindex);
4619 assert(align > 0);
4620
c91cb83c 4621 return buffer_peek(BUS_MESSAGE_FIELDS(m), BUS_MESSAGE_FIELDS_SIZE(m), rindex, align, nbytes, ret);
80a46c73
LP
4622}
4623
9f26c90c
LP
4624static int message_peek_field_uint32(
4625 sd_bus_message *m,
4626 size_t *ri,
6647dc66 4627 size_t item_size,
9f26c90c
LP
4628 uint32_t *ret) {
4629
4630 int r;
4631 void *q;
4632
4633 assert(m);
4634 assert(ri);
4635
6647dc66
LP
4636 if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 4)
4637 return -EBADMSG;
4638
4639 /* identical for gvariant and dbus1 */
4640
9f26c90c
LP
4641 r = message_peek_fields(m, ri, 4, 4, &q);
4642 if (r < 0)
4643 return r;
4644
4645 if (ret)
4646 *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
4647
4648 return 0;
4649}
4650
80a46c73
LP
4651static int message_peek_field_string(
4652 sd_bus_message *m,
6693860f 4653 bool (*validate)(const char *p),
80a46c73 4654 size_t *ri,
6647dc66 4655 size_t item_size,
80a46c73
LP
4656 const char **ret) {
4657
9f26c90c 4658 uint32_t l;
80a46c73
LP
4659 int r;
4660 void *q;
4661
9a17484d 4662 assert(m);
80a46c73
LP
4663 assert(ri);
4664
6647dc66 4665 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4666
6647dc66
LP
4667 if (item_size <= 0)
4668 return -EBADMSG;
4669
4670 r = message_peek_fields(m, ri, 1, item_size, &q);
4671 if (r < 0)
4672 return r;
4673
4674 l = item_size - 1;
4675 } else {
4676 r = message_peek_field_uint32(m, ri, 4, &l);
4677 if (r < 0)
4678 return r;
4679
4680 r = message_peek_fields(m, ri, 1, l+1, &q);
4681 if (r < 0)
4682 return r;
4683 }
9a17484d 4684
6693860f
LP
4685 if (validate) {
4686 if (!validate_nul(q, l))
4687 return -EBADMSG;
4688
4689 if (!validate(q))
ac89bf1d
LP
4690 return -EBADMSG;
4691 } else {
4692 if (!validate_string(q, l))
4693 return -EBADMSG;
4694 }
80a46c73
LP
4695
4696 if (ret)
4697 *ret = q;
4698
4699 return 0;
4700}
4701
4702static int message_peek_field_signature(
4703 sd_bus_message *m,
4704 size_t *ri,
6647dc66 4705 size_t item_size,
80a46c73
LP
4706 const char **ret) {
4707
4708 size_t l;
4709 int r;
4710 void *q;
4711
4712 assert(m);
4713 assert(ri);
4714
6647dc66 4715 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4716
6647dc66
LP
4717 if (item_size <= 0)
4718 return -EBADMSG;
4719
4720 r = message_peek_fields(m, ri, 1, item_size, &q);
4721 if (r < 0)
4722 return r;
4723
4724 l = item_size - 1;
4725 } else {
4726 r = message_peek_fields(m, ri, 1, 1, &q);
4727 if (r < 0)
4728 return r;
4729
4730 l = *(uint8_t*) q;
4731 r = message_peek_fields(m, ri, 1, l+1, &q);
4732 if (r < 0)
4733 return r;
4734 }
80a46c73
LP
4735
4736 if (!validate_signature(q, l))
4737 return -EBADMSG;
4738
4739 if (ret)
4740 *ret = q;
4741
4742 return 0;
4743}
4744
80a46c73
LP
4745static int message_skip_fields(
4746 sd_bus_message *m,
4747 size_t *ri,
4748 uint32_t array_size,
4749 const char **signature) {
4750
4751 size_t original_index;
4752 int r;
4753
4754 assert(m);
4755 assert(ri);
4756 assert(signature);
6647dc66 4757 assert(!BUS_MESSAGE_IS_GVARIANT(m));
80a46c73
LP
4758
4759 original_index = *ri;
4760
4761 for (;;) {
4762 char t;
80a46c73
LP
4763 size_t l;
4764
4765 if (array_size != (uint32_t) -1 &&
4766 array_size <= *ri - original_index)
4767 return 0;
4768
4769 t = **signature;
4770 if (!t)
4771 return 0;
4772
6693860f
LP
4773 if (t == SD_BUS_TYPE_STRING) {
4774
6647dc66 4775 r = message_peek_field_string(m, NULL, ri, 0, NULL);
6693860f
LP
4776 if (r < 0)
4777 return r;
4778
4779 (*signature)++;
4780
4781 } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
80a46c73 4782
6647dc66 4783 r = message_peek_field_string(m, object_path_is_valid, ri, 0, NULL);
80a46c73
LP
4784 if (r < 0)
4785 return r;
4786
4787 (*signature)++;
4788
4789 } else if (t == SD_BUS_TYPE_SIGNATURE) {
4790
6647dc66 4791 r = message_peek_field_signature(m, ri, 0, NULL);
80a46c73
LP
4792 if (r < 0)
4793 return r;
4794
4795 (*signature)++;
4796
4797 } else if (bus_type_is_basic(t)) {
27f6e5c7 4798 ssize_t align, k;
80a46c73 4799
c66a2e0c
TG
4800 align = bus_type_get_alignment(t);
4801 k = bus_type_get_size(t);
27f6e5c7 4802 assert(align > 0 && k > 0);
80a46c73
LP
4803
4804 r = message_peek_fields(m, ri, align, k, NULL);
4805 if (r < 0)
4806 return r;
9a17484d 4807
80a46c73
LP
4808 (*signature)++;
4809
4810 } else if (t == SD_BUS_TYPE_ARRAY) {
4811
4812 r = signature_element_length(*signature+1, &l);
4813 if (r < 0)
4814 return r;
4815
4816 assert(l >= 1);
4817 {
4818 char sig[l-1], *s;
9f26c90c 4819 uint32_t nas;
80a46c73
LP
4820 int alignment;
4821
4822 strncpy(sig, *signature + 1, l-1);
4823 s = sig;
4824
4825 alignment = bus_type_get_alignment(sig[0]);
4826 if (alignment < 0)
4827 return alignment;
4828
6647dc66 4829 r = message_peek_field_uint32(m, ri, 0, &nas);
80a46c73
LP
4830 if (r < 0)
4831 return r;
ac89bf1d 4832 if (nas > BUS_ARRAY_MAX_SIZE)
80a46c73
LP
4833 return -EBADMSG;
4834
4835 r = message_peek_fields(m, ri, alignment, 0, NULL);
4836 if (r < 0)
4837 return r;
4838
4839 r = message_skip_fields(m, ri, nas, (const char**) &s);
4840 if (r < 0)
4841 return r;
4842 }
4843
4844 (*signature) += 1 + l;
4845
4846 } else if (t == SD_BUS_TYPE_VARIANT) {
4847 const char *s;
4848
6647dc66 4849 r = message_peek_field_signature(m, ri, 0, &s);
80a46c73
LP
4850 if (r < 0)
4851 return r;
4852
4853 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
4854 if (r < 0)
4855 return r;
4856
4857 (*signature)++;
4858
4859 } else if (t == SD_BUS_TYPE_STRUCT ||
4860 t == SD_BUS_TYPE_DICT_ENTRY) {
4861
4862 r = signature_element_length(*signature, &l);
4863 if (r < 0)
4864 return r;
4865
4866 assert(l >= 2);
4867 {
4868 char sig[l-1], *s;
4869 strncpy(sig, *signature + 1, l-1);
4870 s = sig;
4871
4872 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
4873 if (r < 0)
4874 return r;
4875 }
4876
4877 *signature += l;
4878 } else
4879 return -EINVAL;
4880 }
4881}
4882
6629161f 4883int bus_message_parse_fields(sd_bus_message *m) {
80a46c73
LP
4884 size_t ri;
4885 int r;
2c93b4ef 4886 uint32_t unix_fds = 0;
6647dc66
LP
4887 void *offsets = NULL;
4888 unsigned n_offsets = 0;
8f2e44f8 4889 size_t sz = 0;
6647dc66 4890 unsigned i = 0;
80a46c73
LP
4891
4892 assert(m);
4893
6647dc66
LP
4894 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4895 void *q;
4896
4897 sz = determine_word_size(BUS_MESSAGE_FIELDS_SIZE(m), 0);
4898 if (sz > 0) {
4899 size_t framing;
4900
4901 ri = BUS_MESSAGE_FIELDS_SIZE(m) - sz;
4902 r = message_peek_fields(m, &ri, 1, sz, &q);
4903 if (r < 0)
4904 return r;
4905
4906 framing = read_word_le(q, sz);
4907 if (framing >= BUS_MESSAGE_FIELDS_SIZE(m) - sz)
4908 return -EBADMSG;
4909 if ((BUS_MESSAGE_FIELDS_SIZE(m) - framing) % sz != 0)
4910 return -EBADMSG;
4911
4912 ri = framing;
4913 r = message_peek_fields(m, &ri, 1, BUS_MESSAGE_FIELDS_SIZE(m) - framing, &offsets);
4914 if (r < 0)
4915 return r;
4916
4917 n_offsets = (BUS_MESSAGE_FIELDS_SIZE(m) - framing) / sz;
4918 }
4919 }
4920
4921 ri = 0;
4922 while (ri < BUS_MESSAGE_FIELDS_SIZE(m)) {
4923 _cleanup_free_ char *sig = NULL;
80a46c73
LP
4924 const char *signature;
4925 uint8_t *header;
6647dc66
LP
4926 size_t item_size = (size_t) -1;
4927
4928 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4929 if (i >= n_offsets)
4930 break;
4931
4932 if (i == 0)
4933 ri = 0;
4934 else
4935 ri = ALIGN_TO(read_word_le((uint8_t*) offsets + (i-1)*sz, sz), 8);
4936 }
80a46c73
LP
4937
4938 r = message_peek_fields(m, &ri, 8, 1, (void**) &header);
4939 if (r < 0)
4940 return r;
4941
6647dc66
LP
4942 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4943 size_t where, end;
4944 char *b;
4945 void *q;
4946
4947 end = read_word_le((uint8_t*) offsets + i*sz, sz);
4948
4949 if (end < ri)
4950 return -EBADMSG;
4951
4952 where = ri = ALIGN_TO(ri, 8);
4953 item_size = end - ri;
4954 r = message_peek_fields(m, &where, 1, item_size, &q);
4955 if (r < 0)
4956 return r;
4957
4958 b = memrchr(q, 0, item_size);
4959 if (!b)
4960 return -EBADMSG;
4961
4962 sig = strndup(b+1, item_size - (b+1-(char*) q));
4963 if (!sig)
4964 return -ENOMEM;
4965
4966 signature = sig;
4967 item_size = b - (char*) q;
4968 } else {
4969 r = message_peek_field_signature(m, &ri, 0, &signature);
4970 if (r < 0)
4971 return r;
4972 }
80a46c73
LP
4973
4974 switch (*header) {
0461f8cd 4975 case _BUS_MESSAGE_HEADER_INVALID:
80a46c73
LP
4976 return -EBADMSG;
4977
0461f8cd 4978 case BUS_MESSAGE_HEADER_PATH:
2c93b4ef
LP
4979
4980 if (m->path)
4981 return -EBADMSG;
4982
80a46c73
LP
4983 if (!streq(signature, "o"))
4984 return -EBADMSG;
4985
6647dc66 4986 r = message_peek_field_string(m, object_path_is_valid, &ri, item_size, &m->path);
80a46c73
LP
4987 break;
4988
0461f8cd 4989 case BUS_MESSAGE_HEADER_INTERFACE:
2c93b4ef
LP
4990
4991 if (m->interface)
4992 return -EBADMSG;
4993
80a46c73
LP
4994 if (!streq(signature, "s"))
4995 return -EBADMSG;
4996
6647dc66 4997 r = message_peek_field_string(m, interface_name_is_valid, &ri, item_size, &m->interface);
80a46c73
LP
4998 break;
4999
0461f8cd 5000 case BUS_MESSAGE_HEADER_MEMBER:
2c93b4ef
LP
5001
5002 if (m->member)
5003 return -EBADMSG;
5004
80a46c73
LP
5005 if (!streq(signature, "s"))
5006 return -EBADMSG;
5007
6647dc66 5008 r = message_peek_field_string(m, member_name_is_valid, &ri, item_size, &m->member);
80a46c73
LP
5009 break;
5010
0461f8cd 5011 case BUS_MESSAGE_HEADER_ERROR_NAME:
2c93b4ef
LP
5012
5013 if (m->error.name)
5014 return -EBADMSG;
5015
80a46c73
LP
5016 if (!streq(signature, "s"))
5017 return -EBADMSG;
5018
6647dc66 5019 r = message_peek_field_string(m, error_name_is_valid, &ri, item_size, &m->error.name);
79f8d3d2
LP
5020 if (r >= 0)
5021 m->error._need_free = -1;
5022
80a46c73
LP
5023 break;
5024
0461f8cd 5025 case BUS_MESSAGE_HEADER_DESTINATION:
2c93b4ef
LP
5026
5027 if (m->destination)
5028 return -EBADMSG;
5029
80a46c73
LP
5030 if (!streq(signature, "s"))
5031 return -EBADMSG;
5032
6647dc66 5033 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->destination);
80a46c73
LP
5034 break;
5035
0461f8cd 5036 case BUS_MESSAGE_HEADER_SENDER:
2c93b4ef
LP
5037
5038 if (m->sender)
5039 return -EBADMSG;
5040
80a46c73
LP
5041 if (!streq(signature, "s"))
5042 return -EBADMSG;
5043
6647dc66 5044 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
49b832c5
LP
5045
5046 if (r >= 0 && m->sender[0] == ':' && m->bus && m->bus->bus_client && !m->bus->is_kernel) {
5047 m->creds.unique_name = (char*) m->sender;
5048 m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
5049 }
5050
80a46c73
LP
5051 break;
5052
5053
0461f8cd 5054 case BUS_MESSAGE_HEADER_SIGNATURE: {
80a46c73
LP
5055 const char *s;
5056 char *c;
5057
2c93b4ef
LP
5058 if (m->root_container.signature)
5059 return -EBADMSG;
5060
80a46c73
LP
5061 if (!streq(signature, "g"))
5062 return -EBADMSG;
5063
6647dc66 5064 r = message_peek_field_signature(m, &ri, item_size, &s);
80a46c73
LP
5065 if (r < 0)
5066 return r;
5067
5068 c = strdup(s);
5069 if (!c)
5070 return -ENOMEM;
5071
5072 free(m->root_container.signature);
5073 m->root_container.signature = c;
80a46c73
LP
5074 break;
5075 }
5076
0461f8cd 5077 case BUS_MESSAGE_HEADER_REPLY_SERIAL:
693eb9a2 5078 if (m->reply_cookie != 0)
2c93b4ef
LP
5079 return -EBADMSG;
5080
80a46c73
LP
5081 if (!streq(signature, "u"))
5082 return -EBADMSG;
5083
693eb9a2 5084 r = message_peek_field_uint32(m, &ri, item_size, &m->reply_cookie);
6693860f
LP
5085 if (r < 0)
5086 return r;
5087
693eb9a2 5088 if (m->reply_cookie == 0)
6693860f
LP
5089 return -EBADMSG;
5090
80a46c73
LP
5091 break;
5092
0461f8cd 5093 case BUS_MESSAGE_HEADER_UNIX_FDS:
2c93b4ef
LP
5094 if (unix_fds != 0)
5095 return -EBADMSG;
5096
5097 if (!streq(signature, "u"))
5098 return -EBADMSG;
5099
6647dc66 5100 r = message_peek_field_uint32(m, &ri, item_size, &unix_fds);
2c93b4ef
LP
5101 if (r < 0)
5102 return -EBADMSG;
5103
5104 if (unix_fds == 0)
5105 return -EBADMSG;
5106
5107 break;
5108
80a46c73 5109 default:
6647dc66
LP
5110 if (!BUS_MESSAGE_IS_GVARIANT(m))
5111 r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
80a46c73
LP
5112 }
5113
5114 if (r < 0)
5115 return r;
6647dc66
LP
5116
5117 i++;
80a46c73
LP
5118 }
5119
2c93b4ef
LP
5120 if (m->n_fds != unix_fds)
5121 return -EBADMSG;
5122
80a46c73
LP
5123 switch (m->header->type) {
5124
40ca29a1 5125 case SD_BUS_MESSAGE_SIGNAL:
80a46c73
LP
5126 if (!m->path || !m->interface || !m->member)
5127 return -EBADMSG;
5128 break;
5129
40ca29a1 5130 case SD_BUS_MESSAGE_METHOD_CALL:
80a46c73
LP
5131
5132 if (!m->path || !m->member)
5133 return -EBADMSG;
5134
5135 break;
5136
40ca29a1 5137 case SD_BUS_MESSAGE_METHOD_RETURN:
80a46c73 5138
693eb9a2 5139 if (m->reply_cookie == 0)
80a46c73
LP
5140 return -EBADMSG;
5141 break;
5142
40ca29a1 5143 case SD_BUS_MESSAGE_METHOD_ERROR:
80a46c73 5144
693eb9a2 5145 if (m->reply_cookie == 0 || !m->error.name)
80a46c73
LP
5146 return -EBADMSG;
5147 break;
5148 }
9a17484d 5149
35473296
LP
5150 /* Refuse non-local messages that claim they are local */
5151 if (streq_ptr(m->path, "/org/freedesktop/DBus/Local"))
5152 return -EBADMSG;
5153 if (streq_ptr(m->interface, "org.freedesktop.DBus.Local"))
5154 return -EBADMSG;
5155 if (streq_ptr(m->sender, "org.freedesktop.DBus.Local"))
5156 return -EBADMSG;
5157
6647dc66
LP
5158 m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
5159
5160 if (BUS_MESSAGE_IS_GVARIANT(m)) {
5161 r = build_struct_offsets(
5162 m,
5163 m->root_container.signature,
5164 BUS_MESSAGE_BODY_SIZE(m),
5165 &m->root_container.item_size,
5166 &m->root_container.offsets,
5167 &m->root_container.n_offsets);
5168 if (r < 0)
5169 return r;
5170 }
5171
89ffcd2a 5172 /* Try to read the error message, but if we can't it's a non-issue */
40ca29a1 5173 if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
89ffcd2a
LP
5174 sd_bus_message_read(m, "s", &m->error.message);
5175
9a17484d
LP
5176 return 0;
5177}
5178
d9f644e2 5179_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
9d6c7c82
LP
5180 assert_return(m, -EINVAL);
5181 assert_return(destination, -EINVAL);
5182 assert_return(!m->sealed, -EPERM);
5183 assert_return(!m->destination, -EEXIST);
9a17484d 5184
0461f8cd 5185 return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
9a17484d
LP
5186}
5187
de1c301e
LP
5188int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
5189 size_t total;
de1c301e 5190 void *p, *e;
bc7fd8cd
LP
5191 unsigned i;
5192 struct bus_body_part *part;
de1c301e
LP
5193
5194 assert(m);
5195 assert(buffer);
5196 assert(sz);
5197
6629161f 5198 total = BUS_MESSAGE_SIZE(m);
de1c301e
LP
5199
5200 p = malloc(total);
5201 if (!p)
5202 return -ENOMEM;
5203
c91cb83c 5204 e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m));
9b29bb68 5205 MESSAGE_FOREACH_PART(part, i, m)
bc7fd8cd 5206 e = mempcpy(e, part->data, part->size);
2100fa10
LP
5207
5208 assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p));
de1c301e
LP
5209
5210 *buffer = p;
5211 *sz = total;
5212
5213 return 0;
5214}
89ffcd2a
LP
5215
5216int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
5217 int r;
5218
5219 assert(m);
5220 assert(l);
5221
5222 r = sd_bus_message_enter_container(m, 'a', "s");
4686d1b6 5223 if (r <= 0)
89ffcd2a
LP
5224 return r;
5225
5226 for (;;) {
5227 const char *s;
5228
5229 r = sd_bus_message_read_basic(m, 's', &s);
5230 if (r < 0)
5231 return r;
5232 if (r == 0)
5233 break;
5234
5235 r = strv_extend(l, s);
5236 if (r < 0)
5237 return r;
5238 }
5239
5240 r = sd_bus_message_exit_container(m);
5241 if (r < 0)
5242 return r;
5243
405cd3aa 5244 return 1;
89ffcd2a 5245}
392d5b37 5246
ba341e7c 5247_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
4686d1b6
MAP
5248 char **strv = NULL;
5249 int r;
5250
5251 assert_return(m, -EINVAL);
5252 assert_return(m->sealed, -EPERM);
5253 assert_return(l, -EINVAL);
5254
5255 r = bus_message_read_strv_extend(m, &strv);
5256 if (r <= 0) {
5257 strv_free(strv);
5258 return r;
5259 }
5260
5261 *l = strv;
5262 return 1;
5263}
5264
392d5b37
LP
5265const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
5266 int r;
42c5aaf3
LP
5267 const char *t = NULL;
5268 unsigned j;
392d5b37
LP
5269
5270 assert(m);
5271
5272 r = sd_bus_message_rewind(m, true);
5273 if (r < 0)
5274 return NULL;
5275
42c5aaf3
LP
5276 for (j = 0; j <= i; j++) {
5277 char type;
5278
392d5b37
LP
5279 r = sd_bus_message_peek_type(m, &type, NULL);
5280 if (r < 0)
5281 return NULL;
5282
5283 if (type != SD_BUS_TYPE_STRING &&
5284 type != SD_BUS_TYPE_OBJECT_PATH &&
5285 type != SD_BUS_TYPE_SIGNATURE)
5286 return NULL;
5287
5288 r = sd_bus_message_read_basic(m, type, &t);
5289 if (r < 0)
5290 return NULL;
392d5b37
LP
5291 }
5292
392d5b37
LP
5293 return t;
5294}
2100fa10 5295
c91cb83c
LP
5296bool bus_header_is_complete(struct bus_header *h, size_t size) {
5297 size_t full;
5298
5299 assert(h);
5300 assert(size);
5301
5302 if (size < sizeof(struct bus_header))
5303 return false;
5304
5305 full = sizeof(struct bus_header) +
0461f8cd 5306 (h->endian == BUS_NATIVE_ENDIAN ? h->fields_size : bswap_32(h->fields_size));
c91cb83c
LP
5307
5308 return size >= full;
5309}
5310
5311int bus_header_message_size(struct bus_header *h, size_t *sum) {
6629161f
LP
5312 size_t fs, bs;
5313
5314 assert(h);
5315 assert(sum);
5316
0461f8cd 5317 if (h->endian == BUS_NATIVE_ENDIAN) {
6629161f
LP
5318 fs = h->fields_size;
5319 bs = h->body_size;
0461f8cd 5320 } else if (h->endian == BUS_REVERSE_ENDIAN) {
6629161f
LP
5321 fs = bswap_32(h->fields_size);
5322 bs = bswap_32(h->body_size);
5323 } else
5324 return -EBADMSG;
2100fa10 5325
6629161f
LP
5326 *sum = sizeof(struct bus_header) + ALIGN8(fs) + bs;
5327 return 0;
2100fa10 5328}
eb01ba5d 5329
d9f644e2 5330_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
40ca29a1 5331 assert_return(m, -EINVAL);
eb01ba5d 5332
40ca29a1 5333 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
eb01ba5d
LP
5334 return 0;
5335
40ca29a1 5336 return sd_bus_error_get_errno(&m->error);
eb01ba5d 5337}
29ddb38f 5338
d9f644e2 5339_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
29ddb38f
LP
5340 struct bus_container *c;
5341
9d6c7c82 5342 assert_return(m, NULL);
29ddb38f
LP
5343
5344 c = complete ? &m->root_container : message_get_container(m);
d6385068 5345 return strempty(c->signature);
29ddb38f 5346}
c430fee6 5347
d9f644e2 5348_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
c430fee6
LP
5349 bool done_something = false;
5350 int r;
5351
80ba3b84
LP
5352 assert_return(m, -EINVAL);
5353 assert_return(source, -EINVAL);
5354 assert_return(!m->sealed, -EPERM);
5355 assert_return(source->sealed, -EPERM);
5356
c430fee6
LP
5357 do {
5358 const char *contents;
5359 char type;
5360 union {
5361 uint8_t u8;
5362 uint16_t u16;
5363 int16_t s16;
5364 uint32_t u32;
5365 int32_t s32;
5366 uint64_t u64;
5367 int64_t s64;
5368 double d64;
5369 const char *string;
5370 int i;
5371 } basic;
5372
5373 r = sd_bus_message_peek_type(source, &type, &contents);
5374 if (r < 0)
5375 return r;
5376 if (r == 0)
5377 break;
5378
5379 done_something = true;
5380
5381 if (bus_type_is_container(type) > 0) {
5382
5383 r = sd_bus_message_enter_container(source, type, contents);
5384 if (r < 0)
5385 return r;
5386
5387 r = sd_bus_message_open_container(m, type, contents);
5388 if (r < 0)
5389 return r;
5390
5391 r = sd_bus_message_copy(m, source, true);
5392 if (r < 0)
5393 return r;
5394
5395 r = sd_bus_message_close_container(m);
5396 if (r < 0)
5397 return r;
5398
5399 r = sd_bus_message_exit_container(source);
5400 if (r < 0)
5401 return r;
5402
5403 continue;
5404 }
5405
5406 r = sd_bus_message_read_basic(source, type, &basic);
5407 if (r < 0)
5408 return r;
5409
5410 assert(r > 0);
5411
5412 if (type == SD_BUS_TYPE_OBJECT_PATH ||
5413 type == SD_BUS_TYPE_SIGNATURE ||
5414 type == SD_BUS_TYPE_STRING)
5415 r = sd_bus_message_append_basic(m, type, basic.string);
5416 else
5417 r = sd_bus_message_append_basic(m, type, &basic);
5418
5419 if (r < 0)
5420 return r;
5421
5422 } while (all);
5423
5424 return done_something;
5425}
5426
d9f644e2 5427_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
c430fee6
LP
5428 const char *c;
5429 char t;
5430 int r;
5431
5432 assert_return(m, -EINVAL);
5433 assert_return(m->sealed, -EPERM);
5434 assert_return(!type || bus_type_is_valid(type), -EINVAL);
5435 assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
5436 assert_return(type || contents, -EINVAL);
5437 assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
5438
5439 r = sd_bus_message_peek_type(m, &t, &c);
5440 if (r <= 0)
5441 return r;
5442
5443 if (type != 0 && type != t)
5444 return 0;
5445
5446 if (contents && !streq_ptr(contents, c))
5447 return 0;
5448
5449 return 1;
5450}
2be44176
LP
5451
5452_public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) {
5453 assert_return(m, NULL);
5454
5455 return m->bus;
5456}
e1c433c6
LP
5457
5458int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
5459 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
5460 usec_t timeout;
5461 int r;
5462
5463 assert(bus);
5464 assert(m);
5465 assert(*m);
5466
5467 switch ((*m)->header->type) {
5468
5469 case SD_BUS_MESSAGE_SIGNAL:
5470 r = sd_bus_message_new_signal(bus, (*m)->path, (*m)->interface, (*m)->member, &n);
5471 if (r < 0)
5472 return r;
5473
5474 break;
5475
5476 case SD_BUS_MESSAGE_METHOD_CALL:
5477 r = sd_bus_message_new_method_call(bus, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member, &n);
5478 if (r < 0)
5479 return r;
5480
5481 break;
5482
5483 case SD_BUS_MESSAGE_METHOD_RETURN:
5484 case SD_BUS_MESSAGE_METHOD_ERROR:
5485
5486 n = message_new(bus, (*m)->header->type);
5487 if (!n)
5488 return -ENOMEM;
5489
693eb9a2
LP
5490 n->reply_cookie = (*m)->reply_cookie;
5491 r = message_append_field_uint32(n, BUS_MESSAGE_HEADER_REPLY_SERIAL, n->reply_cookie);
e1c433c6
LP
5492 if (r < 0)
5493 return r;
5494
5495 if ((*m)->header->type == SD_BUS_MESSAGE_METHOD_ERROR && (*m)->error.name) {
5496 r = message_append_field_string(n, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, (*m)->error.name, &n->error.message);
5497 if (r < 0)
5498 return r;
5499
5500 n->error._need_free = -1;
5501 }
5502
5503 break;
5504
5505 default:
5506 return -EINVAL;
5507 }
5508
5509 if ((*m)->destination && !n->destination) {
5510 r = message_append_field_string(n, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, (*m)->destination, &n->destination);
5511 if (r < 0)
5512 return r;
5513 }
5514
5515 if ((*m)->sender && !n->sender) {
5516 r = message_append_field_string(n, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, (*m)->sender, &n->sender);
5517 if (r < 0)
5518 return r;
5519 }
5520
5521 n->header->flags |= (*m)->header->flags & (BUS_MESSAGE_NO_REPLY_EXPECTED|BUS_MESSAGE_NO_AUTO_START);
5522
5523 r = sd_bus_message_copy(n, *m, true);
5524 if (r < 0)
5525 return r;
5526
5527 timeout = (*m)->timeout;
5528 if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED))
5529 timeout = BUS_DEFAULT_TIMEOUT;
5530
693eb9a2 5531 r = bus_message_seal(n, BUS_MESSAGE_COOKIE(*m), timeout);
e1c433c6
LP
5532 if (r < 0)
5533 return r;
5534
5535 sd_bus_message_unref(*m);
5536 *m = n;
5537 n = NULL;
5538
5539 return 0;
5540}
a7639e37
LP
5541
5542int bus_message_append_sender(sd_bus_message *m, const char *sender) {
5543 assert(m);
5544 assert(sender);
5545
5546 assert_return(!m->sealed, -EPERM);
5547 assert_return(!m->sender, -EPERM);
5548
5549 return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
5550}