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