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