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