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