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