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