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