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