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