]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-message.c
process-util: move PID related macros from macro.h to process-util.h
[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 25
de1c301e 26#include "sd-bus.h"
07630cea
LP
27
28#include "bus-gvariant.h"
de1c301e 29#include "bus-internal.h"
3ffd4af2 30#include "bus-message.h"
de1c301e 31#include "bus-signature.h"
07630cea 32#include "bus-type.h"
057171ef 33#include "bus-util.h"
3ffd4af2 34#include "fd-util.h"
07630cea
LP
35#include "memfd-util.h"
36#include "string-util.h"
37#include "strv.h"
38#include "time-util.h"
39#include "utf8.h"
40#include "util.h"
de1c301e 41
80a46c73 42static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
de1c301e 43
bc7fd8cd
LP
44static void *adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) {
45
46 if (p == NULL)
47 return NULL;
48
49 if (old_base == new_base)
50 return (void*) p;
51
52 if ((uint8_t*) p < (uint8_t*) old_base)
53 return (void*) p;
54
55 if ((uint8_t*) p >= (uint8_t*) old_base + sz)
56 return (void*) p;
57
58 return (uint8_t*) new_base + ((uint8_t*) p - (uint8_t*) old_base);
59}
60
61static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
62 assert(m);
63 assert(part);
64
65 if (part->memfd >= 0) {
66b26c5c
LP
66 /* If we can reuse the memfd, try that. For that it
67 * can't be sealed yet. */
bc7fd8cd 68
becb1a6e
DH
69 if (!part->sealed) {
70 assert(part->memfd_offset == 0);
71 assert(part->data == part->mmap_begin);
8e959fbf 72 bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
becb1a6e 73 } else {
89b4fc46 74 if (part->mapped > 0)
7dcd79c2 75 assert_se(munmap(part->mmap_begin, part->mapped) == 0);
bc7fd8cd 76
03e334a1 77 safe_close(part->memfd);
bc7fd8cd
LP
78 }
79
453a0c29 80 } else if (part->munmap_this)
7dcd79c2 81 munmap(part->mmap_begin, part->mapped);
453a0c29 82 else if (part->free_this)
bc7fd8cd
LP
83 free(part->data);
84
85 if (part != &m->body)
86 free(part);
87}
88
89static void message_reset_parts(sd_bus_message *m) {
90 struct bus_body_part *part;
91
92 assert(m);
93
94 part = &m->body;
95 while (m->n_body_parts > 0) {
96 struct bus_body_part *next = part->next;
97 message_free_part(m, part);
98 part = next;
99 m->n_body_parts--;
100 }
101
102 m->body_end = NULL;
103
104 m->cached_rindex_part = NULL;
105 m->cached_rindex_part_begin = 0;
106}
107
108static void message_reset_containers(sd_bus_message *m) {
9a17484d
LP
109 unsigned i;
110
111 assert(m);
112
6647dc66 113 for (i = 0; i < m->n_containers; i++) {
9a17484d 114 free(m->containers[i].signature);
6647dc66
LP
115 free(m->containers[i].offsets);
116 }
9a17484d 117
a1e58e8e 118 m->containers = mfree(m->containers);
9a17484d 119
306f07be 120 m->n_containers = m->containers_allocated = 0;
9a17484d
LP
121 m->root_container.index = 0;
122}
123
de1c301e 124static void message_free(sd_bus_message *m) {
de1c301e
LP
125 assert(m);
126
127 if (m->free_header)
128 free(m->header);
129
bc7fd8cd 130 message_reset_parts(m);
de1c301e 131
72e61104
LP
132 if (m->release_kdbus)
133 bus_kernel_cmd_free(m->bus, (uint8_t *) m->kdbus - (uint8_t *) m->bus->kdbus_buffer);
fd8d62d9 134
fd989a0b
PDS
135 if (m->free_kdbus)
136 free(m->kdbus);
137
2a0958d2 138 sd_bus_unref(m->bus);
f54514f3 139
2c93b4ef
LP
140 if (m->free_fds) {
141 close_many(m->fds, m->n_fds);
142 free(m->fds);
143 }
de1c301e 144
bc7fd8cd
LP
145 if (m->iovec != m->iovec_fixed)
146 free(m->iovec);
147
f00ef7f5 148 m->destination_ptr = mfree(m->destination_ptr);
bc7fd8cd 149 message_reset_containers(m);
9a17484d 150 free(m->root_container.signature);
6647dc66 151 free(m->root_container.offsets);
de1c301e 152
3798fd4c 153 free(m->root_container.peeked_signature);
d8d3d8a7 154
5b12334d 155 bus_creds_done(&m->creds);
de1c301e
LP
156 free(m);
157}
158
c1b9d935 159static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
c91cb83c
LP
160 void *op, *np;
161 size_t old_size, new_size, start;
de1c301e 162
c91cb83c 163 assert(m);
35460afc
LP
164
165 if (m->poisoned)
166 return NULL;
de1c301e 167
2ac7c17f 168 old_size = sizeof(struct bus_header) + m->fields_size;
c91cb83c
LP
169 start = ALIGN_TO(old_size, align);
170 new_size = start + sz;
de1c301e 171
2ac7c17f
LP
172 if (new_size < start ||
173 new_size > (size_t) ((uint32_t) -1))
174 goto poison;
175
c91cb83c
LP
176 if (old_size == new_size)
177 return (uint8_t*) m->header + old_size;
de1c301e 178
c91cb83c
LP
179 if (m->free_header) {
180 np = realloc(m->header, ALIGN8(new_size));
181 if (!np)
182 goto poison;
183 } else {
184 /* Initially, the header is allocated as part of of
185 * the sd_bus_message itself, let's replace it by
186 * dynamic data */
de1c301e 187
c91cb83c
LP
188 np = malloc(ALIGN8(new_size));
189 if (!np)
190 goto poison;
de1c301e 191
c91cb83c
LP
192 memcpy(np, m->header, sizeof(struct bus_header));
193 }
de1c301e 194
c91cb83c
LP
195 /* Zero out padding */
196 if (start > old_size)
29804cc1 197 memzero((uint8_t*) np + old_size, start - old_size);
bc7fd8cd 198
c91cb83c
LP
199 op = m->header;
200 m->header = np;
2ac7c17f 201 m->fields_size = new_size - sizeof(struct bus_header);
de1c301e 202
bc7fd8cd 203 /* Adjust quick access pointers */
c91cb83c
LP
204 m->path = adjust_pointer(m->path, op, old_size, m->header);
205 m->interface = adjust_pointer(m->interface, op, old_size, m->header);
206 m->member = adjust_pointer(m->member, op, old_size, m->header);
207 m->destination = adjust_pointer(m->destination, op, old_size, m->header);
208 m->sender = adjust_pointer(m->sender, op, old_size, m->header);
209 m->error.name = adjust_pointer(m->error.name, op, old_size, m->header);
bc7fd8cd 210
c91cb83c 211 m->free_header = true;
de1c301e 212
c1b9d935
LP
213 if (add_offset) {
214 if (m->n_header_offsets >= ELEMENTSOF(m->header_offsets))
215 goto poison;
216
217 m->header_offsets[m->n_header_offsets++] = new_size - sizeof(struct bus_header);
218 }
219
c91cb83c
LP
220 return (uint8_t*) np + start;
221
222poison:
223 m->poisoned = true;
224 return NULL;
de1c301e
LP
225}
226
227static int message_append_field_string(
228 sd_bus_message *m,
2ac7c17f 229 uint64_t h,
de1c301e
LP
230 char type,
231 const char *s,
232 const char **ret) {
233
234 size_t l;
235 uint8_t *p;
236
237 assert(m);
238
2ac7c17f
LP
239 /* dbus1 only allows 8bit header field ids */
240 if (h > 0xFF)
241 return -EINVAL;
242
c1b9d935
LP
243 /* dbus1 doesn't allow strings over 32bit, let's enforce this
244 * globally, to not risk convertability */
de1c301e
LP
245 l = strlen(s);
246 if (l > (size_t) (uint32_t) -1)
247 return -EINVAL;
248
c1b9d935
LP
249 /* Signature "(yv)" where the variant contains "s" */
250
6647dc66 251 if (BUS_MESSAGE_IS_GVARIANT(m)) {
de1c301e 252
2ac7c17f
LP
253 /* (field id 64bit, ((string + NUL) + NUL + signature string 's') */
254 p = message_extend_fields(m, 8, 8 + l + 1 + 1 + 1, true);
c1b9d935
LP
255 if (!p)
256 return -ENOMEM;
de1c301e 257
2ac7c17f 258 *((uint64_t*) p) = h;
c1b9d935
LP
259 memcpy(p+8, s, l);
260 p[8+l] = 0;
261 p[8+l+1] = 0;
262 p[8+l+2] = type;
de1c301e 263
c1b9d935 264 if (ret)
6647dc66 265 *ret = (char*) p + 8;
c1b9d935
LP
266
267 } else {
268 /* (field id byte + (signature length + signature 's' + NUL) + (string length + string + NUL)) */
269 p = message_extend_fields(m, 8, 4 + 4 + l + 1, false);
270 if (!p)
271 return -ENOMEM;
272
2ac7c17f 273 p[0] = (uint8_t) h;
c1b9d935
LP
274 p[1] = 1;
275 p[2] = type;
276 p[3] = 0;
277
278 ((uint32_t*) p)[1] = l;
279 memcpy(p + 8, s, l + 1);
280
281 if (ret)
282 *ret = (char*) p + 8;
283 }
de1c301e
LP
284
285 return 0;
286}
287
288static int message_append_field_signature(
289 sd_bus_message *m,
2ac7c17f 290 uint64_t h,
de1c301e
LP
291 const char *s,
292 const char **ret) {
293
294 size_t l;
295 uint8_t *p;
296
297 assert(m);
298
2ac7c17f
LP
299 /* dbus1 only allows 8bit header field ids */
300 if (h > 0xFF)
301 return -EINVAL;
302
303 /* dbus1 doesn't allow signatures over 8bit, let's enforce
c1b9d935 304 * this globally, to not risk convertability */
de1c301e
LP
305 l = strlen(s);
306 if (l > 255)
307 return -EINVAL;
308
c1b9d935
LP
309 /* Signature "(yv)" where the variant contains "g" */
310
6647dc66 311 if (BUS_MESSAGE_IS_GVARIANT(m))
c1b9d935
LP
312 /* For gvariant the serialization is the same as for normal strings */
313 return message_append_field_string(m, h, 'g', s, ret);
314 else {
315 /* (field id byte + (signature length + signature 'g' + NUL) + (string length + string + NUL)) */
316 p = message_extend_fields(m, 8, 4 + 1 + l + 1, false);
317 if (!p)
318 return -ENOMEM;
de1c301e 319
2ac7c17f 320 p[0] = (uint8_t) h;
c1b9d935
LP
321 p[1] = 1;
322 p[2] = SD_BUS_TYPE_SIGNATURE;
323 p[3] = 0;
324 p[4] = l;
325 memcpy(p + 5, s, l + 1);
de1c301e 326
c1b9d935
LP
327 if (ret)
328 *ret = (const char*) p + 5;
329 }
de1c301e
LP
330
331 return 0;
332}
333
2ac7c17f 334static int message_append_field_uint32(sd_bus_message *m, uint64_t h, uint32_t x) {
de1c301e
LP
335 uint8_t *p;
336
337 assert(m);
338
2ac7c17f
LP
339 /* dbus1 only allows 8bit header field ids */
340 if (h > 0xFF)
341 return -EINVAL;
342
6647dc66 343 if (BUS_MESSAGE_IS_GVARIANT(m)) {
2ac7c17f 344 /* (field id 64bit + ((value + NUL + signature string 'u') */
c1b9d935 345
2ac7c17f 346 p = message_extend_fields(m, 8, 8 + 4 + 1 + 1, true);
c1b9d935
LP
347 if (!p)
348 return -ENOMEM;
de1c301e 349
2ac7c17f 350 *((uint64_t*) p) = h;
c1b9d935
LP
351 *((uint32_t*) (p + 8)) = x;
352 p[12] = 0;
353 p[13] = 'u';
354 } else {
355 /* (field id byte + (signature length + signature 'u' + NUL) + value) */
356 p = message_extend_fields(m, 8, 4 + 4, false);
357 if (!p)
358 return -ENOMEM;
359
2ac7c17f 360 p[0] = (uint8_t) h;
c1b9d935 361 p[1] = 1;
2ac7c17f 362 p[2] = 'u';
c1b9d935 363 p[3] = 0;
de1c301e 364
c1b9d935
LP
365 ((uint32_t*) p)[1] = x;
366 }
de1c301e
LP
367
368 return 0;
369}
370
2ac7c17f
LP
371static int message_append_field_uint64(sd_bus_message *m, uint64_t h, uint64_t x) {
372 uint8_t *p;
373
374 assert(m);
375
376 /* dbus1 only allows 8bit header field ids */
377 if (h > 0xFF)
378 return -EINVAL;
379
380 if (BUS_MESSAGE_IS_GVARIANT(m)) {
381 /* (field id 64bit + ((value + NUL + signature string 't') */
382
383 p = message_extend_fields(m, 8, 8 + 8 + 1 + 1, true);
384 if (!p)
385 return -ENOMEM;
386
387 *((uint64_t*) p) = h;
388 *((uint64_t*) (p + 8)) = x;
389 p[16] = 0;
390 p[17] = 't';
391 } else {
392 /* (field id byte + (signature length + signature 't' + NUL) + 4 byte padding + value) */
393 p = message_extend_fields(m, 8, 4 + 4 + 8, false);
394 if (!p)
395 return -ENOMEM;
396
397 p[0] = (uint8_t) h;
398 p[1] = 1;
399 p[2] = 't';
400 p[3] = 0;
401 p[4] = 0;
402 p[5] = 0;
403 p[6] = 0;
404 p[7] = 0;
405
406 ((uint64_t*) p)[1] = x;
407 }
408
409 return 0;
410}
411
b267a6d2
LP
412static int message_append_reply_cookie(sd_bus_message *m, uint64_t cookie) {
413 assert(m);
414
415 if (BUS_MESSAGE_IS_GVARIANT(m))
416 return message_append_field_uint64(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, cookie);
417 else {
418 /* 64bit cookies are not supported on dbus1 */
419 if (cookie > 0xffffffffUL)
15411c0c 420 return -EOPNOTSUPP;
b267a6d2
LP
421
422 return message_append_field_uint32(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, (uint32_t) cookie);
423 }
424}
425
6629161f 426int bus_message_from_header(
df2d202e 427 sd_bus *bus,
2ac7c17f
LP
428 void *header,
429 size_t header_accessible,
430 void *footer,
431 size_t footer_accessible,
432 size_t message_size,
2c93b4ef
LP
433 int *fds,
434 unsigned n_fds,
2571ead1 435 const char *label,
6629161f 436 size_t extra,
2571ead1
LP
437 sd_bus_message **ret) {
438
bcf88fc3 439 _cleanup_free_ sd_bus_message *m = NULL;
80a46c73 440 struct bus_header *h;
6629161f 441 size_t a, label_sz;
80a46c73 442
2a0958d2 443 assert(bus);
2ac7c17f
LP
444 assert(header || header_accessible <= 0);
445 assert(footer || footer_accessible <= 0);
2c93b4ef 446 assert(fds || n_fds <= 0);
80a46c73
LP
447 assert(ret);
448
2ac7c17f 449 if (header_accessible < sizeof(struct bus_header))
80a46c73
LP
450 return -EBADMSG;
451
2ac7c17f
LP
452 if (header_accessible > message_size)
453 return -EBADMSG;
454 if (footer_accessible > message_size)
80a46c73
LP
455 return -EBADMSG;
456
2ac7c17f 457 h = header;
bcf88fc3 458 if (!IN_SET(h->version, 1, 2))
954871d8
KS
459 return -EBADMSG;
460
80a46c73
LP
461 if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
462 return -EBADMSG;
463
bcf88fc3 464 if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
80a46c73
LP
465 return -EBADMSG;
466
2ac7c17f
LP
467 /* Note that we are happy with unknown flags in the flags header! */
468
6629161f 469 a = ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
80a46c73 470
2571ead1
LP
471 if (label) {
472 label_sz = strlen(label);
6629161f
LP
473 a += label_sz + 1;
474 }
2571ead1
LP
475
476 m = malloc0(a);
80a46c73
LP
477 if (!m)
478 return -ENOMEM;
479
480 m->n_ref = 1;
2c93b4ef 481 m->sealed = true;
2ac7c17f
LP
482 m->header = header;
483 m->header_accessible = header_accessible;
484 m->footer = footer;
485 m->footer_accessible = footer_accessible;
486
487 if (BUS_MESSAGE_IS_GVARIANT(m)) {
488 size_t ws;
489
490 if (h->dbus2.cookie == 0)
491 return -EBADMSG;
492
493 /* dbus2 derives the sizes from the message size and
494 the offset table at the end, since it is formatted as
495 gvariant "yyyyuta{tv}v". Since the message itself is a
496 structure with precisely to variable sized entries,
497 there's only one offset in the table, which marks the
498 end of the fields array. */
499
500 ws = bus_gvariant_determine_word_size(message_size, 0);
501 if (footer_accessible < ws)
502 return -EBADMSG;
503
504 m->fields_size = bus_gvariant_read_word_le((uint8_t*) footer + footer_accessible - ws, ws);
505 if (ALIGN8(m->fields_size) > message_size - ws)
506 return -EBADMSG;
507 if (m->fields_size < sizeof(struct bus_header))
508 return -EBADMSG;
509
510 m->fields_size -= sizeof(struct bus_header);
511 m->body_size = message_size - (sizeof(struct bus_header) + ALIGN8(m->fields_size));
512 } else {
513 if (h->dbus1.serial == 0)
514 return -EBADMSG;
515
516 /* dbus1 has the sizes in the header */
517 m->fields_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.fields_size);
518 m->body_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.body_size);
519
520 if (sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size != message_size)
521 return -EBADMSG;
522 }
523
2c93b4ef
LP
524 m->fds = fds;
525 m->n_fds = n_fds;
80a46c73 526
2571ead1 527 if (label) {
5b12334d
LP
528 m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
529 memcpy(m->creds.label, label, label_sz + 1);
530
531 m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
2571ead1
LP
532 }
533
2a0958d2 534 m->bus = sd_bus_ref(bus);
6629161f 535 *ret = m;
bcf88fc3 536 m = NULL;
2a0958d2 537
6629161f
LP
538 return 0;
539}
540
541int bus_message_from_malloc(
df2d202e 542 sd_bus *bus,
6629161f
LP
543 void *buffer,
544 size_t length,
545 int *fds,
546 unsigned n_fds,
6629161f
LP
547 const char *label,
548 sd_bus_message **ret) {
549
550 sd_bus_message *m;
5461f53f 551 size_t sz;
6629161f
LP
552 int r;
553
2ac7c17f
LP
554 r = bus_message_from_header(
555 bus,
556 buffer, length, /* in this case the initial bytes and the final bytes are the same */
557 buffer, length,
558 length,
559 fds, n_fds,
aa0d0ed6 560 label,
2ac7c17f 561 0, &m);
6629161f
LP
562 if (r < 0)
563 return r;
564
2ac7c17f 565 sz = length - sizeof(struct bus_header) - ALIGN8(m->fields_size);
5461f53f
LP
566 if (sz > 0) {
567 m->n_body_parts = 1;
2ac7c17f 568 m->body.data = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(m->fields_size);
5461f53f
LP
569 m->body.size = sz;
570 m->body.sealed = true;
571 m->body.memfd = -1;
572 }
6629161f 573
80a46c73 574 m->n_iovec = 1;
bc7fd8cd 575 m->iovec = m->iovec_fixed;
80a46c73
LP
576 m->iovec[0].iov_base = buffer;
577 m->iovec[0].iov_len = length;
578
6629161f 579 r = bus_message_parse_fields(m);
2c93b4ef
LP
580 if (r < 0)
581 goto fail;
582
583 /* We take possession of the memory and fds now */
584 m->free_header = true;
585 m->free_fds = true;
80a46c73
LP
586
587 *ret = m;
588 return 0;
2c93b4ef
LP
589
590fail:
591 message_free(m);
592 return r;
80a46c73
LP
593}
594
de1c301e
LP
595static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
596 sd_bus_message *m;
597
2a0958d2
LP
598 assert(bus);
599
80a46c73 600 m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
de1c301e
LP
601 if (!m)
602 return NULL;
603
604 m->n_ref = 1;
605 m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message)));
0461f8cd 606 m->header->endian = BUS_NATIVE_ENDIAN;
de1c301e 607 m->header->type = type;
37286ade 608 m->header->version = bus->message_version;
609 m->allow_fds = bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING);
6647dc66 610 m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m);
2a0958d2 611 m->bus = sd_bus_ref(bus);
9b05bc48 612
c0765ddb
LP
613 if (bus->allow_interactive_authorization)
614 m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
615
de1c301e
LP
616 return m;
617}
618
d9f644e2 619_public_ int sd_bus_message_new_signal(
de1c301e 620 sd_bus *bus,
151b9b96 621 sd_bus_message **m,
de1c301e
LP
622 const char *path,
623 const char *interface,
151b9b96 624 const char *member) {
de1c301e
LP
625
626 sd_bus_message *t;
627 int r;
628
2a0958d2
LP
629 assert_return(bus, -ENOTCONN);
630 assert_return(bus->state != BUS_UNSET, -ENOTCONN);
9d6c7c82
LP
631 assert_return(object_path_is_valid(path), -EINVAL);
632 assert_return(interface_name_is_valid(interface), -EINVAL);
633 assert_return(member_name_is_valid(member), -EINVAL);
634 assert_return(m, -EINVAL);
de1c301e 635
40ca29a1 636 t = message_new(bus, SD_BUS_MESSAGE_SIGNAL);
de1c301e
LP
637 if (!t)
638 return -ENOMEM;
639
0461f8cd 640 t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
89ffcd2a 641
0461f8cd 642 r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
de1c301e
LP
643 if (r < 0)
644 goto fail;
0461f8cd 645 r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
de1c301e
LP
646 if (r < 0)
647 goto fail;
0461f8cd 648 r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
de1c301e
LP
649 if (r < 0)
650 goto fail;
651
652 *m = t;
653 return 0;
654
655fail:
656 sd_bus_message_unref(t);
657 return r;
658}
659
d9f644e2 660_public_ int sd_bus_message_new_method_call(
de1c301e 661 sd_bus *bus,
151b9b96 662 sd_bus_message **m,
de1c301e
LP
663 const char *destination,
664 const char *path,
665 const char *interface,
151b9b96 666 const char *member) {
de1c301e
LP
667
668 sd_bus_message *t;
669 int r;
670
2a0958d2
LP
671 assert_return(bus, -ENOTCONN);
672 assert_return(bus->state != BUS_UNSET, -ENOTCONN);
9d6c7c82
LP
673 assert_return(!destination || service_name_is_valid(destination), -EINVAL);
674 assert_return(object_path_is_valid(path), -EINVAL);
675 assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
676 assert_return(member_name_is_valid(member), -EINVAL);
677 assert_return(m, -EINVAL);
de1c301e 678
40ca29a1 679 t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL);
de1c301e
LP
680 if (!t)
681 return -ENOMEM;
682
0461f8cd 683 r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
de1c301e
LP
684 if (r < 0)
685 goto fail;
0461f8cd 686 r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
de1c301e
LP
687 if (r < 0)
688 goto fail;
689
690 if (interface) {
0461f8cd 691 r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
de1c301e
LP
692 if (r < 0)
693 goto fail;
694 }
695
696 if (destination) {
0461f8cd 697 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination);
de1c301e
LP
698 if (r < 0)
699 goto fail;
700 }
701
702 *m = t;
703 return 0;
704
705fail:
706 message_free(t);
707 return r;
708}
709
5407f2de 710static int message_new_reply(
de1c301e 711 sd_bus_message *call,
5407f2de 712 uint8_t type,
de1c301e
LP
713 sd_bus_message **m) {
714
715 sd_bus_message *t;
716 int r;
717
9d6c7c82
LP
718 assert_return(call, -EINVAL);
719 assert_return(call->sealed, -EPERM);
720 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
2a0958d2 721 assert_return(call->bus->state != BUS_UNSET, -ENOTCONN);
9d6c7c82 722 assert_return(m, -EINVAL);
de1c301e 723
df2d202e 724 t = message_new(call->bus, type);
de1c301e
LP
725 if (!t)
726 return -ENOMEM;
727
0461f8cd 728 t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
693eb9a2 729 t->reply_cookie = BUS_MESSAGE_COOKIE(call);
2ac7c17f 730 if (t->reply_cookie == 0)
15411c0c 731 return -EOPNOTSUPP;
b381de41 732
b267a6d2 733 r = message_append_reply_cookie(t, t->reply_cookie);
de1c301e
LP
734 if (r < 0)
735 goto fail;
736
737 if (call->sender) {
0461f8cd 738 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination);
de1c301e
LP
739 if (r < 0)
740 goto fail;
741 }
742
0461f8cd 743 t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
6717d473 744 t->enforced_reply_signature = call->enforced_reply_signature;
5407f2de 745
de1c301e 746 *m = t;
89ffcd2a 747 return 0;
de1c301e
LP
748
749fail:
750 message_free(t);
751 return r;
752}
753
d9f644e2 754_public_ int sd_bus_message_new_method_return(
5407f2de
LP
755 sd_bus_message *call,
756 sd_bus_message **m) {
757
df2d202e 758 return message_new_reply(call, SD_BUS_MESSAGE_METHOD_RETURN, m);
5407f2de
LP
759}
760
d9f644e2 761_public_ int sd_bus_message_new_method_error(
de1c301e 762 sd_bus_message *call,
151b9b96
LP
763 sd_bus_message **m,
764 const sd_bus_error *e) {
de1c301e
LP
765
766 sd_bus_message *t;
767 int r;
768
9d6c7c82
LP
769 assert_return(sd_bus_error_is_set(e), -EINVAL);
770 assert_return(m, -EINVAL);
de1c301e 771
df2d202e 772 r = message_new_reply(call, SD_BUS_MESSAGE_METHOD_ERROR, &t);
de1c301e 773 if (r < 0)
5407f2de 774 return r;
de1c301e 775
0461f8cd 776 r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
de1c301e
LP
777 if (r < 0)
778 goto fail;
779
780 if (e->message) {
781 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
782 if (r < 0)
783 goto fail;
784 }
785
79f8d3d2
LP
786 t->error._need_free = -1;
787
de1c301e
LP
788 *m = t;
789 return 0;
790
791fail:
792 message_free(t);
793 return r;
794}
795
d9f644e2 796_public_ int sd_bus_message_new_method_errorf(
29ddb38f
LP
797 sd_bus_message *call,
798 sd_bus_message **m,
799 const char *name,
800 const char *format,
801 ...) {
802
dcf69520 803 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
29ddb38f 804 va_list ap;
29ddb38f 805
40ca29a1
LP
806 assert_return(name, -EINVAL);
807 assert_return(m, -EINVAL);
808
809 va_start(ap, format);
780896a4 810 bus_error_setfv(&error, name, format, ap);
40ca29a1 811 va_end(ap);
29ddb38f 812
151b9b96 813 return sd_bus_message_new_method_error(call, m, &error);
40ca29a1 814}
29ddb38f 815
d9f644e2 816_public_ int sd_bus_message_new_method_errno(
40ca29a1 817 sd_bus_message *call,
151b9b96 818 sd_bus_message **m,
40ca29a1 819 int error,
151b9b96 820 const sd_bus_error *p) {
29ddb38f 821
dcf69520 822 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
29ddb38f 823
40ca29a1 824 if (sd_bus_error_is_set(p))
151b9b96 825 return sd_bus_message_new_method_error(call, m, p);
29ddb38f 826
40ca29a1 827 sd_bus_error_set_errno(&berror, error);
29ddb38f 828
151b9b96 829 return sd_bus_message_new_method_error(call, m, &berror);
40ca29a1 830}
29ddb38f 831
d9f644e2 832_public_ int sd_bus_message_new_method_errnof(
40ca29a1
LP
833 sd_bus_message *call,
834 sd_bus_message **m,
835 int error,
836 const char *format,
837 ...) {
838
dcf69520 839 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
40ca29a1 840 va_list ap;
40ca29a1
LP
841
842 va_start(ap, format);
07a0d22f 843 sd_bus_error_set_errnofv(&berror, error, format, ap);
40ca29a1
LP
844 va_end(ap);
845
151b9b96 846 return sd_bus_message_new_method_error(call, m, &berror);
29ddb38f
LP
847}
848
d29ae291
LP
849void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m) {
850 assert(bus);
851 assert(m);
852
853 m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus.Local";
854 m->creds.well_known_names_local = true;
855 m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
856}
857
858void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m) {
859 assert(bus);
860 assert(m);
861
862 m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
863 m->creds.well_known_names_driver = true;
864 m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
865}
866
eb01ba5d
LP
867int bus_message_new_synthetic_error(
868 sd_bus *bus,
693eb9a2 869 uint64_t cookie,
eb01ba5d
LP
870 const sd_bus_error *e,
871 sd_bus_message **m) {
872
873 sd_bus_message *t;
874 int r;
875
2a0958d2 876 assert(bus);
eb01ba5d
LP
877 assert(sd_bus_error_is_set(e));
878 assert(m);
879
40ca29a1 880 t = message_new(bus, SD_BUS_MESSAGE_METHOD_ERROR);
eb01ba5d
LP
881 if (!t)
882 return -ENOMEM;
883
0461f8cd 884 t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
693eb9a2 885 t->reply_cookie = cookie;
eb01ba5d 886
b267a6d2 887 r = message_append_reply_cookie(t, t->reply_cookie);
eb01ba5d
LP
888 if (r < 0)
889 goto fail;
890
891 if (bus && bus->unique_name) {
0461f8cd 892 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination);
eb01ba5d
LP
893 if (r < 0)
894 goto fail;
895 }
896
0461f8cd 897 r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
3a7d4f1b
LP
898 if (r < 0)
899 goto fail;
900
901 if (e->message) {
902 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
903 if (r < 0)
904 goto fail;
905 }
906
79f8d3d2
LP
907 t->error._need_free = -1;
908
d29ae291
LP
909 bus_message_set_sender_driver(bus, t);
910
eb01ba5d
LP
911 *m = t;
912 return 0;
913
914fail:
915 message_free(t);
916 return r;
917}
918
d9f644e2 919_public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
9d6c7c82 920 assert_return(m, NULL);
de1c301e
LP
921
922 assert(m->n_ref > 0);
923 m->n_ref++;
924
925 return m;
926}
927
d9f644e2 928_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
5b1bc83f
LP
929
930 if (!m)
931 return NULL;
de1c301e
LP
932
933 assert(m->n_ref > 0);
934 m->n_ref--;
935
b5eca3a2
LP
936 if (m->n_ref > 0)
937 return NULL;
de1c301e 938
b5eca3a2 939 message_free(m);
de1c301e
LP
940 return NULL;
941}
942
d9f644e2 943_public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
9d6c7c82
LP
944 assert_return(m, -EINVAL);
945 assert_return(type, -EINVAL);
de1c301e
LP
946
947 *type = m->header->type;
948 return 0;
949}
950
693eb9a2 951_public_ int sd_bus_message_get_cookie(sd_bus_message *m, uint64_t *cookie) {
2ac7c17f
LP
952 uint64_t c;
953
9d6c7c82 954 assert_return(m, -EINVAL);
693eb9a2 955 assert_return(cookie, -EINVAL);
2ac7c17f
LP
956
957 c = BUS_MESSAGE_COOKIE(m);
958 if (c == 0)
959 return -ENODATA;
de1c301e 960
693eb9a2 961 *cookie = BUS_MESSAGE_COOKIE(m);
de1c301e
LP
962 return 0;
963}
964
693eb9a2 965_public_ int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie) {
9d6c7c82 966 assert_return(m, -EINVAL);
693eb9a2 967 assert_return(cookie, -EINVAL);
2ac7c17f
LP
968
969 if (m->reply_cookie == 0)
970 return -ENODATA;
de1c301e 971
693eb9a2 972 *cookie = m->reply_cookie;
de1c301e
LP
973 return 0;
974}
975
eee9ec0e 976_public_ int sd_bus_message_get_expect_reply(sd_bus_message *m) {
9d6c7c82 977 assert_return(m, -EINVAL);
de1c301e 978
eee9ec0e
LP
979 return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
980 !(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
de1c301e
LP
981}
982
eee9ec0e 983_public_ int sd_bus_message_get_auto_start(sd_bus_message *m) {
1fee9de5
LP
984 assert_return(m, -EINVAL);
985
eee9ec0e 986 return !(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
1fee9de5
LP
987}
988
53a83f4b
LP
989_public_ int sd_bus_message_get_allow_interactive_authorization(sd_bus_message *m) {
990 assert_return(m, -EINVAL);
991
992 return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
993 (m->header->flags & BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION);
994}
995
d9f644e2 996_public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
9d6c7c82 997 assert_return(m, NULL);
de1c301e
LP
998
999 return m->path;
1000}
1001
d9f644e2 1002_public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
9d6c7c82 1003 assert_return(m, NULL);
de1c301e
LP
1004
1005 return m->interface;
1006}
1007
d9f644e2 1008_public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
9d6c7c82 1009 assert_return(m, NULL);
de1c301e
LP
1010
1011 return m->member;
1012}
d9f644e2
ZJS
1013
1014_public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
9d6c7c82 1015 assert_return(m, NULL);
de1c301e
LP
1016
1017 return m->destination;
1018}
1019
d9f644e2 1020_public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
9d6c7c82 1021 assert_return(m, NULL);
de1c301e
LP
1022
1023 return m->sender;
1024}
1025
d9f644e2 1026_public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
9d6c7c82 1027 assert_return(m, NULL);
f02b9615
LP
1028
1029 if (!sd_bus_error_is_set(&m->error))
1030 return 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 2688 assert_return(m, -EINVAL);
8ac43fee 2689 assert_return(memfd >= 0, -EBADF);
7dcd79c2
LP
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);
8ac43fee 2765 assert_return(memfd >= 0, -EBADF);
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
eccd47c5
LP
5618static int bus_message_get_arg_skip(
5619 sd_bus_message *m,
5620 unsigned i,
5621 char *_type,
5622 const char **_contents) {
5623
42c5aaf3 5624 unsigned j;
198b158f 5625 int r;
392d5b37 5626
392d5b37
LP
5627 r = sd_bus_message_rewind(m, true);
5628 if (r < 0)
198b158f 5629 return r;
392d5b37 5630
198b158f 5631 for (j = 0;; j++) {
eccd47c5
LP
5632 const char *contents;
5633 char type;
5634
198b158f
LP
5635 r = sd_bus_message_peek_type(m, &type, &contents);
5636 if (r < 0)
5637 return r;
5638 if (r == 0)
5639 return -ENXIO;
5640
5641 /* Don't match against arguments after the first one we don't understand */
5642 if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE) &&
5643 !(type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")))
5644 return -ENXIO;
42c5aaf3 5645
eccd47c5
LP
5646 if (j >= i) {
5647 if (_contents)
5648 *_contents = contents;
5649 if (_type)
5650 *_type = type;
5651 return 0;
5652 }
198b158f
LP
5653
5654 r = sd_bus_message_skip(m, NULL);
392d5b37 5655 if (r < 0)
198b158f
LP
5656 return r;
5657 }
392d5b37 5658
eccd47c5 5659}
392d5b37 5660
eccd47c5
LP
5661int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str) {
5662 char type;
5663 int r;
198b158f 5664
eccd47c5
LP
5665 assert(m);
5666 assert(str);
198b158f 5667
eccd47c5
LP
5668 r = bus_message_get_arg_skip(m, i, &type, NULL);
5669 if (r < 0)
5670 return r;
198b158f 5671
eccd47c5
LP
5672 if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE))
5673 return -ENXIO;
392d5b37 5674
eccd47c5
LP
5675 return sd_bus_message_read_basic(m, type, str);
5676}
5677
5678int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv) {
5679 const char *contents;
5680 char type;
5681 int r;
5682
5683 assert(m);
5684 assert(strv);
5685
5686 r = bus_message_get_arg_skip(m, i, &type, &contents);
5687 if (r < 0)
5688 return r;
5689
5690 if (type != SD_BUS_TYPE_ARRAY)
5691 return -ENXIO;
5692 if (!STR_IN_SET(contents, "s", "o", "g"))
5693 return -ENXIO;
5694
5695 return sd_bus_message_read_strv(m, strv);
392d5b37 5696}
2100fa10 5697
d9f644e2 5698_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
b49ffb29 5699 assert_return(m, EINVAL);
eb01ba5d 5700
40ca29a1 5701 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
eb01ba5d
LP
5702 return 0;
5703
40ca29a1 5704 return sd_bus_error_get_errno(&m->error);
eb01ba5d 5705}
29ddb38f 5706
d9f644e2 5707_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
29ddb38f
LP
5708 struct bus_container *c;
5709
9d6c7c82 5710 assert_return(m, NULL);
29ddb38f
LP
5711
5712 c = complete ? &m->root_container : message_get_container(m);
d6385068 5713 return strempty(c->signature);
29ddb38f 5714}
c430fee6 5715
8022212b
LP
5716_public_ int sd_bus_message_is_empty(sd_bus_message *m) {
5717 assert_return(m, -EINVAL);
5718
5719 return isempty(m->root_container.signature);
5720}
5721
64e96a19
LP
5722_public_ int sd_bus_message_has_signature(sd_bus_message *m, const char *signature) {
5723 assert_return(m, -EINVAL);
5724
5725 return streq(strempty(m->root_container.signature), strempty(signature));
5726}
5727
d9f644e2 5728_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
c430fee6
LP
5729 bool done_something = false;
5730 int r;
5731
80ba3b84
LP
5732 assert_return(m, -EINVAL);
5733 assert_return(source, -EINVAL);
5734 assert_return(!m->sealed, -EPERM);
5735 assert_return(source->sealed, -EPERM);
5736
c430fee6
LP
5737 do {
5738 const char *contents;
5739 char type;
5740 union {
5741 uint8_t u8;
5742 uint16_t u16;
5743 int16_t s16;
5744 uint32_t u32;
5745 int32_t s32;
5746 uint64_t u64;
5747 int64_t s64;
5748 double d64;
5749 const char *string;
5750 int i;
5751 } basic;
5752
5753 r = sd_bus_message_peek_type(source, &type, &contents);
5754 if (r < 0)
5755 return r;
5756 if (r == 0)
5757 break;
5758
5759 done_something = true;
5760
5761 if (bus_type_is_container(type) > 0) {
5762
5763 r = sd_bus_message_enter_container(source, type, contents);
5764 if (r < 0)
5765 return r;
5766
5767 r = sd_bus_message_open_container(m, type, contents);
5768 if (r < 0)
5769 return r;
5770
5771 r = sd_bus_message_copy(m, source, true);
5772 if (r < 0)
5773 return r;
5774
5775 r = sd_bus_message_close_container(m);
5776 if (r < 0)
5777 return r;
5778
5779 r = sd_bus_message_exit_container(source);
5780 if (r < 0)
5781 return r;
5782
5783 continue;
5784 }
5785
5786 r = sd_bus_message_read_basic(source, type, &basic);
5787 if (r < 0)
5788 return r;
5789
5790 assert(r > 0);
5791
5792 if (type == SD_BUS_TYPE_OBJECT_PATH ||
5793 type == SD_BUS_TYPE_SIGNATURE ||
5794 type == SD_BUS_TYPE_STRING)
5795 r = sd_bus_message_append_basic(m, type, basic.string);
5796 else
5797 r = sd_bus_message_append_basic(m, type, &basic);
5798
5799 if (r < 0)
5800 return r;
5801
5802 } while (all);
5803
5804 return done_something;
5805}
5806
d9f644e2 5807_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
c430fee6
LP
5808 const char *c;
5809 char t;
5810 int r;
5811
5812 assert_return(m, -EINVAL);
5813 assert_return(m->sealed, -EPERM);
5814 assert_return(!type || bus_type_is_valid(type), -EINVAL);
5815 assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
5816 assert_return(type || contents, -EINVAL);
5817 assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
5818
5819 r = sd_bus_message_peek_type(m, &t, &c);
5820 if (r <= 0)
5821 return r;
5822
5823 if (type != 0 && type != t)
5824 return 0;
5825
5826 if (contents && !streq_ptr(contents, c))
5827 return 0;
5828
5829 return 1;
5830}
2be44176
LP
5831
5832_public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) {
5833 assert_return(m, NULL);
5834
5835 return m->bus;
5836}
e1c433c6
LP
5837
5838int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
5839 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
5840 usec_t timeout;
5841 int r;
5842
5843 assert(bus);
5844 assert(m);
5845 assert(*m);
5846
5847 switch ((*m)->header->type) {
5848
5849 case SD_BUS_MESSAGE_SIGNAL:
151b9b96 5850 r = sd_bus_message_new_signal(bus, &n, (*m)->path, (*m)->interface, (*m)->member);
e1c433c6
LP
5851 if (r < 0)
5852 return r;
5853
5854 break;
5855
5856 case SD_BUS_MESSAGE_METHOD_CALL:
151b9b96 5857 r = sd_bus_message_new_method_call(bus, &n, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member);
e1c433c6
LP
5858 if (r < 0)
5859 return r;
5860
5861 break;
5862
5863 case SD_BUS_MESSAGE_METHOD_RETURN:
5864 case SD_BUS_MESSAGE_METHOD_ERROR:
5865
5866 n = message_new(bus, (*m)->header->type);
5867 if (!n)
5868 return -ENOMEM;
5869
693eb9a2 5870 n->reply_cookie = (*m)->reply_cookie;
b267a6d2
LP
5871
5872 r = message_append_reply_cookie(n, n->reply_cookie);
e1c433c6
LP
5873 if (r < 0)
5874 return r;
5875
5876 if ((*m)->header->type == SD_BUS_MESSAGE_METHOD_ERROR && (*m)->error.name) {
5877 r = message_append_field_string(n, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, (*m)->error.name, &n->error.message);
5878 if (r < 0)
5879 return r;
5880
5881 n->error._need_free = -1;
5882 }
5883
5884 break;
5885
5886 default:
5887 return -EINVAL;
5888 }
5889
5890 if ((*m)->destination && !n->destination) {
5891 r = message_append_field_string(n, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, (*m)->destination, &n->destination);
5892 if (r < 0)
5893 return r;
5894 }
5895
5896 if ((*m)->sender && !n->sender) {
5897 r = message_append_field_string(n, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, (*m)->sender, &n->sender);
5898 if (r < 0)
5899 return r;
5900 }
5901
5902 n->header->flags |= (*m)->header->flags & (BUS_MESSAGE_NO_REPLY_EXPECTED|BUS_MESSAGE_NO_AUTO_START);
5903
5904 r = sd_bus_message_copy(n, *m, true);
5905 if (r < 0)
5906 return r;
5907
5908 timeout = (*m)->timeout;
5909 if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED))
5910 timeout = BUS_DEFAULT_TIMEOUT;
5911
693eb9a2 5912 r = bus_message_seal(n, BUS_MESSAGE_COOKIE(*m), timeout);
e1c433c6
LP
5913 if (r < 0)
5914 return r;
5915
5916 sd_bus_message_unref(*m);
5917 *m = n;
5918 n = NULL;
5919
5920 return 0;
5921}
a7639e37
LP
5922
5923int bus_message_append_sender(sd_bus_message *m, const char *sender) {
5924 assert(m);
5925 assert(sender);
5926
5927 assert_return(!m->sealed, -EPERM);
5928 assert_return(!m->sender, -EPERM);
5929
5930 return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
5931}
ca7b42c8
LP
5932
5933_public_ int sd_bus_message_get_priority(sd_bus_message *m, int64_t *priority) {
5934 assert_return(m, -EINVAL);
5935 assert_return(priority, -EINVAL);
5936
5937 *priority = m->priority;
5938 return 0;
5939}
5940
5941_public_ int sd_bus_message_set_priority(sd_bus_message *m, int64_t priority) {
5942 assert_return(m, -EINVAL);
5943 assert_return(!m->sealed, -EPERM);
5944
5945 m->priority = priority;
5946 return 0;
5947}