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