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