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