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