]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-message.c
bus: do not print (null) if the message has unknown type
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-message.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
de1c301e
LP
2
3#include <errno.h>
2c93b4ef 4#include <fcntl.h>
bc7fd8cd 5#include <sys/mman.h>
de1c301e 6
de1c301e 7#include "sd-bus.h"
07630cea 8
b5efdb8a 9#include "alloc-util.h"
07630cea 10#include "bus-gvariant.h"
de1c301e 11#include "bus-internal.h"
3ffd4af2 12#include "bus-message.h"
de1c301e 13#include "bus-signature.h"
07630cea 14#include "bus-type.h"
057171ef 15#include "bus-util.h"
3ffd4af2 16#include "fd-util.h"
afc5dbf3 17#include "io-util.h"
07630cea
LP
18#include "memfd-util.h"
19#include "string-util.h"
20#include "strv.h"
21#include "time-util.h"
22#include "utf8.h"
23#include "util.h"
de1c301e 24
80a46c73 25static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
de1c301e 26
bc7fd8cd
LP
27static void *adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) {
28
29 if (p == NULL)
30 return NULL;
31
32 if (old_base == new_base)
33 return (void*) p;
34
35 if ((uint8_t*) p < (uint8_t*) old_base)
36 return (void*) p;
37
38 if ((uint8_t*) p >= (uint8_t*) old_base + sz)
39 return (void*) p;
40
41 return (uint8_t*) new_base + ((uint8_t*) p - (uint8_t*) old_base);
42}
43
44static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
45 assert(m);
46 assert(part);
47
a132bef0
ZJS
48 if (part->memfd >= 0)
49 close_and_munmap(part->memfd, part->mmap_begin, part->mapped);
50 else if (part->munmap_this)
7dcd79c2 51 munmap(part->mmap_begin, part->mapped);
453a0c29 52 else if (part->free_this)
bc7fd8cd
LP
53 free(part->data);
54
55 if (part != &m->body)
56 free(part);
57}
58
59static void message_reset_parts(sd_bus_message *m) {
60 struct bus_body_part *part;
61
62 assert(m);
63
64 part = &m->body;
65 while (m->n_body_parts > 0) {
66 struct bus_body_part *next = part->next;
67 message_free_part(m, part);
68 part = next;
69 m->n_body_parts--;
70 }
71
72 m->body_end = NULL;
73
74 m->cached_rindex_part = NULL;
75 m->cached_rindex_part_begin = 0;
76}
77
9c65778d 78static struct bus_container *message_get_last_container(sd_bus_message *m) {
6d1e0f4f
ZJS
79 assert(m);
80
81 if (m->n_containers == 0)
82 return &m->root_container;
83
84 assert(m->containers);
85 return m->containers + m->n_containers - 1;
86}
87
88static void message_free_last_container(sd_bus_message *m) {
89 struct bus_container *c;
90
9c65778d 91 c = message_get_last_container(m);
6d1e0f4f
ZJS
92
93 free(c->signature);
94 free(c->peeked_signature);
95 free(c->offsets);
96
97 /* Move to previous container, but not if we are on root container */
98 if (m->n_containers > 0)
99 m->n_containers--;
100}
9a17484d 101
6d1e0f4f 102static void message_reset_containers(sd_bus_message *m) {
9a17484d
LP
103 assert(m);
104
6d1e0f4f
ZJS
105 while (m->n_containers > 0)
106 message_free_last_container(m);
9a17484d 107
a1e58e8e 108 m->containers = mfree(m->containers);
6d1e0f4f 109 m->containers_allocated = 0;
9a17484d
LP
110 m->root_container.index = 0;
111}
112
2ab3a635 113static sd_bus_message* message_free(sd_bus_message *m) {
de1c301e
LP
114 assert(m);
115
116 if (m->free_header)
117 free(m->header);
118
bc7fd8cd 119 message_reset_parts(m);
de1c301e 120
2a0958d2 121 sd_bus_unref(m->bus);
f54514f3 122
2c93b4ef
LP
123 if (m->free_fds) {
124 close_many(m->fds, m->n_fds);
125 free(m->fds);
126 }
de1c301e 127
bc7fd8cd
LP
128 if (m->iovec != m->iovec_fixed)
129 free(m->iovec);
130
bc7fd8cd 131 message_reset_containers(m);
6d1e0f4f
ZJS
132 assert(m->n_containers == 0);
133 message_free_last_container(m);
d8d3d8a7 134
5b12334d 135 bus_creds_done(&m->creds);
2ab3a635 136 return mfree(m);
de1c301e
LP
137}
138
2ab3a635
DT
139DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, message_free);
140
c1b9d935 141static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
c91cb83c
LP
142 void *op, *np;
143 size_t old_size, new_size, start;
de1c301e 144
c91cb83c 145 assert(m);
35460afc
LP
146
147 if (m->poisoned)
148 return NULL;
de1c301e 149
2ac7c17f 150 old_size = sizeof(struct bus_header) + m->fields_size;
c91cb83c
LP
151 start = ALIGN_TO(old_size, align);
152 new_size = start + sz;
de1c301e 153
2ac7c17f
LP
154 if (new_size < start ||
155 new_size > (size_t) ((uint32_t) -1))
156 goto poison;
157
c91cb83c
LP
158 if (old_size == new_size)
159 return (uint8_t*) m->header + old_size;
de1c301e 160
c91cb83c
LP
161 if (m->free_header) {
162 np = realloc(m->header, ALIGN8(new_size));
163 if (!np)
164 goto poison;
165 } else {
61233823 166 /* Initially, the header is allocated as part of
c91cb83c
LP
167 * the sd_bus_message itself, let's replace it by
168 * dynamic data */
de1c301e 169
c91cb83c
LP
170 np = malloc(ALIGN8(new_size));
171 if (!np)
172 goto poison;
de1c301e 173
c91cb83c
LP
174 memcpy(np, m->header, sizeof(struct bus_header));
175 }
de1c301e 176
c91cb83c
LP
177 /* Zero out padding */
178 if (start > old_size)
29804cc1 179 memzero((uint8_t*) np + old_size, start - old_size);
bc7fd8cd 180
c91cb83c
LP
181 op = m->header;
182 m->header = np;
2ac7c17f 183 m->fields_size = new_size - sizeof(struct bus_header);
de1c301e 184
bc7fd8cd 185 /* Adjust quick access pointers */
c91cb83c
LP
186 m->path = adjust_pointer(m->path, op, old_size, m->header);
187 m->interface = adjust_pointer(m->interface, op, old_size, m->header);
188 m->member = adjust_pointer(m->member, op, old_size, m->header);
189 m->destination = adjust_pointer(m->destination, op, old_size, m->header);
190 m->sender = adjust_pointer(m->sender, op, old_size, m->header);
191 m->error.name = adjust_pointer(m->error.name, op, old_size, m->header);
bc7fd8cd 192
c91cb83c 193 m->free_header = true;
de1c301e 194
c1b9d935
LP
195 if (add_offset) {
196 if (m->n_header_offsets >= ELEMENTSOF(m->header_offsets))
197 goto poison;
198
199 m->header_offsets[m->n_header_offsets++] = new_size - sizeof(struct bus_header);
200 }
201
c91cb83c
LP
202 return (uint8_t*) np + start;
203
204poison:
205 m->poisoned = true;
206 return NULL;
de1c301e
LP
207}
208
209static int message_append_field_string(
210 sd_bus_message *m,
2ac7c17f 211 uint64_t h,
de1c301e
LP
212 char type,
213 const char *s,
214 const char **ret) {
215
216 size_t l;
217 uint8_t *p;
218
219 assert(m);
220
2ac7c17f
LP
221 /* dbus1 only allows 8bit header field ids */
222 if (h > 0xFF)
223 return -EINVAL;
224
c1b9d935
LP
225 /* dbus1 doesn't allow strings over 32bit, let's enforce this
226 * globally, to not risk convertability */
de1c301e 227 l = strlen(s);
f22c308a 228 if (l > UINT32_MAX)
de1c301e
LP
229 return -EINVAL;
230
c1b9d935
LP
231 /* Signature "(yv)" where the variant contains "s" */
232
6647dc66 233 if (BUS_MESSAGE_IS_GVARIANT(m)) {
de1c301e 234
2ac7c17f
LP
235 /* (field id 64bit, ((string + NUL) + NUL + signature string 's') */
236 p = message_extend_fields(m, 8, 8 + l + 1 + 1 + 1, true);
c1b9d935
LP
237 if (!p)
238 return -ENOMEM;
de1c301e 239
2ac7c17f 240 *((uint64_t*) p) = h;
c1b9d935
LP
241 memcpy(p+8, s, l);
242 p[8+l] = 0;
243 p[8+l+1] = 0;
244 p[8+l+2] = type;
de1c301e 245
c1b9d935 246 if (ret)
6647dc66 247 *ret = (char*) p + 8;
c1b9d935
LP
248
249 } else {
250 /* (field id byte + (signature length + signature 's' + NUL) + (string length + string + NUL)) */
251 p = message_extend_fields(m, 8, 4 + 4 + l + 1, false);
252 if (!p)
253 return -ENOMEM;
254
2ac7c17f 255 p[0] = (uint8_t) h;
c1b9d935
LP
256 p[1] = 1;
257 p[2] = type;
258 p[3] = 0;
259
260 ((uint32_t*) p)[1] = l;
261 memcpy(p + 8, s, l + 1);
262
263 if (ret)
264 *ret = (char*) p + 8;
265 }
de1c301e
LP
266
267 return 0;
268}
269
270static int message_append_field_signature(
271 sd_bus_message *m,
2ac7c17f 272 uint64_t h,
de1c301e
LP
273 const char *s,
274 const char **ret) {
275
276 size_t l;
277 uint8_t *p;
278
279 assert(m);
280
2ac7c17f
LP
281 /* dbus1 only allows 8bit header field ids */
282 if (h > 0xFF)
283 return -EINVAL;
284
285 /* dbus1 doesn't allow signatures over 8bit, let's enforce
c1b9d935 286 * this globally, to not risk convertability */
de1c301e
LP
287 l = strlen(s);
288 if (l > 255)
289 return -EINVAL;
290
c1b9d935
LP
291 /* Signature "(yv)" where the variant contains "g" */
292
6647dc66 293 if (BUS_MESSAGE_IS_GVARIANT(m))
c1b9d935
LP
294 /* For gvariant the serialization is the same as for normal strings */
295 return message_append_field_string(m, h, 'g', s, ret);
296 else {
297 /* (field id byte + (signature length + signature 'g' + NUL) + (string length + string + NUL)) */
298 p = message_extend_fields(m, 8, 4 + 1 + l + 1, false);
299 if (!p)
300 return -ENOMEM;
de1c301e 301
2ac7c17f 302 p[0] = (uint8_t) h;
c1b9d935
LP
303 p[1] = 1;
304 p[2] = SD_BUS_TYPE_SIGNATURE;
305 p[3] = 0;
306 p[4] = l;
307 memcpy(p + 5, s, l + 1);
de1c301e 308
c1b9d935
LP
309 if (ret)
310 *ret = (const char*) p + 5;
311 }
de1c301e
LP
312
313 return 0;
314}
315
2ac7c17f 316static int message_append_field_uint32(sd_bus_message *m, uint64_t h, uint32_t x) {
de1c301e
LP
317 uint8_t *p;
318
319 assert(m);
320
2ac7c17f
LP
321 /* dbus1 only allows 8bit header field ids */
322 if (h > 0xFF)
323 return -EINVAL;
324
6647dc66 325 if (BUS_MESSAGE_IS_GVARIANT(m)) {
2ac7c17f 326 /* (field id 64bit + ((value + NUL + signature string 'u') */
c1b9d935 327
2ac7c17f 328 p = message_extend_fields(m, 8, 8 + 4 + 1 + 1, true);
c1b9d935
LP
329 if (!p)
330 return -ENOMEM;
de1c301e 331
2ac7c17f 332 *((uint64_t*) p) = h;
c1b9d935
LP
333 *((uint32_t*) (p + 8)) = x;
334 p[12] = 0;
335 p[13] = 'u';
336 } else {
337 /* (field id byte + (signature length + signature 'u' + NUL) + value) */
338 p = message_extend_fields(m, 8, 4 + 4, false);
339 if (!p)
340 return -ENOMEM;
341
2ac7c17f 342 p[0] = (uint8_t) h;
c1b9d935 343 p[1] = 1;
2ac7c17f 344 p[2] = 'u';
c1b9d935 345 p[3] = 0;
de1c301e 346
c1b9d935
LP
347 ((uint32_t*) p)[1] = x;
348 }
de1c301e
LP
349
350 return 0;
351}
352
2ac7c17f
LP
353static int message_append_field_uint64(sd_bus_message *m, uint64_t h, uint64_t x) {
354 uint8_t *p;
355
356 assert(m);
357
358 /* dbus1 only allows 8bit header field ids */
359 if (h > 0xFF)
360 return -EINVAL;
361
362 if (BUS_MESSAGE_IS_GVARIANT(m)) {
363 /* (field id 64bit + ((value + NUL + signature string 't') */
364
365 p = message_extend_fields(m, 8, 8 + 8 + 1 + 1, true);
366 if (!p)
367 return -ENOMEM;
368
369 *((uint64_t*) p) = h;
370 *((uint64_t*) (p + 8)) = x;
371 p[16] = 0;
372 p[17] = 't';
373 } else {
374 /* (field id byte + (signature length + signature 't' + NUL) + 4 byte padding + value) */
375 p = message_extend_fields(m, 8, 4 + 4 + 8, false);
376 if (!p)
377 return -ENOMEM;
378
379 p[0] = (uint8_t) h;
380 p[1] = 1;
381 p[2] = 't';
382 p[3] = 0;
383 p[4] = 0;
384 p[5] = 0;
385 p[6] = 0;
386 p[7] = 0;
387
388 ((uint64_t*) p)[1] = x;
389 }
390
391 return 0;
392}
393
b267a6d2
LP
394static int message_append_reply_cookie(sd_bus_message *m, uint64_t cookie) {
395 assert(m);
396
397 if (BUS_MESSAGE_IS_GVARIANT(m))
398 return message_append_field_uint64(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, cookie);
399 else {
400 /* 64bit cookies are not supported on dbus1 */
401 if (cookie > 0xffffffffUL)
15411c0c 402 return -EOPNOTSUPP;
b267a6d2
LP
403
404 return message_append_field_uint32(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, (uint32_t) cookie);
405 }
406}
407
6629161f 408int bus_message_from_header(
df2d202e 409 sd_bus *bus,
2ac7c17f
LP
410 void *header,
411 size_t header_accessible,
412 void *footer,
413 size_t footer_accessible,
414 size_t message_size,
2c93b4ef 415 int *fds,
da6053d0 416 size_t n_fds,
2571ead1 417 const char *label,
6629161f 418 size_t extra,
2571ead1
LP
419 sd_bus_message **ret) {
420
bcf88fc3 421 _cleanup_free_ sd_bus_message *m = NULL;
80a46c73 422 struct bus_header *h;
6629161f 423 size_t a, label_sz;
80a46c73 424
2a0958d2 425 assert(bus);
2ac7c17f
LP
426 assert(header || header_accessible <= 0);
427 assert(footer || footer_accessible <= 0);
2c93b4ef 428 assert(fds || n_fds <= 0);
80a46c73
LP
429 assert(ret);
430
2ac7c17f 431 if (header_accessible < sizeof(struct bus_header))
80a46c73
LP
432 return -EBADMSG;
433
2ac7c17f
LP
434 if (header_accessible > message_size)
435 return -EBADMSG;
436 if (footer_accessible > message_size)
80a46c73
LP
437 return -EBADMSG;
438
2ac7c17f 439 h = header;
bcf88fc3 440 if (!IN_SET(h->version, 1, 2))
954871d8
KS
441 return -EBADMSG;
442
80a46c73
LP
443 if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
444 return -EBADMSG;
445
bcf88fc3 446 if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
80a46c73
LP
447 return -EBADMSG;
448
2ac7c17f
LP
449 /* Note that we are happy with unknown flags in the flags header! */
450
6629161f 451 a = ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
80a46c73 452
2571ead1
LP
453 if (label) {
454 label_sz = strlen(label);
6629161f
LP
455 a += label_sz + 1;
456 }
2571ead1
LP
457
458 m = malloc0(a);
80a46c73
LP
459 if (!m)
460 return -ENOMEM;
461
462 m->n_ref = 1;
2c93b4ef 463 m->sealed = true;
2ac7c17f
LP
464 m->header = header;
465 m->header_accessible = header_accessible;
466 m->footer = footer;
467 m->footer_accessible = footer_accessible;
468
469 if (BUS_MESSAGE_IS_GVARIANT(m)) {
470 size_t ws;
471
472 if (h->dbus2.cookie == 0)
473 return -EBADMSG;
474
475 /* dbus2 derives the sizes from the message size and
476 the offset table at the end, since it is formatted as
477 gvariant "yyyyuta{tv}v". Since the message itself is a
478 structure with precisely to variable sized entries,
479 there's only one offset in the table, which marks the
480 end of the fields array. */
481
482 ws = bus_gvariant_determine_word_size(message_size, 0);
483 if (footer_accessible < ws)
484 return -EBADMSG;
485
486 m->fields_size = bus_gvariant_read_word_le((uint8_t*) footer + footer_accessible - ws, ws);
487 if (ALIGN8(m->fields_size) > message_size - ws)
488 return -EBADMSG;
489 if (m->fields_size < sizeof(struct bus_header))
490 return -EBADMSG;
491
492 m->fields_size -= sizeof(struct bus_header);
493 m->body_size = message_size - (sizeof(struct bus_header) + ALIGN8(m->fields_size));
494 } else {
495 if (h->dbus1.serial == 0)
496 return -EBADMSG;
497
498 /* dbus1 has the sizes in the header */
499 m->fields_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.fields_size);
500 m->body_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.body_size);
501
502 if (sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size != message_size)
503 return -EBADMSG;
504 }
505
2c93b4ef
LP
506 m->fds = fds;
507 m->n_fds = n_fds;
80a46c73 508
2571ead1 509 if (label) {
5b12334d
LP
510 m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
511 memcpy(m->creds.label, label, label_sz + 1);
512
513 m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
2571ead1
LP
514 }
515
2a0958d2 516 m->bus = sd_bus_ref(bus);
1cc6c93a 517 *ret = TAKE_PTR(m);
2a0958d2 518
6629161f
LP
519 return 0;
520}
521
522int bus_message_from_malloc(
df2d202e 523 sd_bus *bus,
6629161f
LP
524 void *buffer,
525 size_t length,
526 int *fds,
da6053d0 527 size_t n_fds,
6629161f
LP
528 const char *label,
529 sd_bus_message **ret) {
530
2ab3a635 531 _cleanup_(message_freep) sd_bus_message *m = NULL;
5461f53f 532 size_t sz;
6629161f
LP
533 int r;
534
2ac7c17f
LP
535 r = bus_message_from_header(
536 bus,
537 buffer, length, /* in this case the initial bytes and the final bytes are the same */
538 buffer, length,
539 length,
540 fds, n_fds,
aa0d0ed6 541 label,
2ac7c17f 542 0, &m);
6629161f
LP
543 if (r < 0)
544 return r;
545
2ac7c17f 546 sz = length - sizeof(struct bus_header) - ALIGN8(m->fields_size);
5461f53f
LP
547 if (sz > 0) {
548 m->n_body_parts = 1;
2ac7c17f 549 m->body.data = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(m->fields_size);
5461f53f
LP
550 m->body.size = sz;
551 m->body.sealed = true;
552 m->body.memfd = -1;
553 }
6629161f 554
80a46c73 555 m->n_iovec = 1;
bc7fd8cd 556 m->iovec = m->iovec_fixed;
80a46c73
LP
557 m->iovec[0].iov_base = buffer;
558 m->iovec[0].iov_len = length;
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;
589 t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message)));
590 t->header->endian = BUS_NATIVE_ENDIAN;
591 t->header->type = type;
592 t->header->version = bus->message_version;
593 t->allow_fds = bus->can_fds || !IN_SET(bus->state, BUS_HELLO, BUS_RUNNING);
594 t->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(t);
595 t->bus = sd_bus_ref(bus);
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
9d6c7c82
LP
2447 assert_return(m, -EINVAL);
2448 assert_return(types, -EINVAL);
2449 assert_return(!m->sealed, -EPERM);
2450 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
2451
2452 va_start(ap, types);
19fe49f6 2453 r = sd_bus_message_appendv(m, types, ap);
de1c301e
LP
2454 va_end(ap);
2455
2456 return r;
2457}
2458
c1b9d935
LP
2459_public_ int sd_bus_message_append_array_space(
2460 sd_bus_message *m,
2461 char type,
2462 size_t size,
2463 void **ptr) {
2464
b3af9646
LP
2465 ssize_t align, sz;
2466 void *a;
2467 int r;
2468
9d6c7c82
LP
2469 assert_return(m, -EINVAL);
2470 assert_return(!m->sealed, -EPERM);
0039a203 2471 assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL);
9d6c7c82
LP
2472 assert_return(ptr || size == 0, -EINVAL);
2473 assert_return(!m->poisoned, -ESTALE);
b3af9646 2474
0039a203
LP
2475 /* alignment and size of the trivial types (except bool) is
2476 * identical for gvariant and dbus1 marshalling */
b3af9646
LP
2477 align = bus_type_get_alignment(type);
2478 sz = bus_type_get_size(type);
2479
2480 assert_se(align > 0);
2481 assert_se(sz > 0);
2482
2483 if (size % sz != 0)
2484 return -EINVAL;
2485
2486 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2487 if (r < 0)
2488 return r;
2489
2ac7c17f 2490 a = message_extend_body(m, align, size, false, false);
bc7fd8cd
LP
2491 if (!a)
2492 return -ENOMEM;
b3af9646
LP
2493
2494 r = sd_bus_message_close_container(m);
2495 if (r < 0)
bc7fd8cd 2496 return r;
b3af9646
LP
2497
2498 *ptr = a;
2499 return 0;
b3af9646
LP
2500}
2501
7dcd79c2
LP
2502_public_ int sd_bus_message_append_array(
2503 sd_bus_message *m,
2504 char type,
2505 const void *ptr,
2506 size_t size) {
b3af9646
LP
2507 int r;
2508 void *p;
2509
9d6c7c82
LP
2510 assert_return(m, -EINVAL);
2511 assert_return(!m->sealed, -EPERM);
2512 assert_return(bus_type_is_trivial(type), -EINVAL);
2513 assert_return(ptr || size == 0, -EINVAL);
2514 assert_return(!m->poisoned, -ESTALE);
b3af9646 2515
f8e013f8 2516 r = sd_bus_message_append_array_space(m, type, size, &p);
b3af9646
LP
2517 if (r < 0)
2518 return r;
2519
75f32f04 2520 memcpy_safe(p, ptr, size);
b3af9646
LP
2521
2522 return 0;
2523}
2524
938bcbab
LP
2525_public_ int sd_bus_message_append_array_iovec(
2526 sd_bus_message *m,
2527 char type,
2528 const struct iovec *iov,
da6053d0 2529 unsigned n /* should be size_t, but is API now… 😞 */) {
938bcbab
LP
2530
2531 size_t size;
2532 unsigned i;
2533 void *p;
2534 int r;
2535
2536 assert_return(m, -EINVAL);
2537 assert_return(!m->sealed, -EPERM);
2538 assert_return(bus_type_is_trivial(type), -EINVAL);
2539 assert_return(iov || n == 0, -EINVAL);
2540 assert_return(!m->poisoned, -ESTALE);
2541
2542 size = IOVEC_TOTAL_SIZE(iov, n);
2543
2544 r = sd_bus_message_append_array_space(m, type, size, &p);
2545 if (r < 0)
2546 return r;
2547
2548 for (i = 0; i < n; i++) {
2549
2550 if (iov[i].iov_base)
2551 memcpy(p, iov[i].iov_base, iov[i].iov_len);
2552 else
29804cc1 2553 memzero(p, iov[i].iov_len);
938bcbab
LP
2554
2555 p = (uint8_t*) p + iov[i].iov_len;
2556 }
2557
2558 return 0;
2559}
2560
7dcd79c2
LP
2561_public_ int sd_bus_message_append_array_memfd(
2562 sd_bus_message *m,
2563 char type,
2564 int memfd,
2565 uint64_t offset,
2566 uint64_t size) {
2567
453a0c29
LP
2568 _cleanup_close_ int copy_fd = -1;
2569 struct bus_body_part *part;
2570 ssize_t align, sz;
7dcd79c2 2571 uint64_t real_size;
453a0c29
LP
2572 void *a;
2573 int r;
2574
7dcd79c2 2575 assert_return(m, -EINVAL);
8ac43fee 2576 assert_return(memfd >= 0, -EBADF);
7dcd79c2
LP
2577 assert_return(bus_type_is_trivial(type), -EINVAL);
2578 assert_return(size > 0, -EINVAL);
2579 assert_return(!m->sealed, -EPERM);
2580 assert_return(!m->poisoned, -ESTALE);
453a0c29 2581
fac9c0d5 2582 r = memfd_set_sealed(memfd);
453a0c29
LP
2583 if (r < 0)
2584 return r;
2585
40164c2c 2586 copy_fd = fcntl(memfd, F_DUPFD_CLOEXEC, 3);
453a0c29
LP
2587 if (copy_fd < 0)
2588 return copy_fd;
2589
7dcd79c2 2590 r = memfd_get_size(memfd, &real_size);
453a0c29
LP
2591 if (r < 0)
2592 return r;
2593
7dcd79c2
LP
2594 if (offset == 0 && size == (uint64_t) -1)
2595 size = real_size;
2596 else if (offset + size > real_size)
2597 return -EMSGSIZE;
2598
453a0c29
LP
2599 align = bus_type_get_alignment(type);
2600 sz = bus_type_get_size(type);
2601
2602 assert_se(align > 0);
2603 assert_se(sz > 0);
2604
7dcd79c2
LP
2605 if (offset % align != 0)
2606 return -EINVAL;
2607
453a0c29
LP
2608 if (size % sz != 0)
2609 return -EINVAL;
2610
5cbe7492 2611 if (size > (uint64_t) (uint32_t) -1)
453a0c29
LP
2612 return -EINVAL;
2613
2614 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2615 if (r < 0)
2616 return r;
2617
2ac7c17f 2618 a = message_extend_body(m, align, 0, false, false);
453a0c29
LP
2619 if (!a)
2620 return -ENOMEM;
2621
2622 part = message_append_part(m);
2623 if (!part)
2624 return -ENOMEM;
2625
2626 part->memfd = copy_fd;
7dcd79c2 2627 part->memfd_offset = offset;
453a0c29
LP
2628 part->sealed = true;
2629 part->size = size;
2630 copy_fd = -1;
2631
2ac7c17f 2632 m->body_size += size;
0039a203 2633 message_extend_containers(m, size);
453a0c29
LP
2634
2635 return sd_bus_message_close_container(m);
2636}
2637
7dcd79c2
LP
2638_public_ int sd_bus_message_append_string_memfd(
2639 sd_bus_message *m,
2640 int memfd,
2641 uint64_t offset,
2642 uint64_t size) {
2643
5cbe7492
LP
2644 _cleanup_close_ int copy_fd = -1;
2645 struct bus_body_part *part;
2646 struct bus_container *c;
7dcd79c2 2647 uint64_t real_size;
5cbe7492
LP
2648 void *a;
2649 int r;
2650
55736ed0 2651 assert_return(m, -EINVAL);
8ac43fee 2652 assert_return(memfd >= 0, -EBADF);
7dcd79c2 2653 assert_return(size > 0, -EINVAL);
55736ed0
LP
2654 assert_return(!m->sealed, -EPERM);
2655 assert_return(!m->poisoned, -ESTALE);
5cbe7492 2656
fac9c0d5 2657 r = memfd_set_sealed(memfd);
5cbe7492
LP
2658 if (r < 0)
2659 return r;
2660
40164c2c 2661 copy_fd = fcntl(memfd, FD_CLOEXEC, 3);
5cbe7492
LP
2662 if (copy_fd < 0)
2663 return copy_fd;
2664
7dcd79c2 2665 r = memfd_get_size(memfd, &real_size);
5cbe7492
LP
2666 if (r < 0)
2667 return r;
2668
7dcd79c2
LP
2669 if (offset == 0 && size == (uint64_t) -1)
2670 size = real_size;
2671 else if (offset + size > real_size)
2672 return -EMSGSIZE;
2673
5cbe7492
LP
2674 /* We require this to be NUL terminated */
2675 if (size == 0)
2676 return -EINVAL;
2677
2678 if (size > (uint64_t) (uint32_t) -1)
2679 return -EINVAL;
2680
9c65778d 2681 c = message_get_last_container(m);
5cbe7492
LP
2682 if (c->signature && c->signature[c->index]) {
2683 /* Container signature is already set */
2684
2685 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
2686 return -ENXIO;
2687 } else {
2688 char *e;
2689
ad67ef27 2690 /* Maybe we can append to the signature? But only if this is the top-level container */
5cbe7492
LP
2691 if (c->enclosing != 0)
2692 return -ENXIO;
2693
2694 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
2695 if (!e) {
2696 m->poisoned = true;
2697 return -ENOMEM;
2698 }
2699 }
2700
6647dc66 2701 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
2ac7c17f 2702 a = message_extend_body(m, 4, 4, false, false);
c1b9d935
LP
2703 if (!a)
2704 return -ENOMEM;
5cbe7492 2705
c1b9d935
LP
2706 *(uint32_t*) a = size - 1;
2707 }
5cbe7492
LP
2708
2709 part = message_append_part(m);
2710 if (!part)
2711 return -ENOMEM;
2712
2713 part->memfd = copy_fd;
7dcd79c2 2714 part->memfd_offset = offset;
5cbe7492
LP
2715 part->sealed = true;
2716 part->size = size;
2717 copy_fd = -1;
2718
2ac7c17f 2719 m->body_size += size;
c1b9d935
LP
2720 message_extend_containers(m, size);
2721
6647dc66 2722 if (BUS_MESSAGE_IS_GVARIANT(m)) {
2ac7c17f 2723 r = message_add_offset(m, m->body_size);
c1b9d935
LP
2724 if (r < 0) {
2725 m->poisoned = true;
2726 return -ENOMEM;
2727 }
2728 }
5cbe7492
LP
2729
2730 if (c->enclosing != SD_BUS_TYPE_ARRAY)
2731 c->index++;
2732
2733 return 0;
2734}
2735
d9f644e2 2736_public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) {
55736ed0
LP
2737 char **i;
2738 int r;
2739
2740 assert_return(m, -EINVAL);
2741 assert_return(!m->sealed, -EPERM);
2742 assert_return(!m->poisoned, -ESTALE);
2743
2744 r = sd_bus_message_open_container(m, 'a', "s");
2745 if (r < 0)
2746 return r;
2747
2748 STRV_FOREACH(i, l) {
2749 r = sd_bus_message_append_basic(m, 's', *i);
2750 if (r < 0)
2751 return r;
2752 }
2753
2754 return sd_bus_message_close_container(m);
2755}
2756
81389225 2757static int bus_message_close_header(sd_bus_message *m) {
81389225
LP
2758
2759 assert(m);
2760
2ac7c17f
LP
2761 /* The actual user data is finished now, we just complete the
2762 variant and struct now (at least on gvariant). Remember
61233823 2763 this position, so that during parsing we know where to
2ac7c17f
LP
2764 put the outer container end. */
2765 m->user_body_size = m->body_size;
81389225 2766
2ac7c17f
LP
2767 if (BUS_MESSAGE_IS_GVARIANT(m)) {
2768 const char *signature;
2769 size_t sz, l;
2770 void *d;
b381de41 2771
2ac7c17f
LP
2772 /* Add offset table to end of fields array */
2773 if (m->n_header_offsets >= 1) {
2774 uint8_t *a;
2775 unsigned i;
b381de41 2776
2ac7c17f 2777 assert(m->fields_size == m->header_offsets[m->n_header_offsets-1]);
b381de41 2778
2ac7c17f
LP
2779 sz = bus_gvariant_determine_word_size(m->fields_size, m->n_header_offsets);
2780 a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
2781 if (!a)
2782 return -ENOMEM;
2783
2784 for (i = 0; i < m->n_header_offsets; i++)
2785 bus_gvariant_write_word_le(a + sz*i, sz, m->header_offsets[i]);
2786 }
2787
2788 /* Add gvariant NUL byte plus signature to the end of
2789 * the body, followed by the final offset pointing to
2790 * the end of the fields array */
b381de41 2791
2ac7c17f
LP
2792 signature = strempty(m->root_container.signature);
2793 l = strlen(signature);
2794
03ebf5e8
DH
2795 sz = bus_gvariant_determine_word_size(sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size + 1 + l + 2, 1);
2796 d = message_extend_body(m, 1, 1 + l + 2 + sz, false, true);
2ac7c17f
LP
2797 if (!d)
2798 return -ENOMEM;
2799
2800 *(uint8_t*) d = 0;
03ebf5e8
DH
2801 *((uint8_t*) d + 1) = SD_BUS_TYPE_STRUCT_BEGIN;
2802 memcpy((uint8_t*) d + 2, signature, l);
2803 *((uint8_t*) d + 1 + l + 1) = SD_BUS_TYPE_STRUCT_END;
2ac7c17f 2804
03ebf5e8 2805 bus_gvariant_write_word_le((uint8_t*) d + 1 + l + 2, sz, sizeof(struct bus_header) + m->fields_size);
2ac7c17f
LP
2806
2807 m->footer = d;
03ebf5e8 2808 m->footer_accessible = 1 + l + 2 + sz;
2ac7c17f
LP
2809 } else {
2810 m->header->dbus1.fields_size = m->fields_size;
2811 m->header->dbus1.body_size = m->body_size;
2812 }
81389225
LP
2813
2814 return 0;
2815}
2816
75bcbcf2 2817_public_ int sd_bus_message_seal(sd_bus_message *m, uint64_t cookie, uint64_t timeout_usec) {
81389225 2818 struct bus_body_part *part;
2ac7c17f 2819 size_t a;
81389225
LP
2820 unsigned i;
2821 int r;
2822
75bcbcf2 2823 assert_return(m, -EINVAL);
81389225
LP
2824
2825 if (m->sealed)
2826 return -EPERM;
2827
2828 if (m->n_containers > 0)
2829 return -EBADMSG;
2830
2831 if (m->poisoned)
2832 return -ESTALE;
2833
2ac7c17f
LP
2834 if (cookie > 0xffffffffULL &&
2835 !BUS_MESSAGE_IS_GVARIANT(m))
15411c0c 2836 return -EOPNOTSUPP;
2ac7c17f 2837
81389225
LP
2838 /* In vtables the return signature of method calls is listed,
2839 * let's check if they match if this is a response */
2840 if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
2841 m->enforced_reply_signature &&
2842 !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
2843 return -ENOMSG;
2844
2845 /* If gvariant marshalling is used we need to close the body structure */
2846 r = bus_message_close_struct(m, &m->root_container, false);
2847 if (r < 0)
2848 return r;
2849
2ac7c17f
LP
2850 /* If there's a non-trivial signature set, then add it in
2851 * here, but only on dbus1 */
2852 if (!isempty(m->root_container.signature) && !BUS_MESSAGE_IS_GVARIANT(m)) {
81389225
LP
2853 r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
2854 if (r < 0)
2855 return r;
2856 }
2857
2858 if (m->n_fds > 0) {
2859 r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
2860 if (r < 0)
2861 return r;
2862 }
2863
2864 r = bus_message_close_header(m);
2865 if (r < 0)
2866 return r;
2867
2ac7c17f
LP
2868 if (BUS_MESSAGE_IS_GVARIANT(m))
2869 m->header->dbus2.cookie = cookie;
2870 else
2871 m->header->dbus1.serial = (uint32_t) cookie;
2872
75bcbcf2 2873 m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout_usec;
81389225
LP
2874
2875 /* Add padding at the end of the fields part, since we know
2876 * the body needs to start at an 8 byte alignment. We made
2877 * sure we allocated enough space for this, so all we need to
2878 * do here is to zero it out. */
2ac7c17f 2879 a = ALIGN8(m->fields_size) - m->fields_size;
81389225 2880 if (a > 0)
2ac7c17f 2881 memzero((uint8_t*) BUS_MESSAGE_FIELDS(m) + m->fields_size, a);
81389225
LP
2882
2883 /* If this is something we can send as memfd, then let's seal
2884 the memfd now. Note that we can send memfds as payload only
2885 for directed messages, and not for broadcasts. */
2a0958d2 2886 if (m->destination && m->bus->use_memfd) {
81389225 2887 MESSAGE_FOREACH_PART(part, i, m)
2ac7c17f
LP
2888 if (part->memfd >= 0 &&
2889 !part->sealed &&
2890 (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0) &&
2891 part != m->body_end) { /* The last part may never be sent as memfd */
8e959fbf
LP
2892 uint64_t sz;
2893
2894 /* Try to seal it if that makes
2895 * sense. First, unmap our own map to
2896 * make sure we don't keep it busy. */
81389225
LP
2897 bus_body_part_unmap(part);
2898
8e959fbf
LP
2899 /* Then, sync up real memfd size */
2900 sz = part->size;
73843b52
LP
2901 r = memfd_set_size(part->memfd, sz);
2902 if (r < 0)
2903 return r;
8e959fbf
LP
2904
2905 /* Finally, try to seal */
73843b52 2906 if (memfd_set_sealed(part->memfd) >= 0)
81389225
LP
2907 part->sealed = true;
2908 }
2909 }
2910
2ac7c17f 2911 m->root_container.end = m->user_body_size;
81389225
LP
2912 m->root_container.index = 0;
2913 m->root_container.offset_index = 0;
2914 m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
2915
2916 m->sealed = true;
2917
2918 return 0;
2919}
2920
a392d361 2921int bus_body_part_map(struct bus_body_part *part) {
453a0c29 2922 void *p;
7dcd79c2 2923 size_t psz, shift;
453a0c29
LP
2924
2925 assert_se(part);
2926
2927 if (part->data)
2928 return 0;
2929
2930 if (part->size <= 0)
2931 return 0;
2932
1307c3ff
LP
2933 /* For smaller zero parts (as used for padding) we don't need to map anything... */
2934 if (part->memfd < 0 && part->is_zero && part->size < 8) {
2935 static const uint8_t zeroes[7] = { };
2936 part->data = (void*) zeroes;
2937 return 0;
2938 }
2939
7dcd79c2
LP
2940 shift = part->memfd_offset - ((part->memfd_offset / page_size()) * page_size());
2941 psz = PAGE_ALIGN(part->size + shift);
453a0c29
LP
2942
2943 if (part->memfd >= 0)
7dcd79c2 2944 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE, part->memfd, part->memfd_offset - shift);
453a0c29
LP
2945 else if (part->is_zero)
2946 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
2947 else
2948 return -EINVAL;
2949
2950 if (p == MAP_FAILED)
2951 return -errno;
2952
2953 part->mapped = psz;
7dcd79c2
LP
2954 part->mmap_begin = p;
2955 part->data = (uint8_t*) p + shift;
a392d361
LP
2956 part->munmap_this = true;
2957
453a0c29
LP
2958 return 0;
2959}
2960
a392d361
LP
2961void bus_body_part_unmap(struct bus_body_part *part) {
2962
2963 assert_se(part);
2964
2965 if (part->memfd < 0)
2966 return;
2967
7dcd79c2 2968 if (!part->mmap_begin)
a392d361
LP
2969 return;
2970
bf30e48f
KS
2971 if (!part->munmap_this)
2972 return;
a392d361 2973
7dcd79c2 2974 assert_se(munmap(part->mmap_begin, part->mapped) == 0);
a392d361 2975
7dcd79c2 2976 part->mmap_begin = NULL;
a392d361
LP
2977 part->data = NULL;
2978 part->mapped = 0;
2979 part->munmap_this = false;
2980
2981 return;
2982}
2983
9a17484d 2984static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
bc7fd8cd 2985 size_t k, start, end;
de1c301e 2986
9a17484d
LP
2987 assert(rindex);
2988 assert(align > 0);
de1c301e 2989
9a17484d 2990 start = ALIGN_TO((size_t) *rindex, align);
bc7fd8cd 2991 end = start + nbytes;
9a17484d 2992
bc7fd8cd 2993 if (end > sz)
9a17484d
LP
2994 return -EBADMSG;
2995
2996 /* Verify that padding is 0 */
2997 for (k = *rindex; k < start; k++)
2998 if (((const uint8_t*) p)[k] != 0)
2999 return -EBADMSG;
3000
3001 if (r)
3002 *r = (uint8_t*) p + start;
3003
bc7fd8cd 3004 *rindex = end;
9a17484d
LP
3005
3006 return 1;
de1c301e
LP
3007}
3008
7b058942
LP
3009static bool message_end_of_signature(sd_bus_message *m) {
3010 struct bus_container *c;
3011
3012 assert(m);
3013
9c65778d 3014 c = message_get_last_container(m);
7b058942
LP
3015 return !c->signature || c->signature[c->index] == 0;
3016}
3017
9a17484d
LP
3018static bool message_end_of_array(sd_bus_message *m, size_t index) {
3019 struct bus_container *c;
de1c301e 3020
9a17484d 3021 assert(m);
de1c301e 3022
9c65778d 3023 c = message_get_last_container(m);
6647dc66 3024 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 3025 return false;
de1c301e 3026
6647dc66
LP
3027 if (BUS_MESSAGE_IS_GVARIANT(m))
3028 return index >= c->end;
3029 else {
3030 assert(c->array_size);
3031 return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
3032 }
de1c301e
LP
3033}
3034
1405bef3 3035_public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
7b058942
LP
3036 assert_return(m, -EINVAL);
3037 assert_return(m->sealed, -EPERM);
3038
3039 if (complete && m->n_containers > 0)
3040 return false;
3041
3042 if (message_end_of_signature(m))
3043 return true;
3044
3045 if (message_end_of_array(m, m->rindex))
3046 return true;
3047
3048 return false;
3049}
3050
bc7fd8cd
LP
3051static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
3052 struct bus_body_part *part;
3053 size_t begin;
453a0c29
LP
3054 int r;
3055
bc7fd8cd
LP
3056 assert(m);
3057
3058 if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) {
3059 part = m->cached_rindex_part;
3060 begin = m->cached_rindex_part_begin;
3061 } else {
3062 part = &m->body;
3063 begin = 0;
3064 }
3065
3066 while (part) {
3067 if (index < begin)
3068 return NULL;
3069
3070 if (index + sz <= begin + part->size) {
453a0c29 3071
a392d361 3072 r = bus_body_part_map(part);
453a0c29
LP
3073 if (r < 0)
3074 return NULL;
3075
bc7fd8cd 3076 if (p)
453a0c29 3077 *p = (uint8_t*) part->data + index - begin;
bc7fd8cd
LP
3078
3079 m->cached_rindex_part = part;
3080 m->cached_rindex_part_begin = begin;
3081
3082 return part;
3083 }
3084
453a0c29 3085 begin += part->size;
bc7fd8cd
LP
3086 part = part->next;
3087 }
3088
3089 return NULL;
3090}
3091
6647dc66
LP
3092static int container_next_item(sd_bus_message *m, struct bus_container *c, size_t *rindex) {
3093 int r;
3094
3095 assert(m);
3096 assert(c);
3097 assert(rindex);
3098
3099 if (!BUS_MESSAGE_IS_GVARIANT(m))
3100 return 0;
3101
3102 if (c->enclosing == SD_BUS_TYPE_ARRAY) {
3103 int sz;
3104
3105 sz = bus_gvariant_get_size(c->signature);
3106 if (sz < 0) {
3107 int alignment;
3108
3109 if (c->offset_index+1 >= c->n_offsets)
3110 goto end;
3111
3112 /* Variable-size array */
3113
3114 alignment = bus_gvariant_get_alignment(c->signature);
3115 assert(alignment > 0);
3116
3117 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
3118 c->item_size = c->offsets[c->offset_index+1] - *rindex;
3119 } else {
0039a203
LP
3120
3121 if (c->offset_index+1 >= (c->end-c->begin)/sz)
3122 goto end;
3123
6647dc66 3124 /* Fixed-size array */
0039a203 3125 *rindex = c->begin + (c->offset_index+1) * sz;
6647dc66
LP
3126 c->item_size = sz;
3127 }
3128
3129 c->offset_index++;
3130
945c2931 3131 } else if (IN_SET(c->enclosing, 0, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) {
6647dc66
LP
3132
3133 int alignment;
3134 size_t n, j;
3135
3136 if (c->offset_index+1 >= c->n_offsets)
3137 goto end;
3138
3139 r = signature_element_length(c->signature + c->index, &n);
3140 if (r < 0)
3141 return r;
3142
3143 r = signature_element_length(c->signature + c->index + n, &j);
3144 if (r < 0)
3145 return r;
3146 else {
3147 char t[j+1];
3148 memcpy(t, c->signature + c->index + n, j);
3149 t[j] = 0;
3150
3151 alignment = bus_gvariant_get_alignment(t);
3152 }
3153
3154 assert(alignment > 0);
3155
3156 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
3157 c->item_size = c->offsets[c->offset_index+1] - *rindex;
3158
3159 c->offset_index++;
3160
3161 } else if (c->enclosing == SD_BUS_TYPE_VARIANT)
3162 goto end;
3163 else
3164 assert_not_reached("Unknown container type");
3165
3166 return 0;
3167
3168end:
3169 /* Reached the end */
3170 *rindex = c->end;
3171 c->item_size = 0;
3172 return 0;
3173}
3174
bc7fd8cd
LP
3175static int message_peek_body(
3176 sd_bus_message *m,
3177 size_t *rindex,
3178 size_t align,
3179 size_t nbytes,
3180 void **ret) {
3181
3182 size_t k, start, end, padding;
3183 struct bus_body_part *part;
3184 uint8_t *q;
3185
de1c301e 3186 assert(m);
9a17484d
LP
3187 assert(rindex);
3188 assert(align > 0);
de1c301e 3189
bc7fd8cd
LP
3190 start = ALIGN_TO((size_t) *rindex, align);
3191 padding = start - *rindex;
3192 end = start + nbytes;
3193
2ac7c17f 3194 if (end > m->user_body_size)
bc7fd8cd
LP
3195 return -EBADMSG;
3196
3197 part = find_part(m, *rindex, padding, (void**) &q);
3198 if (!part)
3199 return -EBADMSG;
3200
3201 if (q) {
3202 /* Verify padding */
3203 for (k = 0; k < padding; k++)
3204 if (q[k] != 0)
3205 return -EBADMSG;
3206 }
3207
3208 part = find_part(m, start, nbytes, (void**) &q);
5f7e8903 3209 if (!part || (nbytes > 0 && !q))
bc7fd8cd
LP
3210 return -EBADMSG;
3211
3212 *rindex = end;
3213
3214 if (ret)
3215 *ret = q;
3216
18f5b48f 3217 return 0;
9a17484d 3218}
de1c301e 3219
ac89bf1d 3220static bool validate_nul(const char *s, size_t l) {
de1c301e 3221
9a17484d
LP
3222 /* Check for NUL chars in the string */
3223 if (memchr(s, 0, l))
3224 return false;
de1c301e 3225
9a17484d
LP
3226 /* Check for NUL termination */
3227 if (s[l] != 0)
3228 return false;
de1c301e 3229
ac89bf1d
LP
3230 return true;
3231}
3232
3233static bool validate_string(const char *s, size_t l) {
3234
3235 if (!validate_nul(s, l))
3236 return false;
3237
9a17484d
LP
3238 /* Check if valid UTF8 */
3239 if (!utf8_is_valid(s))
3240 return false;
3241
3242 return true;
de1c301e
LP
3243}
3244
9a17484d 3245static bool validate_signature(const char *s, size_t l) {
de1c301e 3246
ac89bf1d 3247 if (!validate_nul(s, l))
9a17484d 3248 return false;
de1c301e 3249
9a17484d
LP
3250 /* Check if valid signature */
3251 if (!signature_is_valid(s, true))
3252 return false;
3253
3254 return true;
3255}
3256
ac89bf1d
LP
3257static bool validate_object_path(const char *s, size_t l) {
3258
3259 if (!validate_nul(s, l))
3260 return false;
3261
3262 if (!object_path_is_valid(s))
3263 return false;
3264
3265 return true;
3266}
3267
d9f644e2 3268_public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
9a17484d 3269 struct bus_container *c;
6647dc66 3270 size_t rindex;
9a17484d 3271 void *q;
0dcd14b9 3272 int r;
9a17484d 3273
9d6c7c82
LP
3274 assert_return(m, -EINVAL);
3275 assert_return(m->sealed, -EPERM);
3276 assert_return(bus_type_is_basic(type), -EINVAL);
de1c301e 3277
7b058942 3278 if (message_end_of_signature(m))
430fb8fa 3279 return -ENXIO;
9a17484d 3280
1daf8121
LP
3281 if (message_end_of_array(m, m->rindex))
3282 return 0;
3283
9c65778d 3284 c = message_get_last_container(m);
9a17484d
LP
3285 if (c->signature[c->index] != type)
3286 return -ENXIO;
3287
6647dc66 3288 rindex = m->rindex;
9a17484d 3289
6647dc66 3290 if (BUS_MESSAGE_IS_GVARIANT(m)) {
9a17484d 3291
6647dc66
LP
3292 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
3293 bool ok;
9a17484d 3294
81b6e630
ZJS
3295 /* D-Bus spec: The marshalling formats for the string-like types all end
3296 * with a single zero (NUL) byte, but that byte is not considered to be part
3297 * of the text. */
3298 if (c->item_size == 0)
3299 return -EBADMSG;
3300
6647dc66 3301 r = message_peek_body(m, &rindex, 1, c->item_size, &q);
18f5b48f 3302 if (r < 0)
6647dc66
LP
3303 return r;
3304
3305 if (type == SD_BUS_TYPE_STRING)
3306 ok = validate_string(q, c->item_size-1);
3307 else if (type == SD_BUS_TYPE_OBJECT_PATH)
3308 ok = validate_object_path(q, c->item_size-1);
3309 else
3310 ok = validate_signature(q, c->item_size-1);
9a17484d 3311
6647dc66 3312 if (!ok)
ac89bf1d 3313 return -EBADMSG;
6647dc66
LP
3314
3315 if (p)
3316 *(const char**) p = q;
ac89bf1d 3317 } else {
6647dc66
LP
3318 int sz, align;
3319
3320 sz = bus_gvariant_get_size(CHAR_TO_STR(type));
3321 assert(sz > 0);
3322 if ((size_t) sz != c->item_size)
ac89bf1d 3323 return -EBADMSG;
9a17484d 3324
6647dc66
LP
3325 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
3326 assert(align > 0);
0dcd14b9 3327
6647dc66 3328 r = message_peek_body(m, &rindex, align, c->item_size, &q);
18f5b48f 3329 if (r < 0)
6647dc66 3330 return r;
de1c301e 3331
6647dc66 3332 switch (type) {
9a17484d 3333
6647dc66
LP
3334 case SD_BUS_TYPE_BYTE:
3335 if (p)
3336 *(uint8_t*) p = *(uint8_t*) q;
3337 break;
9a17484d 3338
6647dc66
LP
3339 case SD_BUS_TYPE_BOOLEAN:
3340 if (p)
3341 *(int*) p = !!*(uint8_t*) q;
3342 break;
9a17484d 3343
6647dc66
LP
3344 case SD_BUS_TYPE_INT16:
3345 case SD_BUS_TYPE_UINT16:
3346 if (p)
3347 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3348 break;
3349
3350 case SD_BUS_TYPE_INT32:
3351 case SD_BUS_TYPE_UINT32:
3352 if (p)
3353 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3354 break;
9a17484d 3355
6647dc66
LP
3356 case SD_BUS_TYPE_INT64:
3357 case SD_BUS_TYPE_UINT64:
3358 case SD_BUS_TYPE_DOUBLE:
3359 if (p)
3360 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3361 break;
0dcd14b9 3362
6647dc66
LP
3363 case SD_BUS_TYPE_UNIX_FD: {
3364 uint32_t j;
de1c301e 3365
6647dc66
LP
3366 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3367 if (j >= m->n_fds)
3368 return -EBADMSG;
de1c301e 3369
6647dc66
LP
3370 if (p)
3371 *(int*) p = m->fds[j];
de1c301e 3372
6647dc66
LP
3373 break;
3374 }
3375
3376 default:
3377 assert_not_reached("unexpected type");
3378 }
3379 }
3380
3381 r = container_next_item(m, c, &rindex);
3382 if (r < 0)
9a17484d 3383 return r;
6647dc66 3384 } else {
9a17484d 3385
6647dc66
LP
3386 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
3387 uint32_t l;
3388 bool ok;
9a17484d 3389
6647dc66 3390 r = message_peek_body(m, &rindex, 4, 4, &q);
18f5b48f 3391 if (r < 0)
6647dc66 3392 return r;
9a17484d 3393
6647dc66
LP
3394 l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3395 r = message_peek_body(m, &rindex, 1, l+1, &q);
3396 if (r < 0)
3397 return r;
9a17484d 3398
6647dc66
LP
3399 if (type == SD_BUS_TYPE_OBJECT_PATH)
3400 ok = validate_object_path(q, l);
3401 else
3402 ok = validate_string(q, l);
3403 if (!ok)
3404 return -EBADMSG;
9a17484d 3405
0dcd14b9 3406 if (p)
6647dc66 3407 *(const char**) p = q;
9a17484d 3408
6647dc66
LP
3409 } else if (type == SD_BUS_TYPE_SIGNATURE) {
3410 uint8_t l;
3411
3412 r = message_peek_body(m, &rindex, 1, 1, &q);
18f5b48f 3413 if (r < 0)
6647dc66
LP
3414 return r;
3415
3416 l = *(uint8_t*) q;
3417 r = message_peek_body(m, &rindex, 1, l+1, &q);
3418 if (r < 0)
3419 return r;
2c93b4ef 3420
6647dc66 3421 if (!validate_signature(q, l))
2c93b4ef
LP
3422 return -EBADMSG;
3423
0dcd14b9 3424 if (p)
6647dc66 3425 *(const char**) p = q;
2c93b4ef 3426
6647dc66
LP
3427 } else {
3428 ssize_t sz, align;
9a17484d 3429
6647dc66
LP
3430 align = bus_type_get_alignment(type);
3431 assert(align > 0);
2c93b4ef 3432
6647dc66
LP
3433 sz = bus_type_get_size(type);
3434 assert(sz > 0);
3435
3436 r = message_peek_body(m, &rindex, align, sz, &q);
18f5b48f 3437 if (r < 0)
6647dc66
LP
3438 return r;
3439
3440 switch (type) {
3441
3442 case SD_BUS_TYPE_BYTE:
3443 if (p)
3444 *(uint8_t*) p = *(uint8_t*) q;
3445 break;
3446
3447 case SD_BUS_TYPE_BOOLEAN:
3448 if (p)
3449 *(int*) p = !!*(uint32_t*) q;
3450 break;
3451
3452 case SD_BUS_TYPE_INT16:
3453 case SD_BUS_TYPE_UINT16:
3454 if (p)
3455 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3456 break;
3457
3458 case SD_BUS_TYPE_INT32:
3459 case SD_BUS_TYPE_UINT32:
3460 if (p)
3461 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3462 break;
3463
3464 case SD_BUS_TYPE_INT64:
3465 case SD_BUS_TYPE_UINT64:
3466 case SD_BUS_TYPE_DOUBLE:
3467 if (p)
3468 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3469 break;
3470
3471 case SD_BUS_TYPE_UNIX_FD: {
3472 uint32_t j;
3473
3474 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3475 if (j >= m->n_fds)
3476 return -EBADMSG;
3477
3478 if (p)
3479 *(int*) p = m->fds[j];
3480 break;
3481 }
3482
3483 default:
3484 assert_not_reached("Unknown basic type...");
3485 }
3486 }
9a17484d
LP
3487 }
3488
6647dc66
LP
3489 m->rindex = rindex;
3490
9a17484d
LP
3491 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3492 c->index++;
3493
3494 return 1;
de1c301e
LP
3495}
3496
9a17484d
LP
3497static int bus_message_enter_array(
3498 sd_bus_message *m,
3499 struct bus_container *c,
3500 const char *contents,
6647dc66
LP
3501 uint32_t **array_size,
3502 size_t *item_size,
3503 size_t **offsets,
3504 size_t *n_offsets) {
9a17484d
LP
3505
3506 size_t rindex;
3507 void *q;
3508 int r, alignment;
3509
3510 assert(m);
3511 assert(c);
3512 assert(contents);
3513 assert(array_size);
6647dc66
LP
3514 assert(item_size);
3515 assert(offsets);
3516 assert(n_offsets);
9a17484d 3517
29ddb38f 3518 if (!signature_is_single(contents, true))
de1c301e 3519 return -EINVAL;
9a17484d 3520
9a17484d 3521 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3522 return -ENXIO;
9a17484d
LP
3523
3524 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
3525 return -ENXIO;
3526
3527 if (!startswith(c->signature + c->index + 1, contents))
3528 return -ENXIO;
3529
3530 rindex = m->rindex;
9a17484d 3531
6647dc66
LP
3532 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3533 /* dbus1 */
9a17484d 3534
6647dc66 3535 r = message_peek_body(m, &rindex, 4, 4, &q);
18f5b48f 3536 if (r < 0)
6647dc66 3537 return r;
9a17484d 3538
6647dc66
LP
3539 if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE)
3540 return -EBADMSG;
9a17484d 3541
6647dc66
LP
3542 alignment = bus_type_get_alignment(contents[0]);
3543 if (alignment < 0)
3544 return alignment;
3545
3546 r = message_peek_body(m, &rindex, alignment, 0, NULL);
3547 if (r < 0)
3548 return r;
6647dc66
LP
3549
3550 *array_size = (uint32_t*) q;
3551
3552 } else if (c->item_size <= 0) {
3553
3554 /* gvariant: empty array */
3555 *item_size = 0;
3556 *offsets = NULL;
3557 *n_offsets = 0;
3558
3559 } else if (bus_gvariant_is_fixed_size(contents)) {
3560
3561 /* gvariant: fixed length array */
3562 *item_size = bus_gvariant_get_size(contents);
3563 *offsets = NULL;
3564 *n_offsets = 0;
3565
3566 } else {
3567 size_t where, p = 0, framing, sz;
3568 unsigned i;
3569
3570 /* gvariant: variable length array */
2ac7c17f 3571 sz = bus_gvariant_determine_word_size(c->item_size, 0);
6647dc66
LP
3572
3573 where = rindex + c->item_size - sz;
3574 r = message_peek_body(m, &where, 1, sz, &q);
3575 if (r < 0)
3576 return r;
6647dc66 3577
2ac7c17f 3578 framing = bus_gvariant_read_word_le(q, sz);
6647dc66
LP
3579 if (framing > c->item_size - sz)
3580 return -EBADMSG;
3581 if ((c->item_size - framing) % sz != 0)
3582 return -EBADMSG;
3583
3584 *n_offsets = (c->item_size - framing) / sz;
3585
3586 where = rindex + framing;
3587 r = message_peek_body(m, &where, 1, *n_offsets * sz, &q);
3588 if (r < 0)
3589 return r;
6647dc66
LP
3590
3591 *offsets = new(size_t, *n_offsets);
3592 if (!*offsets)
3593 return -ENOMEM;
3594
3595 for (i = 0; i < *n_offsets; i++) {
3596 size_t x;
3597
2ac7c17f 3598 x = bus_gvariant_read_word_le((uint8_t*) q + i * sz, sz);
6647dc66
LP
3599 if (x > c->item_size - sz)
3600 return -EBADMSG;
3601 if (x < p)
3602 return -EBADMSG;
3603
3604 (*offsets)[i] = rindex + x;
3605 p = x;
3606 }
3607
3608 *item_size = (*offsets)[0] - rindex;
3609 }
3610
3611 m->rindex = rindex;
3612
3613 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3614 c->index += 1 + strlen(contents);
9a17484d
LP
3615
3616 return 1;
3617}
3618
3619static int bus_message_enter_variant(
3620 sd_bus_message *m,
3621 struct bus_container *c,
6647dc66
LP
3622 const char *contents,
3623 size_t *item_size) {
9a17484d
LP
3624
3625 size_t rindex;
3626 uint8_t l;
3627 void *q;
3628 int r;
3629
3630 assert(m);
3631 assert(c);
3632 assert(contents);
6647dc66 3633 assert(item_size);
9a17484d 3634
29ddb38f 3635 if (!signature_is_single(contents, false))
de1c301e 3636 return -EINVAL;
de1c301e 3637
9a17484d
LP
3638 if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
3639 return -EINVAL;
3640
3641 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3642 return -ENXIO;
9a17484d
LP
3643
3644 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
3645 return -ENXIO;
3646
3647 rindex = m->rindex;
9a17484d 3648
6647dc66
LP
3649 if (BUS_MESSAGE_IS_GVARIANT(m)) {
3650 size_t k, where;
3651
3652 k = strlen(contents);
3653 if (1+k > c->item_size)
3654 return -EBADMSG;
3655
3656 where = rindex + c->item_size - (1+k);
3657 r = message_peek_body(m, &where, 1, 1+k, &q);
3658 if (r < 0)
3659 return r;
6647dc66
LP
3660
3661 if (*(char*) q != 0)
3662 return -EBADMSG;
3663
3664 if (memcmp((uint8_t*) q+1, contents, k))
3665 return -ENXIO;
3666
3667 *item_size = c->item_size - (1+k);
3668
3669 } else {
3670 r = message_peek_body(m, &rindex, 1, 1, &q);
3671 if (r < 0)
3672 return r;
6647dc66
LP
3673
3674 l = *(uint8_t*) q;
3675 r = message_peek_body(m, &rindex, 1, l+1, &q);
3676 if (r < 0)
3677 return r;
6647dc66
LP
3678
3679 if (!validate_signature(q, l))
3680 return -EBADMSG;
3681
3682 if (!streq(q, contents))
3683 return -ENXIO;
3684 }
3685
3686 m->rindex = rindex;
3687
3688 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3689 c->index++;
3690
3691 return 1;
3692}
3693
3694static int build_struct_offsets(
3695 sd_bus_message *m,
3696 const char *signature,
3697 size_t size,
3698 size_t *item_size,
3699 size_t **offsets,
3700 size_t *n_offsets) {
3701
3702 unsigned n_variable = 0, n_total = 0, v;
3703 size_t previous = 0, where;
3704 const char *p;
3705 size_t sz;
3706 void *q;
3707 int r;
3708
3709 assert(m);
6647dc66
LP
3710 assert(item_size);
3711 assert(offsets);
3712 assert(n_offsets);
3713
d6385068 3714 if (isempty(signature)) {
e53d21d0
DH
3715 /* Unary type is encoded as *fixed* 1 byte padding */
3716 r = message_peek_body(m, &m->rindex, 1, 1, &q);
3717 if (r < 0)
3718 return r;
3719
3720 if (*(uint8_t *) q != 0)
3721 return -EBADMSG;
3722
d6385068
LP
3723 *item_size = 0;
3724 *offsets = NULL;
3725 *n_offsets = 0;
3726 return 0;
3727 }
3728
2ac7c17f 3729 sz = bus_gvariant_determine_word_size(size, 0);
d6385068
LP
3730 if (sz <= 0)
3731 return -EBADMSG;
6647dc66
LP
3732
3733 /* First, loop over signature and count variable elements and
3734 * elements in general. We use this to know how large the
3735 * offset array is at the end of the structure. Note that
3736 * GVariant only stores offsets for all variable size elements
3737 * that are not the last item. */
3738
3739 p = signature;
3740 while (*p != 0) {
3741 size_t n;
3742
3743 r = signature_element_length(p, &n);
3744 if (r < 0)
3745 return r;
3746 else {
3747 char t[n+1];
3748
3749 memcpy(t, p, n);
3750 t[n] = 0;
3751
3752 r = bus_gvariant_is_fixed_size(t);
3753 }
3754
3755 if (r < 0)
3756 return r;
3757 if (r == 0 && p[n] != 0) /* except the last item */
313cefa1 3758 n_variable++;
6647dc66
LP
3759 n_total++;
3760
3761 p += n;
3762 }
3763
3764 if (size < n_variable * sz)
3765 return -EBADMSG;
3766
3767 where = m->rindex + size - (n_variable * sz);
3768 r = message_peek_body(m, &where, 1, n_variable * sz, &q);
9a17484d
LP
3769 if (r < 0)
3770 return r;
9a17484d 3771
6647dc66 3772 v = n_variable;
9a17484d 3773
6647dc66
LP
3774 *offsets = new(size_t, n_total);
3775 if (!*offsets)
3776 return -ENOMEM;
9a17484d 3777
6647dc66 3778 *n_offsets = 0;
9a17484d 3779
6647dc66
LP
3780 /* Second, loop again and build an offset table */
3781 p = signature;
3782 while (*p != 0) {
3783 size_t n, offset;
3784 int k;
9a17484d 3785
6647dc66
LP
3786 r = signature_element_length(p, &n);
3787 if (r < 0)
3788 return r;
3789 else {
3790 char t[n+1];
3791
3792 memcpy(t, p, n);
3793 t[n] = 0;
3794
3795 k = bus_gvariant_get_size(t);
3796 if (k < 0) {
3797 size_t x;
3798
3799 /* variable size */
3800 if (v > 0) {
3801 v--;
3802
2ac7c17f 3803 x = bus_gvariant_read_word_le((uint8_t*) q + v*sz, sz);
6647dc66
LP
3804 if (x >= size)
3805 return -EBADMSG;
3806 if (m->rindex + x < previous)
3807 return -EBADMSG;
3808 } else
3809 /* The last item's end
3810 * is determined from
3811 * the start of the
3812 * offset array */
3813 x = size - (n_variable * sz);
3814
3815 offset = m->rindex + x;
3816
3817 } else {
3818 size_t align;
3819
3820 /* fixed size */
3821 align = bus_gvariant_get_alignment(t);
3822 assert(align > 0);
3823
3824 offset = (*n_offsets == 0 ? m->rindex : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k;
3825 }
3826 }
3827
3828 previous = (*offsets)[(*n_offsets)++] = offset;
3829 p += n;
3830 }
3831
3832 assert(v == 0);
3833 assert(*n_offsets == n_total);
3834
3835 *item_size = (*offsets)[0] - m->rindex;
3836 return 0;
3837}
3838
3839static int enter_struct_or_dict_entry(
3840 sd_bus_message *m,
3841 struct bus_container *c,
3842 const char *contents,
3843 size_t *item_size,
3844 size_t **offsets,
3845 size_t *n_offsets) {
3846
3847 int r;
3848
3849 assert(m);
3850 assert(c);
3851 assert(contents);
3852 assert(item_size);
3853 assert(offsets);
3854 assert(n_offsets);
3855
3856 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3857
3858 /* dbus1 */
3859 r = message_peek_body(m, &m->rindex, 8, 0, NULL);
18f5b48f 3860 if (r < 0)
6647dc66
LP
3861 return r;
3862
6647dc66
LP
3863 } else
3864 /* gvariant with contents */
3865 return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets);
3866
3867 return 0;
de1c301e
LP
3868}
3869
9a17484d
LP
3870static int bus_message_enter_struct(
3871 sd_bus_message *m,
3872 struct bus_container *c,
6647dc66
LP
3873 const char *contents,
3874 size_t *item_size,
3875 size_t **offsets,
3876 size_t *n_offsets) {
9a17484d
LP
3877
3878 size_t l;
3879 int r;
3880
3881 assert(m);
3882 assert(c);
3883 assert(contents);
6647dc66
LP
3884 assert(item_size);
3885 assert(offsets);
3886 assert(n_offsets);
9a17484d
LP
3887
3888 if (!signature_is_valid(contents, false))
3889 return -EINVAL;
3890
3891 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3892 return -ENXIO;
9a17484d
LP
3893
3894 l = strlen(contents);
3895
3896 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
3897 !startswith(c->signature + c->index + 1, contents) ||
3898 c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
3899 return -ENXIO;
3900
6647dc66
LP
3901 r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
3902 if (r < 0)
9a17484d
LP
3903 return r;
3904
3905 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3906 c->index += 1 + l + 1;
3907
3908 return 1;
3909}
3910
3911static int bus_message_enter_dict_entry(
3912 sd_bus_message *m,
3913 struct bus_container *c,
6647dc66
LP
3914 const char *contents,
3915 size_t *item_size,
3916 size_t **offsets,
3917 size_t *n_offsets) {
9a17484d
LP
3918
3919 size_t l;
3920 int r;
3921
3922 assert(m);
3923 assert(c);
3924 assert(contents);
3925
3926 if (!signature_is_pair(contents))
3927 return -EINVAL;
3928
3929 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3930 return -ENXIO;
3931
3932 if (!c->signature || c->signature[c->index] == 0)
3933 return 0;
3934
3935 l = strlen(contents);
3936
3937 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
3938 !startswith(c->signature + c->index + 1, contents) ||
3939 c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
3940 return -ENXIO;
3941
6647dc66
LP
3942 r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
3943 if (r < 0)
9a17484d
LP
3944 return r;
3945
3946 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3947 c->index += 1 + l + 1;
3948
3949 return 1;
3950}
3951
d9f644e2
ZJS
3952_public_ int sd_bus_message_enter_container(sd_bus_message *m,
3953 char type,
3954 const char *contents) {
cf81c68e 3955 struct bus_container *c;
9a17484d 3956 uint32_t *array_size = NULL;
7a4b8512 3957 _cleanup_free_ char *signature = NULL;
cf81c68e 3958 size_t before, end;
7a4b8512 3959 _cleanup_free_ size_t *offsets = NULL;
6647dc66 3960 size_t n_offsets = 0, item_size = 0;
9a17484d
LP
3961 int r;
3962
275b39fe
LP
3963 assert_return(m, -EINVAL);
3964 assert_return(m->sealed, -EPERM);
3965 assert_return(type != 0 || !contents, -EINVAL);
3966
3967 if (type == 0 || !contents) {
3968 const char *cc;
3969 char tt;
3970
3971 /* Allow entering into anonymous containers */
3972 r = sd_bus_message_peek_type(m, &tt, &cc);
18f5b48f 3973 if (r < 0)
275b39fe
LP
3974 return r;
3975
3976 if (type != 0 && type != tt)
3977 return -ENXIO;
3978
3979 if (contents && !streq(contents, cc))
3980 return -ENXIO;
3981
3982 type = tt;
3983 contents = cc;
3984 }
9a17484d 3985
ed205a6b
LP
3986 /*
3987 * We enforce a global limit on container depth, that is much
3988 * higher than the 32 structs and 32 arrays the specification
3989 * mandates. This is simpler to implement for us, and we need
3990 * this only to ensure our container array doesn't grow
3991 * without bounds. We are happy to return any data from a
3992 * message as long as the data itself is valid, even if the
3993 * overall message might be not.
3994 *
3995 * Note that the message signature is validated when
3996 * parsing the headers, and that validation does check the
3997 * 32/32 limit.
3998 *
3999 * Note that the specification defines no limits on the depth
4000 * of stacked variants, but we do.
4001 */
4002 if (m->n_containers >= BUS_CONTAINER_DEPTH)
4003 return -EBADMSG;
4004
306f07be 4005 if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1))
9a17484d 4006 return -ENOMEM;
9a17484d 4007
7b058942 4008 if (message_end_of_signature(m))
430fb8fa 4009 return -ENXIO;
9a17484d 4010
1daf8121
LP
4011 if (message_end_of_array(m, m->rindex))
4012 return 0;
4013
9c65778d 4014 c = message_get_last_container(m);
7b058942 4015
9a17484d
LP
4016 signature = strdup(contents);
4017 if (!signature)
4018 return -ENOMEM;
4019
b3af9646
LP
4020 c->saved_index = c->index;
4021 before = m->rindex;
4022
9a17484d 4023 if (type == SD_BUS_TYPE_ARRAY)
6647dc66 4024 r = bus_message_enter_array(m, c, contents, &array_size, &item_size, &offsets, &n_offsets);
9a17484d 4025 else if (type == SD_BUS_TYPE_VARIANT)
6647dc66 4026 r = bus_message_enter_variant(m, c, contents, &item_size);
9a17484d 4027 else if (type == SD_BUS_TYPE_STRUCT)
6647dc66 4028 r = bus_message_enter_struct(m, c, contents, &item_size, &offsets, &n_offsets);
9a17484d 4029 else if (type == SD_BUS_TYPE_DICT_ENTRY)
6647dc66 4030 r = bus_message_enter_dict_entry(m, c, contents, &item_size, &offsets, &n_offsets);
9a17484d
LP
4031 else
4032 r = -EINVAL;
7a4b8512 4033 if (r <= 0)
9a17484d 4034 return r;
9a17484d
LP
4035
4036 /* OK, let's fill it in */
e53d21d0
DH
4037 if (BUS_MESSAGE_IS_GVARIANT(m) &&
4038 type == SD_BUS_TYPE_STRUCT &&
4039 isempty(signature))
cf81c68e 4040 end = m->rindex + 0;
e53d21d0 4041 else
cf81c68e
ZJS
4042 end = m->rindex + c->item_size;
4043
4044 m->containers[m->n_containers++] = (struct bus_container) {
4045 .enclosing = type,
4046 .signature = TAKE_PTR(signature),
4047
4048 .before = before,
4049 .begin = m->rindex,
4050 /* Unary type has fixed size of 1, but virtual size of 0 */
4051 .end = end,
4052 .array_size = array_size,
4053 .item_size = item_size,
4054 .offsets = TAKE_PTR(offsets),
4055 .n_offsets = n_offsets,
4056 };
9a17484d
LP
4057
4058 return 1;
4059}
4060
d9f644e2 4061_public_ int sd_bus_message_exit_container(sd_bus_message *m) {
9a17484d 4062 struct bus_container *c;
5763192a 4063 unsigned saved;
6647dc66 4064 int r;
9a17484d 4065
9d6c7c82
LP
4066 assert_return(m, -EINVAL);
4067 assert_return(m->sealed, -EPERM);
f959af20 4068 assert_return(m->n_containers > 0, -ENXIO);
9a17484d 4069
9c65778d 4070 c = message_get_last_container(m);
6647dc66
LP
4071
4072 if (c->enclosing != SD_BUS_TYPE_ARRAY) {
4073 if (c->signature && c->signature[c->index] != 0)
4074 return -EBUSY;
4075 }
4076
4077 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4078 if (m->rindex < c->end)
4079 return -EBUSY;
4080
4081 } else if (c->enclosing == SD_BUS_TYPE_ARRAY) {
9a17484d
LP
4082 uint32_t l;
4083
4084 l = BUS_MESSAGE_BSWAP32(m, *c->array_size);
4085 if (c->begin + l != m->rindex)
4086 return -EBUSY;
9a17484d
LP
4087 }
4088
6d1e0f4f 4089 message_free_last_container(m);
9a17484d 4090
9c65778d 4091 c = message_get_last_container(m);
5763192a
LP
4092 saved = c->index;
4093 c->index = c->saved_index;
6647dc66 4094 r = container_next_item(m, c, &m->rindex);
5763192a 4095 c->index = saved;
6647dc66
LP
4096 if (r < 0)
4097 return r;
4098
9a17484d
LP
4099 return 1;
4100}
4101
b3af9646
LP
4102static void message_quit_container(sd_bus_message *m) {
4103 struct bus_container *c;
4104
4105 assert(m);
4106 assert(m->sealed);
4107 assert(m->n_containers > 0);
4108
b3af9646 4109 /* Undo seeks */
9c65778d 4110 c = message_get_last_container(m);
b3af9646
LP
4111 assert(m->rindex >= c->before);
4112 m->rindex = c->before;
4113
4114 /* Free container */
6d1e0f4f 4115 message_free_last_container(m);
b3af9646
LP
4116
4117 /* Correct index of new top-level container */
9c65778d 4118 c = message_get_last_container(m);
b3af9646
LP
4119 c->index = c->saved_index;
4120}
4121
d9f644e2 4122_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
9a17484d
LP
4123 struct bus_container *c;
4124 int r;
4125
c430fee6
LP
4126 assert_return(m, -EINVAL);
4127 assert_return(m->sealed, -EPERM);
9a17484d 4128
7b058942 4129 if (message_end_of_signature(m))
9a17484d
LP
4130 goto eof;
4131
4132 if (message_end_of_array(m, m->rindex))
4133 goto eof;
4134
9c65778d 4135 c = message_get_last_container(m);
7b058942 4136
9a17484d
LP
4137 if (bus_type_is_basic(c->signature[c->index])) {
4138 if (contents)
4139 *contents = NULL;
4140 if (type)
4141 *type = c->signature[c->index];
4142 return 1;
4143 }
4144
4145 if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) {
4146
4147 if (contents) {
4148 size_t l;
9a17484d
LP
4149
4150 r = signature_element_length(c->signature+c->index+1, &l);
4151 if (r < 0)
4152 return r;
4153
7f546026 4154 /* signature_element_length does verification internally */
80a46c73 4155
ec6bda56 4156 /* The array element must not be empty */
7f546026
ZJS
4157 assert(l >= 1);
4158 if (free_and_strndup(&c->peeked_signature,
4159 c->signature + c->index + 1, l) < 0)
9a17484d
LP
4160 return -ENOMEM;
4161
7f546026 4162 *contents = c->peeked_signature;
9a17484d
LP
4163 }
4164
4165 if (type)
4166 *type = SD_BUS_TYPE_ARRAY;
4167
4168 return 1;
4169 }
4170
4c701096 4171 if (IN_SET(c->signature[c->index], SD_BUS_TYPE_STRUCT_BEGIN, SD_BUS_TYPE_DICT_ENTRY_BEGIN)) {
9a17484d
LP
4172
4173 if (contents) {
4174 size_t l;
9a17484d
LP
4175
4176 r = signature_element_length(c->signature+c->index, &l);
4177 if (r < 0)
4178 return r;
4179
ec6bda56 4180 assert(l >= 3);
7f546026
ZJS
4181 if (free_and_strndup(&c->peeked_signature,
4182 c->signature + c->index + 1, l - 2) < 0)
9a17484d
LP
4183 return -ENOMEM;
4184
7f546026 4185 *contents = c->peeked_signature;
9a17484d
LP
4186 }
4187
4188 if (type)
4189 *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
4190
4191 return 1;
4192 }
4193
4194 if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) {
4195 if (contents) {
9a17484d
LP
4196 void *q;
4197
6647dc66
LP
4198 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4199 size_t k;
9a17484d 4200
6647dc66
LP
4201 if (c->item_size < 2)
4202 return -EBADMSG;
9a17484d 4203
6647dc66
LP
4204 /* Look for the NUL delimiter that
4205 separates the payload from the
4206 signature. Since the body might be
4207 in a different part that then the
4208 signature we map byte by byte. */
4209
4210 for (k = 2; k <= c->item_size; k++) {
4211 size_t where;
4212
4213 where = m->rindex + c->item_size - k;
4214 r = message_peek_body(m, &where, 1, k, &q);
4215 if (r < 0)
4216 return r;
6647dc66
LP
4217
4218 if (*(char*) q == 0)
4219 break;
4220 }
4221
4222 if (k > c->item_size)
4223 return -EBADMSG;
4224
7f546026
ZJS
4225 if (free_and_strndup(&c->peeked_signature,
4226 (char*) q + 1, k - 1) < 0)
6647dc66
LP
4227 return -ENOMEM;
4228
3798fd4c 4229 if (!signature_is_valid(c->peeked_signature, true))
6647dc66
LP
4230 return -EBADMSG;
4231
3798fd4c 4232 *contents = c->peeked_signature;
6647dc66
LP
4233 } else {
4234 size_t rindex, l;
4235
4236 rindex = m->rindex;
4237 r = message_peek_body(m, &rindex, 1, 1, &q);
4238 if (r < 0)
4239 return r;
9a17484d 4240
6647dc66
LP
4241 l = *(uint8_t*) q;
4242 r = message_peek_body(m, &rindex, 1, l+1, &q);
4243 if (r < 0)
4244 return r;
6647dc66
LP
4245
4246 if (!validate_signature(q, l))
4247 return -EBADMSG;
4248
4249 *contents = q;
4250 }
9a17484d
LP
4251 }
4252
4253 if (type)
4254 *type = SD_BUS_TYPE_VARIANT;
4255
4256 return 1;
4257 }
4258
4259 return -EINVAL;
4260
4261eof:
4262 if (type)
7b058942 4263 *type = 0;
9a17484d
LP
4264 if (contents)
4265 *contents = NULL;
4266 return 0;
4267}
4268
d9f644e2 4269_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
9a17484d
LP
4270 struct bus_container *c;
4271
9d6c7c82
LP
4272 assert_return(m, -EINVAL);
4273 assert_return(m->sealed, -EPERM);
9a17484d
LP
4274
4275 if (complete) {
bc7fd8cd 4276 message_reset_containers(m);
9a17484d 4277 m->rindex = 0;
9a17484d 4278
9c65778d 4279 c = message_get_last_container(m);
9a17484d 4280 } else {
9c65778d 4281 c = message_get_last_container(m);
9a17484d 4282
6647dc66 4283 c->offset_index = 0;
9a17484d
LP
4284 c->index = 0;
4285 m->rindex = c->begin;
4286 }
4287
d36b7031 4288 c->offset_index = 0;
e4bb80a0 4289 c->item_size = (c->n_offsets > 0 ? c->offsets[0] : c->end) - c->begin;
d36b7031 4290
9a17484d
LP
4291 return !isempty(c->signature);
4292}
718db961 4293
11ce0db2 4294_public_ int sd_bus_message_readv(
1b492614
LP
4295 sd_bus_message *m,
4296 const char *types,
4297 va_list ap) {
9a17484d 4298
fe1d424d
LP
4299 unsigned n_array, n_struct;
4300 TypeStack stack[BUS_CONTAINER_DEPTH];
4301 unsigned stack_ptr = 0;
430fb8fa 4302 unsigned n_loop = 0;
9a17484d
LP
4303 int r;
4304
11ce0db2
VH
4305 assert_return(m, -EINVAL);
4306 assert_return(m->sealed, -EPERM);
4307 assert_return(types, -EINVAL);
1b492614 4308
430fb8fa 4309 if (isempty(types))
1b492614 4310 return 0;
9a17484d 4311
fe1d424d
LP
4312 /* Ideally, we'd just call ourselves recursively on every
4313 * complex type. However, the state of a va_list that is
4314 * passed to a function is undefined after that function
22509a8d 4315 * returns. This means we need to decode the va_list linearly
fe1d424d
LP
4316 * in a single stackframe. We hence implement our own
4317 * home-grown stack in an array. */
4318
6f285378 4319 n_array = (unsigned) -1; /* length of current array entries */
430fb8fa 4320 n_struct = strlen(types); /* length of current struct contents signature */
fe1d424d
LP
4321
4322 for (;;) {
4323 const char *t;
4324
430fb8fa
LP
4325 n_loop++;
4326
1b492614 4327 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
fe1d424d
LP
4328 r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
4329 if (r < 0)
4330 return r;
4331 if (r == 0)
4332 break;
4333
4334 r = sd_bus_message_exit_container(m);
4335 if (r < 0)
4336 return r;
4337
4338 continue;
4339 }
4340
4341 t = types;
4342 if (n_array != (unsigned) -1)
313cefa1 4343 n_array--;
fe1d424d 4344 else {
313cefa1 4345 types++;
fe1d424d
LP
4346 n_struct--;
4347 }
4348
9a17484d
LP
4349 switch (*t) {
4350
4351 case SD_BUS_TYPE_BYTE:
4352 case SD_BUS_TYPE_BOOLEAN:
4353 case SD_BUS_TYPE_INT16:
4354 case SD_BUS_TYPE_UINT16:
4355 case SD_BUS_TYPE_INT32:
4356 case SD_BUS_TYPE_UINT32:
4357 case SD_BUS_TYPE_INT64:
4358 case SD_BUS_TYPE_UINT64:
4359 case SD_BUS_TYPE_DOUBLE:
4360 case SD_BUS_TYPE_STRING:
4361 case SD_BUS_TYPE_OBJECT_PATH:
2c93b4ef
LP
4362 case SD_BUS_TYPE_SIGNATURE:
4363 case SD_BUS_TYPE_UNIX_FD: {
9a17484d
LP
4364 void *p;
4365
4366 p = va_arg(ap, void*);
4367 r = sd_bus_message_read_basic(m, *t, p);
fe1d424d
LP
4368 if (r < 0)
4369 return r;
430fb8fa
LP
4370 if (r == 0) {
4371 if (n_loop <= 1)
4372 return 0;
4373
fe1d424d 4374 return -ENXIO;
430fb8fa 4375 }
fe1d424d 4376
9a17484d
LP
4377 break;
4378 }
4379
4380 case SD_BUS_TYPE_ARRAY: {
4381 size_t k;
4382
4383 r = signature_element_length(t + 1, &k);
4384 if (r < 0)
4385 return r;
4386
4387 {
9a17484d 4388 char s[k + 1];
9a17484d
LP
4389 memcpy(s, t + 1, k);
4390 s[k] = 0;
9a17484d
LP
4391
4392 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4393 if (r < 0)
4394 return r;
430fb8fa
LP
4395 if (r == 0) {
4396 if (n_loop <= 1)
4397 return 0;
4398
9a17484d 4399 return -ENXIO;
430fb8fa 4400 }
fe1d424d 4401 }
9a17484d 4402
fe1d424d
LP
4403 if (n_array == (unsigned) -1) {
4404 types += k;
4405 n_struct -= k;
9a17484d
LP
4406 }
4407
fe1d424d
LP
4408 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4409 if (r < 0)
4410 return r;
4411
4412 types = t + 1;
4413 n_struct = k;
4414 n_array = va_arg(ap, unsigned);
4415
9a17484d
LP
4416 break;
4417 }
4418
4419 case SD_BUS_TYPE_VARIANT: {
4420 const char *s;
4421
4422 s = va_arg(ap, const char *);
4423 if (!s)
4424 return -EINVAL;
4425
4426 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s);
4427 if (r < 0)
4428 return r;
430fb8fa
LP
4429 if (r == 0) {
4430 if (n_loop <= 1)
4431 return 0;
4432
9a17484d 4433 return -ENXIO;
430fb8fa 4434 }
9a17484d 4435
fe1d424d 4436 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
9a17484d
LP
4437 if (r < 0)
4438 return r;
9a17484d 4439
fe1d424d
LP
4440 types = s;
4441 n_struct = strlen(s);
4442 n_array = (unsigned) -1;
4443
9a17484d
LP
4444 break;
4445 }
4446
4447 case SD_BUS_TYPE_STRUCT_BEGIN:
4448 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4449 size_t k;
4450
4451 r = signature_element_length(t, &k);
4452 if (r < 0)
4453 return r;
4454
4455 {
4456 char s[k - 1];
4457 memcpy(s, t + 1, k - 2);
4458 s[k - 2] = 0;
4459
4460 r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4461 if (r < 0)
4462 return r;
430fb8fa
LP
4463 if (r == 0) {
4464 if (n_loop <= 1)
4465 return 0;
9a17484d 4466 return -ENXIO;
430fb8fa 4467 }
fe1d424d 4468 }
9a17484d 4469
fe1d424d
LP
4470 if (n_array == (unsigned) -1) {
4471 types += k - 1;
4472 n_struct -= k - 1;
4473 }
9a17484d 4474
fe1d424d
LP
4475 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4476 if (r < 0)
4477 return r;
9a17484d 4478
fe1d424d
LP
4479 types = t + 1;
4480 n_struct = k - 2;
4481 n_array = (unsigned) -1;
9a17484d
LP
4482
4483 break;
4484 }
4485
4486 default:
fe1d424d 4487 return -EINVAL;
9a17484d 4488 }
9a17484d
LP
4489 }
4490
4491 return 1;
4492}
4493
d9f644e2 4494_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
9a17484d
LP
4495 va_list ap;
4496 int r;
4497
9b07511d
LP
4498 assert_return(m, -EINVAL);
4499 assert_return(m->sealed, -EPERM);
4500 assert_return(types, -EINVAL);
9a17484d
LP
4501
4502 va_start(ap, types);
11ce0db2 4503 r = sd_bus_message_readv(m, types, ap);
9a17484d
LP
4504 va_end(ap);
4505
4506 return r;
4507}
4508
d9f644e2 4509_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
9b07511d
LP
4510 int r;
4511
4512 assert_return(m, -EINVAL);
4513 assert_return(m->sealed, -EPERM);
9b07511d 4514
d9fba533
LP
4515 /* If types is NULL, read exactly one element */
4516 if (!types) {
4517 struct bus_container *c;
4518 size_t l;
4519
4520 if (message_end_of_signature(m))
4521 return -ENXIO;
4522
4523 if (message_end_of_array(m, m->rindex))
4524 return 0;
4525
9c65778d 4526 c = message_get_last_container(m);
d9fba533
LP
4527
4528 r = signature_element_length(c->signature + c->index, &l);
4529 if (r < 0)
4530 return r;
4531
4532 types = strndupa(c->signature + c->index, l);
4533 }
9b07511d
LP
4534
4535 switch (*types) {
4536
d9fba533
LP
4537 case 0: /* Nothing to drop */
4538 return 0;
4539
9b07511d
LP
4540 case SD_BUS_TYPE_BYTE:
4541 case SD_BUS_TYPE_BOOLEAN:
4542 case SD_BUS_TYPE_INT16:
4543 case SD_BUS_TYPE_UINT16:
4544 case SD_BUS_TYPE_INT32:
4545 case SD_BUS_TYPE_UINT32:
4546 case SD_BUS_TYPE_INT64:
4547 case SD_BUS_TYPE_UINT64:
4548 case SD_BUS_TYPE_DOUBLE:
4549 case SD_BUS_TYPE_STRING:
4550 case SD_BUS_TYPE_OBJECT_PATH:
4551 case SD_BUS_TYPE_SIGNATURE:
4552 case SD_BUS_TYPE_UNIX_FD:
4553
4554 r = sd_bus_message_read_basic(m, *types, NULL);
4555 if (r <= 0)
4556 return r;
4557
4558 r = sd_bus_message_skip(m, types + 1);
4559 if (r < 0)
4560 return r;
4561
4562 return 1;
4563
4564 case SD_BUS_TYPE_ARRAY: {
4565 size_t k;
4566
4567 r = signature_element_length(types + 1, &k);
4568 if (r < 0)
4569 return r;
4570
4571 {
4572 char s[k+1];
4573 memcpy(s, types+1, k);
4574 s[k] = 0;
4575
4576 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4577 if (r <= 0)
4578 return r;
4579
4580 for (;;) {
4581 r = sd_bus_message_skip(m, s);
4582 if (r < 0)
4583 return r;
4584 if (r == 0)
4585 break;
4586 }
4587
4588 r = sd_bus_message_exit_container(m);
4589 if (r < 0)
4590 return r;
4591 }
4592
4593 r = sd_bus_message_skip(m, types + 1 + k);
4594 if (r < 0)
4595 return r;
4596
4597 return 1;
4598 }
4599
4600 case SD_BUS_TYPE_VARIANT: {
4601 const char *contents;
4602 char x;
4603
4604 r = sd_bus_message_peek_type(m, &x, &contents);
4605 if (r <= 0)
4606 return r;
4607
4608 if (x != SD_BUS_TYPE_VARIANT)
4609 return -ENXIO;
4610
4611 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
4612 if (r <= 0)
4613 return r;
4614
4615 r = sd_bus_message_skip(m, contents);
4616 if (r < 0)
4617 return r;
4618 assert(r != 0);
4619
4620 r = sd_bus_message_exit_container(m);
4621 if (r < 0)
4622 return r;
4623
4624 r = sd_bus_message_skip(m, types + 1);
4625 if (r < 0)
4626 return r;
4627
4628 return 1;
4629 }
4630
4631 case SD_BUS_TYPE_STRUCT_BEGIN:
4632 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4633 size_t k;
4634
4635 r = signature_element_length(types, &k);
4636 if (r < 0)
4637 return r;
4638
4639 {
4640 char s[k-1];
4641 memcpy(s, types+1, k-2);
4642 s[k-2] = 0;
4643
4644 r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4645 if (r <= 0)
4646 return r;
4647
4648 r = sd_bus_message_skip(m, s);
4649 if (r < 0)
4650 return r;
9b07511d
LP
4651
4652 r = sd_bus_message_exit_container(m);
4653 if (r < 0)
4654 return r;
4655 }
4656
4657 r = sd_bus_message_skip(m, types + k);
4658 if (r < 0)
4659 return r;
4660
4661 return 1;
4662 }
4663
4664 default:
4665 return -EINVAL;
4666 }
4667}
4668
2ac7c17f
LP
4669_public_ int sd_bus_message_read_array(
4670 sd_bus_message *m,
4671 char type,
4672 const void **ptr,
4673 size_t *size) {
4674
b3af9646
LP
4675 struct bus_container *c;
4676 void *p;
4677 size_t sz;
4678 ssize_t align;
4679 int r;
4680
9d6c7c82
LP
4681 assert_return(m, -EINVAL);
4682 assert_return(m->sealed, -EPERM);
4683 assert_return(bus_type_is_trivial(type), -EINVAL);
4684 assert_return(ptr, -EINVAL);
4685 assert_return(size, -EINVAL);
15411c0c 4686 assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -EOPNOTSUPP);
b3af9646 4687
b3af9646 4688 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
66b26c5c 4689 if (r <= 0)
b3af9646
LP
4690 return r;
4691
9c65778d 4692 c = message_get_last_container(m);
6647dc66
LP
4693
4694 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4695 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
4696 if (align < 0)
4697 return align;
4698
18f5b48f 4699 sz = c->end - c->begin;
6647dc66
LP
4700 } else {
4701 align = bus_type_get_alignment(type);
4702 if (align < 0)
4703 return align;
4704
4705 sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
4706 }
b3af9646 4707
5e86fd7b
LP
4708 if (sz == 0)
4709 /* Zero length array, let's return some aligned
4710 * pointer that is not NULL */
0241c1c0 4711 p = (uint8_t*) align;
5e86fd7b
LP
4712 else {
4713 r = message_peek_body(m, &m->rindex, align, sz, &p);
4714 if (r < 0)
4715 goto fail;
b3af9646
LP
4716 }
4717
4718 r = sd_bus_message_exit_container(m);
4719 if (r < 0)
4720 goto fail;
4721
4722 *ptr = (const void*) p;
4723 *size = sz;
4724
4725 return 1;
4726
4727fail:
4728 message_quit_container(m);
4729 return r;
4730}
4731
80a46c73
LP
4732static int message_peek_fields(
4733 sd_bus_message *m,
4734 size_t *rindex,
4735 size_t align,
4736 size_t nbytes,
4737 void **ret) {
4738
4739 assert(m);
4740 assert(rindex);
4741 assert(align > 0);
4742
2ac7c17f 4743 return buffer_peek(BUS_MESSAGE_FIELDS(m), m->fields_size, rindex, align, nbytes, ret);
80a46c73
LP
4744}
4745
9f26c90c
LP
4746static int message_peek_field_uint32(
4747 sd_bus_message *m,
4748 size_t *ri,
6647dc66 4749 size_t item_size,
9f26c90c
LP
4750 uint32_t *ret) {
4751
4752 int r;
4753 void *q;
4754
4755 assert(m);
4756 assert(ri);
4757
6647dc66
LP
4758 if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 4)
4759 return -EBADMSG;
4760
4761 /* identical for gvariant and dbus1 */
4762
9f26c90c
LP
4763 r = message_peek_fields(m, ri, 4, 4, &q);
4764 if (r < 0)
4765 return r;
4766
4767 if (ret)
4768 *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
4769
4770 return 0;
4771}
4772
2ac7c17f
LP
4773static int message_peek_field_uint64(
4774 sd_bus_message *m,
4775 size_t *ri,
4776 size_t item_size,
4777 uint64_t *ret) {
4778
4779 int r;
4780 void *q;
4781
4782 assert(m);
4783 assert(ri);
4784
4785 if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 8)
4786 return -EBADMSG;
4787
4788 /* identical for gvariant and dbus1 */
4789
4790 r = message_peek_fields(m, ri, 8, 8, &q);
4791 if (r < 0)
4792 return r;
4793
4794 if (ret)
4795 *ret = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
4796
4797 return 0;
4798}
4799
80a46c73
LP
4800static int message_peek_field_string(
4801 sd_bus_message *m,
6693860f 4802 bool (*validate)(const char *p),
80a46c73 4803 size_t *ri,
6647dc66 4804 size_t item_size,
80a46c73
LP
4805 const char **ret) {
4806
9f26c90c 4807 uint32_t l;
80a46c73
LP
4808 int r;
4809 void *q;
4810
9a17484d 4811 assert(m);
80a46c73
LP
4812 assert(ri);
4813
6647dc66 4814 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4815
6647dc66
LP
4816 if (item_size <= 0)
4817 return -EBADMSG;
4818
4819 r = message_peek_fields(m, ri, 1, item_size, &q);
4820 if (r < 0)
4821 return r;
4822
4823 l = item_size - 1;
4824 } else {
4825 r = message_peek_field_uint32(m, ri, 4, &l);
4826 if (r < 0)
4827 return r;
4828
4829 r = message_peek_fields(m, ri, 1, l+1, &q);
4830 if (r < 0)
4831 return r;
4832 }
9a17484d 4833
6693860f
LP
4834 if (validate) {
4835 if (!validate_nul(q, l))
4836 return -EBADMSG;
4837
4838 if (!validate(q))
ac89bf1d
LP
4839 return -EBADMSG;
4840 } else {
4841 if (!validate_string(q, l))
4842 return -EBADMSG;
4843 }
80a46c73
LP
4844
4845 if (ret)
4846 *ret = q;
4847
4848 return 0;
4849}
4850
4851static int message_peek_field_signature(
4852 sd_bus_message *m,
4853 size_t *ri,
6647dc66 4854 size_t item_size,
80a46c73
LP
4855 const char **ret) {
4856
4857 size_t l;
4858 int r;
4859 void *q;
4860
4861 assert(m);
4862 assert(ri);
4863
6647dc66 4864 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4865
6647dc66
LP
4866 if (item_size <= 0)
4867 return -EBADMSG;
4868
4869 r = message_peek_fields(m, ri, 1, item_size, &q);
4870 if (r < 0)
4871 return r;
4872
4873 l = item_size - 1;
4874 } else {
4875 r = message_peek_fields(m, ri, 1, 1, &q);
4876 if (r < 0)
4877 return r;
4878
4879 l = *(uint8_t*) q;
4880 r = message_peek_fields(m, ri, 1, l+1, &q);
4881 if (r < 0)
4882 return r;
4883 }
80a46c73
LP
4884
4885 if (!validate_signature(q, l))
4886 return -EBADMSG;
4887
4888 if (ret)
4889 *ret = q;
4890
4891 return 0;
4892}
4893
80a46c73
LP
4894static int message_skip_fields(
4895 sd_bus_message *m,
4896 size_t *ri,
4897 uint32_t array_size,
4898 const char **signature) {
4899
4900 size_t original_index;
4901 int r;
4902
4903 assert(m);
4904 assert(ri);
4905 assert(signature);
6647dc66 4906 assert(!BUS_MESSAGE_IS_GVARIANT(m));
80a46c73
LP
4907
4908 original_index = *ri;
4909
4910 for (;;) {
4911 char t;
80a46c73
LP
4912 size_t l;
4913
4914 if (array_size != (uint32_t) -1 &&
4915 array_size <= *ri - original_index)
4916 return 0;
4917
4918 t = **signature;
4919 if (!t)
4920 return 0;
4921
6693860f
LP
4922 if (t == SD_BUS_TYPE_STRING) {
4923
6647dc66 4924 r = message_peek_field_string(m, NULL, ri, 0, NULL);
6693860f
LP
4925 if (r < 0)
4926 return r;
4927
4928 (*signature)++;
4929
4930 } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
80a46c73 4931
6647dc66 4932 r = message_peek_field_string(m, object_path_is_valid, ri, 0, NULL);
80a46c73
LP
4933 if (r < 0)
4934 return r;
4935
4936 (*signature)++;
4937
4938 } else if (t == SD_BUS_TYPE_SIGNATURE) {
4939
6647dc66 4940 r = message_peek_field_signature(m, ri, 0, NULL);
80a46c73
LP
4941 if (r < 0)
4942 return r;
4943
4944 (*signature)++;
4945
4946 } else if (bus_type_is_basic(t)) {
27f6e5c7 4947 ssize_t align, k;
80a46c73 4948
c66a2e0c
TG
4949 align = bus_type_get_alignment(t);
4950 k = bus_type_get_size(t);
27f6e5c7 4951 assert(align > 0 && k > 0);
80a46c73
LP
4952
4953 r = message_peek_fields(m, ri, align, k, NULL);
4954 if (r < 0)
4955 return r;
9a17484d 4956
80a46c73
LP
4957 (*signature)++;
4958
4959 } else if (t == SD_BUS_TYPE_ARRAY) {
4960
4961 r = signature_element_length(*signature+1, &l);
4962 if (r < 0)
4963 return r;
4964
4965 assert(l >= 1);
4966 {
4967 char sig[l-1], *s;
9f26c90c 4968 uint32_t nas;
80a46c73
LP
4969 int alignment;
4970
4971 strncpy(sig, *signature + 1, l-1);
4972 s = sig;
4973
4974 alignment = bus_type_get_alignment(sig[0]);
4975 if (alignment < 0)
4976 return alignment;
4977
6647dc66 4978 r = message_peek_field_uint32(m, ri, 0, &nas);
80a46c73
LP
4979 if (r < 0)
4980 return r;
ac89bf1d 4981 if (nas > BUS_ARRAY_MAX_SIZE)
80a46c73
LP
4982 return -EBADMSG;
4983
4984 r = message_peek_fields(m, ri, alignment, 0, NULL);
4985 if (r < 0)
4986 return r;
4987
4988 r = message_skip_fields(m, ri, nas, (const char**) &s);
4989 if (r < 0)
4990 return r;
4991 }
4992
4993 (*signature) += 1 + l;
4994
4995 } else if (t == SD_BUS_TYPE_VARIANT) {
4996 const char *s;
4997
6647dc66 4998 r = message_peek_field_signature(m, ri, 0, &s);
80a46c73
LP
4999 if (r < 0)
5000 return r;
5001
5002 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
5003 if (r < 0)
5004 return r;
5005
5006 (*signature)++;
5007
945c2931 5008 } else if (IN_SET(t, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) {
80a46c73
LP
5009
5010 r = signature_element_length(*signature, &l);
5011 if (r < 0)
5012 return r;
5013
5014 assert(l >= 2);
5015 {
5016 char sig[l-1], *s;
5017 strncpy(sig, *signature + 1, l-1);
5018 s = sig;
5019
5020 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
5021 if (r < 0)
5022 return r;
5023 }
5024
5025 *signature += l;
5026 } else
5027 return -EINVAL;
5028 }
5029}
5030
6629161f 5031int bus_message_parse_fields(sd_bus_message *m) {
80a46c73
LP
5032 size_t ri;
5033 int r;
2c93b4ef 5034 uint32_t unix_fds = 0;
5a4d665a 5035 bool unix_fds_set = false;
6647dc66
LP
5036 void *offsets = NULL;
5037 unsigned n_offsets = 0;
8f2e44f8 5038 size_t sz = 0;
6647dc66 5039 unsigned i = 0;
80a46c73
LP
5040
5041 assert(m);
5042
6647dc66 5043 if (BUS_MESSAGE_IS_GVARIANT(m)) {
2ac7c17f
LP
5044 char *p;
5045
5046 /* Read the signature from the end of the body variant first */
5047 sz = bus_gvariant_determine_word_size(BUS_MESSAGE_SIZE(m), 0);
5048 if (m->footer_accessible < 1 + sz)
5049 return -EBADMSG;
5050
5051 p = (char*) m->footer + m->footer_accessible - (1 + sz);
5052 for (;;) {
5053 if (p < (char*) m->footer)
5054 return -EBADMSG;
5055
5056 if (*p == 0) {
03ebf5e8 5057 size_t l;
2ac7c17f 5058
03ebf5e8
DH
5059 /* We found the beginning of the signature
5060 * string, yay! We require the body to be a
5061 * structure, so verify it and then strip the
5062 * opening/closing brackets. */
2ac7c17f 5063
7f546026 5064 l = (char*) m->footer + m->footer_accessible - p - (1 + sz);
03ebf5e8
DH
5065 if (l < 2 ||
5066 p[1] != SD_BUS_TYPE_STRUCT_BEGIN ||
5067 p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END)
5068 return -EBADMSG;
5069
7f546026
ZJS
5070 if (free_and_strndup(&m->root_container.signature,
5071 p + 1 + 1, l - 2) < 0)
2ac7c17f 5072 return -ENOMEM;
2ac7c17f
LP
5073 break;
5074 }
6647dc66 5075
2ac7c17f
LP
5076 p--;
5077 }
5078
5079 /* Calculate the actual user body size, by removing
5080 * the trailing variant signature and struct offset
5081 * table */
5082 m->user_body_size = m->body_size - ((char*) m->footer + m->footer_accessible - p);
5083
5084 /* Pull out the offset table for the fields array */
5085 sz = bus_gvariant_determine_word_size(m->fields_size, 0);
6647dc66
LP
5086 if (sz > 0) {
5087 size_t framing;
2ac7c17f 5088 void *q;
6647dc66 5089
2ac7c17f 5090 ri = m->fields_size - sz;
6647dc66
LP
5091 r = message_peek_fields(m, &ri, 1, sz, &q);
5092 if (r < 0)
5093 return r;
5094
2ac7c17f
LP
5095 framing = bus_gvariant_read_word_le(q, sz);
5096 if (framing >= m->fields_size - sz)
6647dc66 5097 return -EBADMSG;
2ac7c17f 5098 if ((m->fields_size - framing) % sz != 0)
6647dc66
LP
5099 return -EBADMSG;
5100
5101 ri = framing;
2ac7c17f 5102 r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
6647dc66
LP
5103 if (r < 0)
5104 return r;
5105
2ac7c17f 5106 n_offsets = (m->fields_size - framing) / sz;
6647dc66 5107 }
2ac7c17f
LP
5108 } else
5109 m->user_body_size = m->body_size;
6647dc66
LP
5110
5111 ri = 0;
2ac7c17f 5112 while (ri < m->fields_size) {
6647dc66 5113 _cleanup_free_ char *sig = NULL;
80a46c73 5114 const char *signature;
2ac7c17f 5115 uint64_t field_type;
6647dc66
LP
5116 size_t item_size = (size_t) -1;
5117
5118 if (BUS_MESSAGE_IS_GVARIANT(m)) {
2ac7c17f
LP
5119 uint64_t *u64;
5120
6647dc66
LP
5121 if (i >= n_offsets)
5122 break;
5123
5124 if (i == 0)
5125 ri = 0;
5126 else
2ac7c17f 5127 ri = ALIGN_TO(bus_gvariant_read_word_le((uint8_t*) offsets + (i-1)*sz, sz), 8);
80a46c73 5128
2ac7c17f
LP
5129 r = message_peek_fields(m, &ri, 8, 8, (void**) &u64);
5130 if (r < 0)
5131 return r;
5132
5133 field_type = BUS_MESSAGE_BSWAP64(m, *u64);
5134 } else {
5135 uint8_t *u8;
5136
5137 r = message_peek_fields(m, &ri, 8, 1, (void**) &u8);
5138 if (r < 0)
5139 return r;
5140
5141 field_type = *u8;
5142 }
954871d8 5143
6647dc66
LP
5144 if (BUS_MESSAGE_IS_GVARIANT(m)) {
5145 size_t where, end;
5146 char *b;
5147 void *q;
5148
2ac7c17f 5149 end = bus_gvariant_read_word_le((uint8_t*) offsets + i*sz, sz);
6647dc66
LP
5150
5151 if (end < ri)
5152 return -EBADMSG;
5153
5154 where = ri = ALIGN_TO(ri, 8);
5155 item_size = end - ri;
5156 r = message_peek_fields(m, &where, 1, item_size, &q);
5157 if (r < 0)
5158 return r;
5159
5160 b = memrchr(q, 0, item_size);
5161 if (!b)
5162 return -EBADMSG;
5163
5164 sig = strndup(b+1, item_size - (b+1-(char*) q));
5165 if (!sig)
5166 return -ENOMEM;
5167
5168 signature = sig;
5169 item_size = b - (char*) q;
5170 } else {
5171 r = message_peek_field_signature(m, &ri, 0, &signature);
5172 if (r < 0)
5173 return r;
5174 }
80a46c73 5175
2ac7c17f
LP
5176 switch (field_type) {
5177
0461f8cd 5178 case _BUS_MESSAGE_HEADER_INVALID:
80a46c73
LP
5179 return -EBADMSG;
5180
0461f8cd 5181 case BUS_MESSAGE_HEADER_PATH:
2c93b4ef
LP
5182
5183 if (m->path)
5184 return -EBADMSG;
5185
80a46c73
LP
5186 if (!streq(signature, "o"))
5187 return -EBADMSG;
5188
6647dc66 5189 r = message_peek_field_string(m, object_path_is_valid, &ri, item_size, &m->path);
80a46c73
LP
5190 break;
5191
0461f8cd 5192 case BUS_MESSAGE_HEADER_INTERFACE:
2c93b4ef
LP
5193
5194 if (m->interface)
5195 return -EBADMSG;
5196
80a46c73
LP
5197 if (!streq(signature, "s"))
5198 return -EBADMSG;
5199
6647dc66 5200 r = message_peek_field_string(m, interface_name_is_valid, &ri, item_size, &m->interface);
80a46c73
LP
5201 break;
5202
0461f8cd 5203 case BUS_MESSAGE_HEADER_MEMBER:
2c93b4ef
LP
5204
5205 if (m->member)
5206 return -EBADMSG;
5207
80a46c73
LP
5208 if (!streq(signature, "s"))
5209 return -EBADMSG;
5210
6647dc66 5211 r = message_peek_field_string(m, member_name_is_valid, &ri, item_size, &m->member);
80a46c73
LP
5212 break;
5213
0461f8cd 5214 case BUS_MESSAGE_HEADER_ERROR_NAME:
2c93b4ef
LP
5215
5216 if (m->error.name)
5217 return -EBADMSG;
5218
80a46c73
LP
5219 if (!streq(signature, "s"))
5220 return -EBADMSG;
5221
6647dc66 5222 r = message_peek_field_string(m, error_name_is_valid, &ri, item_size, &m->error.name);
79f8d3d2
LP
5223 if (r >= 0)
5224 m->error._need_free = -1;
5225
80a46c73
LP
5226 break;
5227
0461f8cd 5228 case BUS_MESSAGE_HEADER_DESTINATION:
2c93b4ef
LP
5229
5230 if (m->destination)
5231 return -EBADMSG;
5232
80a46c73
LP
5233 if (!streq(signature, "s"))
5234 return -EBADMSG;
5235
6647dc66 5236 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->destination);
80a46c73
LP
5237 break;
5238
0461f8cd 5239 case BUS_MESSAGE_HEADER_SENDER:
2c93b4ef
LP
5240
5241 if (m->sender)
5242 return -EBADMSG;
5243
80a46c73
LP
5244 if (!streq(signature, "s"))
5245 return -EBADMSG;
5246
6647dc66 5247 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
49b832c5 5248
a132bef0 5249 if (r >= 0 && m->sender[0] == ':' && m->bus->bus_client) {
49b832c5
LP
5250 m->creds.unique_name = (char*) m->sender;
5251 m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
5252 }
5253
80a46c73
LP
5254 break;
5255
0461f8cd 5256 case BUS_MESSAGE_HEADER_SIGNATURE: {
80a46c73
LP
5257 const char *s;
5258 char *c;
5259
2ac7c17f
LP
5260 if (BUS_MESSAGE_IS_GVARIANT(m)) /* only applies to dbus1 */
5261 return -EBADMSG;
5262
2c93b4ef
LP
5263 if (m->root_container.signature)
5264 return -EBADMSG;
5265
80a46c73
LP
5266 if (!streq(signature, "g"))
5267 return -EBADMSG;
5268
6647dc66 5269 r = message_peek_field_signature(m, &ri, item_size, &s);
80a46c73
LP
5270 if (r < 0)
5271 return r;
5272
5273 c = strdup(s);
5274 if (!c)
5275 return -ENOMEM;
5276
7a4b8512 5277 free_and_replace(m->root_container.signature, c);
80a46c73
LP
5278 break;
5279 }
5280
2ac7c17f 5281 case BUS_MESSAGE_HEADER_REPLY_SERIAL:
42c4ebcb 5282
693eb9a2 5283 if (m->reply_cookie != 0)
2c93b4ef
LP
5284 return -EBADMSG;
5285
2ac7c17f
LP
5286 if (BUS_MESSAGE_IS_GVARIANT(m)) {
5287 /* 64bit on dbus2 */
6693860f 5288
2ac7c17f
LP
5289 if (!streq(signature, "t"))
5290 return -EBADMSG;
5291
5292 r = message_peek_field_uint64(m, &ri, item_size, &m->reply_cookie);
5293 if (r < 0)
5294 return r;
5295 } else {
5296 /* 32bit on dbus1 */
5297 uint32_t serial;
5298
5299 if (!streq(signature, "u"))
5300 return -EBADMSG;
b381de41 5301
2ac7c17f
LP
5302 r = message_peek_field_uint32(m, &ri, item_size, &serial);
5303 if (r < 0)
5304 return r;
5305
5306 m->reply_cookie = serial;
5307 }
42c4ebcb 5308
693eb9a2 5309 if (m->reply_cookie == 0)
6693860f
LP
5310 return -EBADMSG;
5311
80a46c73
LP
5312 break;
5313
0461f8cd 5314 case BUS_MESSAGE_HEADER_UNIX_FDS:
5a4d665a 5315 if (unix_fds_set)
2c93b4ef
LP
5316 return -EBADMSG;
5317
5318 if (!streq(signature, "u"))
5319 return -EBADMSG;
5320
6647dc66 5321 r = message_peek_field_uint32(m, &ri, item_size, &unix_fds);
2c93b4ef
LP
5322 if (r < 0)
5323 return -EBADMSG;
5324
5a4d665a 5325 unix_fds_set = true;
2c93b4ef
LP
5326 break;
5327
80a46c73 5328 default:
6647dc66
LP
5329 if (!BUS_MESSAGE_IS_GVARIANT(m))
5330 r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
80a46c73
LP
5331 }
5332
5333 if (r < 0)
5334 return r;
6647dc66
LP
5335
5336 i++;
80a46c73
LP
5337 }
5338
2c93b4ef
LP
5339 if (m->n_fds != unix_fds)
5340 return -EBADMSG;
5341
80a46c73
LP
5342 switch (m->header->type) {
5343
40ca29a1 5344 case SD_BUS_MESSAGE_SIGNAL:
80a46c73
LP
5345 if (!m->path || !m->interface || !m->member)
5346 return -EBADMSG;
7fa934b0
LP
5347
5348 if (m->reply_cookie != 0)
5349 return -EBADMSG;
5350
80a46c73
LP
5351 break;
5352
40ca29a1 5353 case SD_BUS_MESSAGE_METHOD_CALL:
80a46c73
LP
5354
5355 if (!m->path || !m->member)
5356 return -EBADMSG;
5357
7fa934b0
LP
5358 if (m->reply_cookie != 0)
5359 return -EBADMSG;
5360
80a46c73
LP
5361 break;
5362
40ca29a1 5363 case SD_BUS_MESSAGE_METHOD_RETURN:
80a46c73 5364
693eb9a2 5365 if (m->reply_cookie == 0)
80a46c73
LP
5366 return -EBADMSG;
5367 break;
5368
40ca29a1 5369 case SD_BUS_MESSAGE_METHOD_ERROR:
80a46c73 5370
693eb9a2 5371 if (m->reply_cookie == 0 || !m->error.name)
80a46c73
LP
5372 return -EBADMSG;
5373 break;
5374 }
9a17484d 5375
35473296
LP
5376 /* Refuse non-local messages that claim they are local */
5377 if (streq_ptr(m->path, "/org/freedesktop/DBus/Local"))
5378 return -EBADMSG;
5379 if (streq_ptr(m->interface, "org.freedesktop.DBus.Local"))
5380 return -EBADMSG;
5381 if (streq_ptr(m->sender, "org.freedesktop.DBus.Local"))
5382 return -EBADMSG;
5383
2ac7c17f 5384 m->root_container.end = m->user_body_size;
6647dc66
LP
5385
5386 if (BUS_MESSAGE_IS_GVARIANT(m)) {
5387 r = build_struct_offsets(
5388 m,
5389 m->root_container.signature,
2ac7c17f 5390 m->user_body_size,
6647dc66
LP
5391 &m->root_container.item_size,
5392 &m->root_container.offsets,
5393 &m->root_container.n_offsets);
69bd42ca
ZJS
5394 if (r == -EINVAL)
5395 return -EBADMSG;
6647dc66
LP
5396 if (r < 0)
5397 return r;
5398 }
5399
89ffcd2a 5400 /* Try to read the error message, but if we can't it's a non-issue */
40ca29a1 5401 if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
d3839740 5402 (void) sd_bus_message_read(m, "s", &m->error.message);
89ffcd2a 5403
9a17484d
LP
5404 return 0;
5405}
5406
d9f644e2 5407_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
9d6c7c82
LP
5408 assert_return(m, -EINVAL);
5409 assert_return(destination, -EINVAL);
3d51a011 5410 assert_return(service_name_is_valid(destination), -EINVAL);
9d6c7c82
LP
5411 assert_return(!m->sealed, -EPERM);
5412 assert_return(!m->destination, -EEXIST);
9a17484d 5413
0461f8cd 5414 return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
9a17484d
LP
5415}
5416
48ef41a3
LP
5417_public_ int sd_bus_message_set_sender(sd_bus_message *m, const char *sender) {
5418 assert_return(m, -EINVAL);
5419 assert_return(sender, -EINVAL);
3d51a011 5420 assert_return(service_name_is_valid(sender), -EINVAL);
48ef41a3
LP
5421 assert_return(!m->sealed, -EPERM);
5422 assert_return(!m->sender, -EEXIST);
5423
5424 return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
5425}
5426
de1c301e
LP
5427int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
5428 size_t total;
de1c301e 5429 void *p, *e;
da6053d0 5430 size_t i;
bc7fd8cd 5431 struct bus_body_part *part;
de1c301e
LP
5432
5433 assert(m);
5434 assert(buffer);
5435 assert(sz);
5436
6629161f 5437 total = BUS_MESSAGE_SIZE(m);
de1c301e
LP
5438
5439 p = malloc(total);
5440 if (!p)
5441 return -ENOMEM;
5442
c91cb83c 5443 e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m));
9b29bb68 5444 MESSAGE_FOREACH_PART(part, i, m)
bc7fd8cd 5445 e = mempcpy(e, part->data, part->size);
2100fa10
LP
5446
5447 assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p));
de1c301e
LP
5448
5449 *buffer = p;
5450 *sz = total;
5451
5452 return 0;
5453}
89ffcd2a
LP
5454
5455int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
43ef7603 5456 const char *s;
89ffcd2a
LP
5457 int r;
5458
5459 assert(m);
5460 assert(l);
5461
5462 r = sd_bus_message_enter_container(m, 'a', "s");
4686d1b6 5463 if (r <= 0)
89ffcd2a
LP
5464 return r;
5465
43ef7603 5466 while ((r = sd_bus_message_read_basic(m, 's', &s)) > 0) {
89ffcd2a
LP
5467 r = strv_extend(l, s);
5468 if (r < 0)
5469 return r;
5470 }
43ef7603
DH
5471 if (r < 0)
5472 return r;
89ffcd2a
LP
5473
5474 r = sd_bus_message_exit_container(m);
5475 if (r < 0)
5476 return r;
5477
405cd3aa 5478 return 1;
89ffcd2a 5479}
392d5b37 5480
ba341e7c 5481_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
7a4b8512 5482 _cleanup_strv_free_ char **strv = NULL;
4686d1b6
MAP
5483 int r;
5484
5485 assert_return(m, -EINVAL);
5486 assert_return(m->sealed, -EPERM);
5487 assert_return(l, -EINVAL);
5488
5489 r = bus_message_read_strv_extend(m, &strv);
7a4b8512 5490 if (r <= 0)
4686d1b6 5491 return r;
4686d1b6 5492
7a4b8512 5493 *l = TAKE_PTR(strv);
4686d1b6
MAP
5494 return 1;
5495}
5496
eccd47c5
LP
5497static int bus_message_get_arg_skip(
5498 sd_bus_message *m,
5499 unsigned i,
5500 char *_type,
5501 const char **_contents) {
5502
42c5aaf3 5503 unsigned j;
198b158f 5504 int r;
392d5b37 5505
392d5b37
LP
5506 r = sd_bus_message_rewind(m, true);
5507 if (r < 0)
198b158f 5508 return r;
392d5b37 5509
198b158f 5510 for (j = 0;; j++) {
eccd47c5
LP
5511 const char *contents;
5512 char type;
5513
198b158f
LP
5514 r = sd_bus_message_peek_type(m, &type, &contents);
5515 if (r < 0)
5516 return r;
5517 if (r == 0)
5518 return -ENXIO;
5519
5520 /* Don't match against arguments after the first one we don't understand */
5521 if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE) &&
5522 !(type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")))
5523 return -ENXIO;
42c5aaf3 5524
eccd47c5
LP
5525 if (j >= i) {
5526 if (_contents)
5527 *_contents = contents;
5528 if (_type)
5529 *_type = type;
5530 return 0;
5531 }
198b158f
LP
5532
5533 r = sd_bus_message_skip(m, NULL);
392d5b37 5534 if (r < 0)
198b158f
LP
5535 return r;
5536 }
392d5b37 5537
eccd47c5 5538}
392d5b37 5539
eccd47c5
LP
5540int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str) {
5541 char type;
5542 int r;
198b158f 5543
eccd47c5
LP
5544 assert(m);
5545 assert(str);
198b158f 5546
eccd47c5
LP
5547 r = bus_message_get_arg_skip(m, i, &type, NULL);
5548 if (r < 0)
5549 return r;
198b158f 5550
eccd47c5
LP
5551 if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE))
5552 return -ENXIO;
392d5b37 5553
eccd47c5
LP
5554 return sd_bus_message_read_basic(m, type, str);
5555}
5556
5557int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv) {
5558 const char *contents;
5559 char type;
5560 int r;
5561
5562 assert(m);
5563 assert(strv);
5564
5565 r = bus_message_get_arg_skip(m, i, &type, &contents);
5566 if (r < 0)
5567 return r;
5568
5569 if (type != SD_BUS_TYPE_ARRAY)
5570 return -ENXIO;
5571 if (!STR_IN_SET(contents, "s", "o", "g"))
5572 return -ENXIO;
5573
5574 return sd_bus_message_read_strv(m, strv);
392d5b37 5575}
2100fa10 5576
d9f644e2 5577_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
b49ffb29 5578 assert_return(m, EINVAL);
eb01ba5d 5579
40ca29a1 5580 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
eb01ba5d
LP
5581 return 0;
5582
40ca29a1 5583 return sd_bus_error_get_errno(&m->error);
eb01ba5d 5584}
29ddb38f 5585
d9f644e2 5586_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
29ddb38f
LP
5587 struct bus_container *c;
5588
9d6c7c82 5589 assert_return(m, NULL);
29ddb38f 5590
9c65778d 5591 c = complete ? &m->root_container : message_get_last_container(m);
d6385068 5592 return strempty(c->signature);
29ddb38f 5593}
c430fee6 5594
8022212b
LP
5595_public_ int sd_bus_message_is_empty(sd_bus_message *m) {
5596 assert_return(m, -EINVAL);
5597
5598 return isempty(m->root_container.signature);
5599}
5600
64e96a19
LP
5601_public_ int sd_bus_message_has_signature(sd_bus_message *m, const char *signature) {
5602 assert_return(m, -EINVAL);
5603
5604 return streq(strempty(m->root_container.signature), strempty(signature));
5605}
5606
d9f644e2 5607_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
c430fee6
LP
5608 bool done_something = false;
5609 int r;
5610
80ba3b84
LP
5611 assert_return(m, -EINVAL);
5612 assert_return(source, -EINVAL);
5613 assert_return(!m->sealed, -EPERM);
5614 assert_return(source->sealed, -EPERM);
5615
c430fee6
LP
5616 do {
5617 const char *contents;
5618 char type;
5619 union {
5620 uint8_t u8;
5621 uint16_t u16;
5622 int16_t s16;
5623 uint32_t u32;
5624 int32_t s32;
5625 uint64_t u64;
5626 int64_t s64;
5627 double d64;
5628 const char *string;
5629 int i;
5630 } basic;
5631
5632 r = sd_bus_message_peek_type(source, &type, &contents);
5633 if (r < 0)
5634 return r;
5635 if (r == 0)
5636 break;
5637
5638 done_something = true;
5639
5640 if (bus_type_is_container(type) > 0) {
5641
5642 r = sd_bus_message_enter_container(source, type, contents);
5643 if (r < 0)
5644 return r;
5645
5646 r = sd_bus_message_open_container(m, type, contents);
5647 if (r < 0)
5648 return r;
5649
5650 r = sd_bus_message_copy(m, source, true);
5651 if (r < 0)
5652 return r;
5653
5654 r = sd_bus_message_close_container(m);
5655 if (r < 0)
5656 return r;
5657
5658 r = sd_bus_message_exit_container(source);
5659 if (r < 0)
5660 return r;
5661
5662 continue;
5663 }
5664
5665 r = sd_bus_message_read_basic(source, type, &basic);
5666 if (r < 0)
5667 return r;
5668
5669 assert(r > 0);
5670
945c2931 5671 if (IN_SET(type, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE, SD_BUS_TYPE_STRING))
c430fee6
LP
5672 r = sd_bus_message_append_basic(m, type, basic.string);
5673 else
5674 r = sd_bus_message_append_basic(m, type, &basic);
5675
5676 if (r < 0)
5677 return r;
5678
5679 } while (all);
5680
5681 return done_something;
5682}
5683
d9f644e2 5684_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
c430fee6
LP
5685 const char *c;
5686 char t;
5687 int r;
5688
5689 assert_return(m, -EINVAL);
5690 assert_return(m->sealed, -EPERM);
5691 assert_return(!type || bus_type_is_valid(type), -EINVAL);
5692 assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
5693 assert_return(type || contents, -EINVAL);
5694 assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
5695
5696 r = sd_bus_message_peek_type(m, &t, &c);
5697 if (r <= 0)
5698 return r;
5699
5700 if (type != 0 && type != t)
5701 return 0;
5702
5703 if (contents && !streq_ptr(contents, c))
5704 return 0;
5705
5706 return 1;
5707}
2be44176
LP
5708
5709_public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) {
5710 assert_return(m, NULL);
5711
5712 return m->bus;
5713}
e1c433c6
LP
5714
5715int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
4afd3348 5716 _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL;
e1c433c6
LP
5717 usec_t timeout;
5718 int r;
5719
5720 assert(bus);
5721 assert(m);
5722 assert(*m);
5723
5724 switch ((*m)->header->type) {
5725
5726 case SD_BUS_MESSAGE_SIGNAL:
151b9b96 5727 r = sd_bus_message_new_signal(bus, &n, (*m)->path, (*m)->interface, (*m)->member);
e1c433c6
LP
5728 if (r < 0)
5729 return r;
5730
5731 break;
5732
5733 case SD_BUS_MESSAGE_METHOD_CALL:
151b9b96 5734 r = sd_bus_message_new_method_call(bus, &n, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member);
e1c433c6
LP
5735 if (r < 0)
5736 return r;
5737
5738 break;
5739
5740 case SD_BUS_MESSAGE_METHOD_RETURN:
5741 case SD_BUS_MESSAGE_METHOD_ERROR:
5742
75bcbcf2
SA
5743 r = sd_bus_message_new(bus, &n, (*m)->header->type);
5744 if (r < 0)
e1c433c6
LP
5745 return -ENOMEM;
5746
75bcbcf2
SA
5747 assert(n);
5748
693eb9a2 5749 n->reply_cookie = (*m)->reply_cookie;
b267a6d2
LP
5750
5751 r = message_append_reply_cookie(n, n->reply_cookie);
e1c433c6
LP
5752 if (r < 0)
5753 return r;
5754
5755 if ((*m)->header->type == SD_BUS_MESSAGE_METHOD_ERROR && (*m)->error.name) {
5756 r = message_append_field_string(n, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, (*m)->error.name, &n->error.message);
5757 if (r < 0)
5758 return r;
5759
5760 n->error._need_free = -1;
5761 }
5762
5763 break;
5764
5765 default:
5766 return -EINVAL;
5767 }
5768
5769 if ((*m)->destination && !n->destination) {
5770 r = message_append_field_string(n, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, (*m)->destination, &n->destination);
5771 if (r < 0)
5772 return r;
5773 }
5774
5775 if ((*m)->sender && !n->sender) {
5776 r = message_append_field_string(n, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, (*m)->sender, &n->sender);
5777 if (r < 0)
5778 return r;
5779 }
5780
5781 n->header->flags |= (*m)->header->flags & (BUS_MESSAGE_NO_REPLY_EXPECTED|BUS_MESSAGE_NO_AUTO_START);
5782
5783 r = sd_bus_message_copy(n, *m, true);
5784 if (r < 0)
5785 return r;
5786
5787 timeout = (*m)->timeout;
385b2eb2
YW
5788 if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)) {
5789 r = sd_bus_get_method_call_timeout(bus, &timeout);
5790 if (r < 0)
5791 return r;
5792 }
e1c433c6 5793
75bcbcf2 5794 r = sd_bus_message_seal(n, BUS_MESSAGE_COOKIE(*m), timeout);
e1c433c6
LP
5795 if (r < 0)
5796 return r;
5797
5798 sd_bus_message_unref(*m);
1cc6c93a 5799 *m = TAKE_PTR(n);
e1c433c6
LP
5800
5801 return 0;
5802}
a7639e37
LP
5803
5804int bus_message_append_sender(sd_bus_message *m, const char *sender) {
5805 assert(m);
5806 assert(sender);
5807
5808 assert_return(!m->sealed, -EPERM);
5809 assert_return(!m->sender, -EPERM);
5810
5811 return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
5812}
ca7b42c8
LP
5813
5814_public_ int sd_bus_message_get_priority(sd_bus_message *m, int64_t *priority) {
5815 assert_return(m, -EINVAL);
5816 assert_return(priority, -EINVAL);
5817
5818 *priority = m->priority;
5819 return 0;
5820}
5821
5822_public_ int sd_bus_message_set_priority(sd_bus_message *m, int64_t priority) {
5823 assert_return(m, -EINVAL);
5824 assert_return(!m->sealed, -EPERM);
5825
5826 m->priority = priority;
5827 return 0;
5828}