]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-message.c
bus: properly deserialize gvariant fixed size arrays
[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);
de1c301e 164
c91cb83c 165 if (m->poisoned)
de1c301e
LP
166 return NULL;
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) {
9d6c7c82 794 assert_return(m, NULL);
de1c301e
LP
795
796 assert(m->n_ref > 0);
797 m->n_ref--;
798
799 if (m->n_ref <= 0)
800 message_free(m);
801
802 return NULL;
803}
804
d9f644e2 805_public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
9d6c7c82
LP
806 assert_return(m, -EINVAL);
807 assert_return(type, -EINVAL);
de1c301e
LP
808
809 *type = m->header->type;
810 return 0;
811}
812
d9f644e2 813_public_ int sd_bus_message_get_serial(sd_bus_message *m, uint64_t *serial) {
9d6c7c82
LP
814 assert_return(m, -EINVAL);
815 assert_return(serial, -EINVAL);
816 assert_return(m->header->serial != 0, -ENOENT);
de1c301e
LP
817
818 *serial = BUS_MESSAGE_SERIAL(m);
819 return 0;
820}
821
d9f644e2 822_public_ int sd_bus_message_get_reply_serial(sd_bus_message *m, uint64_t *serial) {
9d6c7c82
LP
823 assert_return(m, -EINVAL);
824 assert_return(serial, -EINVAL);
825 assert_return(m->reply_serial != 0, -ENOENT);
de1c301e
LP
826
827 *serial = m->reply_serial;
828 return 0;
829}
830
d9f644e2 831_public_ int sd_bus_message_get_no_reply(sd_bus_message *m) {
9d6c7c82 832 assert_return(m, -EINVAL);
de1c301e 833
0461f8cd 834 return m->header->type == SD_BUS_MESSAGE_METHOD_CALL ? !!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) : 0;
de1c301e
LP
835}
836
1fee9de5
LP
837_public_ int sd_bus_message_get_no_auto_start(sd_bus_message *m) {
838 assert_return(m, -EINVAL);
839
0461f8cd 840 return !!(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
1fee9de5
LP
841}
842
d9f644e2 843_public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
9d6c7c82 844 assert_return(m, NULL);
de1c301e
LP
845
846 return m->path;
847}
848
d9f644e2 849_public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
9d6c7c82 850 assert_return(m, NULL);
de1c301e
LP
851
852 return m->interface;
853}
854
d9f644e2 855_public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
9d6c7c82 856 assert_return(m, NULL);
de1c301e
LP
857
858 return m->member;
859}
d9f644e2
ZJS
860
861_public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
9d6c7c82 862 assert_return(m, NULL);
de1c301e
LP
863
864 return m->destination;
865}
866
d9f644e2 867_public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
9d6c7c82 868 assert_return(m, NULL);
de1c301e
LP
869
870 return m->sender;
871}
872
d9f644e2 873_public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
9d6c7c82
LP
874 assert_return(m, NULL);
875 assert_return(sd_bus_error_is_set(&m->error), NULL);
de1c301e
LP
876
877 return &m->error;
878}
879
d9f644e2 880_public_ int sd_bus_message_get_monotonic_timestamp(sd_bus_message *m, uint64_t *usec) {
9d6c7c82
LP
881 assert_return(m, -EINVAL);
882 assert_return(usec, -EINVAL);
5b12334d 883 assert_return(m->monotonic > 0, -ENODATA);
acb5a3cb 884
69aec65c 885 *usec = m->monotonic;
acb5a3cb
LP
886 return 0;
887}
888
d9f644e2 889_public_ int sd_bus_message_get_realtime_timestamp(sd_bus_message *m, uint64_t *usec) {
9d6c7c82
LP
890 assert_return(m, -EINVAL);
891 assert_return(usec, -EINVAL);
5b12334d 892 assert_return(m->realtime > 0, -ENODATA);
69aec65c
LP
893
894 *usec = m->realtime;
895 return 0;
896}
897
5b12334d
LP
898_public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) {
899 assert_return(m, NULL);
102ea8e4 900
5b12334d
LP
901 if (m->creds.mask == 0)
902 return NULL;
102ea8e4 903
5b12334d 904 return &m->creds;
102ea8e4
LP
905}
906
d9f644e2
ZJS
907_public_ int sd_bus_message_is_signal(sd_bus_message *m,
908 const char *interface,
909 const char *member) {
9d6c7c82 910 assert_return(m, -EINVAL);
de1c301e 911
40ca29a1 912 if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
de1c301e
LP
913 return 0;
914
915 if (interface && (!m->interface || !streq(m->interface, interface)))
916 return 0;
917
918 if (member && (!m->member || !streq(m->member, member)))
919 return 0;
920
921 return 1;
922}
923
d9f644e2
ZJS
924_public_ int sd_bus_message_is_method_call(sd_bus_message *m,
925 const char *interface,
926 const char *member) {
9d6c7c82 927 assert_return(m, -EINVAL);
de1c301e 928
40ca29a1 929 if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
de1c301e
LP
930 return 0;
931
932 if (interface && (!m->interface || !streq(m->interface, interface)))
933 return 0;
934
935 if (member && (!m->member || !streq(m->member, member)))
936 return 0;
937
938 return 1;
939}
940
d9f644e2 941_public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
9d6c7c82 942 assert_return(m, -EINVAL);
de1c301e 943
40ca29a1 944 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
de1c301e
LP
945 return 0;
946
947 if (name && (!m->error.name || !streq(m->error.name, name)))
948 return 0;
949
950 return 1;
951}
952
d9f644e2 953_public_ int sd_bus_message_set_no_reply(sd_bus_message *m, int b) {
9d6c7c82
LP
954 assert_return(m, -EINVAL);
955 assert_return(!m->sealed, -EPERM);
956 assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
de1c301e
LP
957
958 if (b)
0461f8cd 959 m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
de1c301e 960 else
0461f8cd 961 m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED;
de1c301e
LP
962
963 return 0;
964}
965
1fee9de5
LP
966_public_ int sd_bus_message_set_no_auto_start(sd_bus_message *m, int b) {
967 assert_return(m, -EINVAL);
968 assert_return(!m->sealed, -EPERM);
969
970 if (b)
0461f8cd 971 m->header->flags |= BUS_MESSAGE_NO_AUTO_START;
1fee9de5 972 else
0461f8cd 973 m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START;
1fee9de5
LP
974
975 return 0;
976}
977
de1c301e
LP
978static struct bus_container *message_get_container(sd_bus_message *m) {
979 assert(m);
980
981 if (m->n_containers == 0)
982 return &m->root_container;
983
9a17484d
LP
984 assert(m->containers);
985 return m->containers + m->n_containers - 1;
de1c301e
LP
986}
987
bc7fd8cd
LP
988struct bus_body_part *message_append_part(sd_bus_message *m) {
989 struct bus_body_part *part;
990
991 assert(m);
992
993 if (m->poisoned)
994 return NULL;
995
996 if (m->n_body_parts <= 0) {
997 part = &m->body;
998 zero(*part);
999 } else {
1000 assert(m->body_end);
1001
1002 part = new0(struct bus_body_part, 1);
1003 if (!part) {
1004 m->poisoned = true;
1005 return NULL;
1006 }
1007
1008 m->body_end->next = part;
1009 }
1010
1011 part->memfd = -1;
1012 m->body_end = part;
1013 m->n_body_parts ++;
1014
1015 return part;
1016}
1017
1018static void part_zero(struct bus_body_part *part, size_t sz) {
1019 assert(part);
1020 assert(sz > 0);
1021 assert(sz < 8);
1022
453a0c29
LP
1023 /* All other fields can be left in their defaults */
1024 assert(!part->data);
1025 assert(part->memfd < 0);
1026
bc7fd8cd 1027 part->size = sz;
453a0c29
LP
1028 part->is_zero = true;
1029 part->sealed = true;
bc7fd8cd
LP
1030}
1031
1032static int part_make_space(
1033 struct sd_bus_message *m,
1034 struct bus_body_part *part,
1035 size_t sz,
1036 void **q) {
1037
1038 void *n;
1039 int r;
1040
1041 assert(m);
1042 assert(part);
1043 assert(!part->sealed);
1044
1045 if (m->poisoned)
1046 return -ENOMEM;
1047
1048 if (!part->data && part->memfd < 0)
1049 part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped);
1050
1051 if (part->memfd >= 0) {
1052 uint64_t u = sz;
1053
1054 r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &u);
1055 if (r < 0) {
1056 m->poisoned = true;
1057 return -errno;
1058 }
1059
453a0c29
LP
1060 if (!part->data || sz > part->mapped) {
1061 size_t psz = PAGE_ALIGN(sz > 0 ? sz : 1);
bc7fd8cd
LP
1062
1063 if (part->mapped <= 0)
1064 n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
1065 else
1066 n = mremap(part->data, part->mapped, psz, MREMAP_MAYMOVE);
1067
1068 if (n == MAP_FAILED) {
1069 m->poisoned = true;
1070 return -errno;
1071 }
1072
1073 part->mapped = psz;
1074 part->data = n;
1075 }
bf30e48f
KS
1076
1077 part->munmap_this = true;
bc7fd8cd 1078 } else {
23c6f770 1079 n = realloc(part->data, MAX(sz, 1u));
bc7fd8cd
LP
1080 if (!n) {
1081 m->poisoned = true;
1082 return -ENOMEM;
1083 }
1084
1085 part->data = n;
1086 part->free_this = true;
1087 }
1088
1089 if (q)
1090 *q = part->data ? (uint8_t*) part->data + part->size : NULL;
1091
1092 part->size = sz;
1093 return 0;
1094}
1095
c1b9d935
LP
1096static int message_add_offset(sd_bus_message *m, size_t offset) {
1097 struct bus_container *c;
1098
1099 assert(m);
6647dc66 1100 assert(BUS_MESSAGE_IS_GVARIANT(m));
c1b9d935
LP
1101
1102 /* Add offset to current container, unless this is the first
1103 * item in it, which will have the 0 offset, which we can
1104 * ignore. */
1105 c = message_get_container(m);
1106
1107 if (!c->need_offsets)
1108 return 0;
1109
6647dc66 1110 if (!GREEDY_REALLOC(c->offsets, c->n_offsets_allocated, c->n_offsets + 1))
c1b9d935
LP
1111 return -ENOMEM;
1112
1113 c->offsets[c->n_offsets++] = offset;
1114 return 0;
1115}
1116
453a0c29 1117static void message_extend_containers(sd_bus_message *m, size_t expand) {
de1c301e 1118 struct bus_container *c;
453a0c29
LP
1119
1120 assert(m);
1121
1122 if (expand <= 0)
1123 return;
1124
1125 /* Update counters */
c1b9d935
LP
1126 for (c = m->containers; c < m->containers + m->n_containers; c++) {
1127
453a0c29
LP
1128 if (c->array_size)
1129 *c->array_size += expand;
c1b9d935 1130 }
453a0c29
LP
1131}
1132
c1b9d935 1133static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
f3097697 1134 size_t start_body, end_body, padding, added;
bc7fd8cd
LP
1135 void *p;
1136 int r;
de1c301e
LP
1137
1138 assert(m);
9a17484d 1139 assert(align > 0);
bc7fd8cd 1140 assert(!m->sealed);
de1c301e 1141
bc7fd8cd
LP
1142 if (m->poisoned)
1143 return NULL;
de1c301e 1144
bc7fd8cd
LP
1145 start_body = ALIGN_TO((size_t) m->header->body_size, align);
1146 end_body = start_body + sz;
1147
1148 padding = start_body - m->header->body_size;
1149 added = padding + sz;
1150
1151 /* Check for 32bit overflows */
1152 if (end_body > (size_t) ((uint32_t) -1)) {
1153 m->poisoned = true;
de1c301e 1154 return NULL;
bc7fd8cd 1155 }
de1c301e 1156
f3097697
LP
1157 if (added > 0) {
1158 struct bus_body_part *part = NULL;
1159 bool add_new_part;
1160
1161 add_new_part =
1162 m->n_body_parts <= 0 ||
1163 m->body_end->sealed ||
1164 padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
1165
1166 if (add_new_part) {
1167 if (padding > 0) {
1168 part = message_append_part(m);
1169 if (!part)
1170 return NULL;
1171
1172 part_zero(part, padding);
1173 }
de1c301e 1174
bc7fd8cd
LP
1175 part = message_append_part(m);
1176 if (!part)
1177 return NULL;
1178
f3097697
LP
1179 r = part_make_space(m, part, sz, &p);
1180 if (r < 0)
1181 return NULL;
1182 } else {
1183 struct bus_container *c;
1184 void *op;
1185 size_t os, start_part, end_part;
bc7fd8cd 1186
f3097697
LP
1187 part = m->body_end;
1188 op = part->data;
1189 os = part->size;
bc7fd8cd 1190
f3097697
LP
1191 start_part = ALIGN_TO(part->size, align);
1192 end_part = start_part + sz;
bc7fd8cd 1193
f3097697
LP
1194 r = part_make_space(m, part, end_part, &p);
1195 if (r < 0)
1196 return NULL;
bc7fd8cd 1197
f3097697
LP
1198 if (padding > 0) {
1199 memset(p, 0, padding);
1200 p = (uint8_t*) p + padding;
1201 }
bc7fd8cd 1202
f3097697
LP
1203 /* Readjust pointers */
1204 for (c = m->containers; c < m->containers + m->n_containers; c++)
1205 c->array_size = adjust_pointer(c->array_size, op, os, part->data);
bc7fd8cd 1206
f3097697 1207 m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
de1c301e 1208 }
f3097697
LP
1209 } else
1210 /* Return something that is not NULL and is aligned */
1211 p = (uint8_t *) NULL + align;
de1c301e 1212
bc7fd8cd 1213 m->header->body_size = end_body;
453a0c29 1214 message_extend_containers(m, added);
de1c301e 1215
c1b9d935
LP
1216 if (add_offset) {
1217 r = message_add_offset(m, end_body);
1218 if (r < 0) {
1219 m->poisoned = true;
1220 return NULL;
1221 }
1222 }
1223
de1c301e
LP
1224 return p;
1225}
1226
c1b9d935
LP
1227static int message_push_fd(sd_bus_message *m, int fd) {
1228 int *f, copy;
1229
1230 assert(m);
1231
1232 if (fd < 0)
1233 return -EINVAL;
1234
1235 if (!m->allow_fds)
1236 return -ENOTSUP;
1237
1238 copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
1239 if (copy < 0)
1240 return -errno;
1241
1242 f = realloc(m->fds, sizeof(int) * (m->n_fds + 1));
1243 if (!f) {
1244 m->poisoned = true;
1245 close_nointr_nofail(copy);
1246 return -ENOMEM;
1247 }
1248
1249 m->fds = f;
1250 m->fds[m->n_fds] = copy;
1251 m->free_fds = true;
1252
1253 return copy;
1254}
1255
de1c301e 1256int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
c1b9d935 1257 _cleanup_close_ int fd = -1;
de1c301e 1258 struct bus_container *c;
27f6e5c7 1259 ssize_t align, sz;
de1c301e 1260 void *a;
de1c301e 1261
9d6c7c82 1262 assert_return(m, -EINVAL);
9d6c7c82
LP
1263 assert_return(!m->sealed, -EPERM);
1264 assert_return(bus_type_is_basic(type), -EINVAL);
1265 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
1266
1267 c = message_get_container(m);
1268
1269 if (c->signature && c->signature[c->index]) {
1270 /* Container signature is already set */
1271
1272 if (c->signature[c->index] != type)
9a17484d 1273 return -ENXIO;
de1c301e 1274 } else {
5cbe7492
LP
1275 char *e;
1276
de1c301e
LP
1277 /* Maybe we can append to the signature? But only if this is the top-level container*/
1278 if (c->enclosing != 0)
9a17484d 1279 return -ENXIO;
de1c301e
LP
1280
1281 e = strextend(&c->signature, CHAR_TO_STR(type), NULL);
bc7fd8cd
LP
1282 if (!e) {
1283 m->poisoned = true;
de1c301e 1284 return -ENOMEM;
bc7fd8cd 1285 }
de1c301e
LP
1286 }
1287
6647dc66 1288 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
1289 uint8_t u8;
1290 uint32_t u32;
de1c301e 1291
c1b9d935 1292 switch (type) {
cd6f997f 1293
c1b9d935
LP
1294 case SD_BUS_TYPE_SIGNATURE:
1295 case SD_BUS_TYPE_STRING:
1296 p = strempty(p);
b8beb278 1297
c1b9d935
LP
1298 /* Fall through... */
1299 case SD_BUS_TYPE_OBJECT_PATH:
1300 if (!p)
1301 return -EINVAL;
cd6f997f 1302
c1b9d935
LP
1303 align = 1;
1304 sz = strlen(p) + 1;
1305 break;
de1c301e 1306
c1b9d935 1307 case SD_BUS_TYPE_BOOLEAN:
b8beb278 1308
c1b9d935
LP
1309 u8 = p && *(int*) p;
1310 p = &u8;
cd6f997f 1311
c1b9d935
LP
1312 align = sz = 1;
1313 break;
de1c301e 1314
c1b9d935 1315 case SD_BUS_TYPE_UNIX_FD:
b3273daf 1316
c1b9d935
LP
1317 if (!p)
1318 return -EINVAL;
15912917 1319
c1b9d935
LP
1320 fd = message_push_fd(m, *(int*) p);
1321 if (fd < 0)
1322 return fd;
de1c301e 1323
c1b9d935
LP
1324 u32 = m->n_fds;
1325 p = &u32;
de1c301e 1326
c1b9d935
LP
1327 align = sz = 4;
1328 break;
2c93b4ef 1329
c1b9d935
LP
1330 default:
1331 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
6647dc66 1332 sz = bus_gvariant_get_size(CHAR_TO_STR(type));
c1b9d935 1333 break;
15912917
KS
1334 }
1335
c1b9d935
LP
1336 assert(align > 0);
1337 assert(sz > 0);
2c93b4ef 1338
c1b9d935
LP
1339 a = message_extend_body(m, align, sz, true);
1340 if (!a)
1341 return -ENOMEM;
2c93b4ef 1342
c1b9d935 1343 memcpy(a, p, sz);
2c93b4ef 1344
c1b9d935
LP
1345 if (stored)
1346 *stored = (const uint8_t*) a;
2c93b4ef 1347
c1b9d935
LP
1348 } else {
1349 uint32_t u32;
2c93b4ef 1350
c1b9d935 1351 switch (type) {
2c93b4ef 1352
c1b9d935
LP
1353 case SD_BUS_TYPE_STRING:
1354 /* To make things easy we'll serialize a NULL string
1355 * into the empty string */
1356 p = strempty(p);
b3273daf 1357
c1b9d935
LP
1358 /* Fall through... */
1359 case SD_BUS_TYPE_OBJECT_PATH:
de1c301e 1360
c1b9d935
LP
1361 if (!p)
1362 return -EINVAL;
de1c301e 1363
c1b9d935
LP
1364 align = 4;
1365 sz = 4 + strlen(p) + 1;
1366 break;
de1c301e 1367
c1b9d935 1368 case SD_BUS_TYPE_SIGNATURE:
de1c301e 1369
c1b9d935 1370 p = strempty(p);
de1c301e 1371
c1b9d935
LP
1372 align = 1;
1373 sz = 1 + strlen(p) + 1;
1374 break;
de1c301e 1375
c1b9d935 1376 case SD_BUS_TYPE_BOOLEAN:
2c93b4ef 1377
c1b9d935 1378 u32 = p && *(int*) p;
6647dc66
LP
1379 p = &u32;
1380
c1b9d935
LP
1381 align = sz = 4;
1382 break;
2c93b4ef 1383
c1b9d935 1384 case SD_BUS_TYPE_UNIX_FD:
de1c301e 1385
c1b9d935
LP
1386 if (!p)
1387 return -EINVAL;
de1c301e 1388
c1b9d935
LP
1389 fd = message_push_fd(m, *(int*) p);
1390 if (fd < 0)
1391 return fd;
1392
1393 u32 = m->n_fds;
1394 p = &u32;
1395
1396 align = sz = 4;
1397 break;
1398
1399 default:
1400 align = bus_type_get_alignment(type);
1401 sz = bus_type_get_size(type);
1402 break;
1403 }
1404
1405 assert(align > 0);
1406 assert(sz > 0);
1407
1408 a = message_extend_body(m, align, sz, false);
1409 if (!a)
1410 return -ENOMEM;
1411
1412 if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) {
1413 *(uint32_t*) a = sz - 5;
1414 memcpy((uint8_t*) a + 4, p, sz - 4);
1415
1416 if (stored)
1417 *stored = (const uint8_t*) a + 4;
1418
1419 } else if (type == SD_BUS_TYPE_SIGNATURE) {
1420 *(uint8_t*) a = sz - 1;
1421 memcpy((uint8_t*) a + 1, p, sz - 1);
1422
1423 if (stored)
1424 *stored = (const uint8_t*) a + 1;
1425 } else {
1426 memcpy(a, p, sz);
1427
1428 if (stored)
1429 *stored = a;
1430 }
de1c301e
LP
1431 }
1432
c1b9d935
LP
1433 if (type == SD_BUS_TYPE_UNIX_FD)
1434 m->n_fds ++;
1435
de1c301e 1436 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 1437 c->index++;
de1c301e 1438
c1b9d935 1439 fd = -1;
de1c301e
LP
1440 return 0;
1441}
1442
d9f644e2 1443_public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) {
de1c301e
LP
1444 return message_append_basic(m, type, p, NULL);
1445}
1446
938bcbab
LP
1447_public_ int sd_bus_message_append_string_space(
1448 sd_bus_message *m,
1449 size_t size,
1450 char **s) {
1451
f8e013f8 1452 struct bus_container *c;
f8e013f8 1453 void *a;
f8e013f8 1454
9d6c7c82
LP
1455 assert_return(m, -EINVAL);
1456 assert_return(s, -EINVAL);
1457 assert_return(!m->sealed, -EPERM);
1458 assert_return(!m->poisoned, -ESTALE);
f8e013f8
LP
1459
1460 c = message_get_container(m);
1461
1462 if (c->signature && c->signature[c->index]) {
1463 /* Container signature is already set */
1464
1465 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
1466 return -ENXIO;
1467 } else {
5cbe7492
LP
1468 char *e;
1469
f8e013f8
LP
1470 /* Maybe we can append to the signature? But only if this is the top-level container*/
1471 if (c->enclosing != 0)
1472 return -ENXIO;
1473
1474 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
bc7fd8cd
LP
1475 if (!e) {
1476 m->poisoned = true;
f8e013f8 1477 return -ENOMEM;
bc7fd8cd 1478 }
f8e013f8
LP
1479 }
1480
6647dc66 1481 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
1482 a = message_extend_body(m, 1, size + 1, true);
1483 if (!a)
1484 return -ENOMEM;
1485
1486 *s = a;
1487 } else {
1488 a = message_extend_body(m, 4, 4 + size + 1, false);
1489 if (!a)
1490 return -ENOMEM;
f8e013f8 1491
c1b9d935
LP
1492 *(uint32_t*) a = size;
1493 *s = (char*) a + 4;
1494 }
f8e013f8
LP
1495
1496 (*s)[size] = 0;
1497
1498 if (c->enclosing != SD_BUS_TYPE_ARRAY)
1499 c->index++;
1500
1501 return 0;
f8e013f8
LP
1502}
1503
938bcbab
LP
1504_public_ int sd_bus_message_append_string_iovec(
1505 sd_bus_message *m,
1506 const struct iovec *iov,
1507 unsigned n) {
1508
1509 size_t size;
1510 unsigned i;
1511 char *p;
1512 int r;
1513
1514 assert_return(m, -EINVAL);
1515 assert_return(!m->sealed, -EPERM);
1516 assert_return(iov || n == 0, -EINVAL);
1517 assert_return(!m->poisoned, -ESTALE);
1518
1519 size = IOVEC_TOTAL_SIZE(iov, n);
1520
1521 r = sd_bus_message_append_string_space(m, size, &p);
1522 if (r < 0)
1523 return r;
1524
1525 for (i = 0; i < n; i++) {
1526
1527 if (iov[i].iov_base)
1528 memcpy(p, iov[i].iov_base, iov[i].iov_len);
1529 else
1530 memset(p, ' ', iov[i].iov_len);
1531
1532 p += iov[i].iov_len;
1533 }
1534
1535 return 0;
1536}
1537
de1c301e
LP
1538static int bus_message_open_array(
1539 sd_bus_message *m,
1540 struct bus_container *c,
1541 const char *contents,
c1b9d935
LP
1542 uint32_t **array_size,
1543 size_t *begin,
1544 bool *need_offsets) {
de1c301e 1545
9a17484d 1546 unsigned nindex;
c1b9d935 1547 int alignment, r;
de1c301e
LP
1548
1549 assert(m);
1550 assert(c);
1551 assert(contents);
1552 assert(array_size);
c1b9d935
LP
1553 assert(begin);
1554 assert(need_offsets);
de1c301e 1555
29ddb38f 1556 if (!signature_is_single(contents, true))
de1c301e
LP
1557 return -EINVAL;
1558
de1c301e
LP
1559 if (c->signature && c->signature[c->index]) {
1560
1561 /* Verify the existing signature */
1562
1563 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
9a17484d 1564 return -ENXIO;
de1c301e
LP
1565
1566 if (!startswith(c->signature + c->index + 1, contents))
9a17484d 1567 return -ENXIO;
de1c301e
LP
1568
1569 nindex = c->index + 1 + strlen(contents);
1570 } else {
5cbe7492
LP
1571 char *e;
1572
de1c301e 1573 if (c->enclosing != 0)
9a17484d 1574 return -ENXIO;
de1c301e
LP
1575
1576 /* Extend the existing signature */
1577
1578 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL);
bc7fd8cd
LP
1579 if (!e) {
1580 m->poisoned = true;
de1c301e 1581 return -ENOMEM;
bc7fd8cd 1582 }
de1c301e
LP
1583
1584 nindex = e - c->signature;
1585 }
1586
6647dc66 1587 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
1588 alignment = bus_gvariant_get_alignment(contents);
1589 if (alignment < 0)
1590 return alignment;
de1c301e 1591
c1b9d935
LP
1592 /* Add alignment padding and add to offset list */
1593 if (!message_extend_body(m, alignment, 0, false))
1594 return -ENOMEM;
de1c301e 1595
c1b9d935
LP
1596 r = bus_gvariant_is_fixed_size(contents);
1597 if (r < 0)
1598 return r;
1599
1600 *begin = m->header->body_size;
1601 *need_offsets = r == 0;
1602 } else {
1603 void *a, *op;
1604 size_t os;
1605 struct bus_body_part *o;
1606
1607 alignment = bus_type_get_alignment(contents[0]);
1608 if (alignment < 0)
1609 return alignment;
1610
1611 a = message_extend_body(m, 4, 4, false);
1612 if (!a)
1613 return -ENOMEM;
1614
1615 o = m->body_end;
1616 op = m->body_end->data;
1617 os = m->body_end->size;
1618
1619 /* Add alignment between size and first element */
1620 if (!message_extend_body(m, alignment, 0, false))
1621 return -ENOMEM;
1622
1623 /* location of array size might have changed so let's readjust a */
1624 if (o == m->body_end)
1625 a = adjust_pointer(a, op, os, m->body_end->data);
1626
1627 *(uint32_t*) a = 0;
1628 *array_size = a;
1629 }
de1c301e
LP
1630
1631 if (c->enclosing != SD_BUS_TYPE_ARRAY)
1632 c->index = nindex;
1633
de1c301e
LP
1634 return 0;
1635}
1636
1637static int bus_message_open_variant(
1638 sd_bus_message *m,
1639 struct bus_container *c,
1640 const char *contents) {
1641
de1c301e
LP
1642 assert(m);
1643 assert(c);
1644 assert(contents);
1645
29ddb38f 1646 if (!signature_is_single(contents, false))
de1c301e
LP
1647 return -EINVAL;
1648
1649 if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
1650 return -EINVAL;
1651
1652 if (c->signature && c->signature[c->index]) {
1653
1654 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
9a17484d 1655 return -ENXIO;
de1c301e
LP
1656
1657 } else {
5cbe7492
LP
1658 char *e;
1659
de1c301e 1660 if (c->enclosing != 0)
9a17484d 1661 return -ENXIO;
de1c301e
LP
1662
1663 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL);
bc7fd8cd
LP
1664 if (!e) {
1665 m->poisoned = true;
de1c301e 1666 return -ENOMEM;
bc7fd8cd 1667 }
de1c301e
LP
1668 }
1669
6647dc66 1670 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
1671 /* Variants are always aligned to 8 */
1672
1673 if (!message_extend_body(m, 8, 0, false))
1674 return -ENOMEM;
1675
1676 } else {
1677 size_t l;
1678 void *a;
de1c301e 1679
c1b9d935
LP
1680 l = strlen(contents);
1681 a = message_extend_body(m, 1, 1 + l + 1, false);
1682 if (!a)
1683 return -ENOMEM;
1684
1685 *(uint8_t*) a = l;
1686 memcpy((uint8_t*) a + 1, contents, l + 1);
1687 }
de1c301e
LP
1688
1689 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 1690 c->index++;
de1c301e
LP
1691
1692 return 0;
1693}
1694
1695static int bus_message_open_struct(
1696 sd_bus_message *m,
1697 struct bus_container *c,
c1b9d935
LP
1698 const char *contents,
1699 size_t *begin,
1700 bool *need_offsets) {
de1c301e
LP
1701
1702 size_t nindex;
c1b9d935 1703 int r;
de1c301e
LP
1704
1705 assert(m);
1706 assert(c);
1707 assert(contents);
c1b9d935
LP
1708 assert(begin);
1709 assert(need_offsets);
de1c301e
LP
1710
1711 if (!signature_is_valid(contents, false))
1712 return -EINVAL;
1713
1714 if (c->signature && c->signature[c->index]) {
1715 size_t l;
1716
1717 l = strlen(contents);
1718
1719 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
1720 !startswith(c->signature + c->index + 1, contents) ||
1721 c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
9a17484d 1722 return -ENXIO;
de1c301e
LP
1723
1724 nindex = c->index + 1 + l + 1;
1725 } else {
5cbe7492
LP
1726 char *e;
1727
de1c301e 1728 if (c->enclosing != 0)
9a17484d 1729 return -ENXIO;
de1c301e
LP
1730
1731 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL);
bc7fd8cd
LP
1732 if (!e) {
1733 m->poisoned = true;
de1c301e 1734 return -ENOMEM;
bc7fd8cd 1735 }
de1c301e
LP
1736
1737 nindex = e - c->signature;
1738 }
1739
6647dc66 1740 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
1741 int alignment;
1742
1743 alignment = bus_gvariant_get_alignment(contents);
1744 if (alignment < 0)
1745 return alignment;
1746
1747 if (!message_extend_body(m, alignment, 0, false))
1748 return -ENOMEM;
1749
1750 r = bus_gvariant_is_fixed_size(contents);
1751 if (r < 0)
1752 return r;
1753
1754 *begin = m->header->body_size;
1755 *need_offsets = r == 0;
1756 } else {
1757 /* Align contents to 8 byte boundary */
1758 if (!message_extend_body(m, 8, 0, false))
1759 return -ENOMEM;
1760 }
de1c301e
LP
1761
1762 if (c->enclosing != SD_BUS_TYPE_ARRAY)
1763 c->index = nindex;
1764
1765 return 0;
1766}
1767
1768static int bus_message_open_dict_entry(
1769 sd_bus_message *m,
1770 struct bus_container *c,
c1b9d935
LP
1771 const char *contents,
1772 size_t *begin,
1773 bool *need_offsets) {
de1c301e 1774
c1b9d935 1775 int r;
de1c301e
LP
1776
1777 assert(m);
1778 assert(c);
1779 assert(contents);
c1b9d935
LP
1780 assert(begin);
1781 assert(need_offsets);
de1c301e
LP
1782
1783 if (!signature_is_pair(contents))
1784 return -EINVAL;
1785
1786 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 1787 return -ENXIO;
de1c301e
LP
1788
1789 if (c->signature && c->signature[c->index]) {
1790 size_t l;
1791
1792 l = strlen(contents);
1793
1794 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
1795 !startswith(c->signature + c->index + 1, contents) ||
1796 c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
9a17484d 1797 return -ENXIO;
de1c301e 1798 } else
9a17484d 1799 return -ENXIO;
de1c301e 1800
6647dc66 1801 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935 1802 int alignment;
de1c301e 1803
c1b9d935
LP
1804 alignment = bus_gvariant_get_alignment(contents);
1805 if (alignment < 0)
1806 return alignment;
1807
1808 if (!message_extend_body(m, alignment, 0, false))
1809 return -ENOMEM;
1810
1811 r = bus_gvariant_is_fixed_size(contents);
1812 if (r < 0)
1813 return r;
1814
1815 *begin = m->header->body_size;
1816 *need_offsets = r == 0;
1817 } else {
1818 /* Align contents to 8 byte boundary */
1819 if (!message_extend_body(m, 8, 0, false))
1820 return -ENOMEM;
1821 }
de1c301e
LP
1822
1823 return 0;
1824}
1825
d9f644e2 1826_public_ int sd_bus_message_open_container(
de1c301e
LP
1827 sd_bus_message *m,
1828 char type,
1829 const char *contents) {
1830
9a17484d 1831 struct bus_container *c, *w;
de1c301e 1832 uint32_t *array_size = NULL;
9a17484d 1833 char *signature;
c1b9d935
LP
1834 size_t before, begin;
1835 bool need_offsets = false;
de1c301e
LP
1836 int r;
1837
9d6c7c82
LP
1838 assert_return(m, -EINVAL);
1839 assert_return(!m->sealed, -EPERM);
1840 assert_return(contents, -EINVAL);
1841 assert_return(!m->poisoned, -ESTALE);
de1c301e
LP
1842
1843 /* Make sure we have space for one more container */
9a17484d 1844 w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1));
bc7fd8cd
LP
1845 if (!w) {
1846 m->poisoned = true;
de1c301e 1847 return -ENOMEM;
bc7fd8cd
LP
1848 }
1849
9a17484d 1850 m->containers = w;
de1c301e
LP
1851
1852 c = message_get_container(m);
1853
1854 signature = strdup(contents);
bc7fd8cd
LP
1855 if (!signature) {
1856 m->poisoned = true;
de1c301e 1857 return -ENOMEM;
bc7fd8cd 1858 }
de1c301e 1859
b3af9646
LP
1860 /* Save old index in the parent container, in case we have to
1861 * abort this container */
1862 c->saved_index = c->index;
1863 before = m->header->body_size;
1864
de1c301e 1865 if (type == SD_BUS_TYPE_ARRAY)
c1b9d935 1866 r = bus_message_open_array(m, c, contents, &array_size, &begin, &need_offsets);
de1c301e
LP
1867 else if (type == SD_BUS_TYPE_VARIANT)
1868 r = bus_message_open_variant(m, c, contents);
1869 else if (type == SD_BUS_TYPE_STRUCT)
c1b9d935 1870 r = bus_message_open_struct(m, c, contents, &begin, &need_offsets);
de1c301e 1871 else if (type == SD_BUS_TYPE_DICT_ENTRY)
c1b9d935 1872 r = bus_message_open_dict_entry(m, c, contents, &begin, &need_offsets);
de1c301e
LP
1873 else
1874 r = -EINVAL;
1875
1876 if (r < 0) {
1877 free(signature);
1878 return r;
1879 }
1880
1881 /* OK, let's fill it in */
9a17484d
LP
1882 w += m->n_containers++;
1883 w->enclosing = type;
1884 w->signature = signature;
1885 w->index = 0;
1886 w->array_size = array_size;
b3af9646 1887 w->before = before;
c1b9d935 1888 w->begin = begin;
6647dc66 1889 w->n_offsets = w->n_offsets_allocated = 0;
c1b9d935
LP
1890 w->offsets = NULL;
1891 w->need_offsets = need_offsets;
1892
1893 return 0;
1894}
1895
6647dc66
LP
1896static size_t determine_word_size(size_t sz, size_t extra) {
1897 if (sz <= 0 && extra == 0)
1898 return 0;
1899 else if (sz + extra <= 0xFF)
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
2698int bus_message_seal(sd_bus_message *m, uint64_t serial) {
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;
2745
2746 /* Add padding at the end of the fields part, since we know
2747 * the body needs to start at an 8 byte alignment. We made
2748 * sure we allocated enough space for this, so all we need to
2749 * do here is to zero it out. */
2750 l = BUS_MESSAGE_FIELDS_SIZE(m);
2751 a = ALIGN8(l) - l;
2752 if (a > 0)
2753 memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a);
2754
2755 /* If this is something we can send as memfd, then let's seal
2756 the memfd now. Note that we can send memfds as payload only
2757 for directed messages, and not for broadcasts. */
2758 if (m->destination && m->bus && m->bus->use_memfd) {
2759 MESSAGE_FOREACH_PART(part, i, m)
2760 if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) {
2761 bus_body_part_unmap(part);
2762
2763 if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
2764 part->sealed = true;
2765 }
2766 }
2767
2768 m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
2769 m->root_container.index = 0;
2770 m->root_container.offset_index = 0;
2771 m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
2772
2773 m->sealed = true;
2774
2775 return 0;
2776}
2777
a392d361 2778int bus_body_part_map(struct bus_body_part *part) {
453a0c29
LP
2779 void *p;
2780 size_t psz;
2781
2782 assert_se(part);
2783
2784 if (part->data)
2785 return 0;
2786
2787 if (part->size <= 0)
2788 return 0;
2789
1307c3ff
LP
2790 /* For smaller zero parts (as used for padding) we don't need to map anything... */
2791 if (part->memfd < 0 && part->is_zero && part->size < 8) {
2792 static const uint8_t zeroes[7] = { };
2793 part->data = (void*) zeroes;
2794 return 0;
2795 }
2796
453a0c29
LP
2797 psz = PAGE_ALIGN(part->size);
2798
2799 if (part->memfd >= 0)
2800 p = mmap(NULL, psz, PROT_READ, MAP_SHARED, part->memfd, 0);
2801 else if (part->is_zero)
2802 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
2803 else
2804 return -EINVAL;
2805
2806 if (p == MAP_FAILED)
2807 return -errno;
2808
2809 part->mapped = psz;
2810 part->data = p;
a392d361
LP
2811 part->munmap_this = true;
2812
453a0c29
LP
2813 return 0;
2814}
2815
a392d361
LP
2816void bus_body_part_unmap(struct bus_body_part *part) {
2817
2818 assert_se(part);
2819
2820 if (part->memfd < 0)
2821 return;
2822
a392d361
LP
2823 if (!part->data)
2824 return;
2825
bf30e48f
KS
2826 if (!part->munmap_this)
2827 return;
a392d361
LP
2828
2829 assert_se(munmap(part->data, part->mapped) == 0);
2830
2831 part->data = NULL;
2832 part->mapped = 0;
2833 part->munmap_this = false;
2834
2835 return;
2836}
2837
9a17484d 2838static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
bc7fd8cd 2839 size_t k, start, end;
de1c301e 2840
9a17484d
LP
2841 assert(rindex);
2842 assert(align > 0);
de1c301e 2843
9a17484d 2844 start = ALIGN_TO((size_t) *rindex, align);
bc7fd8cd 2845 end = start + nbytes;
9a17484d 2846
bc7fd8cd 2847 if (end > sz)
9a17484d
LP
2848 return -EBADMSG;
2849
2850 /* Verify that padding is 0 */
2851 for (k = *rindex; k < start; k++)
2852 if (((const uint8_t*) p)[k] != 0)
2853 return -EBADMSG;
2854
2855 if (r)
2856 *r = (uint8_t*) p + start;
2857
bc7fd8cd 2858 *rindex = end;
9a17484d
LP
2859
2860 return 1;
de1c301e
LP
2861}
2862
7b058942
LP
2863static bool message_end_of_signature(sd_bus_message *m) {
2864 struct bus_container *c;
2865
2866 assert(m);
2867
2868 c = message_get_container(m);
2869 return !c->signature || c->signature[c->index] == 0;
2870}
2871
9a17484d
LP
2872static bool message_end_of_array(sd_bus_message *m, size_t index) {
2873 struct bus_container *c;
de1c301e 2874
9a17484d 2875 assert(m);
de1c301e 2876
9a17484d 2877 c = message_get_container(m);
6647dc66 2878 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 2879 return false;
de1c301e 2880
6647dc66
LP
2881 if (BUS_MESSAGE_IS_GVARIANT(m))
2882 return index >= c->end;
2883 else {
2884 assert(c->array_size);
2885 return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
2886 }
de1c301e
LP
2887}
2888
1405bef3 2889_public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
7b058942
LP
2890 assert_return(m, -EINVAL);
2891 assert_return(m->sealed, -EPERM);
2892
2893 if (complete && m->n_containers > 0)
2894 return false;
2895
2896 if (message_end_of_signature(m))
2897 return true;
2898
2899 if (message_end_of_array(m, m->rindex))
2900 return true;
2901
2902 return false;
2903}
2904
bc7fd8cd
LP
2905static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
2906 struct bus_body_part *part;
2907 size_t begin;
453a0c29
LP
2908 int r;
2909
bc7fd8cd
LP
2910 assert(m);
2911
2912 if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) {
2913 part = m->cached_rindex_part;
2914 begin = m->cached_rindex_part_begin;
2915 } else {
2916 part = &m->body;
2917 begin = 0;
2918 }
2919
2920 while (part) {
2921 if (index < begin)
2922 return NULL;
2923
2924 if (index + sz <= begin + part->size) {
453a0c29 2925
a392d361 2926 r = bus_body_part_map(part);
453a0c29
LP
2927 if (r < 0)
2928 return NULL;
2929
bc7fd8cd 2930 if (p)
453a0c29 2931 *p = (uint8_t*) part->data + index - begin;
bc7fd8cd
LP
2932
2933 m->cached_rindex_part = part;
2934 m->cached_rindex_part_begin = begin;
2935
2936 return part;
2937 }
2938
453a0c29 2939 begin += part->size;
bc7fd8cd
LP
2940 part = part->next;
2941 }
2942
2943 return NULL;
2944}
2945
6647dc66
LP
2946static int container_next_item(sd_bus_message *m, struct bus_container *c, size_t *rindex) {
2947 int r;
2948
2949 assert(m);
2950 assert(c);
2951 assert(rindex);
2952
2953 if (!BUS_MESSAGE_IS_GVARIANT(m))
2954 return 0;
2955
2956 if (c->enclosing == SD_BUS_TYPE_ARRAY) {
2957 int sz;
2958
2959 sz = bus_gvariant_get_size(c->signature);
2960 if (sz < 0) {
2961 int alignment;
2962
2963 if (c->offset_index+1 >= c->n_offsets)
2964 goto end;
2965
2966 /* Variable-size array */
2967
2968 alignment = bus_gvariant_get_alignment(c->signature);
2969 assert(alignment > 0);
2970
2971 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
2972 c->item_size = c->offsets[c->offset_index+1] - *rindex;
2973 } else {
0039a203
LP
2974
2975 if (c->offset_index+1 >= (c->end-c->begin)/sz)
2976 goto end;
2977
6647dc66 2978 /* Fixed-size array */
0039a203 2979 *rindex = c->begin + (c->offset_index+1) * sz;
6647dc66
LP
2980 c->item_size = sz;
2981 }
2982
2983 c->offset_index++;
2984
2985 } else if (c->enclosing == 0 ||
2986 c->enclosing == SD_BUS_TYPE_STRUCT ||
2987 c->enclosing == SD_BUS_TYPE_DICT_ENTRY) {
2988
2989 int alignment;
2990 size_t n, j;
2991
2992 if (c->offset_index+1 >= c->n_offsets)
2993 goto end;
2994
2995 r = signature_element_length(c->signature + c->index, &n);
2996 if (r < 0)
2997 return r;
2998
2999 r = signature_element_length(c->signature + c->index + n, &j);
3000 if (r < 0)
3001 return r;
3002 else {
3003 char t[j+1];
3004 memcpy(t, c->signature + c->index + n, j);
3005 t[j] = 0;
3006
3007 alignment = bus_gvariant_get_alignment(t);
3008 }
3009
3010 assert(alignment > 0);
3011
3012 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
3013 c->item_size = c->offsets[c->offset_index+1] - *rindex;
3014
3015 c->offset_index++;
3016
3017 } else if (c->enclosing == SD_BUS_TYPE_VARIANT)
3018 goto end;
3019 else
3020 assert_not_reached("Unknown container type");
3021
3022 return 0;
3023
3024end:
3025 /* Reached the end */
3026 *rindex = c->end;
3027 c->item_size = 0;
3028 return 0;
3029}
3030
3031
bc7fd8cd
LP
3032static int message_peek_body(
3033 sd_bus_message *m,
3034 size_t *rindex,
3035 size_t align,
3036 size_t nbytes,
3037 void **ret) {
3038
3039 size_t k, start, end, padding;
3040 struct bus_body_part *part;
3041 uint8_t *q;
3042
de1c301e 3043 assert(m);
9a17484d
LP
3044 assert(rindex);
3045 assert(align > 0);
de1c301e 3046
bc7fd8cd
LP
3047 start = ALIGN_TO((size_t) *rindex, align);
3048 padding = start - *rindex;
3049 end = start + nbytes;
3050
3051 if (end > BUS_MESSAGE_BODY_SIZE(m))
3052 return -EBADMSG;
3053
3054 part = find_part(m, *rindex, padding, (void**) &q);
3055 if (!part)
3056 return -EBADMSG;
3057
3058 if (q) {
3059 /* Verify padding */
3060 for (k = 0; k < padding; k++)
3061 if (q[k] != 0)
3062 return -EBADMSG;
3063 }
3064
3065 part = find_part(m, start, nbytes, (void**) &q);
3066 if (!part || !q)
3067 return -EBADMSG;
3068
3069 *rindex = end;
3070
3071 if (ret)
3072 *ret = q;
3073
18f5b48f 3074 return 0;
9a17484d 3075}
de1c301e 3076
ac89bf1d 3077static bool validate_nul(const char *s, size_t l) {
de1c301e 3078
9a17484d
LP
3079 /* Check for NUL chars in the string */
3080 if (memchr(s, 0, l))
3081 return false;
de1c301e 3082
9a17484d
LP
3083 /* Check for NUL termination */
3084 if (s[l] != 0)
3085 return false;
de1c301e 3086
ac89bf1d
LP
3087 return true;
3088}
3089
3090static bool validate_string(const char *s, size_t l) {
3091
3092 if (!validate_nul(s, l))
3093 return false;
3094
9a17484d
LP
3095 /* Check if valid UTF8 */
3096 if (!utf8_is_valid(s))
3097 return false;
3098
3099 return true;
de1c301e
LP
3100}
3101
9a17484d 3102static bool validate_signature(const char *s, size_t l) {
de1c301e 3103
ac89bf1d 3104 if (!validate_nul(s, l))
9a17484d 3105 return false;
de1c301e 3106
9a17484d
LP
3107 /* Check if valid signature */
3108 if (!signature_is_valid(s, true))
3109 return false;
3110
3111 return true;
3112}
3113
ac89bf1d
LP
3114static bool validate_object_path(const char *s, size_t l) {
3115
3116 if (!validate_nul(s, l))
3117 return false;
3118
3119 if (!object_path_is_valid(s))
3120 return false;
3121
3122 return true;
3123}
3124
d9f644e2 3125_public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
9a17484d 3126 struct bus_container *c;
6647dc66 3127 size_t rindex;
9a17484d 3128 void *q;
0dcd14b9 3129 int r;
9a17484d 3130
9d6c7c82
LP
3131 assert_return(m, -EINVAL);
3132 assert_return(m->sealed, -EPERM);
3133 assert_return(bus_type_is_basic(type), -EINVAL);
de1c301e 3134
7b058942 3135 if (message_end_of_signature(m))
430fb8fa 3136 return -ENXIO;
9a17484d 3137
1daf8121
LP
3138 if (message_end_of_array(m, m->rindex))
3139 return 0;
3140
7b058942 3141 c = message_get_container(m);
9a17484d
LP
3142 if (c->signature[c->index] != type)
3143 return -ENXIO;
3144
6647dc66 3145 rindex = m->rindex;
9a17484d 3146
6647dc66 3147 if (BUS_MESSAGE_IS_GVARIANT(m)) {
9a17484d 3148
6647dc66
LP
3149 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
3150 bool ok;
9a17484d 3151
6647dc66 3152 r = message_peek_body(m, &rindex, 1, c->item_size, &q);
18f5b48f 3153 if (r < 0)
6647dc66
LP
3154 return r;
3155
3156 if (type == SD_BUS_TYPE_STRING)
3157 ok = validate_string(q, c->item_size-1);
3158 else if (type == SD_BUS_TYPE_OBJECT_PATH)
3159 ok = validate_object_path(q, c->item_size-1);
3160 else
3161 ok = validate_signature(q, c->item_size-1);
9a17484d 3162
6647dc66 3163 if (!ok)
ac89bf1d 3164 return -EBADMSG;
6647dc66
LP
3165
3166 if (p)
3167 *(const char**) p = q;
ac89bf1d 3168 } else {
6647dc66
LP
3169 int sz, align;
3170
3171 sz = bus_gvariant_get_size(CHAR_TO_STR(type));
3172 assert(sz > 0);
3173 if ((size_t) sz != c->item_size)
ac89bf1d 3174 return -EBADMSG;
9a17484d 3175
6647dc66
LP
3176 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
3177 assert(align > 0);
0dcd14b9 3178
6647dc66 3179 r = message_peek_body(m, &rindex, align, c->item_size, &q);
18f5b48f 3180 if (r < 0)
6647dc66 3181 return r;
de1c301e 3182
6647dc66 3183 switch (type) {
9a17484d 3184
6647dc66
LP
3185 case SD_BUS_TYPE_BYTE:
3186 if (p)
3187 *(uint8_t*) p = *(uint8_t*) q;
3188 break;
9a17484d 3189
6647dc66
LP
3190 case SD_BUS_TYPE_BOOLEAN:
3191 if (p)
3192 *(int*) p = !!*(uint8_t*) q;
3193 break;
9a17484d 3194
6647dc66
LP
3195 case SD_BUS_TYPE_INT16:
3196 case SD_BUS_TYPE_UINT16:
3197 if (p)
3198 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3199 break;
3200
3201 case SD_BUS_TYPE_INT32:
3202 case SD_BUS_TYPE_UINT32:
3203 if (p)
3204 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3205 break;
9a17484d 3206
6647dc66
LP
3207 case SD_BUS_TYPE_INT64:
3208 case SD_BUS_TYPE_UINT64:
3209 case SD_BUS_TYPE_DOUBLE:
3210 if (p)
3211 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3212 break;
0dcd14b9 3213
6647dc66
LP
3214 case SD_BUS_TYPE_UNIX_FD: {
3215 uint32_t j;
de1c301e 3216
6647dc66
LP
3217 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3218 if (j >= m->n_fds)
3219 return -EBADMSG;
de1c301e 3220
6647dc66
LP
3221 if (p)
3222 *(int*) p = m->fds[j];
de1c301e 3223
6647dc66
LP
3224 break;
3225 }
3226
3227 default:
3228 assert_not_reached("unexpected type");
3229 }
3230 }
3231
3232 r = container_next_item(m, c, &rindex);
3233 if (r < 0)
9a17484d 3234 return r;
6647dc66 3235 } else {
9a17484d 3236
6647dc66 3237 rindex = m->rindex;
9a17484d 3238
6647dc66
LP
3239 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
3240 uint32_t l;
3241 bool ok;
9a17484d 3242
6647dc66 3243 r = message_peek_body(m, &rindex, 4, 4, &q);
18f5b48f 3244 if (r < 0)
6647dc66 3245 return r;
9a17484d 3246
6647dc66
LP
3247 l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3248 r = message_peek_body(m, &rindex, 1, l+1, &q);
3249 if (r < 0)
3250 return r;
9a17484d 3251
6647dc66
LP
3252 if (type == SD_BUS_TYPE_OBJECT_PATH)
3253 ok = validate_object_path(q, l);
3254 else
3255 ok = validate_string(q, l);
3256 if (!ok)
3257 return -EBADMSG;
9a17484d 3258
0dcd14b9 3259 if (p)
6647dc66 3260 *(const char**) p = q;
9a17484d 3261
6647dc66
LP
3262 } else if (type == SD_BUS_TYPE_SIGNATURE) {
3263 uint8_t l;
3264
3265 r = message_peek_body(m, &rindex, 1, 1, &q);
18f5b48f 3266 if (r < 0)
6647dc66
LP
3267 return r;
3268
3269 l = *(uint8_t*) q;
3270 r = message_peek_body(m, &rindex, 1, l+1, &q);
3271 if (r < 0)
3272 return r;
2c93b4ef 3273
6647dc66 3274 if (!validate_signature(q, l))
2c93b4ef
LP
3275 return -EBADMSG;
3276
0dcd14b9 3277 if (p)
6647dc66 3278 *(const char**) p = q;
2c93b4ef 3279
6647dc66
LP
3280 } else {
3281 ssize_t sz, align;
9a17484d 3282
6647dc66
LP
3283 align = bus_type_get_alignment(type);
3284 assert(align > 0);
2c93b4ef 3285
6647dc66
LP
3286 sz = bus_type_get_size(type);
3287 assert(sz > 0);
3288
3289 r = message_peek_body(m, &rindex, align, sz, &q);
18f5b48f 3290 if (r < 0)
6647dc66
LP
3291 return r;
3292
3293 switch (type) {
3294
3295 case SD_BUS_TYPE_BYTE:
3296 if (p)
3297 *(uint8_t*) p = *(uint8_t*) q;
3298 break;
3299
3300 case SD_BUS_TYPE_BOOLEAN:
3301 if (p)
3302 *(int*) p = !!*(uint32_t*) q;
3303 break;
3304
3305 case SD_BUS_TYPE_INT16:
3306 case SD_BUS_TYPE_UINT16:
3307 if (p)
3308 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3309 break;
3310
3311 case SD_BUS_TYPE_INT32:
3312 case SD_BUS_TYPE_UINT32:
3313 if (p)
3314 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3315 break;
3316
3317 case SD_BUS_TYPE_INT64:
3318 case SD_BUS_TYPE_UINT64:
3319 case SD_BUS_TYPE_DOUBLE:
3320 if (p)
3321 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3322 break;
3323
3324 case SD_BUS_TYPE_UNIX_FD: {
3325 uint32_t j;
3326
3327 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3328 if (j >= m->n_fds)
3329 return -EBADMSG;
3330
3331 if (p)
3332 *(int*) p = m->fds[j];
3333 break;
3334 }
3335
3336 default:
3337 assert_not_reached("Unknown basic type...");
3338 }
3339 }
9a17484d
LP
3340 }
3341
6647dc66
LP
3342 m->rindex = rindex;
3343
9a17484d
LP
3344 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3345 c->index++;
3346
3347 return 1;
de1c301e
LP
3348}
3349
9a17484d
LP
3350static int bus_message_enter_array(
3351 sd_bus_message *m,
3352 struct bus_container *c,
3353 const char *contents,
6647dc66
LP
3354 uint32_t **array_size,
3355 size_t *item_size,
3356 size_t **offsets,
3357 size_t *n_offsets) {
9a17484d
LP
3358
3359 size_t rindex;
3360 void *q;
3361 int r, alignment;
3362
3363 assert(m);
3364 assert(c);
3365 assert(contents);
3366 assert(array_size);
6647dc66
LP
3367 assert(item_size);
3368 assert(offsets);
3369 assert(n_offsets);
9a17484d 3370
29ddb38f 3371 if (!signature_is_single(contents, true))
de1c301e 3372 return -EINVAL;
9a17484d 3373
9a17484d 3374 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3375 return -ENXIO;
9a17484d
LP
3376
3377 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
3378 return -ENXIO;
3379
3380 if (!startswith(c->signature + c->index + 1, contents))
3381 return -ENXIO;
3382
3383 rindex = m->rindex;
9a17484d 3384
6647dc66
LP
3385 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3386 /* dbus1 */
9a17484d 3387
6647dc66 3388 r = message_peek_body(m, &rindex, 4, 4, &q);
18f5b48f 3389 if (r < 0)
6647dc66 3390 return r;
9a17484d 3391
6647dc66
LP
3392 if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE)
3393 return -EBADMSG;
9a17484d 3394
6647dc66
LP
3395 alignment = bus_type_get_alignment(contents[0]);
3396 if (alignment < 0)
3397 return alignment;
3398
3399 r = message_peek_body(m, &rindex, alignment, 0, NULL);
3400 if (r < 0)
3401 return r;
6647dc66
LP
3402
3403 *array_size = (uint32_t*) q;
3404
3405 } else if (c->item_size <= 0) {
3406
3407 /* gvariant: empty array */
3408 *item_size = 0;
3409 *offsets = NULL;
3410 *n_offsets = 0;
3411
3412 } else if (bus_gvariant_is_fixed_size(contents)) {
3413
3414 /* gvariant: fixed length array */
3415 *item_size = bus_gvariant_get_size(contents);
3416 *offsets = NULL;
3417 *n_offsets = 0;
3418
3419 } else {
3420 size_t where, p = 0, framing, sz;
3421 unsigned i;
3422
3423 /* gvariant: variable length array */
3424 sz = determine_word_size(c->item_size, 0);
3425
3426 where = rindex + c->item_size - sz;
3427 r = message_peek_body(m, &where, 1, sz, &q);
3428 if (r < 0)
3429 return r;
6647dc66
LP
3430
3431 framing = read_word_le(q, sz);
3432 if (framing > c->item_size - sz)
3433 return -EBADMSG;
3434 if ((c->item_size - framing) % sz != 0)
3435 return -EBADMSG;
3436
3437 *n_offsets = (c->item_size - framing) / sz;
3438
3439 where = rindex + framing;
3440 r = message_peek_body(m, &where, 1, *n_offsets * sz, &q);
3441 if (r < 0)
3442 return r;
6647dc66
LP
3443
3444 *offsets = new(size_t, *n_offsets);
3445 if (!*offsets)
3446 return -ENOMEM;
3447
3448 for (i = 0; i < *n_offsets; i++) {
3449 size_t x;
3450
3451 x = read_word_le((uint8_t*) q + i * sz, sz);
3452 if (x > c->item_size - sz)
3453 return -EBADMSG;
3454 if (x < p)
3455 return -EBADMSG;
3456
3457 (*offsets)[i] = rindex + x;
3458 p = x;
3459 }
3460
3461 *item_size = (*offsets)[0] - rindex;
3462 }
3463
3464 m->rindex = rindex;
3465
3466 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3467 c->index += 1 + strlen(contents);
9a17484d
LP
3468
3469 return 1;
3470}
3471
3472static int bus_message_enter_variant(
3473 sd_bus_message *m,
3474 struct bus_container *c,
6647dc66
LP
3475 const char *contents,
3476 size_t *item_size) {
9a17484d
LP
3477
3478 size_t rindex;
3479 uint8_t l;
3480 void *q;
3481 int r;
3482
3483 assert(m);
3484 assert(c);
3485 assert(contents);
6647dc66 3486 assert(item_size);
9a17484d 3487
29ddb38f 3488 if (!signature_is_single(contents, false))
de1c301e 3489 return -EINVAL;
de1c301e 3490
9a17484d
LP
3491 if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
3492 return -EINVAL;
3493
3494 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3495 return -ENXIO;
9a17484d
LP
3496
3497 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
3498 return -ENXIO;
3499
3500 rindex = m->rindex;
9a17484d 3501
6647dc66
LP
3502 if (BUS_MESSAGE_IS_GVARIANT(m)) {
3503 size_t k, where;
3504
3505 k = strlen(contents);
3506 if (1+k > c->item_size)
3507 return -EBADMSG;
3508
3509 where = rindex + c->item_size - (1+k);
3510 r = message_peek_body(m, &where, 1, 1+k, &q);
3511 if (r < 0)
3512 return r;
6647dc66
LP
3513
3514 if (*(char*) q != 0)
3515 return -EBADMSG;
3516
3517 if (memcmp((uint8_t*) q+1, contents, k))
3518 return -ENXIO;
3519
3520 *item_size = c->item_size - (1+k);
3521
3522 } else {
3523 r = message_peek_body(m, &rindex, 1, 1, &q);
3524 if (r < 0)
3525 return r;
6647dc66
LP
3526
3527 l = *(uint8_t*) q;
3528 r = message_peek_body(m, &rindex, 1, l+1, &q);
3529 if (r < 0)
3530 return r;
6647dc66
LP
3531
3532 if (!validate_signature(q, l))
3533 return -EBADMSG;
3534
3535 if (!streq(q, contents))
3536 return -ENXIO;
3537 }
3538
3539 m->rindex = rindex;
3540
3541 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3542 c->index++;
3543
3544 return 1;
3545}
3546
3547static int build_struct_offsets(
3548 sd_bus_message *m,
3549 const char *signature,
3550 size_t size,
3551 size_t *item_size,
3552 size_t **offsets,
3553 size_t *n_offsets) {
3554
3555 unsigned n_variable = 0, n_total = 0, v;
3556 size_t previous = 0, where;
3557 const char *p;
3558 size_t sz;
3559 void *q;
3560 int r;
3561
3562 assert(m);
6647dc66
LP
3563 assert(item_size);
3564 assert(offsets);
3565 assert(n_offsets);
3566
d6385068
LP
3567 if (isempty(signature)) {
3568 *item_size = 0;
3569 *offsets = NULL;
3570 *n_offsets = 0;
3571 return 0;
3572 }
3573
6647dc66 3574 sz = determine_word_size(size, 0);
d6385068
LP
3575 if (sz <= 0)
3576 return -EBADMSG;
6647dc66
LP
3577
3578 /* First, loop over signature and count variable elements and
3579 * elements in general. We use this to know how large the
3580 * offset array is at the end of the structure. Note that
3581 * GVariant only stores offsets for all variable size elements
3582 * that are not the last item. */
3583
3584 p = signature;
3585 while (*p != 0) {
3586 size_t n;
3587
3588 r = signature_element_length(p, &n);
3589 if (r < 0)
3590 return r;
3591 else {
3592 char t[n+1];
3593
3594 memcpy(t, p, n);
3595 t[n] = 0;
3596
3597 r = bus_gvariant_is_fixed_size(t);
3598 }
3599
3600 if (r < 0)
3601 return r;
3602 if (r == 0 && p[n] != 0) /* except the last item */
3603 n_variable ++;
3604 n_total++;
3605
3606 p += n;
3607 }
3608
3609 if (size < n_variable * sz)
3610 return -EBADMSG;
3611
3612 where = m->rindex + size - (n_variable * sz);
3613 r = message_peek_body(m, &where, 1, n_variable * sz, &q);
9a17484d
LP
3614 if (r < 0)
3615 return r;
9a17484d 3616
6647dc66 3617 v = n_variable;
9a17484d 3618
6647dc66
LP
3619 *offsets = new(size_t, n_total);
3620 if (!*offsets)
3621 return -ENOMEM;
9a17484d 3622
6647dc66 3623 *n_offsets = 0;
9a17484d 3624
6647dc66
LP
3625 /* Second, loop again and build an offset table */
3626 p = signature;
3627 while (*p != 0) {
3628 size_t n, offset;
3629 int k;
9a17484d 3630
6647dc66
LP
3631 r = signature_element_length(p, &n);
3632 if (r < 0)
3633 return r;
3634 else {
3635 char t[n+1];
3636
3637 memcpy(t, p, n);
3638 t[n] = 0;
3639
3640 k = bus_gvariant_get_size(t);
3641 if (k < 0) {
3642 size_t x;
3643
3644 /* variable size */
3645 if (v > 0) {
3646 v--;
3647
3648 x = read_word_le((uint8_t*) q + v*sz, sz);
3649 if (x >= size)
3650 return -EBADMSG;
3651 if (m->rindex + x < previous)
3652 return -EBADMSG;
3653 } else
3654 /* The last item's end
3655 * is determined from
3656 * the start of the
3657 * offset array */
3658 x = size - (n_variable * sz);
3659
3660 offset = m->rindex + x;
3661
3662 } else {
3663 size_t align;
3664
3665 /* fixed size */
3666 align = bus_gvariant_get_alignment(t);
3667 assert(align > 0);
3668
3669 offset = (*n_offsets == 0 ? m->rindex : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k;
3670 }
3671 }
3672
3673 previous = (*offsets)[(*n_offsets)++] = offset;
3674 p += n;
3675 }
3676
3677 assert(v == 0);
3678 assert(*n_offsets == n_total);
3679
3680 *item_size = (*offsets)[0] - m->rindex;
3681 return 0;
3682}
3683
3684static int enter_struct_or_dict_entry(
3685 sd_bus_message *m,
3686 struct bus_container *c,
3687 const char *contents,
3688 size_t *item_size,
3689 size_t **offsets,
3690 size_t *n_offsets) {
3691
3692 int r;
3693
3694 assert(m);
3695 assert(c);
3696 assert(contents);
3697 assert(item_size);
3698 assert(offsets);
3699 assert(n_offsets);
3700
3701 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3702
3703 /* dbus1 */
3704 r = message_peek_body(m, &m->rindex, 8, 0, NULL);
18f5b48f 3705 if (r < 0)
6647dc66
LP
3706 return r;
3707
3708 } else if (c->item_size <= 0) {
3709
3710 /* gvariant empty struct */
3711 *item_size = 0;
3712 *offsets = NULL;
3713 *n_offsets = 0;
3714 } else
3715 /* gvariant with contents */
3716 return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets);
3717
3718 return 0;
de1c301e
LP
3719}
3720
9a17484d
LP
3721static int bus_message_enter_struct(
3722 sd_bus_message *m,
3723 struct bus_container *c,
6647dc66
LP
3724 const char *contents,
3725 size_t *item_size,
3726 size_t **offsets,
3727 size_t *n_offsets) {
9a17484d
LP
3728
3729 size_t l;
3730 int r;
3731
3732 assert(m);
3733 assert(c);
3734 assert(contents);
6647dc66
LP
3735 assert(item_size);
3736 assert(offsets);
3737 assert(n_offsets);
9a17484d
LP
3738
3739 if (!signature_is_valid(contents, false))
3740 return -EINVAL;
3741
3742 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3743 return -ENXIO;
9a17484d
LP
3744
3745 l = strlen(contents);
3746
3747 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
3748 !startswith(c->signature + c->index + 1, contents) ||
3749 c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
3750 return -ENXIO;
3751
6647dc66
LP
3752 r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
3753 if (r < 0)
9a17484d
LP
3754 return r;
3755
3756 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3757 c->index += 1 + l + 1;
3758
3759 return 1;
3760}
3761
3762static int bus_message_enter_dict_entry(
3763 sd_bus_message *m,
3764 struct bus_container *c,
6647dc66
LP
3765 const char *contents,
3766 size_t *item_size,
3767 size_t **offsets,
3768 size_t *n_offsets) {
9a17484d
LP
3769
3770 size_t l;
3771 int r;
3772
3773 assert(m);
3774 assert(c);
3775 assert(contents);
3776
3777 if (!signature_is_pair(contents))
3778 return -EINVAL;
3779
3780 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3781 return -ENXIO;
3782
3783 if (!c->signature || c->signature[c->index] == 0)
3784 return 0;
3785
3786 l = strlen(contents);
3787
3788 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
3789 !startswith(c->signature + c->index + 1, contents) ||
3790 c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
3791 return -ENXIO;
3792
6647dc66
LP
3793 r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
3794 if (r < 0)
9a17484d
LP
3795 return r;
3796
3797 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3798 c->index += 1 + l + 1;
3799
3800 return 1;
3801}
3802
d9f644e2
ZJS
3803_public_ int sd_bus_message_enter_container(sd_bus_message *m,
3804 char type,
3805 const char *contents) {
9a17484d
LP
3806 struct bus_container *c, *w;
3807 uint32_t *array_size = NULL;
3808 char *signature;
b3af9646 3809 size_t before;
6647dc66
LP
3810 size_t *offsets = NULL;
3811 size_t n_offsets = 0, item_size = 0;
9a17484d
LP
3812 int r;
3813
275b39fe
LP
3814 assert_return(m, -EINVAL);
3815 assert_return(m->sealed, -EPERM);
3816 assert_return(type != 0 || !contents, -EINVAL);
3817
3818 if (type == 0 || !contents) {
3819 const char *cc;
3820 char tt;
3821
3822 /* Allow entering into anonymous containers */
3823 r = sd_bus_message_peek_type(m, &tt, &cc);
18f5b48f 3824 if (r < 0)
275b39fe
LP
3825 return r;
3826
3827 if (type != 0 && type != tt)
3828 return -ENXIO;
3829
3830 if (contents && !streq(contents, cc))
3831 return -ENXIO;
3832
3833 type = tt;
3834 contents = cc;
3835 }
9a17484d 3836
ed205a6b
LP
3837 /*
3838 * We enforce a global limit on container depth, that is much
3839 * higher than the 32 structs and 32 arrays the specification
3840 * mandates. This is simpler to implement for us, and we need
3841 * this only to ensure our container array doesn't grow
3842 * without bounds. We are happy to return any data from a
3843 * message as long as the data itself is valid, even if the
3844 * overall message might be not.
3845 *
3846 * Note that the message signature is validated when
3847 * parsing the headers, and that validation does check the
3848 * 32/32 limit.
3849 *
3850 * Note that the specification defines no limits on the depth
3851 * of stacked variants, but we do.
3852 */
3853 if (m->n_containers >= BUS_CONTAINER_DEPTH)
3854 return -EBADMSG;
3855
9a17484d
LP
3856 w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1));
3857 if (!w)
3858 return -ENOMEM;
3859 m->containers = w;
3860
7b058942 3861 if (message_end_of_signature(m))
430fb8fa 3862 return -ENXIO;
9a17484d 3863
1daf8121
LP
3864 if (message_end_of_array(m, m->rindex))
3865 return 0;
3866
7b058942
LP
3867 c = message_get_container(m);
3868
9a17484d
LP
3869 signature = strdup(contents);
3870 if (!signature)
3871 return -ENOMEM;
3872
b3af9646
LP
3873 c->saved_index = c->index;
3874 before = m->rindex;
3875
9a17484d 3876 if (type == SD_BUS_TYPE_ARRAY)
6647dc66 3877 r = bus_message_enter_array(m, c, contents, &array_size, &item_size, &offsets, &n_offsets);
9a17484d 3878 else if (type == SD_BUS_TYPE_VARIANT)
6647dc66 3879 r = bus_message_enter_variant(m, c, contents, &item_size);
9a17484d 3880 else if (type == SD_BUS_TYPE_STRUCT)
6647dc66 3881 r = bus_message_enter_struct(m, c, contents, &item_size, &offsets, &n_offsets);
9a17484d 3882 else if (type == SD_BUS_TYPE_DICT_ENTRY)
6647dc66 3883 r = bus_message_enter_dict_entry(m, c, contents, &item_size, &offsets, &n_offsets);
9a17484d
LP
3884 else
3885 r = -EINVAL;
3886
3887 if (r <= 0) {
3888 free(signature);
6647dc66 3889 free(offsets);
9a17484d
LP
3890 return r;
3891 }
3892
3893 /* OK, let's fill it in */
3894 w += m->n_containers++;
3895 w->enclosing = type;
3896 w->signature = signature;
3897 w->index = 0;
6647dc66 3898
b3af9646 3899 w->before = before;
9a17484d 3900 w->begin = m->rindex;
6647dc66
LP
3901 w->end = m->rindex + c->item_size;
3902
3903 w->array_size = array_size;
3904 w->item_size = item_size;
3905 w->offsets = offsets;
3906 w->n_offsets = n_offsets;
3907 w->offset_index = 0;
9a17484d
LP
3908
3909 return 1;
3910}
3911
d9f644e2 3912_public_ int sd_bus_message_exit_container(sd_bus_message *m) {
9a17484d 3913 struct bus_container *c;
6647dc66 3914 int r;
9a17484d 3915
9d6c7c82
LP
3916 assert_return(m, -EINVAL);
3917 assert_return(m->sealed, -EPERM);
f959af20 3918 assert_return(m->n_containers > 0, -ENXIO);
9a17484d
LP
3919
3920 c = message_get_container(m);
6647dc66
LP
3921
3922 if (c->enclosing != SD_BUS_TYPE_ARRAY) {
3923 if (c->signature && c->signature[c->index] != 0)
3924 return -EBUSY;
3925 }
3926
3927 if (BUS_MESSAGE_IS_GVARIANT(m)) {
3928 if (m->rindex < c->end)
3929 return -EBUSY;
3930
3931 } else if (c->enclosing == SD_BUS_TYPE_ARRAY) {
9a17484d
LP
3932 uint32_t l;
3933
3934 l = BUS_MESSAGE_BSWAP32(m, *c->array_size);
3935 if (c->begin + l != m->rindex)
3936 return -EBUSY;
9a17484d
LP
3937 }
3938
3939 free(c->signature);
6647dc66 3940 free(c->offsets);
9a17484d
LP
3941 m->n_containers--;
3942
6647dc66
LP
3943 c = message_get_container(m);
3944
3945 r = container_next_item(m, c, &m->rindex);
3946 if (r < 0)
3947 return r;
3948
9a17484d
LP
3949 return 1;
3950}
3951
b3af9646
LP
3952static void message_quit_container(sd_bus_message *m) {
3953 struct bus_container *c;
3954
3955 assert(m);
3956 assert(m->sealed);
3957 assert(m->n_containers > 0);
3958
3959 c = message_get_container(m);
3960
3961 /* Undo seeks */
3962 assert(m->rindex >= c->before);
3963 m->rindex = c->before;
3964
3965 /* Free container */
3966 free(c->signature);
6647dc66 3967 free(c->offsets);
b3af9646
LP
3968 m->n_containers--;
3969
3970 /* Correct index of new top-level container */
3971 c = message_get_container(m);
3972 c->index = c->saved_index;
3973}
3974
d9f644e2 3975_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
9a17484d
LP
3976 struct bus_container *c;
3977 int r;
3978
c430fee6
LP
3979 assert_return(m, -EINVAL);
3980 assert_return(m->sealed, -EPERM);
9a17484d 3981
7b058942 3982 if (message_end_of_signature(m))
9a17484d
LP
3983 goto eof;
3984
3985 if (message_end_of_array(m, m->rindex))
3986 goto eof;
3987
7b058942
LP
3988 c = message_get_container(m);
3989
9a17484d
LP
3990 if (bus_type_is_basic(c->signature[c->index])) {
3991 if (contents)
3992 *contents = NULL;
3993 if (type)
3994 *type = c->signature[c->index];
3995 return 1;
3996 }
3997
3998 if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) {
3999
4000 if (contents) {
4001 size_t l;
4002 char *sig;
4003
4004 r = signature_element_length(c->signature+c->index+1, &l);
4005 if (r < 0)
4006 return r;
4007
80a46c73
LP
4008 assert(l >= 1);
4009
9a17484d
LP
4010 sig = strndup(c->signature + c->index + 1, l);
4011 if (!sig)
4012 return -ENOMEM;
4013
4014 free(m->peeked_signature);
4015 m->peeked_signature = sig;
4016
4017 *contents = sig;
4018 }
4019
4020 if (type)
4021 *type = SD_BUS_TYPE_ARRAY;
4022
4023 return 1;
4024 }
4025
4026 if (c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ||
4027 c->signature[c->index] == SD_BUS_TYPE_DICT_ENTRY_BEGIN) {
4028
4029 if (contents) {
4030 size_t l;
4031 char *sig;
4032
4033 r = signature_element_length(c->signature+c->index, &l);
4034 if (r < 0)
4035 return r;
4036
4037 assert(l >= 2);
4038 sig = strndup(c->signature + c->index + 1, l - 2);
4039 if (!sig)
4040 return -ENOMEM;
4041
4042 free(m->peeked_signature);
4043 m->peeked_signature = sig;
4044
4045 *contents = sig;
4046 }
4047
4048 if (type)
4049 *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
4050
4051 return 1;
4052 }
4053
4054 if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) {
4055 if (contents) {
9a17484d
LP
4056 void *q;
4057
6647dc66
LP
4058 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4059 size_t k;
9a17484d 4060
6647dc66
LP
4061 if (c->item_size < 2)
4062 return -EBADMSG;
9a17484d 4063
6647dc66
LP
4064 /* Look for the NUL delimiter that
4065 separates the payload from the
4066 signature. Since the body might be
4067 in a different part that then the
4068 signature we map byte by byte. */
4069
4070 for (k = 2; k <= c->item_size; k++) {
4071 size_t where;
4072
4073 where = m->rindex + c->item_size - k;
4074 r = message_peek_body(m, &where, 1, k, &q);
4075 if (r < 0)
4076 return r;
6647dc66
LP
4077
4078 if (*(char*) q == 0)
4079 break;
4080 }
4081
4082 if (k > c->item_size)
4083 return -EBADMSG;
4084
4085 free(m->peeked_signature);
4086 m->peeked_signature = strndup((char*) q + 1, k - 1);
4087 if (!m->peeked_signature)
4088 return -ENOMEM;
4089
4090 if (!signature_is_valid(m->peeked_signature, true))
4091 return -EBADMSG;
4092
4093 *contents = m->peeked_signature;
4094 } else {
4095 size_t rindex, l;
4096
4097 rindex = m->rindex;
4098 r = message_peek_body(m, &rindex, 1, 1, &q);
4099 if (r < 0)
4100 return r;
9a17484d 4101
6647dc66
LP
4102 l = *(uint8_t*) q;
4103 r = message_peek_body(m, &rindex, 1, l+1, &q);
4104 if (r < 0)
4105 return r;
6647dc66
LP
4106
4107 if (!validate_signature(q, l))
4108 return -EBADMSG;
4109
4110 *contents = q;
4111 }
9a17484d
LP
4112 }
4113
4114 if (type)
4115 *type = SD_BUS_TYPE_VARIANT;
4116
4117 return 1;
4118 }
4119
4120 return -EINVAL;
4121
4122eof:
4123 if (type)
7b058942 4124 *type = 0;
9a17484d
LP
4125 if (contents)
4126 *contents = NULL;
4127 return 0;
4128}
4129
d9f644e2 4130_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
9a17484d
LP
4131 struct bus_container *c;
4132
9d6c7c82
LP
4133 assert_return(m, -EINVAL);
4134 assert_return(m->sealed, -EPERM);
9a17484d
LP
4135
4136 if (complete) {
bc7fd8cd 4137 message_reset_containers(m);
9a17484d 4138 m->rindex = 0;
9a17484d
LP
4139
4140 c = message_get_container(m);
4141 } else {
4142 c = message_get_container(m);
4143
6647dc66 4144 c->offset_index = 0;
9a17484d
LP
4145 c->index = 0;
4146 m->rindex = c->begin;
4147 }
4148
4149 return !isempty(c->signature);
4150}
718db961 4151
1b492614
LP
4152static int message_read_ap(
4153 sd_bus_message *m,
4154 const char *types,
4155 va_list ap) {
9a17484d 4156
fe1d424d
LP
4157 unsigned n_array, n_struct;
4158 TypeStack stack[BUS_CONTAINER_DEPTH];
4159 unsigned stack_ptr = 0;
430fb8fa 4160 unsigned n_loop = 0;
9a17484d
LP
4161 int r;
4162
4163 assert(m);
1b492614 4164
430fb8fa 4165 if (isempty(types))
1b492614 4166 return 0;
9a17484d 4167
fe1d424d
LP
4168 /* Ideally, we'd just call ourselves recursively on every
4169 * complex type. However, the state of a va_list that is
4170 * passed to a function is undefined after that function
4171 * returns. This means we need to docode the va_list linearly
4172 * in a single stackframe. We hence implement our own
4173 * home-grown stack in an array. */
4174
430fb8fa
LP
4175 n_array = (unsigned) -1; /* lenght of current array entries */
4176 n_struct = strlen(types); /* length of current struct contents signature */
fe1d424d
LP
4177
4178 for (;;) {
4179 const char *t;
4180
430fb8fa
LP
4181 n_loop++;
4182
1b492614 4183 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
fe1d424d
LP
4184 r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
4185 if (r < 0)
4186 return r;
4187 if (r == 0)
4188 break;
4189
4190 r = sd_bus_message_exit_container(m);
4191 if (r < 0)
4192 return r;
4193
4194 continue;
4195 }
4196
4197 t = types;
4198 if (n_array != (unsigned) -1)
4199 n_array --;
4200 else {
4201 types ++;
4202 n_struct--;
4203 }
4204
9a17484d
LP
4205 switch (*t) {
4206
4207 case SD_BUS_TYPE_BYTE:
4208 case SD_BUS_TYPE_BOOLEAN:
4209 case SD_BUS_TYPE_INT16:
4210 case SD_BUS_TYPE_UINT16:
4211 case SD_BUS_TYPE_INT32:
4212 case SD_BUS_TYPE_UINT32:
4213 case SD_BUS_TYPE_INT64:
4214 case SD_BUS_TYPE_UINT64:
4215 case SD_BUS_TYPE_DOUBLE:
4216 case SD_BUS_TYPE_STRING:
4217 case SD_BUS_TYPE_OBJECT_PATH:
2c93b4ef
LP
4218 case SD_BUS_TYPE_SIGNATURE:
4219 case SD_BUS_TYPE_UNIX_FD: {
9a17484d
LP
4220 void *p;
4221
4222 p = va_arg(ap, void*);
4223 r = sd_bus_message_read_basic(m, *t, p);
fe1d424d
LP
4224 if (r < 0)
4225 return r;
430fb8fa
LP
4226 if (r == 0) {
4227 if (n_loop <= 1)
4228 return 0;
4229
fe1d424d 4230 return -ENXIO;
430fb8fa 4231 }
fe1d424d 4232
9a17484d
LP
4233 break;
4234 }
4235
4236 case SD_BUS_TYPE_ARRAY: {
4237 size_t k;
4238
4239 r = signature_element_length(t + 1, &k);
4240 if (r < 0)
4241 return r;
4242
4243 {
9a17484d 4244 char s[k + 1];
9a17484d
LP
4245 memcpy(s, t + 1, k);
4246 s[k] = 0;
9a17484d
LP
4247
4248 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4249 if (r < 0)
4250 return r;
430fb8fa
LP
4251 if (r == 0) {
4252 if (n_loop <= 1)
4253 return 0;
4254
9a17484d 4255 return -ENXIO;
430fb8fa 4256 }
fe1d424d 4257 }
9a17484d 4258
fe1d424d
LP
4259 if (n_array == (unsigned) -1) {
4260 types += k;
4261 n_struct -= k;
9a17484d
LP
4262 }
4263
fe1d424d
LP
4264 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4265 if (r < 0)
4266 return r;
4267
4268 types = t + 1;
4269 n_struct = k;
4270 n_array = va_arg(ap, unsigned);
4271
9a17484d
LP
4272 break;
4273 }
4274
4275 case SD_BUS_TYPE_VARIANT: {
4276 const char *s;
4277
4278 s = va_arg(ap, const char *);
4279 if (!s)
4280 return -EINVAL;
4281
4282 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s);
4283 if (r < 0)
4284 return r;
430fb8fa
LP
4285 if (r == 0) {
4286 if (n_loop <= 1)
4287 return 0;
4288
9a17484d 4289 return -ENXIO;
430fb8fa 4290 }
9a17484d 4291
fe1d424d 4292 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
9a17484d
LP
4293 if (r < 0)
4294 return r;
9a17484d 4295
fe1d424d
LP
4296 types = s;
4297 n_struct = strlen(s);
4298 n_array = (unsigned) -1;
4299
9a17484d
LP
4300 break;
4301 }
4302
4303 case SD_BUS_TYPE_STRUCT_BEGIN:
4304 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4305 size_t k;
4306
4307 r = signature_element_length(t, &k);
4308 if (r < 0)
4309 return r;
4310
4311 {
4312 char s[k - 1];
4313 memcpy(s, t + 1, k - 2);
4314 s[k - 2] = 0;
4315
4316 r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4317 if (r < 0)
4318 return r;
430fb8fa
LP
4319 if (r == 0) {
4320 if (n_loop <= 1)
4321 return 0;
9a17484d 4322 return -ENXIO;
430fb8fa 4323 }
fe1d424d 4324 }
9a17484d 4325
fe1d424d
LP
4326 if (n_array == (unsigned) -1) {
4327 types += k - 1;
4328 n_struct -= k - 1;
4329 }
9a17484d 4330
fe1d424d
LP
4331 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4332 if (r < 0)
4333 return r;
9a17484d 4334
fe1d424d
LP
4335 types = t + 1;
4336 n_struct = k - 2;
4337 n_array = (unsigned) -1;
9a17484d
LP
4338
4339 break;
4340 }
4341
4342 default:
fe1d424d 4343 return -EINVAL;
9a17484d 4344 }
9a17484d
LP
4345 }
4346
4347 return 1;
4348}
4349
d9f644e2 4350_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
9a17484d
LP
4351 va_list ap;
4352 int r;
4353
9b07511d
LP
4354 assert_return(m, -EINVAL);
4355 assert_return(m->sealed, -EPERM);
4356 assert_return(types, -EINVAL);
9a17484d
LP
4357
4358 va_start(ap, types);
4359 r = message_read_ap(m, types, ap);
4360 va_end(ap);
4361
4362 return r;
4363}
4364
d9f644e2 4365_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
9b07511d
LP
4366 int r;
4367
4368 assert_return(m, -EINVAL);
4369 assert_return(m->sealed, -EPERM);
4370 assert_return(types, -EINVAL);
4371
4372 if (isempty(types))
4373 return 0;
4374
4375 switch (*types) {
4376
4377 case SD_BUS_TYPE_BYTE:
4378 case SD_BUS_TYPE_BOOLEAN:
4379 case SD_BUS_TYPE_INT16:
4380 case SD_BUS_TYPE_UINT16:
4381 case SD_BUS_TYPE_INT32:
4382 case SD_BUS_TYPE_UINT32:
4383 case SD_BUS_TYPE_INT64:
4384 case SD_BUS_TYPE_UINT64:
4385 case SD_BUS_TYPE_DOUBLE:
4386 case SD_BUS_TYPE_STRING:
4387 case SD_BUS_TYPE_OBJECT_PATH:
4388 case SD_BUS_TYPE_SIGNATURE:
4389 case SD_BUS_TYPE_UNIX_FD:
4390
4391 r = sd_bus_message_read_basic(m, *types, NULL);
4392 if (r <= 0)
4393 return r;
4394
4395 r = sd_bus_message_skip(m, types + 1);
4396 if (r < 0)
4397 return r;
4398
4399 return 1;
4400
4401 case SD_BUS_TYPE_ARRAY: {
4402 size_t k;
4403
4404 r = signature_element_length(types + 1, &k);
4405 if (r < 0)
4406 return r;
4407
4408 {
4409 char s[k+1];
4410 memcpy(s, types+1, k);
4411 s[k] = 0;
4412
4413 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4414 if (r <= 0)
4415 return r;
4416
4417 for (;;) {
4418 r = sd_bus_message_skip(m, s);
4419 if (r < 0)
4420 return r;
4421 if (r == 0)
4422 break;
4423 }
4424
4425 r = sd_bus_message_exit_container(m);
4426 if (r < 0)
4427 return r;
4428 }
4429
4430 r = sd_bus_message_skip(m, types + 1 + k);
4431 if (r < 0)
4432 return r;
4433
4434 return 1;
4435 }
4436
4437 case SD_BUS_TYPE_VARIANT: {
4438 const char *contents;
4439 char x;
4440
4441 r = sd_bus_message_peek_type(m, &x, &contents);
4442 if (r <= 0)
4443 return r;
4444
4445 if (x != SD_BUS_TYPE_VARIANT)
4446 return -ENXIO;
4447
4448 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
4449 if (r <= 0)
4450 return r;
4451
4452 r = sd_bus_message_skip(m, contents);
4453 if (r < 0)
4454 return r;
4455 assert(r != 0);
4456
4457 r = sd_bus_message_exit_container(m);
4458 if (r < 0)
4459 return r;
4460
4461 r = sd_bus_message_skip(m, types + 1);
4462 if (r < 0)
4463 return r;
4464
4465 return 1;
4466 }
4467
4468 case SD_BUS_TYPE_STRUCT_BEGIN:
4469 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4470 size_t k;
4471
4472 r = signature_element_length(types, &k);
4473 if (r < 0)
4474 return r;
4475
4476 {
4477 char s[k-1];
4478 memcpy(s, types+1, k-2);
4479 s[k-2] = 0;
4480
4481 r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4482 if (r <= 0)
4483 return r;
4484
4485 r = sd_bus_message_skip(m, s);
4486 if (r < 0)
4487 return r;
4488 assert(r != 0);
4489
4490 r = sd_bus_message_exit_container(m);
4491 if (r < 0)
4492 return r;
4493 }
4494
4495 r = sd_bus_message_skip(m, types + k);
4496 if (r < 0)
4497 return r;
4498
4499 return 1;
4500 }
4501
4502 default:
4503 return -EINVAL;
4504 }
4505}
4506
d9f644e2
ZJS
4507_public_ int sd_bus_message_read_array(sd_bus_message *m,
4508 char type,
4509 const void **ptr,
4510 size_t *size) {
b3af9646
LP
4511 struct bus_container *c;
4512 void *p;
4513 size_t sz;
4514 ssize_t align;
4515 int r;
4516
9d6c7c82
LP
4517 assert_return(m, -EINVAL);
4518 assert_return(m->sealed, -EPERM);
4519 assert_return(bus_type_is_trivial(type), -EINVAL);
4520 assert_return(ptr, -EINVAL);
4521 assert_return(size, -EINVAL);
4522 assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -ENOTSUP);
b3af9646 4523
b3af9646 4524 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
66b26c5c 4525 if (r <= 0)
b3af9646
LP
4526 return r;
4527
4528 c = message_get_container(m);
6647dc66
LP
4529
4530 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4531 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
4532 if (align < 0)
4533 return align;
4534
18f5b48f 4535 sz = c->end - c->begin;
6647dc66
LP
4536 } else {
4537 align = bus_type_get_alignment(type);
4538 if (align < 0)
4539 return align;
4540
4541 sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
4542 }
b3af9646 4543
5e86fd7b
LP
4544 if (sz == 0)
4545 /* Zero length array, let's return some aligned
4546 * pointer that is not NULL */
4547 p = (uint8_t*) NULL + align;
4548 else {
4549 r = message_peek_body(m, &m->rindex, align, sz, &p);
4550 if (r < 0)
4551 goto fail;
b3af9646
LP
4552 }
4553
4554 r = sd_bus_message_exit_container(m);
4555 if (r < 0)
4556 goto fail;
4557
4558 *ptr = (const void*) p;
4559 *size = sz;
4560
4561 return 1;
4562
4563fail:
4564 message_quit_container(m);
4565 return r;
4566}
4567
80a46c73
LP
4568static int message_peek_fields(
4569 sd_bus_message *m,
4570 size_t *rindex,
4571 size_t align,
4572 size_t nbytes,
4573 void **ret) {
4574
4575 assert(m);
4576 assert(rindex);
4577 assert(align > 0);
4578
c91cb83c 4579 return buffer_peek(BUS_MESSAGE_FIELDS(m), BUS_MESSAGE_FIELDS_SIZE(m), rindex, align, nbytes, ret);
80a46c73
LP
4580}
4581
9f26c90c
LP
4582static int message_peek_field_uint32(
4583 sd_bus_message *m,
4584 size_t *ri,
6647dc66 4585 size_t item_size,
9f26c90c
LP
4586 uint32_t *ret) {
4587
4588 int r;
4589 void *q;
4590
4591 assert(m);
4592 assert(ri);
4593
6647dc66
LP
4594 if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 4)
4595 return -EBADMSG;
4596
4597 /* identical for gvariant and dbus1 */
4598
9f26c90c
LP
4599 r = message_peek_fields(m, ri, 4, 4, &q);
4600 if (r < 0)
4601 return r;
4602
4603 if (ret)
4604 *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
4605
4606 return 0;
4607}
4608
80a46c73
LP
4609static int message_peek_field_string(
4610 sd_bus_message *m,
6693860f 4611 bool (*validate)(const char *p),
80a46c73 4612 size_t *ri,
6647dc66 4613 size_t item_size,
80a46c73
LP
4614 const char **ret) {
4615
9f26c90c 4616 uint32_t l;
80a46c73
LP
4617 int r;
4618 void *q;
4619
9a17484d 4620 assert(m);
80a46c73
LP
4621 assert(ri);
4622
6647dc66 4623 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4624
6647dc66
LP
4625 if (item_size <= 0)
4626 return -EBADMSG;
4627
4628 r = message_peek_fields(m, ri, 1, item_size, &q);
4629 if (r < 0)
4630 return r;
4631
4632 l = item_size - 1;
4633 } else {
4634 r = message_peek_field_uint32(m, ri, 4, &l);
4635 if (r < 0)
4636 return r;
4637
4638 r = message_peek_fields(m, ri, 1, l+1, &q);
4639 if (r < 0)
4640 return r;
4641 }
9a17484d 4642
6693860f
LP
4643 if (validate) {
4644 if (!validate_nul(q, l))
4645 return -EBADMSG;
4646
4647 if (!validate(q))
ac89bf1d
LP
4648 return -EBADMSG;
4649 } else {
4650 if (!validate_string(q, l))
4651 return -EBADMSG;
4652 }
80a46c73
LP
4653
4654 if (ret)
4655 *ret = q;
4656
4657 return 0;
4658}
4659
4660static int message_peek_field_signature(
4661 sd_bus_message *m,
4662 size_t *ri,
6647dc66 4663 size_t item_size,
80a46c73
LP
4664 const char **ret) {
4665
4666 size_t l;
4667 int r;
4668 void *q;
4669
4670 assert(m);
4671 assert(ri);
4672
6647dc66 4673 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4674
6647dc66
LP
4675 if (item_size <= 0)
4676 return -EBADMSG;
4677
4678 r = message_peek_fields(m, ri, 1, item_size, &q);
4679 if (r < 0)
4680 return r;
4681
4682 l = item_size - 1;
4683 } else {
4684 r = message_peek_fields(m, ri, 1, 1, &q);
4685 if (r < 0)
4686 return r;
4687
4688 l = *(uint8_t*) q;
4689 r = message_peek_fields(m, ri, 1, l+1, &q);
4690 if (r < 0)
4691 return r;
4692 }
80a46c73
LP
4693
4694 if (!validate_signature(q, l))
4695 return -EBADMSG;
4696
4697 if (ret)
4698 *ret = q;
4699
4700 return 0;
4701}
4702
80a46c73
LP
4703static int message_skip_fields(
4704 sd_bus_message *m,
4705 size_t *ri,
4706 uint32_t array_size,
4707 const char **signature) {
4708
4709 size_t original_index;
4710 int r;
4711
4712 assert(m);
4713 assert(ri);
4714 assert(signature);
6647dc66 4715 assert(!BUS_MESSAGE_IS_GVARIANT(m));
80a46c73
LP
4716
4717 original_index = *ri;
4718
4719 for (;;) {
4720 char t;
80a46c73
LP
4721 size_t l;
4722
4723 if (array_size != (uint32_t) -1 &&
4724 array_size <= *ri - original_index)
4725 return 0;
4726
4727 t = **signature;
4728 if (!t)
4729 return 0;
4730
6693860f
LP
4731 if (t == SD_BUS_TYPE_STRING) {
4732
6647dc66 4733 r = message_peek_field_string(m, NULL, ri, 0, NULL);
6693860f
LP
4734 if (r < 0)
4735 return r;
4736
4737 (*signature)++;
4738
4739 } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
80a46c73 4740
6647dc66 4741 r = message_peek_field_string(m, object_path_is_valid, ri, 0, NULL);
80a46c73
LP
4742 if (r < 0)
4743 return r;
4744
4745 (*signature)++;
4746
4747 } else if (t == SD_BUS_TYPE_SIGNATURE) {
4748
6647dc66 4749 r = message_peek_field_signature(m, ri, 0, NULL);
80a46c73
LP
4750 if (r < 0)
4751 return r;
4752
4753 (*signature)++;
4754
4755 } else if (bus_type_is_basic(t)) {
27f6e5c7 4756 ssize_t align, k;
80a46c73 4757
c66a2e0c
TG
4758 align = bus_type_get_alignment(t);
4759 k = bus_type_get_size(t);
27f6e5c7 4760 assert(align > 0 && k > 0);
80a46c73
LP
4761
4762 r = message_peek_fields(m, ri, align, k, NULL);
4763 if (r < 0)
4764 return r;
9a17484d 4765
80a46c73
LP
4766 (*signature)++;
4767
4768 } else if (t == SD_BUS_TYPE_ARRAY) {
4769
4770 r = signature_element_length(*signature+1, &l);
4771 if (r < 0)
4772 return r;
4773
4774 assert(l >= 1);
4775 {
4776 char sig[l-1], *s;
9f26c90c 4777 uint32_t nas;
80a46c73
LP
4778 int alignment;
4779
4780 strncpy(sig, *signature + 1, l-1);
4781 s = sig;
4782
4783 alignment = bus_type_get_alignment(sig[0]);
4784 if (alignment < 0)
4785 return alignment;
4786
6647dc66 4787 r = message_peek_field_uint32(m, ri, 0, &nas);
80a46c73
LP
4788 if (r < 0)
4789 return r;
ac89bf1d 4790 if (nas > BUS_ARRAY_MAX_SIZE)
80a46c73
LP
4791 return -EBADMSG;
4792
4793 r = message_peek_fields(m, ri, alignment, 0, NULL);
4794 if (r < 0)
4795 return r;
4796
4797 r = message_skip_fields(m, ri, nas, (const char**) &s);
4798 if (r < 0)
4799 return r;
4800 }
4801
4802 (*signature) += 1 + l;
4803
4804 } else if (t == SD_BUS_TYPE_VARIANT) {
4805 const char *s;
4806
6647dc66 4807 r = message_peek_field_signature(m, ri, 0, &s);
80a46c73
LP
4808 if (r < 0)
4809 return r;
4810
4811 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
4812 if (r < 0)
4813 return r;
4814
4815 (*signature)++;
4816
4817 } else if (t == SD_BUS_TYPE_STRUCT ||
4818 t == SD_BUS_TYPE_DICT_ENTRY) {
4819
4820 r = signature_element_length(*signature, &l);
4821 if (r < 0)
4822 return r;
4823
4824 assert(l >= 2);
4825 {
4826 char sig[l-1], *s;
4827 strncpy(sig, *signature + 1, l-1);
4828 s = sig;
4829
4830 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
4831 if (r < 0)
4832 return r;
4833 }
4834
4835 *signature += l;
4836 } else
4837 return -EINVAL;
4838 }
4839}
4840
6629161f 4841int bus_message_parse_fields(sd_bus_message *m) {
80a46c73
LP
4842 size_t ri;
4843 int r;
2c93b4ef 4844 uint32_t unix_fds = 0;
6647dc66
LP
4845 void *offsets = NULL;
4846 unsigned n_offsets = 0;
4847 size_t sz;
4848 unsigned i = 0;
80a46c73
LP
4849
4850 assert(m);
4851
6647dc66
LP
4852 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4853 void *q;
4854
4855 sz = determine_word_size(BUS_MESSAGE_FIELDS_SIZE(m), 0);
4856 if (sz > 0) {
4857 size_t framing;
4858
4859 ri = BUS_MESSAGE_FIELDS_SIZE(m) - sz;
4860 r = message_peek_fields(m, &ri, 1, sz, &q);
4861 if (r < 0)
4862 return r;
4863
4864 framing = read_word_le(q, sz);
4865 if (framing >= BUS_MESSAGE_FIELDS_SIZE(m) - sz)
4866 return -EBADMSG;
4867 if ((BUS_MESSAGE_FIELDS_SIZE(m) - framing) % sz != 0)
4868 return -EBADMSG;
4869
4870 ri = framing;
4871 r = message_peek_fields(m, &ri, 1, BUS_MESSAGE_FIELDS_SIZE(m) - framing, &offsets);
4872 if (r < 0)
4873 return r;
4874
4875 n_offsets = (BUS_MESSAGE_FIELDS_SIZE(m) - framing) / sz;
4876 }
4877 }
4878
4879 ri = 0;
4880 while (ri < BUS_MESSAGE_FIELDS_SIZE(m)) {
4881 _cleanup_free_ char *sig = NULL;
80a46c73
LP
4882 const char *signature;
4883 uint8_t *header;
6647dc66
LP
4884 size_t item_size = (size_t) -1;
4885
4886 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4887 if (i >= n_offsets)
4888 break;
4889
4890 if (i == 0)
4891 ri = 0;
4892 else
4893 ri = ALIGN_TO(read_word_le((uint8_t*) offsets + (i-1)*sz, sz), 8);
4894 }
80a46c73
LP
4895
4896 r = message_peek_fields(m, &ri, 8, 1, (void**) &header);
4897 if (r < 0)
4898 return r;
4899
6647dc66
LP
4900 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4901 size_t where, end;
4902 char *b;
4903 void *q;
4904
4905 end = read_word_le((uint8_t*) offsets + i*sz, sz);
4906
4907 if (end < ri)
4908 return -EBADMSG;
4909
4910 where = ri = ALIGN_TO(ri, 8);
4911 item_size = end - ri;
4912 r = message_peek_fields(m, &where, 1, item_size, &q);
4913 if (r < 0)
4914 return r;
4915
4916 b = memrchr(q, 0, item_size);
4917 if (!b)
4918 return -EBADMSG;
4919
4920 sig = strndup(b+1, item_size - (b+1-(char*) q));
4921 if (!sig)
4922 return -ENOMEM;
4923
4924 signature = sig;
4925 item_size = b - (char*) q;
4926 } else {
4927 r = message_peek_field_signature(m, &ri, 0, &signature);
4928 if (r < 0)
4929 return r;
4930 }
80a46c73
LP
4931
4932 switch (*header) {
0461f8cd 4933 case _BUS_MESSAGE_HEADER_INVALID:
80a46c73
LP
4934 return -EBADMSG;
4935
0461f8cd 4936 case BUS_MESSAGE_HEADER_PATH:
2c93b4ef
LP
4937
4938 if (m->path)
4939 return -EBADMSG;
4940
80a46c73
LP
4941 if (!streq(signature, "o"))
4942 return -EBADMSG;
4943
6647dc66 4944 r = message_peek_field_string(m, object_path_is_valid, &ri, item_size, &m->path);
80a46c73
LP
4945 break;
4946
0461f8cd 4947 case BUS_MESSAGE_HEADER_INTERFACE:
2c93b4ef
LP
4948
4949 if (m->interface)
4950 return -EBADMSG;
4951
80a46c73
LP
4952 if (!streq(signature, "s"))
4953 return -EBADMSG;
4954
6647dc66 4955 r = message_peek_field_string(m, interface_name_is_valid, &ri, item_size, &m->interface);
80a46c73
LP
4956 break;
4957
0461f8cd 4958 case BUS_MESSAGE_HEADER_MEMBER:
2c93b4ef
LP
4959
4960 if (m->member)
4961 return -EBADMSG;
4962
80a46c73
LP
4963 if (!streq(signature, "s"))
4964 return -EBADMSG;
4965
6647dc66 4966 r = message_peek_field_string(m, member_name_is_valid, &ri, item_size, &m->member);
80a46c73
LP
4967 break;
4968
0461f8cd 4969 case BUS_MESSAGE_HEADER_ERROR_NAME:
2c93b4ef
LP
4970
4971 if (m->error.name)
4972 return -EBADMSG;
4973
80a46c73
LP
4974 if (!streq(signature, "s"))
4975 return -EBADMSG;
4976
6647dc66 4977 r = message_peek_field_string(m, error_name_is_valid, &ri, item_size, &m->error.name);
79f8d3d2
LP
4978 if (r >= 0)
4979 m->error._need_free = -1;
4980
80a46c73
LP
4981 break;
4982
0461f8cd 4983 case BUS_MESSAGE_HEADER_DESTINATION:
2c93b4ef
LP
4984
4985 if (m->destination)
4986 return -EBADMSG;
4987
80a46c73
LP
4988 if (!streq(signature, "s"))
4989 return -EBADMSG;
4990
6647dc66 4991 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->destination);
80a46c73
LP
4992 break;
4993
0461f8cd 4994 case BUS_MESSAGE_HEADER_SENDER:
2c93b4ef
LP
4995
4996 if (m->sender)
4997 return -EBADMSG;
4998
80a46c73
LP
4999 if (!streq(signature, "s"))
5000 return -EBADMSG;
5001
6647dc66 5002 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
49b832c5
LP
5003
5004 if (r >= 0 && m->sender[0] == ':' && m->bus && m->bus->bus_client && !m->bus->is_kernel) {
5005 m->creds.unique_name = (char*) m->sender;
5006 m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
5007 }
5008
80a46c73
LP
5009 break;
5010
5011
0461f8cd 5012 case BUS_MESSAGE_HEADER_SIGNATURE: {
80a46c73
LP
5013 const char *s;
5014 char *c;
5015
2c93b4ef
LP
5016 if (m->root_container.signature)
5017 return -EBADMSG;
5018
80a46c73
LP
5019 if (!streq(signature, "g"))
5020 return -EBADMSG;
5021
6647dc66 5022 r = message_peek_field_signature(m, &ri, item_size, &s);
80a46c73
LP
5023 if (r < 0)
5024 return r;
5025
5026 c = strdup(s);
5027 if (!c)
5028 return -ENOMEM;
5029
5030 free(m->root_container.signature);
5031 m->root_container.signature = c;
80a46c73
LP
5032 break;
5033 }
5034
0461f8cd 5035 case BUS_MESSAGE_HEADER_REPLY_SERIAL:
2c93b4ef
LP
5036 if (m->reply_serial != 0)
5037 return -EBADMSG;
5038
80a46c73
LP
5039 if (!streq(signature, "u"))
5040 return -EBADMSG;
5041
6647dc66 5042 r = message_peek_field_uint32(m, &ri, item_size, &m->reply_serial);
6693860f
LP
5043 if (r < 0)
5044 return r;
5045
5046 if (m->reply_serial == 0)
5047 return -EBADMSG;
5048
80a46c73
LP
5049 break;
5050
0461f8cd 5051 case BUS_MESSAGE_HEADER_UNIX_FDS:
2c93b4ef
LP
5052 if (unix_fds != 0)
5053 return -EBADMSG;
5054
5055 if (!streq(signature, "u"))
5056 return -EBADMSG;
5057
6647dc66 5058 r = message_peek_field_uint32(m, &ri, item_size, &unix_fds);
2c93b4ef
LP
5059 if (r < 0)
5060 return -EBADMSG;
5061
5062 if (unix_fds == 0)
5063 return -EBADMSG;
5064
5065 break;
5066
80a46c73 5067 default:
6647dc66
LP
5068 if (!BUS_MESSAGE_IS_GVARIANT(m))
5069 r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
80a46c73
LP
5070 }
5071
5072 if (r < 0)
5073 return r;
6647dc66
LP
5074
5075 i++;
80a46c73
LP
5076 }
5077
2c93b4ef
LP
5078 if (m->n_fds != unix_fds)
5079 return -EBADMSG;
5080
80a46c73
LP
5081 if (isempty(m->root_container.signature) != (BUS_MESSAGE_BODY_SIZE(m) == 0))
5082 return -EBADMSG;
5083
5084 switch (m->header->type) {
5085
40ca29a1 5086 case SD_BUS_MESSAGE_SIGNAL:
80a46c73
LP
5087 if (!m->path || !m->interface || !m->member)
5088 return -EBADMSG;
5089 break;
5090
40ca29a1 5091 case SD_BUS_MESSAGE_METHOD_CALL:
80a46c73
LP
5092
5093 if (!m->path || !m->member)
5094 return -EBADMSG;
5095
5096 break;
5097
40ca29a1 5098 case SD_BUS_MESSAGE_METHOD_RETURN:
80a46c73
LP
5099
5100 if (m->reply_serial == 0)
5101 return -EBADMSG;
5102 break;
5103
40ca29a1 5104 case SD_BUS_MESSAGE_METHOD_ERROR:
80a46c73
LP
5105
5106 if (m->reply_serial == 0 || !m->error.name)
5107 return -EBADMSG;
5108 break;
5109 }
9a17484d 5110
6647dc66
LP
5111 m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
5112
5113 if (BUS_MESSAGE_IS_GVARIANT(m)) {
5114 r = build_struct_offsets(
5115 m,
5116 m->root_container.signature,
5117 BUS_MESSAGE_BODY_SIZE(m),
5118 &m->root_container.item_size,
5119 &m->root_container.offsets,
5120 &m->root_container.n_offsets);
5121 if (r < 0)
5122 return r;
5123 }
5124
89ffcd2a 5125 /* Try to read the error message, but if we can't it's a non-issue */
40ca29a1 5126 if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
89ffcd2a
LP
5127 sd_bus_message_read(m, "s", &m->error.message);
5128
9a17484d
LP
5129 return 0;
5130}
5131
d9f644e2 5132_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
9d6c7c82
LP
5133 assert_return(m, -EINVAL);
5134 assert_return(destination, -EINVAL);
5135 assert_return(!m->sealed, -EPERM);
5136 assert_return(!m->destination, -EEXIST);
9a17484d 5137
0461f8cd 5138 return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
9a17484d
LP
5139}
5140
de1c301e
LP
5141int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
5142 size_t total;
de1c301e 5143 void *p, *e;
bc7fd8cd
LP
5144 unsigned i;
5145 struct bus_body_part *part;
de1c301e
LP
5146
5147 assert(m);
5148 assert(buffer);
5149 assert(sz);
5150
6629161f 5151 total = BUS_MESSAGE_SIZE(m);
de1c301e
LP
5152
5153 p = malloc(total);
5154 if (!p)
5155 return -ENOMEM;
5156
c91cb83c 5157 e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m));
9b29bb68 5158 MESSAGE_FOREACH_PART(part, i, m)
bc7fd8cd 5159 e = mempcpy(e, part->data, part->size);
2100fa10
LP
5160
5161 assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p));
de1c301e
LP
5162
5163 *buffer = p;
5164 *sz = total;
5165
5166 return 0;
5167}
89ffcd2a
LP
5168
5169int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
5170 int r;
5171
5172 assert(m);
5173 assert(l);
5174
5175 r = sd_bus_message_enter_container(m, 'a', "s");
4686d1b6 5176 if (r <= 0)
89ffcd2a
LP
5177 return r;
5178
5179 for (;;) {
5180 const char *s;
5181
5182 r = sd_bus_message_read_basic(m, 's', &s);
5183 if (r < 0)
5184 return r;
5185 if (r == 0)
5186 break;
5187
5188 r = strv_extend(l, s);
5189 if (r < 0)
5190 return r;
5191 }
5192
5193 r = sd_bus_message_exit_container(m);
5194 if (r < 0)
5195 return r;
5196
405cd3aa 5197 return 1;
89ffcd2a 5198}
392d5b37 5199
ba341e7c 5200_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
4686d1b6
MAP
5201 char **strv = NULL;
5202 int r;
5203
5204 assert_return(m, -EINVAL);
5205 assert_return(m->sealed, -EPERM);
5206 assert_return(l, -EINVAL);
5207
5208 r = bus_message_read_strv_extend(m, &strv);
5209 if (r <= 0) {
5210 strv_free(strv);
5211 return r;
5212 }
5213
5214 *l = strv;
5215 return 1;
5216}
5217
392d5b37
LP
5218const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
5219 int r;
42c5aaf3
LP
5220 const char *t = NULL;
5221 unsigned j;
392d5b37
LP
5222
5223 assert(m);
5224
5225 r = sd_bus_message_rewind(m, true);
5226 if (r < 0)
5227 return NULL;
5228
42c5aaf3
LP
5229 for (j = 0; j <= i; j++) {
5230 char type;
5231
392d5b37
LP
5232 r = sd_bus_message_peek_type(m, &type, NULL);
5233 if (r < 0)
5234 return NULL;
5235
5236 if (type != SD_BUS_TYPE_STRING &&
5237 type != SD_BUS_TYPE_OBJECT_PATH &&
5238 type != SD_BUS_TYPE_SIGNATURE)
5239 return NULL;
5240
5241 r = sd_bus_message_read_basic(m, type, &t);
5242 if (r < 0)
5243 return NULL;
392d5b37
LP
5244 }
5245
392d5b37
LP
5246 return t;
5247}
2100fa10 5248
c91cb83c
LP
5249bool bus_header_is_complete(struct bus_header *h, size_t size) {
5250 size_t full;
5251
5252 assert(h);
5253 assert(size);
5254
5255 if (size < sizeof(struct bus_header))
5256 return false;
5257
5258 full = sizeof(struct bus_header) +
0461f8cd 5259 (h->endian == BUS_NATIVE_ENDIAN ? h->fields_size : bswap_32(h->fields_size));
c91cb83c
LP
5260
5261 return size >= full;
5262}
5263
5264int bus_header_message_size(struct bus_header *h, size_t *sum) {
6629161f
LP
5265 size_t fs, bs;
5266
5267 assert(h);
5268 assert(sum);
5269
0461f8cd 5270 if (h->endian == BUS_NATIVE_ENDIAN) {
6629161f
LP
5271 fs = h->fields_size;
5272 bs = h->body_size;
0461f8cd 5273 } else if (h->endian == BUS_REVERSE_ENDIAN) {
6629161f
LP
5274 fs = bswap_32(h->fields_size);
5275 bs = bswap_32(h->body_size);
5276 } else
5277 return -EBADMSG;
2100fa10 5278
6629161f
LP
5279 *sum = sizeof(struct bus_header) + ALIGN8(fs) + bs;
5280 return 0;
2100fa10 5281}
eb01ba5d 5282
d9f644e2 5283_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
40ca29a1 5284 assert_return(m, -EINVAL);
eb01ba5d 5285
40ca29a1 5286 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
eb01ba5d
LP
5287 return 0;
5288
40ca29a1 5289 return sd_bus_error_get_errno(&m->error);
eb01ba5d 5290}
29ddb38f 5291
d9f644e2 5292_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
29ddb38f
LP
5293 struct bus_container *c;
5294
9d6c7c82 5295 assert_return(m, NULL);
29ddb38f
LP
5296
5297 c = complete ? &m->root_container : message_get_container(m);
d6385068 5298 return strempty(c->signature);
29ddb38f 5299}
c430fee6 5300
d9f644e2 5301_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
c430fee6
LP
5302 bool done_something = false;
5303 int r;
5304
80ba3b84
LP
5305 assert_return(m, -EINVAL);
5306 assert_return(source, -EINVAL);
5307 assert_return(!m->sealed, -EPERM);
5308 assert_return(source->sealed, -EPERM);
5309
c430fee6
LP
5310 do {
5311 const char *contents;
5312 char type;
5313 union {
5314 uint8_t u8;
5315 uint16_t u16;
5316 int16_t s16;
5317 uint32_t u32;
5318 int32_t s32;
5319 uint64_t u64;
5320 int64_t s64;
5321 double d64;
5322 const char *string;
5323 int i;
5324 } basic;
5325
5326 r = sd_bus_message_peek_type(source, &type, &contents);
5327 if (r < 0)
5328 return r;
5329 if (r == 0)
5330 break;
5331
5332 done_something = true;
5333
5334 if (bus_type_is_container(type) > 0) {
5335
5336 r = sd_bus_message_enter_container(source, type, contents);
5337 if (r < 0)
5338 return r;
5339
5340 r = sd_bus_message_open_container(m, type, contents);
5341 if (r < 0)
5342 return r;
5343
5344 r = sd_bus_message_copy(m, source, true);
5345 if (r < 0)
5346 return r;
5347
5348 r = sd_bus_message_close_container(m);
5349 if (r < 0)
5350 return r;
5351
5352 r = sd_bus_message_exit_container(source);
5353 if (r < 0)
5354 return r;
5355
5356 continue;
5357 }
5358
5359 r = sd_bus_message_read_basic(source, type, &basic);
5360 if (r < 0)
5361 return r;
5362
5363 assert(r > 0);
5364
5365 if (type == SD_BUS_TYPE_OBJECT_PATH ||
5366 type == SD_BUS_TYPE_SIGNATURE ||
5367 type == SD_BUS_TYPE_STRING)
5368 r = sd_bus_message_append_basic(m, type, basic.string);
5369 else
5370 r = sd_bus_message_append_basic(m, type, &basic);
5371
5372 if (r < 0)
5373 return r;
5374
5375 } while (all);
5376
5377 return done_something;
5378}
5379
d9f644e2 5380_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
c430fee6
LP
5381 const char *c;
5382 char t;
5383 int r;
5384
5385 assert_return(m, -EINVAL);
5386 assert_return(m->sealed, -EPERM);
5387 assert_return(!type || bus_type_is_valid(type), -EINVAL);
5388 assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
5389 assert_return(type || contents, -EINVAL);
5390 assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
5391
5392 r = sd_bus_message_peek_type(m, &t, &c);
5393 if (r <= 0)
5394 return r;
5395
5396 if (type != 0 && type != t)
5397 return 0;
5398
5399 if (contents && !streq_ptr(contents, c))
5400 return 0;
5401
5402 return 1;
5403}
2be44176
LP
5404
5405_public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) {
5406 assert_return(m, NULL);
5407
5408 return m->bus;
5409}