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