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