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