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