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