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