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