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