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