]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-message.c
bus: it's OK to send messages with an empty payload but non-empty signature
[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;
5763192a 3914 unsigned saved;
6647dc66 3915 int r;
9a17484d 3916
9d6c7c82
LP
3917 assert_return(m, -EINVAL);
3918 assert_return(m->sealed, -EPERM);
f959af20 3919 assert_return(m->n_containers > 0, -ENXIO);
9a17484d
LP
3920
3921 c = message_get_container(m);
6647dc66
LP
3922
3923 if (c->enclosing != SD_BUS_TYPE_ARRAY) {
3924 if (c->signature && c->signature[c->index] != 0)
3925 return -EBUSY;
3926 }
3927
3928 if (BUS_MESSAGE_IS_GVARIANT(m)) {
3929 if (m->rindex < c->end)
3930 return -EBUSY;
3931
3932 } else if (c->enclosing == SD_BUS_TYPE_ARRAY) {
9a17484d
LP
3933 uint32_t l;
3934
3935 l = BUS_MESSAGE_BSWAP32(m, *c->array_size);
3936 if (c->begin + l != m->rindex)
3937 return -EBUSY;
9a17484d
LP
3938 }
3939
3940 free(c->signature);
6647dc66 3941 free(c->offsets);
9a17484d
LP
3942 m->n_containers--;
3943
6647dc66
LP
3944 c = message_get_container(m);
3945
5763192a
LP
3946 saved = c->index;
3947 c->index = c->saved_index;
6647dc66 3948 r = container_next_item(m, c, &m->rindex);
5763192a 3949 c->index = saved;
6647dc66
LP
3950 if (r < 0)
3951 return r;
3952
9a17484d
LP
3953 return 1;
3954}
3955
b3af9646
LP
3956static void message_quit_container(sd_bus_message *m) {
3957 struct bus_container *c;
3958
3959 assert(m);
3960 assert(m->sealed);
3961 assert(m->n_containers > 0);
3962
3963 c = message_get_container(m);
3964
3965 /* Undo seeks */
3966 assert(m->rindex >= c->before);
3967 m->rindex = c->before;
3968
3969 /* Free container */
3970 free(c->signature);
6647dc66 3971 free(c->offsets);
b3af9646
LP
3972 m->n_containers--;
3973
3974 /* Correct index of new top-level container */
3975 c = message_get_container(m);
3976 c->index = c->saved_index;
3977}
3978
d9f644e2 3979_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
9a17484d
LP
3980 struct bus_container *c;
3981 int r;
3982
c430fee6
LP
3983 assert_return(m, -EINVAL);
3984 assert_return(m->sealed, -EPERM);
9a17484d 3985
7b058942 3986 if (message_end_of_signature(m))
9a17484d
LP
3987 goto eof;
3988
3989 if (message_end_of_array(m, m->rindex))
3990 goto eof;
3991
7b058942
LP
3992 c = message_get_container(m);
3993
9a17484d
LP
3994 if (bus_type_is_basic(c->signature[c->index])) {
3995 if (contents)
3996 *contents = NULL;
3997 if (type)
3998 *type = c->signature[c->index];
3999 return 1;
4000 }
4001
4002 if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) {
4003
4004 if (contents) {
4005 size_t l;
4006 char *sig;
4007
4008 r = signature_element_length(c->signature+c->index+1, &l);
4009 if (r < 0)
4010 return r;
4011
80a46c73
LP
4012 assert(l >= 1);
4013
9a17484d
LP
4014 sig = strndup(c->signature + c->index + 1, l);
4015 if (!sig)
4016 return -ENOMEM;
4017
4018 free(m->peeked_signature);
4019 m->peeked_signature = sig;
4020
4021 *contents = sig;
4022 }
4023
4024 if (type)
4025 *type = SD_BUS_TYPE_ARRAY;
4026
4027 return 1;
4028 }
4029
4030 if (c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ||
4031 c->signature[c->index] == SD_BUS_TYPE_DICT_ENTRY_BEGIN) {
4032
4033 if (contents) {
4034 size_t l;
4035 char *sig;
4036
4037 r = signature_element_length(c->signature+c->index, &l);
4038 if (r < 0)
4039 return r;
4040
4041 assert(l >= 2);
4042 sig = strndup(c->signature + c->index + 1, l - 2);
4043 if (!sig)
4044 return -ENOMEM;
4045
4046 free(m->peeked_signature);
4047 m->peeked_signature = sig;
4048
4049 *contents = sig;
4050 }
4051
4052 if (type)
4053 *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
4054
4055 return 1;
4056 }
4057
4058 if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) {
4059 if (contents) {
9a17484d
LP
4060 void *q;
4061
6647dc66
LP
4062 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4063 size_t k;
9a17484d 4064
6647dc66
LP
4065 if (c->item_size < 2)
4066 return -EBADMSG;
9a17484d 4067
6647dc66
LP
4068 /* Look for the NUL delimiter that
4069 separates the payload from the
4070 signature. Since the body might be
4071 in a different part that then the
4072 signature we map byte by byte. */
4073
4074 for (k = 2; k <= c->item_size; k++) {
4075 size_t where;
4076
4077 where = m->rindex + c->item_size - k;
4078 r = message_peek_body(m, &where, 1, k, &q);
4079 if (r < 0)
4080 return r;
6647dc66
LP
4081
4082 if (*(char*) q == 0)
4083 break;
4084 }
4085
4086 if (k > c->item_size)
4087 return -EBADMSG;
4088
4089 free(m->peeked_signature);
4090 m->peeked_signature = strndup((char*) q + 1, k - 1);
4091 if (!m->peeked_signature)
4092 return -ENOMEM;
4093
4094 if (!signature_is_valid(m->peeked_signature, true))
4095 return -EBADMSG;
4096
4097 *contents = m->peeked_signature;
4098 } else {
4099 size_t rindex, l;
4100
4101 rindex = m->rindex;
4102 r = message_peek_body(m, &rindex, 1, 1, &q);
4103 if (r < 0)
4104 return r;
9a17484d 4105
6647dc66
LP
4106 l = *(uint8_t*) q;
4107 r = message_peek_body(m, &rindex, 1, l+1, &q);
4108 if (r < 0)
4109 return r;
6647dc66
LP
4110
4111 if (!validate_signature(q, l))
4112 return -EBADMSG;
4113
4114 *contents = q;
4115 }
9a17484d
LP
4116 }
4117
4118 if (type)
4119 *type = SD_BUS_TYPE_VARIANT;
4120
4121 return 1;
4122 }
4123
4124 return -EINVAL;
4125
4126eof:
4127 if (type)
7b058942 4128 *type = 0;
9a17484d
LP
4129 if (contents)
4130 *contents = NULL;
4131 return 0;
4132}
4133
d9f644e2 4134_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
9a17484d
LP
4135 struct bus_container *c;
4136
9d6c7c82
LP
4137 assert_return(m, -EINVAL);
4138 assert_return(m->sealed, -EPERM);
9a17484d
LP
4139
4140 if (complete) {
bc7fd8cd 4141 message_reset_containers(m);
9a17484d 4142 m->rindex = 0;
9a17484d
LP
4143
4144 c = message_get_container(m);
4145 } else {
4146 c = message_get_container(m);
4147
6647dc66 4148 c->offset_index = 0;
9a17484d
LP
4149 c->index = 0;
4150 m->rindex = c->begin;
4151 }
4152
d36b7031
LP
4153 c->offset_index = 0;
4154 c->item_size = c->n_offsets > 0 ? c->offsets[0] : c->end;
4155
9a17484d
LP
4156 return !isempty(c->signature);
4157}
718db961 4158
1b492614
LP
4159static int message_read_ap(
4160 sd_bus_message *m,
4161 const char *types,
4162 va_list ap) {
9a17484d 4163
fe1d424d
LP
4164 unsigned n_array, n_struct;
4165 TypeStack stack[BUS_CONTAINER_DEPTH];
4166 unsigned stack_ptr = 0;
430fb8fa 4167 unsigned n_loop = 0;
9a17484d
LP
4168 int r;
4169
4170 assert(m);
1b492614 4171
430fb8fa 4172 if (isempty(types))
1b492614 4173 return 0;
9a17484d 4174
fe1d424d
LP
4175 /* Ideally, we'd just call ourselves recursively on every
4176 * complex type. However, the state of a va_list that is
4177 * passed to a function is undefined after that function
4178 * returns. This means we need to docode the va_list linearly
4179 * in a single stackframe. We hence implement our own
4180 * home-grown stack in an array. */
4181
430fb8fa
LP
4182 n_array = (unsigned) -1; /* lenght of current array entries */
4183 n_struct = strlen(types); /* length of current struct contents signature */
fe1d424d
LP
4184
4185 for (;;) {
4186 const char *t;
4187
430fb8fa
LP
4188 n_loop++;
4189
1b492614 4190 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
fe1d424d
LP
4191 r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
4192 if (r < 0)
4193 return r;
4194 if (r == 0)
4195 break;
4196
4197 r = sd_bus_message_exit_container(m);
4198 if (r < 0)
4199 return r;
4200
4201 continue;
4202 }
4203
4204 t = types;
4205 if (n_array != (unsigned) -1)
4206 n_array --;
4207 else {
4208 types ++;
4209 n_struct--;
4210 }
4211
9a17484d
LP
4212 switch (*t) {
4213
4214 case SD_BUS_TYPE_BYTE:
4215 case SD_BUS_TYPE_BOOLEAN:
4216 case SD_BUS_TYPE_INT16:
4217 case SD_BUS_TYPE_UINT16:
4218 case SD_BUS_TYPE_INT32:
4219 case SD_BUS_TYPE_UINT32:
4220 case SD_BUS_TYPE_INT64:
4221 case SD_BUS_TYPE_UINT64:
4222 case SD_BUS_TYPE_DOUBLE:
4223 case SD_BUS_TYPE_STRING:
4224 case SD_BUS_TYPE_OBJECT_PATH:
2c93b4ef
LP
4225 case SD_BUS_TYPE_SIGNATURE:
4226 case SD_BUS_TYPE_UNIX_FD: {
9a17484d
LP
4227 void *p;
4228
4229 p = va_arg(ap, void*);
4230 r = sd_bus_message_read_basic(m, *t, p);
fe1d424d
LP
4231 if (r < 0)
4232 return r;
430fb8fa
LP
4233 if (r == 0) {
4234 if (n_loop <= 1)
4235 return 0;
4236
fe1d424d 4237 return -ENXIO;
430fb8fa 4238 }
fe1d424d 4239
9a17484d
LP
4240 break;
4241 }
4242
4243 case SD_BUS_TYPE_ARRAY: {
4244 size_t k;
4245
4246 r = signature_element_length(t + 1, &k);
4247 if (r < 0)
4248 return r;
4249
4250 {
9a17484d 4251 char s[k + 1];
9a17484d
LP
4252 memcpy(s, t + 1, k);
4253 s[k] = 0;
9a17484d
LP
4254
4255 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4256 if (r < 0)
4257 return r;
430fb8fa
LP
4258 if (r == 0) {
4259 if (n_loop <= 1)
4260 return 0;
4261
9a17484d 4262 return -ENXIO;
430fb8fa 4263 }
fe1d424d 4264 }
9a17484d 4265
fe1d424d
LP
4266 if (n_array == (unsigned) -1) {
4267 types += k;
4268 n_struct -= k;
9a17484d
LP
4269 }
4270
fe1d424d
LP
4271 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4272 if (r < 0)
4273 return r;
4274
4275 types = t + 1;
4276 n_struct = k;
4277 n_array = va_arg(ap, unsigned);
4278
9a17484d
LP
4279 break;
4280 }
4281
4282 case SD_BUS_TYPE_VARIANT: {
4283 const char *s;
4284
4285 s = va_arg(ap, const char *);
4286 if (!s)
4287 return -EINVAL;
4288
4289 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s);
4290 if (r < 0)
4291 return r;
430fb8fa
LP
4292 if (r == 0) {
4293 if (n_loop <= 1)
4294 return 0;
4295
9a17484d 4296 return -ENXIO;
430fb8fa 4297 }
9a17484d 4298
fe1d424d 4299 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
9a17484d
LP
4300 if (r < 0)
4301 return r;
9a17484d 4302
fe1d424d
LP
4303 types = s;
4304 n_struct = strlen(s);
4305 n_array = (unsigned) -1;
4306
9a17484d
LP
4307 break;
4308 }
4309
4310 case SD_BUS_TYPE_STRUCT_BEGIN:
4311 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4312 size_t k;
4313
4314 r = signature_element_length(t, &k);
4315 if (r < 0)
4316 return r;
4317
4318 {
4319 char s[k - 1];
4320 memcpy(s, t + 1, k - 2);
4321 s[k - 2] = 0;
4322
4323 r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4324 if (r < 0)
4325 return r;
430fb8fa
LP
4326 if (r == 0) {
4327 if (n_loop <= 1)
4328 return 0;
9a17484d 4329 return -ENXIO;
430fb8fa 4330 }
fe1d424d 4331 }
9a17484d 4332
fe1d424d
LP
4333 if (n_array == (unsigned) -1) {
4334 types += k - 1;
4335 n_struct -= k - 1;
4336 }
9a17484d 4337
fe1d424d
LP
4338 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4339 if (r < 0)
4340 return r;
9a17484d 4341
fe1d424d
LP
4342 types = t + 1;
4343 n_struct = k - 2;
4344 n_array = (unsigned) -1;
9a17484d
LP
4345
4346 break;
4347 }
4348
4349 default:
fe1d424d 4350 return -EINVAL;
9a17484d 4351 }
9a17484d
LP
4352 }
4353
4354 return 1;
4355}
4356
d9f644e2 4357_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
9a17484d
LP
4358 va_list ap;
4359 int r;
4360
9b07511d
LP
4361 assert_return(m, -EINVAL);
4362 assert_return(m->sealed, -EPERM);
4363 assert_return(types, -EINVAL);
9a17484d
LP
4364
4365 va_start(ap, types);
4366 r = message_read_ap(m, types, ap);
4367 va_end(ap);
4368
4369 return r;
4370}
4371
d9f644e2 4372_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
9b07511d
LP
4373 int r;
4374
4375 assert_return(m, -EINVAL);
4376 assert_return(m->sealed, -EPERM);
4377 assert_return(types, -EINVAL);
4378
4379 if (isempty(types))
4380 return 0;
4381
4382 switch (*types) {
4383
4384 case SD_BUS_TYPE_BYTE:
4385 case SD_BUS_TYPE_BOOLEAN:
4386 case SD_BUS_TYPE_INT16:
4387 case SD_BUS_TYPE_UINT16:
4388 case SD_BUS_TYPE_INT32:
4389 case SD_BUS_TYPE_UINT32:
4390 case SD_BUS_TYPE_INT64:
4391 case SD_BUS_TYPE_UINT64:
4392 case SD_BUS_TYPE_DOUBLE:
4393 case SD_BUS_TYPE_STRING:
4394 case SD_BUS_TYPE_OBJECT_PATH:
4395 case SD_BUS_TYPE_SIGNATURE:
4396 case SD_BUS_TYPE_UNIX_FD:
4397
4398 r = sd_bus_message_read_basic(m, *types, NULL);
4399 if (r <= 0)
4400 return r;
4401
4402 r = sd_bus_message_skip(m, types + 1);
4403 if (r < 0)
4404 return r;
4405
4406 return 1;
4407
4408 case SD_BUS_TYPE_ARRAY: {
4409 size_t k;
4410
4411 r = signature_element_length(types + 1, &k);
4412 if (r < 0)
4413 return r;
4414
4415 {
4416 char s[k+1];
4417 memcpy(s, types+1, k);
4418 s[k] = 0;
4419
4420 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4421 if (r <= 0)
4422 return r;
4423
4424 for (;;) {
4425 r = sd_bus_message_skip(m, s);
4426 if (r < 0)
4427 return r;
4428 if (r == 0)
4429 break;
4430 }
4431
4432 r = sd_bus_message_exit_container(m);
4433 if (r < 0)
4434 return r;
4435 }
4436
4437 r = sd_bus_message_skip(m, types + 1 + k);
4438 if (r < 0)
4439 return r;
4440
4441 return 1;
4442 }
4443
4444 case SD_BUS_TYPE_VARIANT: {
4445 const char *contents;
4446 char x;
4447
4448 r = sd_bus_message_peek_type(m, &x, &contents);
4449 if (r <= 0)
4450 return r;
4451
4452 if (x != SD_BUS_TYPE_VARIANT)
4453 return -ENXIO;
4454
4455 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
4456 if (r <= 0)
4457 return r;
4458
4459 r = sd_bus_message_skip(m, contents);
4460 if (r < 0)
4461 return r;
4462 assert(r != 0);
4463
4464 r = sd_bus_message_exit_container(m);
4465 if (r < 0)
4466 return r;
4467
4468 r = sd_bus_message_skip(m, types + 1);
4469 if (r < 0)
4470 return r;
4471
4472 return 1;
4473 }
4474
4475 case SD_BUS_TYPE_STRUCT_BEGIN:
4476 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4477 size_t k;
4478
4479 r = signature_element_length(types, &k);
4480 if (r < 0)
4481 return r;
4482
4483 {
4484 char s[k-1];
4485 memcpy(s, types+1, k-2);
4486 s[k-2] = 0;
4487
4488 r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4489 if (r <= 0)
4490 return r;
4491
4492 r = sd_bus_message_skip(m, s);
4493 if (r < 0)
4494 return r;
4495 assert(r != 0);
4496
4497 r = sd_bus_message_exit_container(m);
4498 if (r < 0)
4499 return r;
4500 }
4501
4502 r = sd_bus_message_skip(m, types + k);
4503 if (r < 0)
4504 return r;
4505
4506 return 1;
4507 }
4508
4509 default:
4510 return -EINVAL;
4511 }
4512}
4513
d9f644e2
ZJS
4514_public_ int sd_bus_message_read_array(sd_bus_message *m,
4515 char type,
4516 const void **ptr,
4517 size_t *size) {
b3af9646
LP
4518 struct bus_container *c;
4519 void *p;
4520 size_t sz;
4521 ssize_t align;
4522 int r;
4523
9d6c7c82
LP
4524 assert_return(m, -EINVAL);
4525 assert_return(m->sealed, -EPERM);
4526 assert_return(bus_type_is_trivial(type), -EINVAL);
4527 assert_return(ptr, -EINVAL);
4528 assert_return(size, -EINVAL);
4529 assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -ENOTSUP);
b3af9646 4530
b3af9646 4531 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
66b26c5c 4532 if (r <= 0)
b3af9646
LP
4533 return r;
4534
4535 c = message_get_container(m);
6647dc66
LP
4536
4537 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4538 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
4539 if (align < 0)
4540 return align;
4541
18f5b48f 4542 sz = c->end - c->begin;
6647dc66
LP
4543 } else {
4544 align = bus_type_get_alignment(type);
4545 if (align < 0)
4546 return align;
4547
4548 sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
4549 }
b3af9646 4550
5e86fd7b
LP
4551 if (sz == 0)
4552 /* Zero length array, let's return some aligned
4553 * pointer that is not NULL */
4554 p = (uint8_t*) NULL + align;
4555 else {
4556 r = message_peek_body(m, &m->rindex, align, sz, &p);
4557 if (r < 0)
4558 goto fail;
b3af9646
LP
4559 }
4560
4561 r = sd_bus_message_exit_container(m);
4562 if (r < 0)
4563 goto fail;
4564
4565 *ptr = (const void*) p;
4566 *size = sz;
4567
4568 return 1;
4569
4570fail:
4571 message_quit_container(m);
4572 return r;
4573}
4574
80a46c73
LP
4575static int message_peek_fields(
4576 sd_bus_message *m,
4577 size_t *rindex,
4578 size_t align,
4579 size_t nbytes,
4580 void **ret) {
4581
4582 assert(m);
4583 assert(rindex);
4584 assert(align > 0);
4585
c91cb83c 4586 return buffer_peek(BUS_MESSAGE_FIELDS(m), BUS_MESSAGE_FIELDS_SIZE(m), rindex, align, nbytes, ret);
80a46c73
LP
4587}
4588
9f26c90c
LP
4589static int message_peek_field_uint32(
4590 sd_bus_message *m,
4591 size_t *ri,
6647dc66 4592 size_t item_size,
9f26c90c
LP
4593 uint32_t *ret) {
4594
4595 int r;
4596 void *q;
4597
4598 assert(m);
4599 assert(ri);
4600
6647dc66
LP
4601 if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 4)
4602 return -EBADMSG;
4603
4604 /* identical for gvariant and dbus1 */
4605
9f26c90c
LP
4606 r = message_peek_fields(m, ri, 4, 4, &q);
4607 if (r < 0)
4608 return r;
4609
4610 if (ret)
4611 *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
4612
4613 return 0;
4614}
4615
80a46c73
LP
4616static int message_peek_field_string(
4617 sd_bus_message *m,
6693860f 4618 bool (*validate)(const char *p),
80a46c73 4619 size_t *ri,
6647dc66 4620 size_t item_size,
80a46c73
LP
4621 const char **ret) {
4622
9f26c90c 4623 uint32_t l;
80a46c73
LP
4624 int r;
4625 void *q;
4626
9a17484d 4627 assert(m);
80a46c73
LP
4628 assert(ri);
4629
6647dc66 4630 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4631
6647dc66
LP
4632 if (item_size <= 0)
4633 return -EBADMSG;
4634
4635 r = message_peek_fields(m, ri, 1, item_size, &q);
4636 if (r < 0)
4637 return r;
4638
4639 l = item_size - 1;
4640 } else {
4641 r = message_peek_field_uint32(m, ri, 4, &l);
4642 if (r < 0)
4643 return r;
4644
4645 r = message_peek_fields(m, ri, 1, l+1, &q);
4646 if (r < 0)
4647 return r;
4648 }
9a17484d 4649
6693860f
LP
4650 if (validate) {
4651 if (!validate_nul(q, l))
4652 return -EBADMSG;
4653
4654 if (!validate(q))
ac89bf1d
LP
4655 return -EBADMSG;
4656 } else {
4657 if (!validate_string(q, l))
4658 return -EBADMSG;
4659 }
80a46c73
LP
4660
4661 if (ret)
4662 *ret = q;
4663
4664 return 0;
4665}
4666
4667static int message_peek_field_signature(
4668 sd_bus_message *m,
4669 size_t *ri,
6647dc66 4670 size_t item_size,
80a46c73
LP
4671 const char **ret) {
4672
4673 size_t l;
4674 int r;
4675 void *q;
4676
4677 assert(m);
4678 assert(ri);
4679
6647dc66 4680 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4681
6647dc66
LP
4682 if (item_size <= 0)
4683 return -EBADMSG;
4684
4685 r = message_peek_fields(m, ri, 1, item_size, &q);
4686 if (r < 0)
4687 return r;
4688
4689 l = item_size - 1;
4690 } else {
4691 r = message_peek_fields(m, ri, 1, 1, &q);
4692 if (r < 0)
4693 return r;
4694
4695 l = *(uint8_t*) q;
4696 r = message_peek_fields(m, ri, 1, l+1, &q);
4697 if (r < 0)
4698 return r;
4699 }
80a46c73
LP
4700
4701 if (!validate_signature(q, l))
4702 return -EBADMSG;
4703
4704 if (ret)
4705 *ret = q;
4706
4707 return 0;
4708}
4709
80a46c73
LP
4710static int message_skip_fields(
4711 sd_bus_message *m,
4712 size_t *ri,
4713 uint32_t array_size,
4714 const char **signature) {
4715
4716 size_t original_index;
4717 int r;
4718
4719 assert(m);
4720 assert(ri);
4721 assert(signature);
6647dc66 4722 assert(!BUS_MESSAGE_IS_GVARIANT(m));
80a46c73
LP
4723
4724 original_index = *ri;
4725
4726 for (;;) {
4727 char t;
80a46c73
LP
4728 size_t l;
4729
4730 if (array_size != (uint32_t) -1 &&
4731 array_size <= *ri - original_index)
4732 return 0;
4733
4734 t = **signature;
4735 if (!t)
4736 return 0;
4737
6693860f
LP
4738 if (t == SD_BUS_TYPE_STRING) {
4739
6647dc66 4740 r = message_peek_field_string(m, NULL, ri, 0, NULL);
6693860f
LP
4741 if (r < 0)
4742 return r;
4743
4744 (*signature)++;
4745
4746 } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
80a46c73 4747
6647dc66 4748 r = message_peek_field_string(m, object_path_is_valid, ri, 0, NULL);
80a46c73
LP
4749 if (r < 0)
4750 return r;
4751
4752 (*signature)++;
4753
4754 } else if (t == SD_BUS_TYPE_SIGNATURE) {
4755
6647dc66 4756 r = message_peek_field_signature(m, ri, 0, NULL);
80a46c73
LP
4757 if (r < 0)
4758 return r;
4759
4760 (*signature)++;
4761
4762 } else if (bus_type_is_basic(t)) {
27f6e5c7 4763 ssize_t align, k;
80a46c73 4764
c66a2e0c
TG
4765 align = bus_type_get_alignment(t);
4766 k = bus_type_get_size(t);
27f6e5c7 4767 assert(align > 0 && k > 0);
80a46c73
LP
4768
4769 r = message_peek_fields(m, ri, align, k, NULL);
4770 if (r < 0)
4771 return r;
9a17484d 4772
80a46c73
LP
4773 (*signature)++;
4774
4775 } else if (t == SD_BUS_TYPE_ARRAY) {
4776
4777 r = signature_element_length(*signature+1, &l);
4778 if (r < 0)
4779 return r;
4780
4781 assert(l >= 1);
4782 {
4783 char sig[l-1], *s;
9f26c90c 4784 uint32_t nas;
80a46c73
LP
4785 int alignment;
4786
4787 strncpy(sig, *signature + 1, l-1);
4788 s = sig;
4789
4790 alignment = bus_type_get_alignment(sig[0]);
4791 if (alignment < 0)
4792 return alignment;
4793
6647dc66 4794 r = message_peek_field_uint32(m, ri, 0, &nas);
80a46c73
LP
4795 if (r < 0)
4796 return r;
ac89bf1d 4797 if (nas > BUS_ARRAY_MAX_SIZE)
80a46c73
LP
4798 return -EBADMSG;
4799
4800 r = message_peek_fields(m, ri, alignment, 0, NULL);
4801 if (r < 0)
4802 return r;
4803
4804 r = message_skip_fields(m, ri, nas, (const char**) &s);
4805 if (r < 0)
4806 return r;
4807 }
4808
4809 (*signature) += 1 + l;
4810
4811 } else if (t == SD_BUS_TYPE_VARIANT) {
4812 const char *s;
4813
6647dc66 4814 r = message_peek_field_signature(m, ri, 0, &s);
80a46c73
LP
4815 if (r < 0)
4816 return r;
4817
4818 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
4819 if (r < 0)
4820 return r;
4821
4822 (*signature)++;
4823
4824 } else if (t == SD_BUS_TYPE_STRUCT ||
4825 t == SD_BUS_TYPE_DICT_ENTRY) {
4826
4827 r = signature_element_length(*signature, &l);
4828 if (r < 0)
4829 return r;
4830
4831 assert(l >= 2);
4832 {
4833 char sig[l-1], *s;
4834 strncpy(sig, *signature + 1, l-1);
4835 s = sig;
4836
4837 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
4838 if (r < 0)
4839 return r;
4840 }
4841
4842 *signature += l;
4843 } else
4844 return -EINVAL;
4845 }
4846}
4847
6629161f 4848int bus_message_parse_fields(sd_bus_message *m) {
80a46c73
LP
4849 size_t ri;
4850 int r;
2c93b4ef 4851 uint32_t unix_fds = 0;
6647dc66
LP
4852 void *offsets = NULL;
4853 unsigned n_offsets = 0;
8f2e44f8 4854 size_t sz = 0;
6647dc66 4855 unsigned i = 0;
80a46c73
LP
4856
4857 assert(m);
4858
6647dc66
LP
4859 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4860 void *q;
4861
4862 sz = determine_word_size(BUS_MESSAGE_FIELDS_SIZE(m), 0);
4863 if (sz > 0) {
4864 size_t framing;
4865
4866 ri = BUS_MESSAGE_FIELDS_SIZE(m) - sz;
4867 r = message_peek_fields(m, &ri, 1, sz, &q);
4868 if (r < 0)
4869 return r;
4870
4871 framing = read_word_le(q, sz);
4872 if (framing >= BUS_MESSAGE_FIELDS_SIZE(m) - sz)
4873 return -EBADMSG;
4874 if ((BUS_MESSAGE_FIELDS_SIZE(m) - framing) % sz != 0)
4875 return -EBADMSG;
4876
4877 ri = framing;
4878 r = message_peek_fields(m, &ri, 1, BUS_MESSAGE_FIELDS_SIZE(m) - framing, &offsets);
4879 if (r < 0)
4880 return r;
4881
4882 n_offsets = (BUS_MESSAGE_FIELDS_SIZE(m) - framing) / sz;
4883 }
4884 }
4885
4886 ri = 0;
4887 while (ri < BUS_MESSAGE_FIELDS_SIZE(m)) {
4888 _cleanup_free_ char *sig = NULL;
80a46c73
LP
4889 const char *signature;
4890 uint8_t *header;
6647dc66
LP
4891 size_t item_size = (size_t) -1;
4892
4893 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4894 if (i >= n_offsets)
4895 break;
4896
4897 if (i == 0)
4898 ri = 0;
4899 else
4900 ri = ALIGN_TO(read_word_le((uint8_t*) offsets + (i-1)*sz, sz), 8);
4901 }
80a46c73
LP
4902
4903 r = message_peek_fields(m, &ri, 8, 1, (void**) &header);
4904 if (r < 0)
4905 return r;
4906
6647dc66
LP
4907 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4908 size_t where, end;
4909 char *b;
4910 void *q;
4911
4912 end = read_word_le((uint8_t*) offsets + i*sz, sz);
4913
4914 if (end < ri)
4915 return -EBADMSG;
4916
4917 where = ri = ALIGN_TO(ri, 8);
4918 item_size = end - ri;
4919 r = message_peek_fields(m, &where, 1, item_size, &q);
4920 if (r < 0)
4921 return r;
4922
4923 b = memrchr(q, 0, item_size);
4924 if (!b)
4925 return -EBADMSG;
4926
4927 sig = strndup(b+1, item_size - (b+1-(char*) q));
4928 if (!sig)
4929 return -ENOMEM;
4930
4931 signature = sig;
4932 item_size = b - (char*) q;
4933 } else {
4934 r = message_peek_field_signature(m, &ri, 0, &signature);
4935 if (r < 0)
4936 return r;
4937 }
80a46c73
LP
4938
4939 switch (*header) {
0461f8cd 4940 case _BUS_MESSAGE_HEADER_INVALID:
80a46c73
LP
4941 return -EBADMSG;
4942
0461f8cd 4943 case BUS_MESSAGE_HEADER_PATH:
2c93b4ef
LP
4944
4945 if (m->path)
4946 return -EBADMSG;
4947
80a46c73
LP
4948 if (!streq(signature, "o"))
4949 return -EBADMSG;
4950
6647dc66 4951 r = message_peek_field_string(m, object_path_is_valid, &ri, item_size, &m->path);
80a46c73
LP
4952 break;
4953
0461f8cd 4954 case BUS_MESSAGE_HEADER_INTERFACE:
2c93b4ef
LP
4955
4956 if (m->interface)
4957 return -EBADMSG;
4958
80a46c73
LP
4959 if (!streq(signature, "s"))
4960 return -EBADMSG;
4961
6647dc66 4962 r = message_peek_field_string(m, interface_name_is_valid, &ri, item_size, &m->interface);
80a46c73
LP
4963 break;
4964
0461f8cd 4965 case BUS_MESSAGE_HEADER_MEMBER:
2c93b4ef
LP
4966
4967 if (m->member)
4968 return -EBADMSG;
4969
80a46c73
LP
4970 if (!streq(signature, "s"))
4971 return -EBADMSG;
4972
6647dc66 4973 r = message_peek_field_string(m, member_name_is_valid, &ri, item_size, &m->member);
80a46c73
LP
4974 break;
4975
0461f8cd 4976 case BUS_MESSAGE_HEADER_ERROR_NAME:
2c93b4ef
LP
4977
4978 if (m->error.name)
4979 return -EBADMSG;
4980
80a46c73
LP
4981 if (!streq(signature, "s"))
4982 return -EBADMSG;
4983
6647dc66 4984 r = message_peek_field_string(m, error_name_is_valid, &ri, item_size, &m->error.name);
79f8d3d2
LP
4985 if (r >= 0)
4986 m->error._need_free = -1;
4987
80a46c73
LP
4988 break;
4989
0461f8cd 4990 case BUS_MESSAGE_HEADER_DESTINATION:
2c93b4ef
LP
4991
4992 if (m->destination)
4993 return -EBADMSG;
4994
80a46c73
LP
4995 if (!streq(signature, "s"))
4996 return -EBADMSG;
4997
6647dc66 4998 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->destination);
80a46c73
LP
4999 break;
5000
0461f8cd 5001 case BUS_MESSAGE_HEADER_SENDER:
2c93b4ef
LP
5002
5003 if (m->sender)
5004 return -EBADMSG;
5005
80a46c73
LP
5006 if (!streq(signature, "s"))
5007 return -EBADMSG;
5008
6647dc66 5009 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
49b832c5
LP
5010
5011 if (r >= 0 && m->sender[0] == ':' && m->bus && m->bus->bus_client && !m->bus->is_kernel) {
5012 m->creds.unique_name = (char*) m->sender;
5013 m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
5014 }
5015
80a46c73
LP
5016 break;
5017
5018
0461f8cd 5019 case BUS_MESSAGE_HEADER_SIGNATURE: {
80a46c73
LP
5020 const char *s;
5021 char *c;
5022
2c93b4ef
LP
5023 if (m->root_container.signature)
5024 return -EBADMSG;
5025
80a46c73
LP
5026 if (!streq(signature, "g"))
5027 return -EBADMSG;
5028
6647dc66 5029 r = message_peek_field_signature(m, &ri, item_size, &s);
80a46c73
LP
5030 if (r < 0)
5031 return r;
5032
5033 c = strdup(s);
5034 if (!c)
5035 return -ENOMEM;
5036
5037 free(m->root_container.signature);
5038 m->root_container.signature = c;
80a46c73
LP
5039 break;
5040 }
5041
0461f8cd 5042 case BUS_MESSAGE_HEADER_REPLY_SERIAL:
2c93b4ef
LP
5043 if (m->reply_serial != 0)
5044 return -EBADMSG;
5045
80a46c73
LP
5046 if (!streq(signature, "u"))
5047 return -EBADMSG;
5048
6647dc66 5049 r = message_peek_field_uint32(m, &ri, item_size, &m->reply_serial);
6693860f
LP
5050 if (r < 0)
5051 return r;
5052
5053 if (m->reply_serial == 0)
5054 return -EBADMSG;
5055
80a46c73
LP
5056 break;
5057
0461f8cd 5058 case BUS_MESSAGE_HEADER_UNIX_FDS:
2c93b4ef
LP
5059 if (unix_fds != 0)
5060 return -EBADMSG;
5061
5062 if (!streq(signature, "u"))
5063 return -EBADMSG;
5064
6647dc66 5065 r = message_peek_field_uint32(m, &ri, item_size, &unix_fds);
2c93b4ef
LP
5066 if (r < 0)
5067 return -EBADMSG;
5068
5069 if (unix_fds == 0)
5070 return -EBADMSG;
5071
5072 break;
5073
80a46c73 5074 default:
6647dc66
LP
5075 if (!BUS_MESSAGE_IS_GVARIANT(m))
5076 r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
80a46c73
LP
5077 }
5078
5079 if (r < 0)
5080 return r;
6647dc66
LP
5081
5082 i++;
80a46c73
LP
5083 }
5084
2c93b4ef
LP
5085 if (m->n_fds != unix_fds)
5086 return -EBADMSG;
5087
80a46c73
LP
5088 switch (m->header->type) {
5089
40ca29a1 5090 case SD_BUS_MESSAGE_SIGNAL:
80a46c73
LP
5091 if (!m->path || !m->interface || !m->member)
5092 return -EBADMSG;
5093 break;
5094
40ca29a1 5095 case SD_BUS_MESSAGE_METHOD_CALL:
80a46c73
LP
5096
5097 if (!m->path || !m->member)
5098 return -EBADMSG;
5099
5100 break;
5101
40ca29a1 5102 case SD_BUS_MESSAGE_METHOD_RETURN:
80a46c73
LP
5103
5104 if (m->reply_serial == 0)
5105 return -EBADMSG;
5106 break;
5107
40ca29a1 5108 case SD_BUS_MESSAGE_METHOD_ERROR:
80a46c73
LP
5109
5110 if (m->reply_serial == 0 || !m->error.name)
5111 return -EBADMSG;
5112 break;
5113 }
9a17484d 5114
6647dc66
LP
5115 m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
5116
5117 if (BUS_MESSAGE_IS_GVARIANT(m)) {
5118 r = build_struct_offsets(
5119 m,
5120 m->root_container.signature,
5121 BUS_MESSAGE_BODY_SIZE(m),
5122 &m->root_container.item_size,
5123 &m->root_container.offsets,
5124 &m->root_container.n_offsets);
5125 if (r < 0)
5126 return r;
5127 }
5128
89ffcd2a 5129 /* Try to read the error message, but if we can't it's a non-issue */
40ca29a1 5130 if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
89ffcd2a
LP
5131 sd_bus_message_read(m, "s", &m->error.message);
5132
9a17484d
LP
5133 return 0;
5134}
5135
d9f644e2 5136_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
9d6c7c82
LP
5137 assert_return(m, -EINVAL);
5138 assert_return(destination, -EINVAL);
5139 assert_return(!m->sealed, -EPERM);
5140 assert_return(!m->destination, -EEXIST);
9a17484d 5141
0461f8cd 5142 return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
9a17484d
LP
5143}
5144
de1c301e
LP
5145int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
5146 size_t total;
de1c301e 5147 void *p, *e;
bc7fd8cd
LP
5148 unsigned i;
5149 struct bus_body_part *part;
de1c301e
LP
5150
5151 assert(m);
5152 assert(buffer);
5153 assert(sz);
5154
6629161f 5155 total = BUS_MESSAGE_SIZE(m);
de1c301e
LP
5156
5157 p = malloc(total);
5158 if (!p)
5159 return -ENOMEM;
5160
c91cb83c 5161 e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m));
9b29bb68 5162 MESSAGE_FOREACH_PART(part, i, m)
bc7fd8cd 5163 e = mempcpy(e, part->data, part->size);
2100fa10
LP
5164
5165 assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p));
de1c301e
LP
5166
5167 *buffer = p;
5168 *sz = total;
5169
5170 return 0;
5171}
89ffcd2a
LP
5172
5173int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
5174 int r;
5175
5176 assert(m);
5177 assert(l);
5178
5179 r = sd_bus_message_enter_container(m, 'a', "s");
4686d1b6 5180 if (r <= 0)
89ffcd2a
LP
5181 return r;
5182
5183 for (;;) {
5184 const char *s;
5185
5186 r = sd_bus_message_read_basic(m, 's', &s);
5187 if (r < 0)
5188 return r;
5189 if (r == 0)
5190 break;
5191
5192 r = strv_extend(l, s);
5193 if (r < 0)
5194 return r;
5195 }
5196
5197 r = sd_bus_message_exit_container(m);
5198 if (r < 0)
5199 return r;
5200
405cd3aa 5201 return 1;
89ffcd2a 5202}
392d5b37 5203
ba341e7c 5204_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
4686d1b6
MAP
5205 char **strv = NULL;
5206 int r;
5207
5208 assert_return(m, -EINVAL);
5209 assert_return(m->sealed, -EPERM);
5210 assert_return(l, -EINVAL);
5211
5212 r = bus_message_read_strv_extend(m, &strv);
5213 if (r <= 0) {
5214 strv_free(strv);
5215 return r;
5216 }
5217
5218 *l = strv;
5219 return 1;
5220}
5221
392d5b37
LP
5222const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
5223 int r;
42c5aaf3
LP
5224 const char *t = NULL;
5225 unsigned j;
392d5b37
LP
5226
5227 assert(m);
5228
5229 r = sd_bus_message_rewind(m, true);
5230 if (r < 0)
5231 return NULL;
5232
42c5aaf3
LP
5233 for (j = 0; j <= i; j++) {
5234 char type;
5235
392d5b37
LP
5236 r = sd_bus_message_peek_type(m, &type, NULL);
5237 if (r < 0)
5238 return NULL;
5239
5240 if (type != SD_BUS_TYPE_STRING &&
5241 type != SD_BUS_TYPE_OBJECT_PATH &&
5242 type != SD_BUS_TYPE_SIGNATURE)
5243 return NULL;
5244
5245 r = sd_bus_message_read_basic(m, type, &t);
5246 if (r < 0)
5247 return NULL;
392d5b37
LP
5248 }
5249
392d5b37
LP
5250 return t;
5251}
2100fa10 5252
c91cb83c
LP
5253bool bus_header_is_complete(struct bus_header *h, size_t size) {
5254 size_t full;
5255
5256 assert(h);
5257 assert(size);
5258
5259 if (size < sizeof(struct bus_header))
5260 return false;
5261
5262 full = sizeof(struct bus_header) +
0461f8cd 5263 (h->endian == BUS_NATIVE_ENDIAN ? h->fields_size : bswap_32(h->fields_size));
c91cb83c
LP
5264
5265 return size >= full;
5266}
5267
5268int bus_header_message_size(struct bus_header *h, size_t *sum) {
6629161f
LP
5269 size_t fs, bs;
5270
5271 assert(h);
5272 assert(sum);
5273
0461f8cd 5274 if (h->endian == BUS_NATIVE_ENDIAN) {
6629161f
LP
5275 fs = h->fields_size;
5276 bs = h->body_size;
0461f8cd 5277 } else if (h->endian == BUS_REVERSE_ENDIAN) {
6629161f
LP
5278 fs = bswap_32(h->fields_size);
5279 bs = bswap_32(h->body_size);
5280 } else
5281 return -EBADMSG;
2100fa10 5282
6629161f
LP
5283 *sum = sizeof(struct bus_header) + ALIGN8(fs) + bs;
5284 return 0;
2100fa10 5285}
eb01ba5d 5286
d9f644e2 5287_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
40ca29a1 5288 assert_return(m, -EINVAL);
eb01ba5d 5289
40ca29a1 5290 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
eb01ba5d
LP
5291 return 0;
5292
40ca29a1 5293 return sd_bus_error_get_errno(&m->error);
eb01ba5d 5294}
29ddb38f 5295
d9f644e2 5296_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
29ddb38f
LP
5297 struct bus_container *c;
5298
9d6c7c82 5299 assert_return(m, NULL);
29ddb38f
LP
5300
5301 c = complete ? &m->root_container : message_get_container(m);
d6385068 5302 return strempty(c->signature);
29ddb38f 5303}
c430fee6 5304
d9f644e2 5305_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
c430fee6
LP
5306 bool done_something = false;
5307 int r;
5308
80ba3b84
LP
5309 assert_return(m, -EINVAL);
5310 assert_return(source, -EINVAL);
5311 assert_return(!m->sealed, -EPERM);
5312 assert_return(source->sealed, -EPERM);
5313
c430fee6
LP
5314 do {
5315 const char *contents;
5316 char type;
5317 union {
5318 uint8_t u8;
5319 uint16_t u16;
5320 int16_t s16;
5321 uint32_t u32;
5322 int32_t s32;
5323 uint64_t u64;
5324 int64_t s64;
5325 double d64;
5326 const char *string;
5327 int i;
5328 } basic;
5329
5330 r = sd_bus_message_peek_type(source, &type, &contents);
5331 if (r < 0)
5332 return r;
5333 if (r == 0)
5334 break;
5335
5336 done_something = true;
5337
5338 if (bus_type_is_container(type) > 0) {
5339
5340 r = sd_bus_message_enter_container(source, type, contents);
5341 if (r < 0)
5342 return r;
5343
5344 r = sd_bus_message_open_container(m, type, contents);
5345 if (r < 0)
5346 return r;
5347
5348 r = sd_bus_message_copy(m, source, true);
5349 if (r < 0)
5350 return r;
5351
5352 r = sd_bus_message_close_container(m);
5353 if (r < 0)
5354 return r;
5355
5356 r = sd_bus_message_exit_container(source);
5357 if (r < 0)
5358 return r;
5359
5360 continue;
5361 }
5362
5363 r = sd_bus_message_read_basic(source, type, &basic);
5364 if (r < 0)
5365 return r;
5366
5367 assert(r > 0);
5368
5369 if (type == SD_BUS_TYPE_OBJECT_PATH ||
5370 type == SD_BUS_TYPE_SIGNATURE ||
5371 type == SD_BUS_TYPE_STRING)
5372 r = sd_bus_message_append_basic(m, type, basic.string);
5373 else
5374 r = sd_bus_message_append_basic(m, type, &basic);
5375
5376 if (r < 0)
5377 return r;
5378
5379 } while (all);
5380
5381 return done_something;
5382}
5383
d9f644e2 5384_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
c430fee6
LP
5385 const char *c;
5386 char t;
5387 int r;
5388
5389 assert_return(m, -EINVAL);
5390 assert_return(m->sealed, -EPERM);
5391 assert_return(!type || bus_type_is_valid(type), -EINVAL);
5392 assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
5393 assert_return(type || contents, -EINVAL);
5394 assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
5395
5396 r = sd_bus_message_peek_type(m, &t, &c);
5397 if (r <= 0)
5398 return r;
5399
5400 if (type != 0 && type != t)
5401 return 0;
5402
5403 if (contents && !streq_ptr(contents, c))
5404 return 0;
5405
5406 return 1;
5407}
2be44176
LP
5408
5409_public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) {
5410 assert_return(m, NULL);
5411
5412 return m->bus;
5413}