]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-message.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-message.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
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
a9c9f79e 454 if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
80a46c73
LP
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);
a9c9f79e
ZJS
592 /* Creation of messages with _SD_BUS_MESSAGE_TYPE_INVALID is allowed. */
593 assert_return(type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
de1c301e 594
f41df695 595 sd_bus_message *t = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
75bcbcf2
SA
596 if (!t)
597 return -ENOMEM;
598
599 t->n_ref = 1;
e593b6a8 600 t->bus = sd_bus_ref(bus);
75bcbcf2
SA
601 t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message)));
602 t->header->endian = BUS_NATIVE_ENDIAN;
603 t->header->type = type;
604 t->header->version = bus->message_version;
605 t->allow_fds = bus->can_fds || !IN_SET(bus->state, BUS_HELLO, BUS_RUNNING);
606 t->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(t);
9b05bc48 607
c0765ddb 608 if (bus->allow_interactive_authorization)
75bcbcf2 609 t->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
c0765ddb 610
75bcbcf2
SA
611 *m = t;
612 return 0;
de1c301e
LP
613}
614
d9f644e2 615_public_ int sd_bus_message_new_signal(
de1c301e 616 sd_bus *bus,
151b9b96 617 sd_bus_message **m,
de1c301e
LP
618 const char *path,
619 const char *interface,
151b9b96 620 const char *member) {
de1c301e 621
2ab3a635 622 _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
de1c301e
LP
623 int r;
624
2a0958d2 625 assert_return(bus, -ENOTCONN);
501ecd67 626 assert_return(bus = bus_resolve(bus), -ENOPKG);
2a0958d2 627 assert_return(bus->state != BUS_UNSET, -ENOTCONN);
9d6c7c82
LP
628 assert_return(object_path_is_valid(path), -EINVAL);
629 assert_return(interface_name_is_valid(interface), -EINVAL);
630 assert_return(member_name_is_valid(member), -EINVAL);
631 assert_return(m, -EINVAL);
de1c301e 632
75bcbcf2
SA
633 r = sd_bus_message_new(bus, &t, SD_BUS_MESSAGE_SIGNAL);
634 if (r < 0)
de1c301e
LP
635 return -ENOMEM;
636
75bcbcf2
SA
637 assert(t);
638
0461f8cd 639 t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
89ffcd2a 640
0461f8cd 641 r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
de1c301e 642 if (r < 0)
2ab3a635 643 return r;
0461f8cd 644 r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
de1c301e 645 if (r < 0)
2ab3a635 646 return r;
0461f8cd 647 r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
de1c301e 648 if (r < 0)
2ab3a635 649 return r;
de1c301e 650
2ab3a635 651 *m = TAKE_PTR(t);
de1c301e 652 return 0;
de1c301e
LP
653}
654
d9f644e2 655_public_ int sd_bus_message_new_method_call(
de1c301e 656 sd_bus *bus,
151b9b96 657 sd_bus_message **m,
de1c301e
LP
658 const char *destination,
659 const char *path,
660 const char *interface,
151b9b96 661 const char *member) {
de1c301e 662
b41812d1 663 _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
de1c301e
LP
664 int r;
665
2a0958d2 666 assert_return(bus, -ENOTCONN);
501ecd67 667 assert_return(bus = bus_resolve(bus), -ENOPKG);
2a0958d2 668 assert_return(bus->state != BUS_UNSET, -ENOTCONN);
9d6c7c82
LP
669 assert_return(!destination || service_name_is_valid(destination), -EINVAL);
670 assert_return(object_path_is_valid(path), -EINVAL);
671 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
672 assert_return(member_name_is_valid(member), -EINVAL);
673 assert_return(m, -EINVAL);
de1c301e 674
75bcbcf2
SA
675 r = sd_bus_message_new(bus, &t, SD_BUS_MESSAGE_METHOD_CALL);
676 if (r < 0)
de1c301e
LP
677 return -ENOMEM;
678
75bcbcf2
SA
679 assert(t);
680
0461f8cd 681 r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
de1c301e 682 if (r < 0)
2ab3a635 683 return r;
0461f8cd 684 r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
de1c301e 685 if (r < 0)
2ab3a635 686 return r;
de1c301e
LP
687
688 if (interface) {
0461f8cd 689 r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
de1c301e 690 if (r < 0)
2ab3a635 691 return r;
de1c301e
LP
692 }
693
694 if (destination) {
0461f8cd 695 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination);
de1c301e 696 if (r < 0)
2ab3a635 697 return r;
de1c301e
LP
698 }
699
2ab3a635 700 *m = TAKE_PTR(t);
de1c301e 701 return 0;
de1c301e
LP
702}
703
5407f2de 704static int message_new_reply(
de1c301e 705 sd_bus_message *call,
5407f2de 706 uint8_t type,
de1c301e
LP
707 sd_bus_message **m) {
708
b41812d1 709 _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
f581267a 710 uint64_t cookie;
de1c301e
LP
711 int r;
712
9d6c7c82
LP
713 assert_return(call, -EINVAL);
714 assert_return(call->sealed, -EPERM);
715 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
2a0958d2 716 assert_return(call->bus->state != BUS_UNSET, -ENOTCONN);
9d6c7c82 717 assert_return(m, -EINVAL);
de1c301e 718
f581267a
CW
719 cookie = BUS_MESSAGE_COOKIE(call);
720 if (cookie == 0)
721 return -EOPNOTSUPP;
722
75bcbcf2
SA
723 r = sd_bus_message_new(call->bus, &t, type);
724 if (r < 0)
de1c301e
LP
725 return -ENOMEM;
726
75bcbcf2
SA
727 assert(t);
728
0461f8cd 729 t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
f581267a 730 t->reply_cookie = cookie;
b267a6d2 731 r = message_append_reply_cookie(t, t->reply_cookie);
de1c301e 732 if (r < 0)
2ab3a635 733 return r;
de1c301e
LP
734
735 if (call->sender) {
0461f8cd 736 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination);
de1c301e 737 if (r < 0)
2ab3a635 738 return r;
de1c301e
LP
739 }
740
0461f8cd 741 t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
6717d473 742 t->enforced_reply_signature = call->enforced_reply_signature;
5407f2de 743
7a77d2a4
LP
744 /* let's copy the sensitive flag over. Let's do that as a safety precaution to keep a transaction
745 * wholly sensitive if already the incoming message was sensitive. This is particularly useful when a
746 * vtable record sets the SD_BUS_VTABLE_SENSITIVE flag on a method call, since this means it applies
747 * to both the message call and the reply. */
748 t->sensitive = call->sensitive;
749
2ab3a635 750 *m = TAKE_PTR(t);
89ffcd2a 751 return 0;
de1c301e
LP
752}
753
d9f644e2 754_public_ int sd_bus_message_new_method_return(
5407f2de
LP
755 sd_bus_message *call,
756 sd_bus_message **m) {
757
df2d202e 758 return message_new_reply(call, SD_BUS_MESSAGE_METHOD_RETURN, m);
5407f2de
LP
759}
760
d9f644e2 761_public_ int sd_bus_message_new_method_error(
de1c301e 762 sd_bus_message *call,
151b9b96
LP
763 sd_bus_message **m,
764 const sd_bus_error *e) {
de1c301e 765
b41812d1 766 _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
de1c301e
LP
767 int r;
768
9d6c7c82
LP
769 assert_return(sd_bus_error_is_set(e), -EINVAL);
770 assert_return(m, -EINVAL);
de1c301e 771
df2d202e 772 r = message_new_reply(call, SD_BUS_MESSAGE_METHOD_ERROR, &t);
de1c301e 773 if (r < 0)
5407f2de 774 return r;
de1c301e 775
0461f8cd 776 r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
de1c301e 777 if (r < 0)
2ab3a635 778 return r;
de1c301e
LP
779
780 if (e->message) {
781 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
782 if (r < 0)
2ab3a635 783 return r;
de1c301e
LP
784 }
785
79f8d3d2
LP
786 t->error._need_free = -1;
787
2ab3a635 788 *m = TAKE_PTR(t);
de1c301e 789 return 0;
de1c301e
LP
790}
791
d9f644e2 792_public_ int sd_bus_message_new_method_errorf(
29ddb38f
LP
793 sd_bus_message *call,
794 sd_bus_message **m,
795 const char *name,
796 const char *format,
797 ...) {
798
4afd3348 799 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
29ddb38f 800 va_list ap;
29ddb38f 801
40ca29a1
LP
802 assert_return(name, -EINVAL);
803 assert_return(m, -EINVAL);
804
805 va_start(ap, format);
780896a4 806 bus_error_setfv(&error, name, format, ap);
40ca29a1 807 va_end(ap);
29ddb38f 808
151b9b96 809 return sd_bus_message_new_method_error(call, m, &error);
40ca29a1 810}
29ddb38f 811
d9f644e2 812_public_ int sd_bus_message_new_method_errno(
40ca29a1 813 sd_bus_message *call,
151b9b96 814 sd_bus_message **m,
40ca29a1 815 int error,
151b9b96 816 const sd_bus_error *p) {
29ddb38f 817
4afd3348 818 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
29ddb38f 819
40ca29a1 820 if (sd_bus_error_is_set(p))
151b9b96 821 return sd_bus_message_new_method_error(call, m, p);
29ddb38f 822
40ca29a1 823 sd_bus_error_set_errno(&berror, error);
29ddb38f 824
151b9b96 825 return sd_bus_message_new_method_error(call, m, &berror);
40ca29a1 826}
29ddb38f 827
d9f644e2 828_public_ int sd_bus_message_new_method_errnof(
40ca29a1
LP
829 sd_bus_message *call,
830 sd_bus_message **m,
831 int error,
832 const char *format,
833 ...) {
834
4afd3348 835 _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
40ca29a1 836 va_list ap;
40ca29a1
LP
837
838 va_start(ap, format);
07a0d22f 839 sd_bus_error_set_errnofv(&berror, error, format, ap);
40ca29a1
LP
840 va_end(ap);
841
151b9b96 842 return sd_bus_message_new_method_error(call, m, &berror);
29ddb38f
LP
843}
844
d29ae291
LP
845void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m) {
846 assert(bus);
847 assert(m);
848
849 m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus.Local";
850 m->creds.well_known_names_local = true;
851 m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
852}
853
854void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m) {
855 assert(bus);
856 assert(m);
857
858 m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
859 m->creds.well_known_names_driver = true;
860 m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
861}
862
eb01ba5d
LP
863int bus_message_new_synthetic_error(
864 sd_bus *bus,
693eb9a2 865 uint64_t cookie,
eb01ba5d
LP
866 const sd_bus_error *e,
867 sd_bus_message **m) {
868
b41812d1 869 _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
eb01ba5d
LP
870 int r;
871
2a0958d2 872 assert(bus);
eb01ba5d
LP
873 assert(sd_bus_error_is_set(e));
874 assert(m);
875
75bcbcf2
SA
876 r = sd_bus_message_new(bus, &t, SD_BUS_MESSAGE_METHOD_ERROR);
877 if (r < 0)
eb01ba5d
LP
878 return -ENOMEM;
879
75bcbcf2
SA
880 assert(t);
881
0461f8cd 882 t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
693eb9a2 883 t->reply_cookie = cookie;
eb01ba5d 884
b267a6d2 885 r = message_append_reply_cookie(t, t->reply_cookie);
eb01ba5d 886 if (r < 0)
2ab3a635 887 return r;
eb01ba5d
LP
888
889 if (bus && bus->unique_name) {
0461f8cd 890 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination);
eb01ba5d 891 if (r < 0)
2ab3a635 892 return r;
eb01ba5d
LP
893 }
894
0461f8cd 895 r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
3a7d4f1b 896 if (r < 0)
2ab3a635 897 return r;
3a7d4f1b
LP
898
899 if (e->message) {
900 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
901 if (r < 0)
2ab3a635 902 return r;
3a7d4f1b
LP
903 }
904
79f8d3d2
LP
905 t->error._need_free = -1;
906
d29ae291
LP
907 bus_message_set_sender_driver(bus, t);
908
2ab3a635 909 *m = TAKE_PTR(t);
eb01ba5d 910 return 0;
eb01ba5d
LP
911}
912
1b3f9dd7
LP
913_public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
914 if (!m)
915 return NULL;
916
917 /* We are fine if this message so far was either explicitly reffed or not reffed but queued into at
918 * least one bus connection object. */
919 assert(m->n_ref > 0 || m->n_queued > 0);
920
921 m->n_ref++;
922
923 /* Each user reference to a bus message shall also be considered a ref on the bus */
924 sd_bus_ref(m->bus);
925 return m;
926}
927
928_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
929 if (!m)
930 return NULL;
931
932 assert(m->n_ref > 0);
933
934 sd_bus_unref(m->bus); /* Each regular ref is also a ref on the bus connection. Let's hence drop it
935 * here. Note we have to do this before decrementing our own n_ref here, since
936 * otherwise, if this message is currently queued sd_bus_unref() might call
937 * bus_message_unref_queued() for this which might then destroy the message
938 * while we are still processing it. */
939 m->n_ref--;
940
941 if (m->n_ref > 0 || m->n_queued > 0)
942 return NULL;
943
944 /* Unset the bus field if neither the user has a reference nor this message is queued. We are careful
945 * to reset the field only after the last reference to the bus is dropped, after all we might keep
5238e957 946 * multiple references to the bus, once for each reference kept on ourselves. */
1b3f9dd7
LP
947 m->bus = NULL;
948
949 return message_free(m);
950}
951
952sd_bus_message* bus_message_ref_queued(sd_bus_message *m, sd_bus *bus) {
953 if (!m)
954 return NULL;
955
956 /* If this is a different bus than the message is associated with, then implicitly turn this into a
957 * regular reference. This means that you can create a memory leak by enqueuing a message generated
958 * on one bus onto another at the same time as enqueueing a message from the second one on the first,
959 * as we'll not detect the cyclic references there. */
960 if (bus != m->bus)
961 return sd_bus_message_ref(m);
962
963 assert(m->n_ref > 0 || m->n_queued > 0);
964 m->n_queued++;
965
966 return m;
967}
968
969sd_bus_message* bus_message_unref_queued(sd_bus_message *m, sd_bus *bus) {
970 if (!m)
971 return NULL;
972
973 if (bus != m->bus)
974 return sd_bus_message_unref(m);
975
976 assert(m->n_queued > 0);
977 m->n_queued--;
978
979 if (m->n_ref > 0 || m->n_queued > 0)
980 return NULL;
981
982 m->bus = NULL;
983
984 return message_free(m);
985}
de1c301e 986
d9f644e2 987_public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
9d6c7c82
LP
988 assert_return(m, -EINVAL);
989 assert_return(type, -EINVAL);
de1c301e
LP
990
991 *type = m->header->type;
992 return 0;
993}
994
693eb9a2 995_public_ int sd_bus_message_get_cookie(sd_bus_message *m, uint64_t *cookie) {
2ac7c17f
LP
996 uint64_t c;
997
9d6c7c82 998 assert_return(m, -EINVAL);
693eb9a2 999 assert_return(cookie, -EINVAL);
2ac7c17f
LP
1000
1001 c = BUS_MESSAGE_COOKIE(m);
1002 if (c == 0)
1003 return -ENODATA;
de1c301e 1004
693eb9a2 1005 *cookie = BUS_MESSAGE_COOKIE(m);
de1c301e
LP
1006 return 0;
1007}
1008
693eb9a2 1009_public_ int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie) {
9d6c7c82 1010 assert_return(m, -EINVAL);
693eb9a2 1011 assert_return(cookie, -EINVAL);
2ac7c17f
LP
1012
1013 if (m->reply_cookie == 0)
1014 return -ENODATA;
de1c301e 1015
693eb9a2 1016 *cookie = m->reply_cookie;
de1c301e
LP
1017 return 0;
1018}
1019
eee9ec0e 1020_public_ int sd_bus_message_get_expect_reply(sd_bus_message *m) {
9d6c7c82 1021 assert_return(m, -EINVAL);
de1c301e 1022
eee9ec0e
LP
1023 return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
1024 !(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
de1c301e
LP
1025}
1026
eee9ec0e 1027_public_ int sd_bus_message_get_auto_start(sd_bus_message *m) {
1fee9de5
LP
1028 assert_return(m, -EINVAL);
1029
eee9ec0e 1030 return !(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
1fee9de5
LP
1031}
1032
53a83f4b
LP
1033_public_ int sd_bus_message_get_allow_interactive_authorization(sd_bus_message *m) {
1034 assert_return(m, -EINVAL);
1035
1036 return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
1037 (m->header->flags & BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION);
1038}
1039
d9f644e2 1040_public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
9d6c7c82 1041 assert_return(m, NULL);
de1c301e
LP
1042
1043 return m->path;
1044}
1045
d9f644e2 1046_public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
9d6c7c82 1047 assert_return(m, NULL);
de1c301e
LP
1048
1049 return m->interface;
1050}
1051
d9f644e2 1052_public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
9d6c7c82 1053 assert_return(m, NULL);
de1c301e
LP
1054
1055 return m->member;
1056}
d9f644e2
ZJS
1057
1058_public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
9d6c7c82 1059 assert_return(m, NULL);
de1c301e
LP
1060
1061 return m->destination;
1062}
1063
d9f644e2 1064_public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
9d6c7c82 1065 assert_return(m, NULL);
de1c301e
LP
1066
1067 return m->sender;
1068}
1069
d9f644e2 1070_public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
9d6c7c82 1071 assert_return(m, NULL);
f02b9615
LP
1072
1073 if (!sd_bus_error_is_set(&m->error))
1074 return NULL;
de1c301e
LP
1075
1076 return &m->error;
1077}
1078
1fedcf59 1079_public_ int sd_bus_message_get_monotonic_usec(sd_bus_message *m, uint64_t *usec) {
9d6c7c82
LP
1080 assert_return(m, -EINVAL);
1081 assert_return(usec, -EINVAL);
1fedcf59
LP
1082
1083 if (m->monotonic <= 0)
1084 return -ENODATA;
acb5a3cb 1085
69aec65c 1086 *usec = m->monotonic;
acb5a3cb
LP
1087 return 0;
1088}
1089
1fedcf59 1090_public_ int sd_bus_message_get_realtime_usec(sd_bus_message *m, uint64_t *usec) {
9d6c7c82
LP
1091 assert_return(m, -EINVAL);
1092 assert_return(usec, -EINVAL);
1fedcf59
LP
1093
1094 if (m->realtime <= 0)
1095 return -ENODATA;
69aec65c
LP
1096
1097 *usec = m->realtime;
1098 return 0;
1099}
1100
6a0e376c
LP
1101_public_ int sd_bus_message_get_seqnum(sd_bus_message *m, uint64_t *seqnum) {
1102 assert_return(m, -EINVAL);
1103 assert_return(seqnum, -EINVAL);
1fedcf59
LP
1104
1105 if (m->seqnum <= 0)
1106 return -ENODATA;
6a0e376c
LP
1107
1108 *seqnum = m->seqnum;
1109 return 0;
1110}
1111
5b12334d
LP
1112_public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) {
1113 assert_return(m, NULL);
102ea8e4 1114
5b12334d
LP
1115 if (m->creds.mask == 0)
1116 return NULL;
102ea8e4 1117
5b12334d 1118 return &m->creds;
102ea8e4
LP
1119}
1120
2ac7c17f
LP
1121_public_ int sd_bus_message_is_signal(
1122 sd_bus_message *m,
1123 const char *interface,
1124 const char *member) {
1125
9d6c7c82 1126 assert_return(m, -EINVAL);
de1c301e 1127
40ca29a1 1128 if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
de1c301e
LP
1129 return 0;
1130
162c8755 1131 if (interface && !streq_ptr(m->interface, interface))
de1c301e
LP
1132 return 0;
1133
162c8755 1134 if (member && !streq_ptr(m->member, member))
de1c301e
LP
1135 return 0;
1136
1137 return 1;
1138}
1139
2ac7c17f
LP
1140_public_ int sd_bus_message_is_method_call(
1141 sd_bus_message *m,
1142 const char *interface,
1143 const char *member) {
1144
9d6c7c82 1145 assert_return(m, -EINVAL);
de1c301e 1146
40ca29a1 1147 if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
de1c301e
LP
1148 return 0;
1149
162c8755 1150 if (interface && !streq_ptr(m->interface, interface))
de1c301e
LP
1151 return 0;
1152
162c8755 1153 if (member && !streq_ptr(m->member, member))
de1c301e
LP
1154 return 0;
1155
1156 return 1;
1157}
1158
d9f644e2 1159_public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
9d6c7c82 1160 assert_return(m, -EINVAL);
de1c301e 1161
40ca29a1 1162 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
de1c301e
LP
1163 return 0;
1164
162c8755 1165 if (name && !streq_ptr(m->error.name, name))
de1c301e
LP
1166 return 0;
1167
1168 return 1;
1169}
1170
eee9ec0e 1171_public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) {
9d6c7c82
LP
1172 assert_return(m, -EINVAL);
1173 assert_return(!m->sealed, -EPERM);
1174 assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
de1c301e 1175
5883ff60 1176 SET_FLAG(m->header->flags, BUS_MESSAGE_NO_REPLY_EXPECTED, !b);
de1c301e
LP
1177
1178 return 0;
1179}
1180
eee9ec0e 1181_public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) {
1fee9de5
LP
1182 assert_return(m, -EINVAL);
1183 assert_return(!m->sealed, -EPERM);
1184
5883ff60 1185 SET_FLAG(m->header->flags, BUS_MESSAGE_NO_AUTO_START, !b);
1fee9de5
LP
1186
1187 return 0;
1188}
1189
53a83f4b
LP
1190_public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message *m, int b) {
1191 assert_return(m, -EINVAL);
1192 assert_return(!m->sealed, -EPERM);
1193
5883ff60 1194 SET_FLAG(m->header->flags, BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION, b);
53a83f4b
LP
1195
1196 return 0;
1197}
1198
bc7fd8cd
LP
1199struct bus_body_part *message_append_part(sd_bus_message *m) {
1200 struct bus_body_part *part;
1201
1202 assert(m);
35460afc
LP
1203
1204 if (m->poisoned)
1205 return NULL;
bc7fd8cd
LP
1206
1207 if (m->n_body_parts <= 0) {
1208 part = &m->body;
1209 zero(*part);
1210 } else {
1211 assert(m->body_end);
1212
1213 part = new0(struct bus_body_part, 1);
1214 if (!part) {
1215 m->poisoned = true;
1216 return NULL;
1217 }
1218
1219 m->body_end->next = part;
1220 }
1221
1222 part->memfd = -1;
1223 m->body_end = part;
313cefa1 1224 m->n_body_parts++;
bc7fd8cd
LP
1225
1226 return part;
1227}
1228
1229static void part_zero(struct bus_body_part *part, size_t sz) {
1230 assert(part);
1231 assert(sz > 0);
1232 assert(sz < 8);
1233
453a0c29
LP
1234 /* All other fields can be left in their defaults */
1235 assert(!part->data);
1236 assert(part->memfd < 0);
1237
bc7fd8cd 1238 part->size = sz;
453a0c29
LP
1239 part->is_zero = true;
1240 part->sealed = true;
bc7fd8cd
LP
1241}
1242
1243static int part_make_space(
1244 struct sd_bus_message *m,
1245 struct bus_body_part *part,
1246 size_t sz,
1247 void **q) {
1248
1249 void *n;
bc7fd8cd
LP
1250
1251 assert(m);
1252 assert(part);
1253 assert(!part->sealed);
1254
1255 if (m->poisoned)
1256 return -ENOMEM;
1257
a132bef0
ZJS
1258 if (part->allocated == 0 || sz > part->allocated) {
1259 size_t new_allocated;
bc7fd8cd 1260
a132bef0
ZJS
1261 new_allocated = sz > 0 ? 2 * sz : 64;
1262 n = realloc(part->data, new_allocated);
1263 if (!n) {
1264 m->poisoned = true;
1265 return -ENOMEM;
bc7fd8cd 1266 }
bf30e48f 1267
a132bef0
ZJS
1268 part->data = n;
1269 part->allocated = new_allocated;
1270 part->free_this = true;
bc7fd8cd
LP
1271 }
1272
1273 if (q)
1274 *q = part->data ? (uint8_t*) part->data + part->size : NULL;
1275
1276 part->size = sz;
1277 return 0;
1278}
1279
c1b9d935
LP
1280static int message_add_offset(sd_bus_message *m, size_t offset) {
1281 struct bus_container *c;
1282
1283 assert(m);
6647dc66 1284 assert(BUS_MESSAGE_IS_GVARIANT(m));
c1b9d935
LP
1285
1286 /* Add offset to current container, unless this is the first
1287 * item in it, which will have the 0 offset, which we can
1288 * ignore. */
9c65778d 1289 c = message_get_last_container(m);
c1b9d935
LP
1290
1291 if (!c->need_offsets)
1292 return 0;
1293
306f07be 1294 if (!GREEDY_REALLOC(c->offsets, c->offsets_allocated, c->n_offsets + 1))
c1b9d935
LP
1295 return -ENOMEM;
1296
1297 c->offsets[c->n_offsets++] = offset;
1298 return 0;
1299}
1300
453a0c29 1301static void message_extend_containers(sd_bus_message *m, size_t expand) {
453a0c29
LP
1302 assert(m);
1303
1304 if (expand <= 0)
1305 return;
1306
0cd41757
LP
1307 if (m->n_containers <= 0)
1308 return;
c1b9d935 1309
0cd41757
LP
1310 /* Update counters */
1311 for (struct bus_container *c = m->containers; c < m->containers + m->n_containers; c++)
453a0c29
LP
1312 if (c->array_size)
1313 *c->array_size += expand;
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 {
f3097697
LP
1376 void *op;
1377 size_t os, start_part, end_part;
bc7fd8cd 1378
f3097697
LP
1379 part = m->body_end;
1380 op = part->data;
1381 os = part->size;
bc7fd8cd 1382
f3097697
LP
1383 start_part = ALIGN_TO(part->size, align);
1384 end_part = start_part + sz;
bc7fd8cd 1385
f3097697
LP
1386 r = part_make_space(m, part, end_part, &p);
1387 if (r < 0)
1388 return NULL;
bc7fd8cd 1389
f3097697 1390 if (padding > 0) {
29804cc1 1391 memzero(p, padding);
f3097697
LP
1392 p = (uint8_t*) p + padding;
1393 }
bc7fd8cd 1394
f3097697 1395 /* Readjust pointers */
0cd41757
LP
1396 if (m->n_containers > 0)
1397 for (struct bus_container *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
b98f393d 3025 shift = PAGE_OFFSET(part->memfd_offset);
7dcd79c2 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)
b17af3e5
ZJS
3162 *p = part->data ? (uint8_t*) part->data + index - begin
3163 : NULL; /* Avoid dereferencing a NULL pointer. */
bc7fd8cd
LP
3164
3165 m->cached_rindex_part = part;
3166 m->cached_rindex_part_begin = begin;
3167
3168 return part;
3169 }
3170
453a0c29 3171 begin += part->size;
bc7fd8cd
LP
3172 part = part->next;
3173 }
3174
3175 return NULL;
3176}
3177
6647dc66
LP
3178static int container_next_item(sd_bus_message *m, struct bus_container *c, size_t *rindex) {
3179 int r;
3180
3181 assert(m);
3182 assert(c);
3183 assert(rindex);
3184
3185 if (!BUS_MESSAGE_IS_GVARIANT(m))
3186 return 0;
3187
3188 if (c->enclosing == SD_BUS_TYPE_ARRAY) {
3189 int sz;
3190
3191 sz = bus_gvariant_get_size(c->signature);
3192 if (sz < 0) {
3193 int alignment;
3194
3195 if (c->offset_index+1 >= c->n_offsets)
3196 goto end;
3197
3198 /* Variable-size array */
3199
3200 alignment = bus_gvariant_get_alignment(c->signature);
3201 assert(alignment > 0);
3202
3203 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
12603b84 3204 assert(c->offsets[c->offset_index+1] >= *rindex);
6647dc66
LP
3205 c->item_size = c->offsets[c->offset_index+1] - *rindex;
3206 } else {
0039a203
LP
3207
3208 if (c->offset_index+1 >= (c->end-c->begin)/sz)
3209 goto end;
3210
6647dc66 3211 /* Fixed-size array */
0039a203 3212 *rindex = c->begin + (c->offset_index+1) * sz;
6647dc66
LP
3213 c->item_size = sz;
3214 }
3215
3216 c->offset_index++;
3217
945c2931 3218 } else if (IN_SET(c->enclosing, 0, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) {
6647dc66
LP
3219
3220 int alignment;
3221 size_t n, j;
3222
3223 if (c->offset_index+1 >= c->n_offsets)
3224 goto end;
3225
3226 r = signature_element_length(c->signature + c->index, &n);
3227 if (r < 0)
3228 return r;
3229
3230 r = signature_element_length(c->signature + c->index + n, &j);
3231 if (r < 0)
3232 return r;
3233 else {
3234 char t[j+1];
3235 memcpy(t, c->signature + c->index + n, j);
3236 t[j] = 0;
3237
3238 alignment = bus_gvariant_get_alignment(t);
3239 }
3240
3241 assert(alignment > 0);
3242
3243 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
12603b84 3244 assert(c->offsets[c->offset_index+1] >= *rindex);
6647dc66
LP
3245 c->item_size = c->offsets[c->offset_index+1] - *rindex;
3246
3247 c->offset_index++;
3248
3249 } else if (c->enclosing == SD_BUS_TYPE_VARIANT)
3250 goto end;
3251 else
3252 assert_not_reached("Unknown container type");
3253
3254 return 0;
3255
3256end:
3257 /* Reached the end */
3258 *rindex = c->end;
3259 c->item_size = 0;
3260 return 0;
3261}
3262
bc7fd8cd
LP
3263static int message_peek_body(
3264 sd_bus_message *m,
3265 size_t *rindex,
3266 size_t align,
3267 size_t nbytes,
3268 void **ret) {
3269
3270 size_t k, start, end, padding;
3271 struct bus_body_part *part;
3272 uint8_t *q;
3273
de1c301e 3274 assert(m);
9a17484d
LP
3275 assert(rindex);
3276 assert(align > 0);
de1c301e 3277
bc7fd8cd
LP
3278 start = ALIGN_TO((size_t) *rindex, align);
3279 padding = start - *rindex;
3280 end = start + nbytes;
3281
2ac7c17f 3282 if (end > m->user_body_size)
bc7fd8cd
LP
3283 return -EBADMSG;
3284
3285 part = find_part(m, *rindex, padding, (void**) &q);
3286 if (!part)
3287 return -EBADMSG;
3288
3289 if (q) {
3290 /* Verify padding */
3291 for (k = 0; k < padding; k++)
3292 if (q[k] != 0)
3293 return -EBADMSG;
3294 }
3295
3296 part = find_part(m, start, nbytes, (void**) &q);
5f7e8903 3297 if (!part || (nbytes > 0 && !q))
bc7fd8cd
LP
3298 return -EBADMSG;
3299
3300 *rindex = end;
3301
3302 if (ret)
3303 *ret = q;
3304
18f5b48f 3305 return 0;
9a17484d 3306}
de1c301e 3307
ac89bf1d 3308static bool validate_nul(const char *s, size_t l) {
de1c301e 3309
9a17484d
LP
3310 /* Check for NUL chars in the string */
3311 if (memchr(s, 0, l))
3312 return false;
de1c301e 3313
9a17484d
LP
3314 /* Check for NUL termination */
3315 if (s[l] != 0)
3316 return false;
de1c301e 3317
ac89bf1d
LP
3318 return true;
3319}
3320
3321static bool validate_string(const char *s, size_t l) {
3322
3323 if (!validate_nul(s, l))
3324 return false;
3325
9a17484d
LP
3326 /* Check if valid UTF8 */
3327 if (!utf8_is_valid(s))
3328 return false;
3329
3330 return true;
de1c301e
LP
3331}
3332
9a17484d 3333static bool validate_signature(const char *s, size_t l) {
de1c301e 3334
ac89bf1d 3335 if (!validate_nul(s, l))
9a17484d 3336 return false;
de1c301e 3337
9a17484d
LP
3338 /* Check if valid signature */
3339 if (!signature_is_valid(s, true))
3340 return false;
3341
3342 return true;
3343}
3344
ac89bf1d
LP
3345static bool validate_object_path(const char *s, size_t l) {
3346
3347 if (!validate_nul(s, l))
3348 return false;
3349
3350 if (!object_path_is_valid(s))
3351 return false;
3352
3353 return true;
3354}
3355
d9f644e2 3356_public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
9a17484d 3357 struct bus_container *c;
6647dc66 3358 size_t rindex;
9a17484d 3359 void *q;
0dcd14b9 3360 int r;
9a17484d 3361
9d6c7c82
LP
3362 assert_return(m, -EINVAL);
3363 assert_return(m->sealed, -EPERM);
3364 assert_return(bus_type_is_basic(type), -EINVAL);
de1c301e 3365
7b058942 3366 if (message_end_of_signature(m))
430fb8fa 3367 return -ENXIO;
9a17484d 3368
1daf8121
LP
3369 if (message_end_of_array(m, m->rindex))
3370 return 0;
3371
9c65778d 3372 c = message_get_last_container(m);
9a17484d
LP
3373 if (c->signature[c->index] != type)
3374 return -ENXIO;
3375
6647dc66 3376 rindex = m->rindex;
9a17484d 3377
6647dc66 3378 if (BUS_MESSAGE_IS_GVARIANT(m)) {
9a17484d 3379
6647dc66
LP
3380 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
3381 bool ok;
9a17484d 3382
81b6e630
ZJS
3383 /* D-Bus spec: The marshalling formats for the string-like types all end
3384 * with a single zero (NUL) byte, but that byte is not considered to be part
3385 * of the text. */
3386 if (c->item_size == 0)
3387 return -EBADMSG;
3388
6647dc66 3389 r = message_peek_body(m, &rindex, 1, c->item_size, &q);
18f5b48f 3390 if (r < 0)
6647dc66
LP
3391 return r;
3392
3393 if (type == SD_BUS_TYPE_STRING)
3394 ok = validate_string(q, c->item_size-1);
3395 else if (type == SD_BUS_TYPE_OBJECT_PATH)
3396 ok = validate_object_path(q, c->item_size-1);
3397 else
3398 ok = validate_signature(q, c->item_size-1);
9a17484d 3399
6647dc66 3400 if (!ok)
ac89bf1d 3401 return -EBADMSG;
6647dc66
LP
3402
3403 if (p)
3404 *(const char**) p = q;
ac89bf1d 3405 } else {
6647dc66
LP
3406 int sz, align;
3407
3408 sz = bus_gvariant_get_size(CHAR_TO_STR(type));
3409 assert(sz > 0);
3410 if ((size_t) sz != c->item_size)
ac89bf1d 3411 return -EBADMSG;
9a17484d 3412
6647dc66
LP
3413 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
3414 assert(align > 0);
0dcd14b9 3415
6647dc66 3416 r = message_peek_body(m, &rindex, align, c->item_size, &q);
18f5b48f 3417 if (r < 0)
6647dc66 3418 return r;
de1c301e 3419
6647dc66 3420 switch (type) {
9a17484d 3421
6647dc66
LP
3422 case SD_BUS_TYPE_BYTE:
3423 if (p)
3424 *(uint8_t*) p = *(uint8_t*) q;
3425 break;
9a17484d 3426
6647dc66
LP
3427 case SD_BUS_TYPE_BOOLEAN:
3428 if (p)
3429 *(int*) p = !!*(uint8_t*) q;
3430 break;
9a17484d 3431
6647dc66
LP
3432 case SD_BUS_TYPE_INT16:
3433 case SD_BUS_TYPE_UINT16:
3434 if (p)
3435 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3436 break;
3437
3438 case SD_BUS_TYPE_INT32:
3439 case SD_BUS_TYPE_UINT32:
3440 if (p)
3441 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3442 break;
9a17484d 3443
6647dc66
LP
3444 case SD_BUS_TYPE_INT64:
3445 case SD_BUS_TYPE_UINT64:
3446 case SD_BUS_TYPE_DOUBLE:
3447 if (p)
3448 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3449 break;
0dcd14b9 3450
6647dc66
LP
3451 case SD_BUS_TYPE_UNIX_FD: {
3452 uint32_t j;
de1c301e 3453
6647dc66
LP
3454 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3455 if (j >= m->n_fds)
3456 return -EBADMSG;
de1c301e 3457
6647dc66
LP
3458 if (p)
3459 *(int*) p = m->fds[j];
de1c301e 3460
6647dc66
LP
3461 break;
3462 }
3463
3464 default:
3465 assert_not_reached("unexpected type");
3466 }
3467 }
3468
3469 r = container_next_item(m, c, &rindex);
3470 if (r < 0)
9a17484d 3471 return r;
6647dc66 3472 } else {
9a17484d 3473
6647dc66
LP
3474 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
3475 uint32_t l;
3476 bool ok;
9a17484d 3477
6647dc66 3478 r = message_peek_body(m, &rindex, 4, 4, &q);
18f5b48f 3479 if (r < 0)
6647dc66 3480 return r;
9a17484d 3481
6647dc66 3482 l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
902000c1
ZJS
3483 if (l == UINT32_MAX)
3484 /* avoid overflow right below */
3485 return -EBADMSG;
3486
6647dc66
LP
3487 r = message_peek_body(m, &rindex, 1, l+1, &q);
3488 if (r < 0)
3489 return r;
9a17484d 3490
6647dc66
LP
3491 if (type == SD_BUS_TYPE_OBJECT_PATH)
3492 ok = validate_object_path(q, l);
3493 else
3494 ok = validate_string(q, l);
3495 if (!ok)
3496 return -EBADMSG;
9a17484d 3497
0dcd14b9 3498 if (p)
6647dc66 3499 *(const char**) p = q;
9a17484d 3500
6647dc66
LP
3501 } else if (type == SD_BUS_TYPE_SIGNATURE) {
3502 uint8_t l;
3503
3504 r = message_peek_body(m, &rindex, 1, 1, &q);
18f5b48f 3505 if (r < 0)
6647dc66
LP
3506 return r;
3507
3508 l = *(uint8_t*) q;
902000c1
ZJS
3509 if (l == UINT8_MAX)
3510 /* avoid overflow right below */
3511 return -EBADMSG;
3512
6647dc66
LP
3513 r = message_peek_body(m, &rindex, 1, l+1, &q);
3514 if (r < 0)
3515 return r;
2c93b4ef 3516
6647dc66 3517 if (!validate_signature(q, l))
2c93b4ef
LP
3518 return -EBADMSG;
3519
0dcd14b9 3520 if (p)
6647dc66 3521 *(const char**) p = q;
2c93b4ef 3522
6647dc66
LP
3523 } else {
3524 ssize_t sz, align;
9a17484d 3525
6647dc66
LP
3526 align = bus_type_get_alignment(type);
3527 assert(align > 0);
2c93b4ef 3528
6647dc66
LP
3529 sz = bus_type_get_size(type);
3530 assert(sz > 0);
3531
3532 r = message_peek_body(m, &rindex, align, sz, &q);
18f5b48f 3533 if (r < 0)
6647dc66
LP
3534 return r;
3535
3536 switch (type) {
3537
3538 case SD_BUS_TYPE_BYTE:
3539 if (p)
3540 *(uint8_t*) p = *(uint8_t*) q;
3541 break;
3542
3543 case SD_BUS_TYPE_BOOLEAN:
3544 if (p)
3545 *(int*) p = !!*(uint32_t*) q;
3546 break;
3547
3548 case SD_BUS_TYPE_INT16:
3549 case SD_BUS_TYPE_UINT16:
3550 if (p)
3551 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3552 break;
3553
3554 case SD_BUS_TYPE_INT32:
3555 case SD_BUS_TYPE_UINT32:
3556 if (p)
3557 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3558 break;
3559
3560 case SD_BUS_TYPE_INT64:
3561 case SD_BUS_TYPE_UINT64:
3562 case SD_BUS_TYPE_DOUBLE:
3563 if (p)
3564 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3565 break;
3566
3567 case SD_BUS_TYPE_UNIX_FD: {
3568 uint32_t j;
3569
3570 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3571 if (j >= m->n_fds)
3572 return -EBADMSG;
3573
3574 if (p)
3575 *(int*) p = m->fds[j];
3576 break;
3577 }
3578
3579 default:
3580 assert_not_reached("Unknown basic type...");
3581 }
3582 }
9a17484d
LP
3583 }
3584
6647dc66
LP
3585 m->rindex = rindex;
3586
9a17484d
LP
3587 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3588 c->index++;
3589
3590 return 1;
de1c301e
LP
3591}
3592
9a17484d
LP
3593static int bus_message_enter_array(
3594 sd_bus_message *m,
3595 struct bus_container *c,
3596 const char *contents,
6647dc66
LP
3597 uint32_t **array_size,
3598 size_t *item_size,
3599 size_t **offsets,
3600 size_t *n_offsets) {
9a17484d
LP
3601
3602 size_t rindex;
3603 void *q;
f88214cf 3604 int r;
9a17484d
LP
3605
3606 assert(m);
3607 assert(c);
3608 assert(contents);
3609 assert(array_size);
6647dc66
LP
3610 assert(item_size);
3611 assert(offsets);
3612 assert(n_offsets);
9a17484d 3613
29ddb38f 3614 if (!signature_is_single(contents, true))
de1c301e 3615 return -EINVAL;
9a17484d 3616
9a17484d 3617 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3618 return -ENXIO;
9a17484d
LP
3619
3620 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
3621 return -ENXIO;
3622
3623 if (!startswith(c->signature + c->index + 1, contents))
3624 return -ENXIO;
3625
3626 rindex = m->rindex;
9a17484d 3627
6647dc66
LP
3628 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3629 /* dbus1 */
f88214cf 3630 int alignment;
9a17484d 3631
6647dc66 3632 r = message_peek_body(m, &rindex, 4, 4, &q);
18f5b48f 3633 if (r < 0)
6647dc66 3634 return r;
9a17484d 3635
6647dc66
LP
3636 if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE)
3637 return -EBADMSG;
9a17484d 3638
6647dc66
LP
3639 alignment = bus_type_get_alignment(contents[0]);
3640 if (alignment < 0)
3641 return alignment;
3642
3643 r = message_peek_body(m, &rindex, alignment, 0, NULL);
3644 if (r < 0)
3645 return r;
6647dc66
LP
3646
3647 *array_size = (uint32_t*) q;
3648
3649 } else if (c->item_size <= 0) {
3650
3651 /* gvariant: empty array */
3652 *item_size = 0;
3653 *offsets = NULL;
3654 *n_offsets = 0;
3655
3656 } else if (bus_gvariant_is_fixed_size(contents)) {
3657
3658 /* gvariant: fixed length array */
3659 *item_size = bus_gvariant_get_size(contents);
3660 *offsets = NULL;
3661 *n_offsets = 0;
3662
3663 } else {
f88214cf
ZJS
3664 size_t where, previous = 0, framing, sz;
3665 int alignment;
6647dc66
LP
3666 unsigned i;
3667
3668 /* gvariant: variable length array */
2ac7c17f 3669 sz = bus_gvariant_determine_word_size(c->item_size, 0);
6647dc66
LP
3670
3671 where = rindex + c->item_size - sz;
3672 r = message_peek_body(m, &where, 1, sz, &q);
3673 if (r < 0)
3674 return r;
6647dc66 3675
2ac7c17f 3676 framing = bus_gvariant_read_word_le(q, sz);
6647dc66
LP
3677 if (framing > c->item_size - sz)
3678 return -EBADMSG;
3679 if ((c->item_size - framing) % sz != 0)
3680 return -EBADMSG;
3681
3682 *n_offsets = (c->item_size - framing) / sz;
3683
3684 where = rindex + framing;
3685 r = message_peek_body(m, &where, 1, *n_offsets * sz, &q);
3686 if (r < 0)
3687 return r;
6647dc66
LP
3688
3689 *offsets = new(size_t, *n_offsets);
3690 if (!*offsets)
3691 return -ENOMEM;
3692
f88214cf
ZJS
3693 alignment = bus_gvariant_get_alignment(c->signature);
3694 assert(alignment > 0);
3695
6647dc66 3696 for (i = 0; i < *n_offsets; i++) {
f88214cf
ZJS
3697 size_t x, start;
3698
3699 start = ALIGN_TO(previous, alignment);
6647dc66 3700
2ac7c17f 3701 x = bus_gvariant_read_word_le((uint8_t*) q + i * sz, sz);
6647dc66
LP
3702 if (x > c->item_size - sz)
3703 return -EBADMSG;
f88214cf 3704 if (x < start)
6647dc66
LP
3705 return -EBADMSG;
3706
3707 (*offsets)[i] = rindex + x;
f88214cf 3708 previous = x;
6647dc66
LP
3709 }
3710
3711 *item_size = (*offsets)[0] - rindex;
3712 }
3713
3714 m->rindex = rindex;
3715
3716 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3717 c->index += 1 + strlen(contents);
9a17484d
LP
3718
3719 return 1;
3720}
3721
3722static int bus_message_enter_variant(
3723 sd_bus_message *m,
3724 struct bus_container *c,
6647dc66
LP
3725 const char *contents,
3726 size_t *item_size) {
9a17484d
LP
3727
3728 size_t rindex;
3729 uint8_t l;
3730 void *q;
3731 int r;
3732
3733 assert(m);
3734 assert(c);
3735 assert(contents);
6647dc66 3736 assert(item_size);
9a17484d 3737
29ddb38f 3738 if (!signature_is_single(contents, false))
de1c301e 3739 return -EINVAL;
de1c301e 3740
9a17484d
LP
3741 if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
3742 return -EINVAL;
3743
3744 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3745 return -ENXIO;
9a17484d
LP
3746
3747 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
3748 return -ENXIO;
3749
3750 rindex = m->rindex;
9a17484d 3751
6647dc66
LP
3752 if (BUS_MESSAGE_IS_GVARIANT(m)) {
3753 size_t k, where;
3754
3755 k = strlen(contents);
3756 if (1+k > c->item_size)
3757 return -EBADMSG;
3758
3759 where = rindex + c->item_size - (1+k);
3760 r = message_peek_body(m, &where, 1, 1+k, &q);
3761 if (r < 0)
3762 return r;
6647dc66
LP
3763
3764 if (*(char*) q != 0)
3765 return -EBADMSG;
3766
3767 if (memcmp((uint8_t*) q+1, contents, k))
3768 return -ENXIO;
3769
3770 *item_size = c->item_size - (1+k);
3771
3772 } else {
3773 r = message_peek_body(m, &rindex, 1, 1, &q);
3774 if (r < 0)
3775 return r;
6647dc66
LP
3776
3777 l = *(uint8_t*) q;
902000c1
ZJS
3778 if (l == UINT8_MAX)
3779 /* avoid overflow right below */
3780 return -EBADMSG;
3781
6647dc66
LP
3782 r = message_peek_body(m, &rindex, 1, l+1, &q);
3783 if (r < 0)
3784 return r;
6647dc66
LP
3785
3786 if (!validate_signature(q, l))
3787 return -EBADMSG;
3788
3789 if (!streq(q, contents))
3790 return -ENXIO;
3791 }
3792
3793 m->rindex = rindex;
3794
3795 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3796 c->index++;
3797
3798 return 1;
3799}
3800
3801static int build_struct_offsets(
3802 sd_bus_message *m,
3803 const char *signature,
3804 size_t size,
3805 size_t *item_size,
3806 size_t **offsets,
3807 size_t *n_offsets) {
3808
3809 unsigned n_variable = 0, n_total = 0, v;
12603b84 3810 size_t previous, where;
6647dc66
LP
3811 const char *p;
3812 size_t sz;
3813 void *q;
3814 int r;
3815
3816 assert(m);
6647dc66
LP
3817 assert(item_size);
3818 assert(offsets);
3819 assert(n_offsets);
3820
d6385068 3821 if (isempty(signature)) {
e53d21d0
DH
3822 /* Unary type is encoded as *fixed* 1 byte padding */
3823 r = message_peek_body(m, &m->rindex, 1, 1, &q);
3824 if (r < 0)
3825 return r;
3826
3827 if (*(uint8_t *) q != 0)
3828 return -EBADMSG;
3829
d6385068
LP
3830 *item_size = 0;
3831 *offsets = NULL;
3832 *n_offsets = 0;
3833 return 0;
3834 }
3835
2ac7c17f 3836 sz = bus_gvariant_determine_word_size(size, 0);
d6385068
LP
3837 if (sz <= 0)
3838 return -EBADMSG;
6647dc66
LP
3839
3840 /* First, loop over signature and count variable elements and
3841 * elements in general. We use this to know how large the
3842 * offset array is at the end of the structure. Note that
3843 * GVariant only stores offsets for all variable size elements
3844 * that are not the last item. */
3845
3846 p = signature;
3847 while (*p != 0) {
3848 size_t n;
3849
3850 r = signature_element_length(p, &n);
3851 if (r < 0)
3852 return r;
3853 else {
3854 char t[n+1];
3855
3856 memcpy(t, p, n);
3857 t[n] = 0;
3858
3859 r = bus_gvariant_is_fixed_size(t);
3860 }
3861
3862 if (r < 0)
3863 return r;
3864 if (r == 0 && p[n] != 0) /* except the last item */
313cefa1 3865 n_variable++;
6647dc66
LP
3866 n_total++;
3867
3868 p += n;
3869 }
3870
3871 if (size < n_variable * sz)
3872 return -EBADMSG;
3873
3874 where = m->rindex + size - (n_variable * sz);
3875 r = message_peek_body(m, &where, 1, n_variable * sz, &q);
9a17484d
LP
3876 if (r < 0)
3877 return r;
9a17484d 3878
6647dc66 3879 v = n_variable;
9a17484d 3880
6647dc66
LP
3881 *offsets = new(size_t, n_total);
3882 if (!*offsets)
3883 return -ENOMEM;
9a17484d 3884
6647dc66 3885 *n_offsets = 0;
9a17484d 3886
6647dc66
LP
3887 /* Second, loop again and build an offset table */
3888 p = signature;
12603b84 3889 previous = m->rindex;
6647dc66
LP
3890 while (*p != 0) {
3891 size_t n, offset;
3892 int k;
9a17484d 3893
6647dc66
LP
3894 r = signature_element_length(p, &n);
3895 if (r < 0)
3896 return r;
3897 else {
3898 char t[n+1];
3899
3900 memcpy(t, p, n);
3901 t[n] = 0;
3902
12603b84
ZJS
3903 size_t align = bus_gvariant_get_alignment(t);
3904 assert(align > 0);
3905
3906 /* The possible start of this member after including alignment */
3907 size_t start = ALIGN_TO(previous, align);
3908
6647dc66
LP
3909 k = bus_gvariant_get_size(t);
3910 if (k < 0) {
3911 size_t x;
3912
12603b84 3913 /* Variable size */
6647dc66
LP
3914 if (v > 0) {
3915 v--;
3916
2ac7c17f 3917 x = bus_gvariant_read_word_le((uint8_t*) q + v*sz, sz);
6647dc66
LP
3918 if (x >= size)
3919 return -EBADMSG;
6647dc66 3920 } else
12603b84
ZJS
3921 /* The last item's end is determined
3922 * from the start of the offset array */
6647dc66
LP
3923 x = size - (n_variable * sz);
3924
3925 offset = m->rindex + x;
baaa35ad
ZJS
3926 if (offset < start)
3927 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
3928 "For type %s with alignment %zu, message specifies offset %zu which is smaller than previous end %zu + alignment = %zu",
3929 t, align,
3930 offset,
3931 previous,
3932 start);
12603b84
ZJS
3933 } else
3934 /* Fixed size */
3935 offset = start + k;
6647dc66
LP
3936 }
3937
3938 previous = (*offsets)[(*n_offsets)++] = offset;
3939 p += n;
3940 }
3941
3942 assert(v == 0);
3943 assert(*n_offsets == n_total);
3944
3945 *item_size = (*offsets)[0] - m->rindex;
3946 return 0;
3947}
3948
3949static int enter_struct_or_dict_entry(
3950 sd_bus_message *m,
3951 struct bus_container *c,
3952 const char *contents,
3953 size_t *item_size,
3954 size_t **offsets,
3955 size_t *n_offsets) {
3956
3957 int r;
3958
3959 assert(m);
3960 assert(c);
3961 assert(contents);
3962 assert(item_size);
3963 assert(offsets);
3964 assert(n_offsets);
3965
3966 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3967
3968 /* dbus1 */
3969 r = message_peek_body(m, &m->rindex, 8, 0, NULL);
18f5b48f 3970 if (r < 0)
6647dc66
LP
3971 return r;
3972
6647dc66
LP
3973 } else
3974 /* gvariant with contents */
3975 return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets);
3976
3977 return 0;
de1c301e
LP
3978}
3979
9a17484d
LP
3980static int bus_message_enter_struct(
3981 sd_bus_message *m,
3982 struct bus_container *c,
6647dc66
LP
3983 const char *contents,
3984 size_t *item_size,
3985 size_t **offsets,
3986 size_t *n_offsets) {
9a17484d
LP
3987
3988 size_t l;
3989 int r;
3990
3991 assert(m);
3992 assert(c);
3993 assert(contents);
6647dc66
LP
3994 assert(item_size);
3995 assert(offsets);
3996 assert(n_offsets);
9a17484d
LP
3997
3998 if (!signature_is_valid(contents, false))
3999 return -EINVAL;
4000
4001 if (!c->signature || c->signature[c->index] == 0)
6647dc66 4002 return -ENXIO;
9a17484d
LP
4003
4004 l = strlen(contents);
4005
4006 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
4007 !startswith(c->signature + c->index + 1, contents) ||
4008 c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
4009 return -ENXIO;
4010
6647dc66
LP
4011 r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
4012 if (r < 0)
9a17484d
LP
4013 return r;
4014
4015 if (c->enclosing != SD_BUS_TYPE_ARRAY)
4016 c->index += 1 + l + 1;
4017
4018 return 1;
4019}
4020
4021static int bus_message_enter_dict_entry(
4022 sd_bus_message *m,
4023 struct bus_container *c,
6647dc66
LP
4024 const char *contents,
4025 size_t *item_size,
4026 size_t **offsets,
4027 size_t *n_offsets) {
9a17484d
LP
4028
4029 size_t l;
4030 int r;
4031
4032 assert(m);
4033 assert(c);
4034 assert(contents);
4035
4036 if (!signature_is_pair(contents))
4037 return -EINVAL;
4038
4039 if (c->enclosing != SD_BUS_TYPE_ARRAY)
4040 return -ENXIO;
4041
4042 if (!c->signature || c->signature[c->index] == 0)
4043 return 0;
4044
4045 l = strlen(contents);
4046
4047 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
4048 !startswith(c->signature + c->index + 1, contents) ||
4049 c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
4050 return -ENXIO;
4051
6647dc66
LP
4052 r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
4053 if (r < 0)
9a17484d
LP
4054 return r;
4055
4056 if (c->enclosing != SD_BUS_TYPE_ARRAY)
4057 c->index += 1 + l + 1;
4058
4059 return 1;
4060}
4061
d9f644e2
ZJS
4062_public_ int sd_bus_message_enter_container(sd_bus_message *m,
4063 char type,
4064 const char *contents) {
cf81c68e 4065 struct bus_container *c;
9a17484d 4066 uint32_t *array_size = NULL;
7a4b8512 4067 _cleanup_free_ char *signature = NULL;
cf81c68e 4068 size_t before, end;
7a4b8512 4069 _cleanup_free_ size_t *offsets = NULL;
6647dc66 4070 size_t n_offsets = 0, item_size = 0;
9a17484d
LP
4071 int r;
4072
275b39fe
LP
4073 assert_return(m, -EINVAL);
4074 assert_return(m->sealed, -EPERM);
4075 assert_return(type != 0 || !contents, -EINVAL);
4076
4077 if (type == 0 || !contents) {
4078 const char *cc;
4079 char tt;
4080
4081 /* Allow entering into anonymous containers */
4082 r = sd_bus_message_peek_type(m, &tt, &cc);
18f5b48f 4083 if (r < 0)
275b39fe
LP
4084 return r;
4085
4086 if (type != 0 && type != tt)
4087 return -ENXIO;
4088
4089 if (contents && !streq(contents, cc))
4090 return -ENXIO;
4091
4092 type = tt;
4093 contents = cc;
4094 }
9a17484d 4095
ed205a6b
LP
4096 /*
4097 * We enforce a global limit on container depth, that is much
4098 * higher than the 32 structs and 32 arrays the specification
4099 * mandates. This is simpler to implement for us, and we need
4100 * this only to ensure our container array doesn't grow
4101 * without bounds. We are happy to return any data from a
4102 * message as long as the data itself is valid, even if the
4103 * overall message might be not.
4104 *
4105 * Note that the message signature is validated when
4106 * parsing the headers, and that validation does check the
4107 * 32/32 limit.
4108 *
4109 * Note that the specification defines no limits on the depth
4110 * of stacked variants, but we do.
4111 */
4112 if (m->n_containers >= BUS_CONTAINER_DEPTH)
4113 return -EBADMSG;
4114
306f07be 4115 if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1))
9a17484d 4116 return -ENOMEM;
9a17484d 4117
7b058942 4118 if (message_end_of_signature(m))
430fb8fa 4119 return -ENXIO;
9a17484d 4120
1daf8121
LP
4121 if (message_end_of_array(m, m->rindex))
4122 return 0;
4123
9c65778d 4124 c = message_get_last_container(m);
7b058942 4125
9a17484d
LP
4126 signature = strdup(contents);
4127 if (!signature)
4128 return -ENOMEM;
4129
b3af9646
LP
4130 c->saved_index = c->index;
4131 before = m->rindex;
4132
9a17484d 4133 if (type == SD_BUS_TYPE_ARRAY)
6647dc66 4134 r = bus_message_enter_array(m, c, contents, &array_size, &item_size, &offsets, &n_offsets);
9a17484d 4135 else if (type == SD_BUS_TYPE_VARIANT)
6647dc66 4136 r = bus_message_enter_variant(m, c, contents, &item_size);
9a17484d 4137 else if (type == SD_BUS_TYPE_STRUCT)
6647dc66 4138 r = bus_message_enter_struct(m, c, contents, &item_size, &offsets, &n_offsets);
9a17484d 4139 else if (type == SD_BUS_TYPE_DICT_ENTRY)
6647dc66 4140 r = bus_message_enter_dict_entry(m, c, contents, &item_size, &offsets, &n_offsets);
9a17484d
LP
4141 else
4142 r = -EINVAL;
7a4b8512 4143 if (r <= 0)
9a17484d 4144 return r;
9a17484d
LP
4145
4146 /* OK, let's fill it in */
e53d21d0
DH
4147 if (BUS_MESSAGE_IS_GVARIANT(m) &&
4148 type == SD_BUS_TYPE_STRUCT &&
4149 isempty(signature))
cf81c68e 4150 end = m->rindex + 0;
e53d21d0 4151 else
cf81c68e 4152 end = m->rindex + c->item_size;
ac0a94f7 4153
cf81c68e
ZJS
4154 m->containers[m->n_containers++] = (struct bus_container) {
4155 .enclosing = type,
4156 .signature = TAKE_PTR(signature),
4157
4158 .before = before,
4159 .begin = m->rindex,
4160 /* Unary type has fixed size of 1, but virtual size of 0 */
4161 .end = end,
4162 .array_size = array_size,
4163 .item_size = item_size,
4164 .offsets = TAKE_PTR(offsets),
4165 .n_offsets = n_offsets,
4166 };
9a17484d
LP
4167
4168 return 1;
4169}
4170
d9f644e2 4171_public_ int sd_bus_message_exit_container(sd_bus_message *m) {
9a17484d 4172 struct bus_container *c;
5763192a 4173 unsigned saved;
6647dc66 4174 int r;
9a17484d 4175
9d6c7c82
LP
4176 assert_return(m, -EINVAL);
4177 assert_return(m->sealed, -EPERM);
f959af20 4178 assert_return(m->n_containers > 0, -ENXIO);
9a17484d 4179
9c65778d 4180 c = message_get_last_container(m);
6647dc66
LP
4181
4182 if (c->enclosing != SD_BUS_TYPE_ARRAY) {
4183 if (c->signature && c->signature[c->index] != 0)
4184 return -EBUSY;
4185 }
4186
4187 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4188 if (m->rindex < c->end)
4189 return -EBUSY;
4190
4191 } else if (c->enclosing == SD_BUS_TYPE_ARRAY) {
9a17484d
LP
4192 uint32_t l;
4193
4194 l = BUS_MESSAGE_BSWAP32(m, *c->array_size);
4195 if (c->begin + l != m->rindex)
4196 return -EBUSY;
9a17484d
LP
4197 }
4198
6d1e0f4f 4199 message_free_last_container(m);
9a17484d 4200
9c65778d 4201 c = message_get_last_container(m);
5763192a
LP
4202 saved = c->index;
4203 c->index = c->saved_index;
6647dc66 4204 r = container_next_item(m, c, &m->rindex);
5763192a 4205 c->index = saved;
6647dc66
LP
4206 if (r < 0)
4207 return r;
4208
9a17484d
LP
4209 return 1;
4210}
4211
b3af9646
LP
4212static void message_quit_container(sd_bus_message *m) {
4213 struct bus_container *c;
4214
4215 assert(m);
4216 assert(m->sealed);
4217 assert(m->n_containers > 0);
4218
b3af9646 4219 /* Undo seeks */
9c65778d 4220 c = message_get_last_container(m);
b3af9646
LP
4221 assert(m->rindex >= c->before);
4222 m->rindex = c->before;
4223
4224 /* Free container */
6d1e0f4f 4225 message_free_last_container(m);
b3af9646
LP
4226
4227 /* Correct index of new top-level container */
9c65778d 4228 c = message_get_last_container(m);
b3af9646
LP
4229 c->index = c->saved_index;
4230}
4231
d9f644e2 4232_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
9a17484d
LP
4233 struct bus_container *c;
4234 int r;
4235
c430fee6
LP
4236 assert_return(m, -EINVAL);
4237 assert_return(m->sealed, -EPERM);
9a17484d 4238
7b058942 4239 if (message_end_of_signature(m))
9a17484d
LP
4240 goto eof;
4241
4242 if (message_end_of_array(m, m->rindex))
4243 goto eof;
4244
9c65778d 4245 c = message_get_last_container(m);
7b058942 4246
9a17484d
LP
4247 if (bus_type_is_basic(c->signature[c->index])) {
4248 if (contents)
4249 *contents = NULL;
4250 if (type)
4251 *type = c->signature[c->index];
4252 return 1;
4253 }
4254
4255 if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) {
4256
4257 if (contents) {
4258 size_t l;
9a17484d
LP
4259
4260 r = signature_element_length(c->signature+c->index+1, &l);
4261 if (r < 0)
4262 return r;
4263
7f546026 4264 /* signature_element_length does verification internally */
80a46c73 4265
ec6bda56 4266 /* The array element must not be empty */
7f546026
ZJS
4267 assert(l >= 1);
4268 if (free_and_strndup(&c->peeked_signature,
4269 c->signature + c->index + 1, l) < 0)
9a17484d
LP
4270 return -ENOMEM;
4271
7f546026 4272 *contents = c->peeked_signature;
9a17484d
LP
4273 }
4274
4275 if (type)
4276 *type = SD_BUS_TYPE_ARRAY;
4277
4278 return 1;
4279 }
4280
4c701096 4281 if (IN_SET(c->signature[c->index], SD_BUS_TYPE_STRUCT_BEGIN, SD_BUS_TYPE_DICT_ENTRY_BEGIN)) {
9a17484d
LP
4282
4283 if (contents) {
4284 size_t l;
9a17484d
LP
4285
4286 r = signature_element_length(c->signature+c->index, &l);
4287 if (r < 0)
4288 return r;
4289
ec6bda56 4290 assert(l >= 3);
7f546026
ZJS
4291 if (free_and_strndup(&c->peeked_signature,
4292 c->signature + c->index + 1, l - 2) < 0)
9a17484d
LP
4293 return -ENOMEM;
4294
7f546026 4295 *contents = c->peeked_signature;
9a17484d
LP
4296 }
4297
4298 if (type)
4299 *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
4300
4301 return 1;
4302 }
4303
4304 if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) {
4305 if (contents) {
9a17484d
LP
4306 void *q;
4307
6647dc66
LP
4308 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4309 size_t k;
9a17484d 4310
6647dc66
LP
4311 if (c->item_size < 2)
4312 return -EBADMSG;
9a17484d 4313
6647dc66
LP
4314 /* Look for the NUL delimiter that
4315 separates the payload from the
4316 signature. Since the body might be
4317 in a different part that then the
4318 signature we map byte by byte. */
4319
4320 for (k = 2; k <= c->item_size; k++) {
4321 size_t where;
4322
4323 where = m->rindex + c->item_size - k;
4324 r = message_peek_body(m, &where, 1, k, &q);
4325 if (r < 0)
4326 return r;
6647dc66
LP
4327
4328 if (*(char*) q == 0)
4329 break;
4330 }
4331
4332 if (k > c->item_size)
4333 return -EBADMSG;
4334
7f546026
ZJS
4335 if (free_and_strndup(&c->peeked_signature,
4336 (char*) q + 1, k - 1) < 0)
6647dc66
LP
4337 return -ENOMEM;
4338
3798fd4c 4339 if (!signature_is_valid(c->peeked_signature, true))
6647dc66
LP
4340 return -EBADMSG;
4341
3798fd4c 4342 *contents = c->peeked_signature;
6647dc66
LP
4343 } else {
4344 size_t rindex, l;
4345
4346 rindex = m->rindex;
4347 r = message_peek_body(m, &rindex, 1, 1, &q);
4348 if (r < 0)
4349 return r;
9a17484d 4350
6647dc66 4351 l = *(uint8_t*) q;
902000c1
ZJS
4352 if (l == UINT8_MAX)
4353 /* avoid overflow right below */
4354 return -EBADMSG;
4355
6647dc66
LP
4356 r = message_peek_body(m, &rindex, 1, l+1, &q);
4357 if (r < 0)
4358 return r;
6647dc66
LP
4359
4360 if (!validate_signature(q, l))
4361 return -EBADMSG;
4362
4363 *contents = q;
4364 }
9a17484d
LP
4365 }
4366
4367 if (type)
4368 *type = SD_BUS_TYPE_VARIANT;
4369
4370 return 1;
4371 }
4372
4373 return -EINVAL;
4374
4375eof:
4376 if (type)
7b058942 4377 *type = 0;
9a17484d
LP
4378 if (contents)
4379 *contents = NULL;
4380 return 0;
4381}
4382
d9f644e2 4383_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
9a17484d
LP
4384 struct bus_container *c;
4385
9d6c7c82
LP
4386 assert_return(m, -EINVAL);
4387 assert_return(m->sealed, -EPERM);
9a17484d
LP
4388
4389 if (complete) {
bc7fd8cd 4390 message_reset_containers(m);
9a17484d 4391 m->rindex = 0;
9a17484d 4392
9c65778d 4393 c = message_get_last_container(m);
9a17484d 4394 } else {
9c65778d 4395 c = message_get_last_container(m);
9a17484d
LP
4396
4397 c->index = 0;
4398 m->rindex = c->begin;
4399 }
4400
d36b7031 4401 c->offset_index = 0;
e4bb80a0 4402 c->item_size = (c->n_offsets > 0 ? c->offsets[0] : c->end) - c->begin;
d36b7031 4403
9a17484d
LP
4404 return !isempty(c->signature);
4405}
718db961 4406
11ce0db2 4407_public_ int sd_bus_message_readv(
1b492614
LP
4408 sd_bus_message *m,
4409 const char *types,
4410 va_list ap) {
9a17484d 4411
fe1d424d
LP
4412 unsigned n_array, n_struct;
4413 TypeStack stack[BUS_CONTAINER_DEPTH];
4414 unsigned stack_ptr = 0;
430fb8fa 4415 unsigned n_loop = 0;
9a17484d
LP
4416 int r;
4417
11ce0db2
VH
4418 assert_return(m, -EINVAL);
4419 assert_return(m->sealed, -EPERM);
4420 assert_return(types, -EINVAL);
1b492614 4421
430fb8fa 4422 if (isempty(types))
1b492614 4423 return 0;
9a17484d 4424
fe1d424d
LP
4425 /* Ideally, we'd just call ourselves recursively on every
4426 * complex type. However, the state of a va_list that is
4427 * passed to a function is undefined after that function
22509a8d 4428 * returns. This means we need to decode the va_list linearly
fe1d424d
LP
4429 * in a single stackframe. We hence implement our own
4430 * home-grown stack in an array. */
4431
6f285378 4432 n_array = (unsigned) -1; /* length of current array entries */
430fb8fa 4433 n_struct = strlen(types); /* length of current struct contents signature */
fe1d424d
LP
4434
4435 for (;;) {
4436 const char *t;
4437
430fb8fa
LP
4438 n_loop++;
4439
1b492614 4440 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
fe1d424d
LP
4441 r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
4442 if (r < 0)
4443 return r;
4444 if (r == 0)
4445 break;
4446
4447 r = sd_bus_message_exit_container(m);
4448 if (r < 0)
4449 return r;
4450
4451 continue;
4452 }
4453
4454 t = types;
4455 if (n_array != (unsigned) -1)
313cefa1 4456 n_array--;
fe1d424d 4457 else {
313cefa1 4458 types++;
fe1d424d
LP
4459 n_struct--;
4460 }
4461
9a17484d
LP
4462 switch (*t) {
4463
4464 case SD_BUS_TYPE_BYTE:
4465 case SD_BUS_TYPE_BOOLEAN:
4466 case SD_BUS_TYPE_INT16:
4467 case SD_BUS_TYPE_UINT16:
4468 case SD_BUS_TYPE_INT32:
4469 case SD_BUS_TYPE_UINT32:
4470 case SD_BUS_TYPE_INT64:
4471 case SD_BUS_TYPE_UINT64:
4472 case SD_BUS_TYPE_DOUBLE:
4473 case SD_BUS_TYPE_STRING:
4474 case SD_BUS_TYPE_OBJECT_PATH:
2c93b4ef
LP
4475 case SD_BUS_TYPE_SIGNATURE:
4476 case SD_BUS_TYPE_UNIX_FD: {
9a17484d
LP
4477 void *p;
4478
4479 p = va_arg(ap, void*);
4480 r = sd_bus_message_read_basic(m, *t, p);
fe1d424d
LP
4481 if (r < 0)
4482 return r;
430fb8fa
LP
4483 if (r == 0) {
4484 if (n_loop <= 1)
4485 return 0;
4486
fe1d424d 4487 return -ENXIO;
430fb8fa 4488 }
fe1d424d 4489
9a17484d
LP
4490 break;
4491 }
4492
4493 case SD_BUS_TYPE_ARRAY: {
4494 size_t k;
4495
4496 r = signature_element_length(t + 1, &k);
4497 if (r < 0)
4498 return r;
4499
4500 {
9a17484d 4501 char s[k + 1];
9a17484d
LP
4502 memcpy(s, t + 1, k);
4503 s[k] = 0;
9a17484d
LP
4504
4505 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4506 if (r < 0)
4507 return r;
430fb8fa
LP
4508 if (r == 0) {
4509 if (n_loop <= 1)
4510 return 0;
4511
9a17484d 4512 return -ENXIO;
430fb8fa 4513 }
fe1d424d 4514 }
9a17484d 4515
fe1d424d
LP
4516 if (n_array == (unsigned) -1) {
4517 types += k;
4518 n_struct -= k;
9a17484d
LP
4519 }
4520
fe1d424d
LP
4521 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4522 if (r < 0)
4523 return r;
4524
4525 types = t + 1;
4526 n_struct = k;
4527 n_array = va_arg(ap, unsigned);
4528
9a17484d
LP
4529 break;
4530 }
4531
4532 case SD_BUS_TYPE_VARIANT: {
4533 const char *s;
4534
4535 s = va_arg(ap, const char *);
4536 if (!s)
4537 return -EINVAL;
4538
4539 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s);
4540 if (r < 0)
4541 return r;
430fb8fa
LP
4542 if (r == 0) {
4543 if (n_loop <= 1)
4544 return 0;
4545
9a17484d 4546 return -ENXIO;
430fb8fa 4547 }
9a17484d 4548
fe1d424d 4549 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
9a17484d
LP
4550 if (r < 0)
4551 return r;
9a17484d 4552
fe1d424d
LP
4553 types = s;
4554 n_struct = strlen(s);
4555 n_array = (unsigned) -1;
4556
9a17484d
LP
4557 break;
4558 }
4559
4560 case SD_BUS_TYPE_STRUCT_BEGIN:
4561 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4562 size_t k;
4563
4564 r = signature_element_length(t, &k);
4565 if (r < 0)
4566 return r;
4567
4568 {
4569 char s[k - 1];
4570 memcpy(s, t + 1, k - 2);
4571 s[k - 2] = 0;
4572
4573 r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4574 if (r < 0)
4575 return r;
430fb8fa
LP
4576 if (r == 0) {
4577 if (n_loop <= 1)
4578 return 0;
9a17484d 4579 return -ENXIO;
430fb8fa 4580 }
fe1d424d 4581 }
9a17484d 4582
fe1d424d
LP
4583 if (n_array == (unsigned) -1) {
4584 types += k - 1;
4585 n_struct -= k - 1;
4586 }
9a17484d 4587
fe1d424d
LP
4588 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4589 if (r < 0)
4590 return r;
9a17484d 4591
fe1d424d
LP
4592 types = t + 1;
4593 n_struct = k - 2;
4594 n_array = (unsigned) -1;
9a17484d
LP
4595
4596 break;
4597 }
4598
4599 default:
fe1d424d 4600 return -EINVAL;
9a17484d 4601 }
9a17484d
LP
4602 }
4603
4604 return 1;
4605}
4606
d9f644e2 4607_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
9a17484d
LP
4608 va_list ap;
4609 int r;
4610
9a17484d 4611 va_start(ap, types);
11ce0db2 4612 r = sd_bus_message_readv(m, types, ap);
9a17484d
LP
4613 va_end(ap);
4614
4615 return r;
4616}
4617
d9f644e2 4618_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
9b07511d
LP
4619 int r;
4620
4621 assert_return(m, -EINVAL);
4622 assert_return(m->sealed, -EPERM);
9b07511d 4623
d9fba533
LP
4624 /* If types is NULL, read exactly one element */
4625 if (!types) {
4626 struct bus_container *c;
4627 size_t l;
4628
4629 if (message_end_of_signature(m))
4630 return -ENXIO;
4631
4632 if (message_end_of_array(m, m->rindex))
4633 return 0;
4634
9c65778d 4635 c = message_get_last_container(m);
d9fba533
LP
4636
4637 r = signature_element_length(c->signature + c->index, &l);
4638 if (r < 0)
4639 return r;
4640
4641 types = strndupa(c->signature + c->index, l);
4642 }
9b07511d
LP
4643
4644 switch (*types) {
4645
d9fba533
LP
4646 case 0: /* Nothing to drop */
4647 return 0;
4648
9b07511d
LP
4649 case SD_BUS_TYPE_BYTE:
4650 case SD_BUS_TYPE_BOOLEAN:
4651 case SD_BUS_TYPE_INT16:
4652 case SD_BUS_TYPE_UINT16:
4653 case SD_BUS_TYPE_INT32:
4654 case SD_BUS_TYPE_UINT32:
4655 case SD_BUS_TYPE_INT64:
4656 case SD_BUS_TYPE_UINT64:
4657 case SD_BUS_TYPE_DOUBLE:
4658 case SD_BUS_TYPE_STRING:
4659 case SD_BUS_TYPE_OBJECT_PATH:
4660 case SD_BUS_TYPE_SIGNATURE:
4661 case SD_BUS_TYPE_UNIX_FD:
4662
4663 r = sd_bus_message_read_basic(m, *types, NULL);
4664 if (r <= 0)
4665 return r;
4666
4667 r = sd_bus_message_skip(m, types + 1);
4668 if (r < 0)
4669 return r;
4670
4671 return 1;
4672
4673 case SD_BUS_TYPE_ARRAY: {
4674 size_t k;
4675
4676 r = signature_element_length(types + 1, &k);
4677 if (r < 0)
4678 return r;
4679
4680 {
4681 char s[k+1];
4682 memcpy(s, types+1, k);
4683 s[k] = 0;
4684
4685 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4686 if (r <= 0)
4687 return r;
4688
4689 for (;;) {
4690 r = sd_bus_message_skip(m, s);
4691 if (r < 0)
4692 return r;
4693 if (r == 0)
4694 break;
4695 }
4696
4697 r = sd_bus_message_exit_container(m);
4698 if (r < 0)
4699 return r;
4700 }
4701
4702 r = sd_bus_message_skip(m, types + 1 + k);
4703 if (r < 0)
4704 return r;
4705
4706 return 1;
4707 }
4708
4709 case SD_BUS_TYPE_VARIANT: {
4710 const char *contents;
4711 char x;
4712
4713 r = sd_bus_message_peek_type(m, &x, &contents);
4714 if (r <= 0)
4715 return r;
4716
4717 if (x != SD_BUS_TYPE_VARIANT)
4718 return -ENXIO;
4719
4720 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
4721 if (r <= 0)
4722 return r;
4723
4724 r = sd_bus_message_skip(m, contents);
4725 if (r < 0)
4726 return r;
4727 assert(r != 0);
4728
4729 r = sd_bus_message_exit_container(m);
4730 if (r < 0)
4731 return r;
4732
4733 r = sd_bus_message_skip(m, types + 1);
4734 if (r < 0)
4735 return r;
4736
4737 return 1;
4738 }
4739
4740 case SD_BUS_TYPE_STRUCT_BEGIN:
4741 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4742 size_t k;
4743
4744 r = signature_element_length(types, &k);
4745 if (r < 0)
4746 return r;
4747
4748 {
4749 char s[k-1];
4750 memcpy(s, types+1, k-2);
4751 s[k-2] = 0;
4752
4753 r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4754 if (r <= 0)
4755 return r;
4756
4757 r = sd_bus_message_skip(m, s);
4758 if (r < 0)
4759 return r;
9b07511d
LP
4760
4761 r = sd_bus_message_exit_container(m);
4762 if (r < 0)
4763 return r;
4764 }
4765
4766 r = sd_bus_message_skip(m, types + k);
4767 if (r < 0)
4768 return r;
4769
4770 return 1;
4771 }
4772
4773 default:
4774 return -EINVAL;
4775 }
4776}
4777
2ac7c17f
LP
4778_public_ int sd_bus_message_read_array(
4779 sd_bus_message *m,
4780 char type,
4781 const void **ptr,
4782 size_t *size) {
4783
b3af9646
LP
4784 struct bus_container *c;
4785 void *p;
4786 size_t sz;
4787 ssize_t align;
4788 int r;
4789
9d6c7c82
LP
4790 assert_return(m, -EINVAL);
4791 assert_return(m->sealed, -EPERM);
4792 assert_return(bus_type_is_trivial(type), -EINVAL);
4793 assert_return(ptr, -EINVAL);
4794 assert_return(size, -EINVAL);
15411c0c 4795 assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -EOPNOTSUPP);
b3af9646 4796
b3af9646 4797 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
6293d958 4798 if (r < 0)
b3af9646 4799 return r;
6293d958
LP
4800 if (r == 0) {
4801 *ptr = NULL;
4802 *size = 0;
4803 return 0;
4804 }
b3af9646 4805
9c65778d 4806 c = message_get_last_container(m);
6647dc66
LP
4807
4808 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4809 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
4810 if (align < 0)
4811 return align;
4812
18f5b48f 4813 sz = c->end - c->begin;
6647dc66
LP
4814 } else {
4815 align = bus_type_get_alignment(type);
4816 if (align < 0)
4817 return align;
4818
4819 sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
4820 }
b3af9646 4821
5e86fd7b
LP
4822 if (sz == 0)
4823 /* Zero length array, let's return some aligned
4824 * pointer that is not NULL */
0241c1c0 4825 p = (uint8_t*) align;
5e86fd7b
LP
4826 else {
4827 r = message_peek_body(m, &m->rindex, align, sz, &p);
4828 if (r < 0)
4829 goto fail;
b3af9646
LP
4830 }
4831
4832 r = sd_bus_message_exit_container(m);
4833 if (r < 0)
4834 goto fail;
4835
4836 *ptr = (const void*) p;
4837 *size = sz;
4838
4839 return 1;
4840
4841fail:
4842 message_quit_container(m);
4843 return r;
4844}
4845
80a46c73
LP
4846static int message_peek_fields(
4847 sd_bus_message *m,
4848 size_t *rindex,
4849 size_t align,
4850 size_t nbytes,
4851 void **ret) {
4852
4853 assert(m);
4854 assert(rindex);
4855 assert(align > 0);
4856
2ac7c17f 4857 return buffer_peek(BUS_MESSAGE_FIELDS(m), m->fields_size, rindex, align, nbytes, ret);
80a46c73
LP
4858}
4859
9f26c90c
LP
4860static int message_peek_field_uint32(
4861 sd_bus_message *m,
4862 size_t *ri,
6647dc66 4863 size_t item_size,
9f26c90c
LP
4864 uint32_t *ret) {
4865
4866 int r;
4867 void *q;
4868
4869 assert(m);
4870 assert(ri);
4871
6647dc66
LP
4872 if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 4)
4873 return -EBADMSG;
4874
4875 /* identical for gvariant and dbus1 */
4876
9f26c90c
LP
4877 r = message_peek_fields(m, ri, 4, 4, &q);
4878 if (r < 0)
4879 return r;
4880
4881 if (ret)
4882 *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
4883
4884 return 0;
4885}
4886
2ac7c17f
LP
4887static int message_peek_field_uint64(
4888 sd_bus_message *m,
4889 size_t *ri,
4890 size_t item_size,
4891 uint64_t *ret) {
4892
4893 int r;
4894 void *q;
4895
4896 assert(m);
4897 assert(ri);
4898
4899 if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 8)
4900 return -EBADMSG;
4901
4902 /* identical for gvariant and dbus1 */
4903
4904 r = message_peek_fields(m, ri, 8, 8, &q);
4905 if (r < 0)
4906 return r;
4907
4908 if (ret)
4909 *ret = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
4910
4911 return 0;
4912}
4913
80a46c73
LP
4914static int message_peek_field_string(
4915 sd_bus_message *m,
6693860f 4916 bool (*validate)(const char *p),
80a46c73 4917 size_t *ri,
6647dc66 4918 size_t item_size,
80a46c73
LP
4919 const char **ret) {
4920
9f26c90c 4921 uint32_t l;
80a46c73
LP
4922 int r;
4923 void *q;
4924
9a17484d 4925 assert(m);
80a46c73
LP
4926 assert(ri);
4927
6647dc66 4928 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4929
6647dc66
LP
4930 if (item_size <= 0)
4931 return -EBADMSG;
4932
4933 r = message_peek_fields(m, ri, 1, item_size, &q);
4934 if (r < 0)
4935 return r;
4936
4937 l = item_size - 1;
4938 } else {
4939 r = message_peek_field_uint32(m, ri, 4, &l);
4940 if (r < 0)
4941 return r;
4942
902000c1
ZJS
4943 if (l == UINT32_MAX)
4944 /* avoid overflow right below */
4945 return -EBADMSG;
4946
6647dc66
LP
4947 r = message_peek_fields(m, ri, 1, l+1, &q);
4948 if (r < 0)
4949 return r;
4950 }
9a17484d 4951
6693860f
LP
4952 if (validate) {
4953 if (!validate_nul(q, l))
4954 return -EBADMSG;
4955
4956 if (!validate(q))
ac89bf1d
LP
4957 return -EBADMSG;
4958 } else {
4959 if (!validate_string(q, l))
4960 return -EBADMSG;
4961 }
80a46c73
LP
4962
4963 if (ret)
4964 *ret = q;
4965
4966 return 0;
4967}
4968
4969static int message_peek_field_signature(
4970 sd_bus_message *m,
4971 size_t *ri,
6647dc66 4972 size_t item_size,
80a46c73
LP
4973 const char **ret) {
4974
4975 size_t l;
4976 int r;
4977 void *q;
4978
4979 assert(m);
4980 assert(ri);
4981
6647dc66 4982 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4983
6647dc66
LP
4984 if (item_size <= 0)
4985 return -EBADMSG;
4986
4987 r = message_peek_fields(m, ri, 1, item_size, &q);
4988 if (r < 0)
4989 return r;
4990
4991 l = item_size - 1;
4992 } else {
4993 r = message_peek_fields(m, ri, 1, 1, &q);
4994 if (r < 0)
4995 return r;
4996
4997 l = *(uint8_t*) q;
902000c1
ZJS
4998 if (l == UINT8_MAX)
4999 /* avoid overflow right below */
5000 return -EBADMSG;
5001
6647dc66
LP
5002 r = message_peek_fields(m, ri, 1, l+1, &q);
5003 if (r < 0)
5004 return r;
5005 }
80a46c73
LP
5006
5007 if (!validate_signature(q, l))
5008 return -EBADMSG;
5009
5010 if (ret)
5011 *ret = q;
5012
5013 return 0;
5014}
5015
80a46c73
LP
5016static int message_skip_fields(
5017 sd_bus_message *m,
5018 size_t *ri,
5019 uint32_t array_size,
5020 const char **signature) {
5021
5022 size_t original_index;
5023 int r;
5024
5025 assert(m);
5026 assert(ri);
5027 assert(signature);
6647dc66 5028 assert(!BUS_MESSAGE_IS_GVARIANT(m));
80a46c73
LP
5029
5030 original_index = *ri;
5031
5032 for (;;) {
5033 char t;
80a46c73
LP
5034 size_t l;
5035
5036 if (array_size != (uint32_t) -1 &&
5037 array_size <= *ri - original_index)
5038 return 0;
5039
5040 t = **signature;
5041 if (!t)
5042 return 0;
5043
6693860f
LP
5044 if (t == SD_BUS_TYPE_STRING) {
5045
6647dc66 5046 r = message_peek_field_string(m, NULL, ri, 0, NULL);
6693860f
LP
5047 if (r < 0)
5048 return r;
5049
5050 (*signature)++;
5051
5052 } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
80a46c73 5053
6647dc66 5054 r = message_peek_field_string(m, object_path_is_valid, ri, 0, NULL);
80a46c73
LP
5055 if (r < 0)
5056 return r;
5057
5058 (*signature)++;
5059
5060 } else if (t == SD_BUS_TYPE_SIGNATURE) {
5061
6647dc66 5062 r = message_peek_field_signature(m, ri, 0, NULL);
80a46c73
LP
5063 if (r < 0)
5064 return r;
5065
5066 (*signature)++;
5067
5068 } else if (bus_type_is_basic(t)) {
27f6e5c7 5069 ssize_t align, k;
80a46c73 5070
c66a2e0c
TG
5071 align = bus_type_get_alignment(t);
5072 k = bus_type_get_size(t);
27f6e5c7 5073 assert(align > 0 && k > 0);
80a46c73
LP
5074
5075 r = message_peek_fields(m, ri, align, k, NULL);
5076 if (r < 0)
5077 return r;
9a17484d 5078
80a46c73
LP
5079 (*signature)++;
5080
5081 } else if (t == SD_BUS_TYPE_ARRAY) {
5082
73777ddb 5083 r = signature_element_length(*signature + 1, &l);
80a46c73
LP
5084 if (r < 0)
5085 return r;
5086
5087 assert(l >= 1);
5088 {
73777ddb 5089 char sig[l + 1], *s = sig;
9f26c90c 5090 uint32_t nas;
80a46c73
LP
5091 int alignment;
5092
73777ddb
ZJS
5093 strncpy(sig, *signature + 1, l);
5094 sig[l] = '\0';
80a46c73
LP
5095
5096 alignment = bus_type_get_alignment(sig[0]);
5097 if (alignment < 0)
5098 return alignment;
5099
6647dc66 5100 r = message_peek_field_uint32(m, ri, 0, &nas);
80a46c73
LP
5101 if (r < 0)
5102 return r;
ac89bf1d 5103 if (nas > BUS_ARRAY_MAX_SIZE)
80a46c73
LP
5104 return -EBADMSG;
5105
5106 r = message_peek_fields(m, ri, alignment, 0, NULL);
5107 if (r < 0)
5108 return r;
5109
5110 r = message_skip_fields(m, ri, nas, (const char**) &s);
5111 if (r < 0)
5112 return r;
5113 }
5114
5115 (*signature) += 1 + l;
5116
5117 } else if (t == SD_BUS_TYPE_VARIANT) {
5118 const char *s;
5119
6647dc66 5120 r = message_peek_field_signature(m, ri, 0, &s);
80a46c73
LP
5121 if (r < 0)
5122 return r;
5123
5124 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
5125 if (r < 0)
5126 return r;
5127
5128 (*signature)++;
5129
945c2931 5130 } else if (IN_SET(t, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) {
80a46c73
LP
5131
5132 r = signature_element_length(*signature, &l);
5133 if (r < 0)
5134 return r;
5135
5136 assert(l >= 2);
5137 {
3d338a30
ZJS
5138 char sig[l + 1], *s = sig;
5139 strncpy(sig, *signature + 1, l);
5140 sig[l] = '\0';
80a46c73
LP
5141
5142 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
5143 if (r < 0)
5144 return r;
5145 }
5146
5147 *signature += l;
5148 } else
d831fb6f 5149 return -EBADMSG;
80a46c73
LP
5150 }
5151}
5152
6629161f 5153int bus_message_parse_fields(sd_bus_message *m) {
80a46c73
LP
5154 size_t ri;
5155 int r;
2c93b4ef 5156 uint32_t unix_fds = 0;
5a4d665a 5157 bool unix_fds_set = false;
6647dc66
LP
5158 void *offsets = NULL;
5159 unsigned n_offsets = 0;
8f2e44f8 5160 size_t sz = 0;
6647dc66 5161 unsigned i = 0;
80a46c73
LP
5162
5163 assert(m);
5164
6647dc66 5165 if (BUS_MESSAGE_IS_GVARIANT(m)) {
2ac7c17f
LP
5166 char *p;
5167
5168 /* Read the signature from the end of the body variant first */
5169 sz = bus_gvariant_determine_word_size(BUS_MESSAGE_SIZE(m), 0);
5170 if (m->footer_accessible < 1 + sz)
5171 return -EBADMSG;
5172
5173 p = (char*) m->footer + m->footer_accessible - (1 + sz);
5174 for (;;) {
5175 if (p < (char*) m->footer)
5176 return -EBADMSG;
5177
5178 if (*p == 0) {
f0ae945e 5179 _cleanup_free_ char *k = NULL;
03ebf5e8 5180 size_t l;
2ac7c17f 5181
03ebf5e8
DH
5182 /* We found the beginning of the signature
5183 * string, yay! We require the body to be a
5184 * structure, so verify it and then strip the
5185 * opening/closing brackets. */
2ac7c17f 5186
7f546026 5187 l = (char*) m->footer + m->footer_accessible - p - (1 + sz);
03ebf5e8
DH
5188 if (l < 2 ||
5189 p[1] != SD_BUS_TYPE_STRUCT_BEGIN ||
5190 p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END)
5191 return -EBADMSG;
5192
ac0a94f7
LP
5193 k = memdup_suffix0(p + 1 + 1, l - 2);
5194 if (!k)
2ac7c17f 5195 return -ENOMEM;
ac0a94f7 5196
f0ae945e
ZJS
5197 if (!signature_is_valid(k, true))
5198 return -EBADMSG;
5199
ac0a94f7 5200 free_and_replace(m->root_container.signature, k);
2ac7c17f
LP
5201 break;
5202 }
6647dc66 5203
2ac7c17f
LP
5204 p--;
5205 }
5206
5207 /* Calculate the actual user body size, by removing
5208 * the trailing variant signature and struct offset
5209 * table */
5210 m->user_body_size = m->body_size - ((char*) m->footer + m->footer_accessible - p);
5211
e0c17a7d
ZJS
5212 /* Pull out the offset table for the fields array, if any */
5213 if (m->fields_size > 0) {
5214 sz = bus_gvariant_determine_word_size(m->fields_size, 0);
5215 if (sz > 0) {
5216 size_t framing;
5217 void *q;
5218
5219 if (m->fields_size < sz)
5220 return -EBADMSG;
6647dc66 5221
e0c17a7d
ZJS
5222 ri = m->fields_size - sz;
5223 r = message_peek_fields(m, &ri, 1, sz, &q);
5224 if (r < 0)
5225 return r;
6647dc66 5226
e0c17a7d
ZJS
5227 framing = bus_gvariant_read_word_le(q, sz);
5228 if (framing >= m->fields_size - sz)
5229 return -EBADMSG;
5230 if ((m->fields_size - framing) % sz != 0)
5231 return -EBADMSG;
6647dc66 5232
e0c17a7d
ZJS
5233 ri = framing;
5234 r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
5235 if (r < 0)
5236 return r;
6647dc66 5237
e0c17a7d
ZJS
5238 n_offsets = (m->fields_size - framing) / sz;
5239 }
6647dc66 5240 }
2ac7c17f
LP
5241 } else
5242 m->user_body_size = m->body_size;
6647dc66
LP
5243
5244 ri = 0;
2ac7c17f 5245 while (ri < m->fields_size) {
6647dc66 5246 _cleanup_free_ char *sig = NULL;
80a46c73 5247 const char *signature;
2ac7c17f 5248 uint64_t field_type;
6647dc66
LP
5249 size_t item_size = (size_t) -1;
5250
5251 if (BUS_MESSAGE_IS_GVARIANT(m)) {
2ac7c17f
LP
5252 uint64_t *u64;
5253
6647dc66
LP
5254 if (i >= n_offsets)
5255 break;
5256
5257 if (i == 0)
5258 ri = 0;
5259 else
2ac7c17f 5260 ri = ALIGN_TO(bus_gvariant_read_word_le((uint8_t*) offsets + (i-1)*sz, sz), 8);
80a46c73 5261
2ac7c17f
LP
5262 r = message_peek_fields(m, &ri, 8, 8, (void**) &u64);
5263 if (r < 0)
5264 return r;
5265
5266 field_type = BUS_MESSAGE_BSWAP64(m, *u64);
5267 } else {
5268 uint8_t *u8;
5269
5270 r = message_peek_fields(m, &ri, 8, 1, (void**) &u8);
5271 if (r < 0)
5272 return r;
5273
5274 field_type = *u8;
5275 }
954871d8 5276
6647dc66
LP
5277 if (BUS_MESSAGE_IS_GVARIANT(m)) {
5278 size_t where, end;
5279 char *b;
5280 void *q;
5281
2ac7c17f 5282 end = bus_gvariant_read_word_le((uint8_t*) offsets + i*sz, sz);
6647dc66
LP
5283
5284 if (end < ri)
5285 return -EBADMSG;
5286
5287 where = ri = ALIGN_TO(ri, 8);
5288 item_size = end - ri;
5289 r = message_peek_fields(m, &where, 1, item_size, &q);
5290 if (r < 0)
5291 return r;
5292
5293 b = memrchr(q, 0, item_size);
5294 if (!b)
5295 return -EBADMSG;
5296
bccd9162 5297 sig = memdup_suffix0(b+1, item_size - (b+1-(char*) q));
6647dc66
LP
5298 if (!sig)
5299 return -ENOMEM;
5300
5301 signature = sig;
5302 item_size = b - (char*) q;
5303 } else {
5304 r = message_peek_field_signature(m, &ri, 0, &signature);
5305 if (r < 0)
5306 return r;
5307 }
80a46c73 5308
2ac7c17f
LP
5309 switch (field_type) {
5310
0461f8cd 5311 case _BUS_MESSAGE_HEADER_INVALID:
80a46c73
LP
5312 return -EBADMSG;
5313
0461f8cd 5314 case BUS_MESSAGE_HEADER_PATH:
2c93b4ef
LP
5315
5316 if (m->path)
5317 return -EBADMSG;
5318
80a46c73
LP
5319 if (!streq(signature, "o"))
5320 return -EBADMSG;
5321
6647dc66 5322 r = message_peek_field_string(m, object_path_is_valid, &ri, item_size, &m->path);
80a46c73
LP
5323 break;
5324
0461f8cd 5325 case BUS_MESSAGE_HEADER_INTERFACE:
2c93b4ef
LP
5326
5327 if (m->interface)
5328 return -EBADMSG;
5329
80a46c73
LP
5330 if (!streq(signature, "s"))
5331 return -EBADMSG;
5332
6647dc66 5333 r = message_peek_field_string(m, interface_name_is_valid, &ri, item_size, &m->interface);
80a46c73
LP
5334 break;
5335
0461f8cd 5336 case BUS_MESSAGE_HEADER_MEMBER:
2c93b4ef
LP
5337
5338 if (m->member)
5339 return -EBADMSG;
5340
80a46c73
LP
5341 if (!streq(signature, "s"))
5342 return -EBADMSG;
5343
6647dc66 5344 r = message_peek_field_string(m, member_name_is_valid, &ri, item_size, &m->member);
80a46c73
LP
5345 break;
5346
0461f8cd 5347 case BUS_MESSAGE_HEADER_ERROR_NAME:
2c93b4ef
LP
5348
5349 if (m->error.name)
5350 return -EBADMSG;
5351
80a46c73
LP
5352 if (!streq(signature, "s"))
5353 return -EBADMSG;
5354
6647dc66 5355 r = message_peek_field_string(m, error_name_is_valid, &ri, item_size, &m->error.name);
79f8d3d2
LP
5356 if (r >= 0)
5357 m->error._need_free = -1;
5358
80a46c73
LP
5359 break;
5360
0461f8cd 5361 case BUS_MESSAGE_HEADER_DESTINATION:
2c93b4ef
LP
5362
5363 if (m->destination)
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->destination);
80a46c73
LP
5370 break;
5371
0461f8cd 5372 case BUS_MESSAGE_HEADER_SENDER:
2c93b4ef
LP
5373
5374 if (m->sender)
5375 return -EBADMSG;
5376
80a46c73
LP
5377 if (!streq(signature, "s"))
5378 return -EBADMSG;
5379
6647dc66 5380 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
49b832c5 5381
a132bef0 5382 if (r >= 0 && m->sender[0] == ':' && m->bus->bus_client) {
49b832c5
LP
5383 m->creds.unique_name = (char*) m->sender;
5384 m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
5385 }
5386
80a46c73
LP
5387 break;
5388
0461f8cd 5389 case BUS_MESSAGE_HEADER_SIGNATURE: {
80a46c73
LP
5390 const char *s;
5391 char *c;
5392
2ac7c17f
LP
5393 if (BUS_MESSAGE_IS_GVARIANT(m)) /* only applies to dbus1 */
5394 return -EBADMSG;
5395
2c93b4ef
LP
5396 if (m->root_container.signature)
5397 return -EBADMSG;
5398
80a46c73
LP
5399 if (!streq(signature, "g"))
5400 return -EBADMSG;
5401
6647dc66 5402 r = message_peek_field_signature(m, &ri, item_size, &s);
80a46c73
LP
5403 if (r < 0)
5404 return r;
5405
5406 c = strdup(s);
5407 if (!c)
5408 return -ENOMEM;
5409
7a4b8512 5410 free_and_replace(m->root_container.signature, c);
80a46c73
LP
5411 break;
5412 }
5413
2ac7c17f 5414 case BUS_MESSAGE_HEADER_REPLY_SERIAL:
42c4ebcb 5415
693eb9a2 5416 if (m->reply_cookie != 0)
2c93b4ef
LP
5417 return -EBADMSG;
5418
2ac7c17f
LP
5419 if (BUS_MESSAGE_IS_GVARIANT(m)) {
5420 /* 64bit on dbus2 */
6693860f 5421
2ac7c17f
LP
5422 if (!streq(signature, "t"))
5423 return -EBADMSG;
5424
5425 r = message_peek_field_uint64(m, &ri, item_size, &m->reply_cookie);
5426 if (r < 0)
5427 return r;
5428 } else {
5429 /* 32bit on dbus1 */
5430 uint32_t serial;
5431
5432 if (!streq(signature, "u"))
5433 return -EBADMSG;
b381de41 5434
2ac7c17f
LP
5435 r = message_peek_field_uint32(m, &ri, item_size, &serial);
5436 if (r < 0)
5437 return r;
5438
5439 m->reply_cookie = serial;
5440 }
42c4ebcb 5441
693eb9a2 5442 if (m->reply_cookie == 0)
6693860f
LP
5443 return -EBADMSG;
5444
80a46c73
LP
5445 break;
5446
0461f8cd 5447 case BUS_MESSAGE_HEADER_UNIX_FDS:
5a4d665a 5448 if (unix_fds_set)
2c93b4ef
LP
5449 return -EBADMSG;
5450
5451 if (!streq(signature, "u"))
5452 return -EBADMSG;
5453
6647dc66 5454 r = message_peek_field_uint32(m, &ri, item_size, &unix_fds);
2c93b4ef
LP
5455 if (r < 0)
5456 return -EBADMSG;
5457
5a4d665a 5458 unix_fds_set = true;
2c93b4ef
LP
5459 break;
5460
80a46c73 5461 default:
6647dc66
LP
5462 if (!BUS_MESSAGE_IS_GVARIANT(m))
5463 r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
80a46c73
LP
5464 }
5465
5466 if (r < 0)
5467 return r;
6647dc66
LP
5468
5469 i++;
80a46c73
LP
5470 }
5471
2c93b4ef
LP
5472 if (m->n_fds != unix_fds)
5473 return -EBADMSG;
5474
80a46c73
LP
5475 switch (m->header->type) {
5476
40ca29a1 5477 case SD_BUS_MESSAGE_SIGNAL:
80a46c73
LP
5478 if (!m->path || !m->interface || !m->member)
5479 return -EBADMSG;
7fa934b0
LP
5480
5481 if (m->reply_cookie != 0)
5482 return -EBADMSG;
5483
80a46c73
LP
5484 break;
5485
40ca29a1 5486 case SD_BUS_MESSAGE_METHOD_CALL:
80a46c73
LP
5487
5488 if (!m->path || !m->member)
5489 return -EBADMSG;
5490
7fa934b0
LP
5491 if (m->reply_cookie != 0)
5492 return -EBADMSG;
5493
80a46c73
LP
5494 break;
5495
40ca29a1 5496 case SD_BUS_MESSAGE_METHOD_RETURN:
80a46c73 5497
693eb9a2 5498 if (m->reply_cookie == 0)
80a46c73
LP
5499 return -EBADMSG;
5500 break;
5501
40ca29a1 5502 case SD_BUS_MESSAGE_METHOD_ERROR:
80a46c73 5503
693eb9a2 5504 if (m->reply_cookie == 0 || !m->error.name)
80a46c73
LP
5505 return -EBADMSG;
5506 break;
5507 }
9a17484d 5508
35473296
LP
5509 /* Refuse non-local messages that claim they are local */
5510 if (streq_ptr(m->path, "/org/freedesktop/DBus/Local"))
5511 return -EBADMSG;
5512 if (streq_ptr(m->interface, "org.freedesktop.DBus.Local"))
5513 return -EBADMSG;
5514 if (streq_ptr(m->sender, "org.freedesktop.DBus.Local"))
5515 return -EBADMSG;
5516
2ac7c17f 5517 m->root_container.end = m->user_body_size;
6647dc66
LP
5518
5519 if (BUS_MESSAGE_IS_GVARIANT(m)) {
5520 r = build_struct_offsets(
5521 m,
5522 m->root_container.signature,
2ac7c17f 5523 m->user_body_size,
6647dc66
LP
5524 &m->root_container.item_size,
5525 &m->root_container.offsets,
5526 &m->root_container.n_offsets);
69bd42ca
ZJS
5527 if (r == -EINVAL)
5528 return -EBADMSG;
6647dc66
LP
5529 if (r < 0)
5530 return r;
5531 }
5532
89ffcd2a 5533 /* Try to read the error message, but if we can't it's a non-issue */
40ca29a1 5534 if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
d3839740 5535 (void) sd_bus_message_read(m, "s", &m->error.message);
89ffcd2a 5536
9a17484d
LP
5537 return 0;
5538}
5539
d9f644e2 5540_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
9d6c7c82
LP
5541 assert_return(m, -EINVAL);
5542 assert_return(destination, -EINVAL);
3d51a011 5543 assert_return(service_name_is_valid(destination), -EINVAL);
9d6c7c82
LP
5544 assert_return(!m->sealed, -EPERM);
5545 assert_return(!m->destination, -EEXIST);
9a17484d 5546
0461f8cd 5547 return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
9a17484d
LP
5548}
5549
48ef41a3
LP
5550_public_ int sd_bus_message_set_sender(sd_bus_message *m, const char *sender) {
5551 assert_return(m, -EINVAL);
5552 assert_return(sender, -EINVAL);
3d51a011 5553 assert_return(service_name_is_valid(sender), -EINVAL);
48ef41a3
LP
5554 assert_return(!m->sealed, -EPERM);
5555 assert_return(!m->sender, -EEXIST);
5556
5557 return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
5558}
5559
de1c301e
LP
5560int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
5561 size_t total;
de1c301e 5562 void *p, *e;
da6053d0 5563 size_t i;
bc7fd8cd 5564 struct bus_body_part *part;
de1c301e
LP
5565
5566 assert(m);
5567 assert(buffer);
5568 assert(sz);
5569
6629161f 5570 total = BUS_MESSAGE_SIZE(m);
de1c301e
LP
5571
5572 p = malloc(total);
5573 if (!p)
5574 return -ENOMEM;
5575
c91cb83c 5576 e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m));
9b29bb68 5577 MESSAGE_FOREACH_PART(part, i, m)
bc7fd8cd 5578 e = mempcpy(e, part->data, part->size);
2100fa10
LP
5579
5580 assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p));
de1c301e
LP
5581
5582 *buffer = p;
5583 *sz = total;
5584
5585 return 0;
5586}
89ffcd2a
LP
5587
5588int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
43ef7603 5589 const char *s;
89ffcd2a
LP
5590 int r;
5591
5592 assert(m);
5593 assert(l);
5594
5595 r = sd_bus_message_enter_container(m, 'a', "s");
4686d1b6 5596 if (r <= 0)
89ffcd2a
LP
5597 return r;
5598
43ef7603 5599 while ((r = sd_bus_message_read_basic(m, 's', &s)) > 0) {
89ffcd2a
LP
5600 r = strv_extend(l, s);
5601 if (r < 0)
5602 return r;
5603 }
43ef7603
DH
5604 if (r < 0)
5605 return r;
89ffcd2a
LP
5606
5607 r = sd_bus_message_exit_container(m);
5608 if (r < 0)
5609 return r;
5610
405cd3aa 5611 return 1;
89ffcd2a 5612}
392d5b37 5613
ba341e7c 5614_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
7a4b8512 5615 _cleanup_strv_free_ char **strv = NULL;
4686d1b6
MAP
5616 int r;
5617
5618 assert_return(m, -EINVAL);
5619 assert_return(m->sealed, -EPERM);
5620 assert_return(l, -EINVAL);
5621
5622 r = bus_message_read_strv_extend(m, &strv);
7a4b8512 5623 if (r <= 0)
4686d1b6 5624 return r;
4686d1b6 5625
7a4b8512 5626 *l = TAKE_PTR(strv);
4686d1b6
MAP
5627 return 1;
5628}
5629
eccd47c5
LP
5630static int bus_message_get_arg_skip(
5631 sd_bus_message *m,
5632 unsigned i,
5633 char *_type,
5634 const char **_contents) {
5635
42c5aaf3 5636 unsigned j;
198b158f 5637 int r;
392d5b37 5638
392d5b37
LP
5639 r = sd_bus_message_rewind(m, true);
5640 if (r < 0)
198b158f 5641 return r;
392d5b37 5642
198b158f 5643 for (j = 0;; j++) {
eccd47c5
LP
5644 const char *contents;
5645 char type;
5646
198b158f
LP
5647 r = sd_bus_message_peek_type(m, &type, &contents);
5648 if (r < 0)
5649 return r;
5650 if (r == 0)
5651 return -ENXIO;
5652
5653 /* Don't match against arguments after the first one we don't understand */
5654 if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE) &&
5655 !(type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")))
5656 return -ENXIO;
42c5aaf3 5657
eccd47c5
LP
5658 if (j >= i) {
5659 if (_contents)
5660 *_contents = contents;
5661 if (_type)
5662 *_type = type;
5663 return 0;
5664 }
198b158f
LP
5665
5666 r = sd_bus_message_skip(m, NULL);
392d5b37 5667 if (r < 0)
198b158f
LP
5668 return r;
5669 }
392d5b37 5670
eccd47c5 5671}
392d5b37 5672
eccd47c5
LP
5673int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str) {
5674 char type;
5675 int r;
198b158f 5676
eccd47c5
LP
5677 assert(m);
5678 assert(str);
198b158f 5679
eccd47c5
LP
5680 r = bus_message_get_arg_skip(m, i, &type, NULL);
5681 if (r < 0)
5682 return r;
198b158f 5683
eccd47c5
LP
5684 if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE))
5685 return -ENXIO;
392d5b37 5686
eccd47c5
LP
5687 return sd_bus_message_read_basic(m, type, str);
5688}
5689
5690int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv) {
5691 const char *contents;
5692 char type;
5693 int r;
5694
5695 assert(m);
5696 assert(strv);
5697
5698 r = bus_message_get_arg_skip(m, i, &type, &contents);
5699 if (r < 0)
5700 return r;
5701
5702 if (type != SD_BUS_TYPE_ARRAY)
5703 return -ENXIO;
5704 if (!STR_IN_SET(contents, "s", "o", "g"))
5705 return -ENXIO;
5706
5707 return sd_bus_message_read_strv(m, strv);
392d5b37 5708}
2100fa10 5709
d9f644e2 5710_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
b49ffb29 5711 assert_return(m, EINVAL);
eb01ba5d 5712
40ca29a1 5713 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
eb01ba5d
LP
5714 return 0;
5715
40ca29a1 5716 return sd_bus_error_get_errno(&m->error);
eb01ba5d 5717}
29ddb38f 5718
d9f644e2 5719_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
29ddb38f
LP
5720 struct bus_container *c;
5721
9d6c7c82 5722 assert_return(m, NULL);
29ddb38f 5723
9c65778d 5724 c = complete ? &m->root_container : message_get_last_container(m);
d6385068 5725 return strempty(c->signature);
29ddb38f 5726}
c430fee6 5727
8022212b
LP
5728_public_ int sd_bus_message_is_empty(sd_bus_message *m) {
5729 assert_return(m, -EINVAL);
5730
5731 return isempty(m->root_container.signature);
5732}
5733
64e96a19
LP
5734_public_ int sd_bus_message_has_signature(sd_bus_message *m, const char *signature) {
5735 assert_return(m, -EINVAL);
5736
5737 return streq(strempty(m->root_container.signature), strempty(signature));
5738}
5739
d9f644e2 5740_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
c430fee6
LP
5741 bool done_something = false;
5742 int r;
5743
80ba3b84
LP
5744 assert_return(m, -EINVAL);
5745 assert_return(source, -EINVAL);
5746 assert_return(!m->sealed, -EPERM);
5747 assert_return(source->sealed, -EPERM);
5748
c430fee6
LP
5749 do {
5750 const char *contents;
5751 char type;
5752 union {
5753 uint8_t u8;
5754 uint16_t u16;
5755 int16_t s16;
5756 uint32_t u32;
5757 int32_t s32;
5758 uint64_t u64;
5759 int64_t s64;
5760 double d64;
5761 const char *string;
5762 int i;
5763 } basic;
5764
5765 r = sd_bus_message_peek_type(source, &type, &contents);
5766 if (r < 0)
5767 return r;
5768 if (r == 0)
5769 break;
5770
5771 done_something = true;
5772
5773 if (bus_type_is_container(type) > 0) {
5774
5775 r = sd_bus_message_enter_container(source, type, contents);
5776 if (r < 0)
5777 return r;
5778
5779 r = sd_bus_message_open_container(m, type, contents);
5780 if (r < 0)
5781 return r;
5782
5783 r = sd_bus_message_copy(m, source, true);
5784 if (r < 0)
5785 return r;
5786
5787 r = sd_bus_message_close_container(m);
5788 if (r < 0)
5789 return r;
5790
5791 r = sd_bus_message_exit_container(source);
5792 if (r < 0)
5793 return r;
5794
5795 continue;
5796 }
5797
5798 r = sd_bus_message_read_basic(source, type, &basic);
5799 if (r < 0)
5800 return r;
5801
5802 assert(r > 0);
5803
945c2931 5804 if (IN_SET(type, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE, SD_BUS_TYPE_STRING))
c430fee6
LP
5805 r = sd_bus_message_append_basic(m, type, basic.string);
5806 else
5807 r = sd_bus_message_append_basic(m, type, &basic);
5808
5809 if (r < 0)
5810 return r;
5811
5812 } while (all);
5813
5814 return done_something;
5815}
5816
d9f644e2 5817_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
c430fee6
LP
5818 const char *c;
5819 char t;
5820 int r;
5821
5822 assert_return(m, -EINVAL);
5823 assert_return(m->sealed, -EPERM);
5824 assert_return(!type || bus_type_is_valid(type), -EINVAL);
5825 assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
5826 assert_return(type || contents, -EINVAL);
5827 assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
5828
5829 r = sd_bus_message_peek_type(m, &t, &c);
5830 if (r <= 0)
5831 return r;
5832
5833 if (type != 0 && type != t)
5834 return 0;
5835
5836 if (contents && !streq_ptr(contents, c))
5837 return 0;
5838
5839 return 1;
5840}
2be44176
LP
5841
5842_public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) {
5843 assert_return(m, NULL);
5844
5845 return m->bus;
5846}
e1c433c6
LP
5847
5848int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
4afd3348 5849 _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL;
e1c433c6
LP
5850 usec_t timeout;
5851 int r;
5852
5853 assert(bus);
5854 assert(m);
5855 assert(*m);
5856
5857 switch ((*m)->header->type) {
5858
5859 case SD_BUS_MESSAGE_SIGNAL:
151b9b96 5860 r = sd_bus_message_new_signal(bus, &n, (*m)->path, (*m)->interface, (*m)->member);
e1c433c6
LP
5861 if (r < 0)
5862 return r;
5863
5864 break;
5865
5866 case SD_BUS_MESSAGE_METHOD_CALL:
151b9b96 5867 r = sd_bus_message_new_method_call(bus, &n, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member);
e1c433c6
LP
5868 if (r < 0)
5869 return r;
5870
5871 break;
5872
5873 case SD_BUS_MESSAGE_METHOD_RETURN:
5874 case SD_BUS_MESSAGE_METHOD_ERROR:
5875
75bcbcf2
SA
5876 r = sd_bus_message_new(bus, &n, (*m)->header->type);
5877 if (r < 0)
e1c433c6
LP
5878 return -ENOMEM;
5879
75bcbcf2
SA
5880 assert(n);
5881
693eb9a2 5882 n->reply_cookie = (*m)->reply_cookie;
b267a6d2
LP
5883
5884 r = message_append_reply_cookie(n, n->reply_cookie);
e1c433c6
LP
5885 if (r < 0)
5886 return r;
5887
5888 if ((*m)->header->type == SD_BUS_MESSAGE_METHOD_ERROR && (*m)->error.name) {
5889 r = message_append_field_string(n, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, (*m)->error.name, &n->error.message);
5890 if (r < 0)
5891 return r;
5892
5893 n->error._need_free = -1;
5894 }
5895
5896 break;
5897
5898 default:
5899 return -EINVAL;
5900 }
5901
5902 if ((*m)->destination && !n->destination) {
5903 r = message_append_field_string(n, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, (*m)->destination, &n->destination);
5904 if (r < 0)
5905 return r;
5906 }
5907
5908 if ((*m)->sender && !n->sender) {
5909 r = message_append_field_string(n, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, (*m)->sender, &n->sender);
5910 if (r < 0)
5911 return r;
5912 }
5913
5914 n->header->flags |= (*m)->header->flags & (BUS_MESSAGE_NO_REPLY_EXPECTED|BUS_MESSAGE_NO_AUTO_START);
5915
5916 r = sd_bus_message_copy(n, *m, true);
5917 if (r < 0)
5918 return r;
5919
5920 timeout = (*m)->timeout;
385b2eb2
YW
5921 if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)) {
5922 r = sd_bus_get_method_call_timeout(bus, &timeout);
5923 if (r < 0)
5924 return r;
5925 }
e1c433c6 5926
75bcbcf2 5927 r = sd_bus_message_seal(n, BUS_MESSAGE_COOKIE(*m), timeout);
e1c433c6
LP
5928 if (r < 0)
5929 return r;
5930
5931 sd_bus_message_unref(*m);
1cc6c93a 5932 *m = TAKE_PTR(n);
e1c433c6
LP
5933
5934 return 0;
5935}
a7639e37 5936
ca7b42c8 5937_public_ int sd_bus_message_get_priority(sd_bus_message *m, int64_t *priority) {
c3362c2f
ZJS
5938 static bool warned = false;
5939
ca7b42c8
LP
5940 assert_return(m, -EINVAL);
5941 assert_return(priority, -EINVAL);
5942
c3362c2f
ZJS
5943 if (!warned) {
5944 log_debug("sd_bus_message_get_priority() is deprecated and always returns 0.");
5945 warned = true;
5946 }
5947
5948 *priority = 0;
ca7b42c8
LP
5949 return 0;
5950}
5951
5952_public_ int sd_bus_message_set_priority(sd_bus_message *m, int64_t priority) {
c3362c2f
ZJS
5953 static bool warned = false;
5954
ca7b42c8
LP
5955 assert_return(m, -EINVAL);
5956 assert_return(!m->sealed, -EPERM);
5957
c3362c2f
ZJS
5958 if (!warned) {
5959 log_debug("sd_bus_message_set_priority() is deprecated and does nothing.");
5960 warned = true;
5961 }
5962
ca7b42c8
LP
5963 return 0;
5964}
7a77d2a4
LP
5965
5966_public_ int sd_bus_message_sensitive(sd_bus_message *m) {
5967 assert_return(m, -EINVAL);
5968
5969 m->sensitive = true;
5970 return 0;
5971}