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