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