]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-message.c
bus: suppress creating empty parts in messages
[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
2029 p = c->signature;
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
6647dc66 2077 p = 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);
2407 assert_return(bus_type_is_trivial(type), -EINVAL);
2408 assert_return(ptr || size == 0, -EINVAL);
2409 assert_return(!m->poisoned, -ESTALE);
b3af9646
LP
2410
2411 align = bus_type_get_alignment(type);
2412 sz = bus_type_get_size(type);
2413
2414 assert_se(align > 0);
2415 assert_se(sz > 0);
2416
2417 if (size % sz != 0)
2418 return -EINVAL;
2419
2420 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2421 if (r < 0)
2422 return r;
2423
c1b9d935 2424 a = message_extend_body(m, align, size, false);
bc7fd8cd
LP
2425 if (!a)
2426 return -ENOMEM;
b3af9646
LP
2427
2428 r = sd_bus_message_close_container(m);
2429 if (r < 0)
bc7fd8cd 2430 return r;
b3af9646
LP
2431
2432 *ptr = a;
2433 return 0;
b3af9646
LP
2434}
2435
d9f644e2
ZJS
2436_public_ int sd_bus_message_append_array(sd_bus_message *m,
2437 char type,
2438 const void *ptr,
2439 size_t size) {
b3af9646
LP
2440 int r;
2441 void *p;
2442
9d6c7c82
LP
2443 assert_return(m, -EINVAL);
2444 assert_return(!m->sealed, -EPERM);
2445 assert_return(bus_type_is_trivial(type), -EINVAL);
2446 assert_return(ptr || size == 0, -EINVAL);
2447 assert_return(!m->poisoned, -ESTALE);
b3af9646 2448
f8e013f8 2449 r = sd_bus_message_append_array_space(m, type, size, &p);
b3af9646
LP
2450 if (r < 0)
2451 return r;
2452
2453 if (size > 0)
2454 memcpy(p, ptr, size);
2455
2456 return 0;
2457}
2458
938bcbab
LP
2459_public_ int sd_bus_message_append_array_iovec(
2460 sd_bus_message *m,
2461 char type,
2462 const struct iovec *iov,
2463 unsigned n) {
2464
2465 size_t size;
2466 unsigned i;
2467 void *p;
2468 int r;
2469
2470 assert_return(m, -EINVAL);
2471 assert_return(!m->sealed, -EPERM);
2472 assert_return(bus_type_is_trivial(type), -EINVAL);
2473 assert_return(iov || n == 0, -EINVAL);
2474 assert_return(!m->poisoned, -ESTALE);
2475
2476 size = IOVEC_TOTAL_SIZE(iov, n);
2477
2478 r = sd_bus_message_append_array_space(m, type, size, &p);
2479 if (r < 0)
2480 return r;
2481
2482 for (i = 0; i < n; i++) {
2483
2484 if (iov[i].iov_base)
2485 memcpy(p, iov[i].iov_base, iov[i].iov_len);
2486 else
2487 memset(p, 0, iov[i].iov_len);
2488
2489 p = (uint8_t*) p + iov[i].iov_len;
2490 }
2491
2492 return 0;
2493}
2494
d9f644e2
ZJS
2495_public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
2496 char type,
2497 sd_memfd *memfd) {
453a0c29
LP
2498 _cleanup_close_ int copy_fd = -1;
2499 struct bus_body_part *part;
2500 ssize_t align, sz;
2501 uint64_t size;
2502 void *a;
2503 int r;
2504
2505 if (!m)
2506 return -EINVAL;
2507 if (!memfd)
2508 return -EINVAL;
2509 if (m->sealed)
2510 return -EPERM;
2511 if (!bus_type_is_trivial(type))
2512 return -EINVAL;
2513 if (m->poisoned)
2514 return -ESTALE;
2515
2516 r = sd_memfd_set_sealed(memfd, true);
2517 if (r < 0)
2518 return r;
2519
2520 copy_fd = sd_memfd_dup_fd(memfd);
2521 if (copy_fd < 0)
2522 return copy_fd;
2523
2524 r = sd_memfd_get_size(memfd, &size);
2525 if (r < 0)
2526 return r;
2527
2528 align = bus_type_get_alignment(type);
2529 sz = bus_type_get_size(type);
2530
2531 assert_se(align > 0);
2532 assert_se(sz > 0);
2533
2534 if (size % sz != 0)
2535 return -EINVAL;
2536
5cbe7492 2537 if (size > (uint64_t) (uint32_t) -1)
453a0c29
LP
2538 return -EINVAL;
2539
2540 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2541 if (r < 0)
2542 return r;
2543
c1b9d935 2544 a = message_extend_body(m, align, 0, false);
453a0c29
LP
2545 if (!a)
2546 return -ENOMEM;
2547
2548 part = message_append_part(m);
2549 if (!part)
2550 return -ENOMEM;
2551
2552 part->memfd = copy_fd;
2553 part->sealed = true;
2554 part->size = size;
2555 copy_fd = -1;
2556
2557 message_extend_containers(m, size);
2558 m->header->body_size += size;
2559
2560 return sd_bus_message_close_container(m);
2561}
2562
d9f644e2 2563_public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) {
5cbe7492
LP
2564 _cleanup_close_ int copy_fd = -1;
2565 struct bus_body_part *part;
2566 struct bus_container *c;
2567 uint64_t size;
2568 void *a;
2569 int r;
2570
55736ed0
LP
2571 assert_return(m, -EINVAL);
2572 assert_return(memfd, -EINVAL);
2573 assert_return(!m->sealed, -EPERM);
2574 assert_return(!m->poisoned, -ESTALE);
5cbe7492
LP
2575
2576 r = sd_memfd_set_sealed(memfd, true);
2577 if (r < 0)
2578 return r;
2579
2580 copy_fd = sd_memfd_dup_fd(memfd);
2581 if (copy_fd < 0)
2582 return copy_fd;
2583
2584 r = sd_memfd_get_size(memfd, &size);
2585 if (r < 0)
2586 return r;
2587
2588 /* We require this to be NUL terminated */
2589 if (size == 0)
2590 return -EINVAL;
2591
2592 if (size > (uint64_t) (uint32_t) -1)
2593 return -EINVAL;
2594
2595 c = message_get_container(m);
2596 if (c->signature && c->signature[c->index]) {
2597 /* Container signature is already set */
2598
2599 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
2600 return -ENXIO;
2601 } else {
2602 char *e;
2603
2604 /* Maybe we can append to the signature? But only if this is the top-level container*/
2605 if (c->enclosing != 0)
2606 return -ENXIO;
2607
2608 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
2609 if (!e) {
2610 m->poisoned = true;
2611 return -ENOMEM;
2612 }
2613 }
2614
6647dc66 2615 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
2616 a = message_extend_body(m, 4, 4, false);
2617 if (!a)
2618 return -ENOMEM;
5cbe7492 2619
c1b9d935
LP
2620 *(uint32_t*) a = size - 1;
2621 }
5cbe7492
LP
2622
2623 part = message_append_part(m);
2624 if (!part)
2625 return -ENOMEM;
2626
2627 part->memfd = copy_fd;
2628 part->sealed = true;
2629 part->size = size;
2630 copy_fd = -1;
2631
5cbe7492 2632 m->header->body_size += size;
c1b9d935
LP
2633 message_extend_containers(m, size);
2634
6647dc66 2635 if (BUS_MESSAGE_IS_GVARIANT(m)) {
c1b9d935
LP
2636 r = message_add_offset(m, m->header->body_size);
2637 if (r < 0) {
2638 m->poisoned = true;
2639 return -ENOMEM;
2640 }
2641 }
5cbe7492
LP
2642
2643 if (c->enclosing != SD_BUS_TYPE_ARRAY)
2644 c->index++;
2645
2646 return 0;
2647}
2648
d9f644e2 2649_public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) {
55736ed0
LP
2650 char **i;
2651 int r;
2652
2653 assert_return(m, -EINVAL);
2654 assert_return(!m->sealed, -EPERM);
2655 assert_return(!m->poisoned, -ESTALE);
2656
2657 r = sd_bus_message_open_container(m, 'a', "s");
2658 if (r < 0)
2659 return r;
2660
2661 STRV_FOREACH(i, l) {
2662 r = sd_bus_message_append_basic(m, 's', *i);
2663 if (r < 0)
2664 return r;
2665 }
2666
2667 return sd_bus_message_close_container(m);
2668}
2669
81389225
LP
2670static int bus_message_close_header(sd_bus_message *m) {
2671 uint8_t *a;
2672 size_t sz, i;
2673
2674 assert(m);
2675
2676 if (!BUS_MESSAGE_IS_GVARIANT(m))
2677 return 0;
2678
2679 if (m->n_header_offsets < 1)
2680 return 0;
2681
2682 assert(m->header->fields_size == m->header_offsets[m->n_header_offsets-1]);
2683
2684 sz = determine_word_size(m->header->fields_size, m->n_header_offsets);
2685
2686 a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
2687 if (!a)
2688 return -ENOMEM;
2689
2690 for (i = 0; i < m->n_header_offsets; i++)
2691 write_word_le(a + sz*i, sz, m->header_offsets[i]);
2692
2693 return 0;
2694}
2695
2696int bus_message_seal(sd_bus_message *m, uint64_t serial) {
2697 struct bus_body_part *part;
2698 size_t l, a;
2699 unsigned i;
2700 int r;
2701
2702 assert(m);
2703
2704 if (m->sealed)
2705 return -EPERM;
2706
2707 if (m->n_containers > 0)
2708 return -EBADMSG;
2709
2710 if (m->poisoned)
2711 return -ESTALE;
2712
2713 /* In vtables the return signature of method calls is listed,
2714 * let's check if they match if this is a response */
2715 if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
2716 m->enforced_reply_signature &&
2717 !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
2718 return -ENOMSG;
2719
2720 /* If gvariant marshalling is used we need to close the body structure */
2721 r = bus_message_close_struct(m, &m->root_container, false);
2722 if (r < 0)
2723 return r;
2724
2725 /* If there's a non-trivial signature set, then add it in here */
2726 if (!isempty(m->root_container.signature)) {
2727 r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
2728 if (r < 0)
2729 return r;
2730 }
2731
2732 if (m->n_fds > 0) {
2733 r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
2734 if (r < 0)
2735 return r;
2736 }
2737
2738 r = bus_message_close_header(m);
2739 if (r < 0)
2740 return r;
2741
2742 m->header->serial = serial;
2743
2744 /* Add padding at the end of the fields part, since we know
2745 * the body needs to start at an 8 byte alignment. We made
2746 * sure we allocated enough space for this, so all we need to
2747 * do here is to zero it out. */
2748 l = BUS_MESSAGE_FIELDS_SIZE(m);
2749 a = ALIGN8(l) - l;
2750 if (a > 0)
2751 memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a);
2752
2753 /* If this is something we can send as memfd, then let's seal
2754 the memfd now. Note that we can send memfds as payload only
2755 for directed messages, and not for broadcasts. */
2756 if (m->destination && m->bus && m->bus->use_memfd) {
2757 MESSAGE_FOREACH_PART(part, i, m)
2758 if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) {
2759 bus_body_part_unmap(part);
2760
2761 if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
2762 part->sealed = true;
2763 }
2764 }
2765
2766 m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
2767 m->root_container.index = 0;
2768 m->root_container.offset_index = 0;
2769 m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
2770
2771 m->sealed = true;
2772
2773 return 0;
2774}
2775
a392d361 2776int bus_body_part_map(struct bus_body_part *part) {
453a0c29
LP
2777 void *p;
2778 size_t psz;
2779
2780 assert_se(part);
2781
2782 if (part->data)
2783 return 0;
2784
2785 if (part->size <= 0)
2786 return 0;
2787
1307c3ff
LP
2788 /* For smaller zero parts (as used for padding) we don't need to map anything... */
2789 if (part->memfd < 0 && part->is_zero && part->size < 8) {
2790 static const uint8_t zeroes[7] = { };
2791 part->data = (void*) zeroes;
2792 return 0;
2793 }
2794
453a0c29
LP
2795 psz = PAGE_ALIGN(part->size);
2796
2797 if (part->memfd >= 0)
2798 p = mmap(NULL, psz, PROT_READ, MAP_SHARED, part->memfd, 0);
2799 else if (part->is_zero)
2800 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
2801 else
2802 return -EINVAL;
2803
2804 if (p == MAP_FAILED)
2805 return -errno;
2806
2807 part->mapped = psz;
2808 part->data = p;
a392d361
LP
2809 part->munmap_this = true;
2810
453a0c29
LP
2811 return 0;
2812}
2813
a392d361
LP
2814void bus_body_part_unmap(struct bus_body_part *part) {
2815
2816 assert_se(part);
2817
2818 if (part->memfd < 0)
2819 return;
2820
a392d361
LP
2821 if (!part->data)
2822 return;
2823
bf30e48f
KS
2824 if (!part->munmap_this)
2825 return;
a392d361
LP
2826
2827 assert_se(munmap(part->data, part->mapped) == 0);
2828
2829 part->data = NULL;
2830 part->mapped = 0;
2831 part->munmap_this = false;
2832
2833 return;
2834}
2835
9a17484d 2836static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
bc7fd8cd 2837 size_t k, start, end;
de1c301e 2838
9a17484d
LP
2839 assert(rindex);
2840 assert(align > 0);
de1c301e 2841
9a17484d 2842 start = ALIGN_TO((size_t) *rindex, align);
bc7fd8cd 2843 end = start + nbytes;
9a17484d 2844
bc7fd8cd 2845 if (end > sz)
9a17484d
LP
2846 return -EBADMSG;
2847
2848 /* Verify that padding is 0 */
2849 for (k = *rindex; k < start; k++)
2850 if (((const uint8_t*) p)[k] != 0)
2851 return -EBADMSG;
2852
2853 if (r)
2854 *r = (uint8_t*) p + start;
2855
bc7fd8cd 2856 *rindex = end;
9a17484d
LP
2857
2858 return 1;
de1c301e
LP
2859}
2860
7b058942
LP
2861static bool message_end_of_signature(sd_bus_message *m) {
2862 struct bus_container *c;
2863
2864 assert(m);
2865
2866 c = message_get_container(m);
2867 return !c->signature || c->signature[c->index] == 0;
2868}
2869
9a17484d
LP
2870static bool message_end_of_array(sd_bus_message *m, size_t index) {
2871 struct bus_container *c;
de1c301e 2872
9a17484d 2873 assert(m);
de1c301e 2874
9a17484d 2875 c = message_get_container(m);
6647dc66 2876 if (c->enclosing != SD_BUS_TYPE_ARRAY)
9a17484d 2877 return false;
de1c301e 2878
6647dc66
LP
2879 if (BUS_MESSAGE_IS_GVARIANT(m))
2880 return index >= c->end;
2881 else {
2882 assert(c->array_size);
2883 return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
2884 }
de1c301e
LP
2885}
2886
1405bef3 2887_public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
7b058942
LP
2888 assert_return(m, -EINVAL);
2889 assert_return(m->sealed, -EPERM);
2890
2891 if (complete && m->n_containers > 0)
2892 return false;
2893
2894 if (message_end_of_signature(m))
2895 return true;
2896
2897 if (message_end_of_array(m, m->rindex))
2898 return true;
2899
2900 return false;
2901}
2902
bc7fd8cd
LP
2903static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
2904 struct bus_body_part *part;
2905 size_t begin;
453a0c29
LP
2906 int r;
2907
bc7fd8cd
LP
2908 assert(m);
2909
2910 if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) {
2911 part = m->cached_rindex_part;
2912 begin = m->cached_rindex_part_begin;
2913 } else {
2914 part = &m->body;
2915 begin = 0;
2916 }
2917
2918 while (part) {
2919 if (index < begin)
2920 return NULL;
2921
2922 if (index + sz <= begin + part->size) {
453a0c29 2923
a392d361 2924 r = bus_body_part_map(part);
453a0c29
LP
2925 if (r < 0)
2926 return NULL;
2927
bc7fd8cd 2928 if (p)
453a0c29 2929 *p = (uint8_t*) part->data + index - begin;
bc7fd8cd
LP
2930
2931 m->cached_rindex_part = part;
2932 m->cached_rindex_part_begin = begin;
2933
2934 return part;
2935 }
2936
453a0c29 2937 begin += part->size;
bc7fd8cd
LP
2938 part = part->next;
2939 }
2940
2941 return NULL;
2942}
2943
6647dc66
LP
2944static int container_next_item(sd_bus_message *m, struct bus_container *c, size_t *rindex) {
2945 int r;
2946
2947 assert(m);
2948 assert(c);
2949 assert(rindex);
2950
2951 if (!BUS_MESSAGE_IS_GVARIANT(m))
2952 return 0;
2953
2954 if (c->enclosing == SD_BUS_TYPE_ARRAY) {
2955 int sz;
2956
2957 sz = bus_gvariant_get_size(c->signature);
2958 if (sz < 0) {
2959 int alignment;
2960
2961 if (c->offset_index+1 >= c->n_offsets)
2962 goto end;
2963
2964 /* Variable-size array */
2965
2966 alignment = bus_gvariant_get_alignment(c->signature);
2967 assert(alignment > 0);
2968
2969 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
2970 c->item_size = c->offsets[c->offset_index+1] - *rindex;
2971 } else {
2972 /* Fixed-size array */
2973 *rindex += sz;
2974 c->item_size = sz;
2975 }
2976
2977 c->offset_index++;
2978
2979 } else if (c->enclosing == 0 ||
2980 c->enclosing == SD_BUS_TYPE_STRUCT ||
2981 c->enclosing == SD_BUS_TYPE_DICT_ENTRY) {
2982
2983 int alignment;
2984 size_t n, j;
2985
2986 if (c->offset_index+1 >= c->n_offsets)
2987 goto end;
2988
2989 r = signature_element_length(c->signature + c->index, &n);
2990 if (r < 0)
2991 return r;
2992
2993 r = signature_element_length(c->signature + c->index + n, &j);
2994 if (r < 0)
2995 return r;
2996 else {
2997 char t[j+1];
2998 memcpy(t, c->signature + c->index + n, j);
2999 t[j] = 0;
3000
3001 alignment = bus_gvariant_get_alignment(t);
3002 }
3003
3004 assert(alignment > 0);
3005
3006 *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
3007 c->item_size = c->offsets[c->offset_index+1] - *rindex;
3008
3009 c->offset_index++;
3010
3011 } else if (c->enclosing == SD_BUS_TYPE_VARIANT)
3012 goto end;
3013 else
3014 assert_not_reached("Unknown container type");
3015
3016 return 0;
3017
3018end:
3019 /* Reached the end */
3020 *rindex = c->end;
3021 c->item_size = 0;
3022 return 0;
3023}
3024
3025
bc7fd8cd
LP
3026static int message_peek_body(
3027 sd_bus_message *m,
3028 size_t *rindex,
3029 size_t align,
3030 size_t nbytes,
3031 void **ret) {
3032
3033 size_t k, start, end, padding;
3034 struct bus_body_part *part;
3035 uint8_t *q;
3036
de1c301e 3037 assert(m);
9a17484d
LP
3038 assert(rindex);
3039 assert(align > 0);
de1c301e 3040
bc7fd8cd
LP
3041 start = ALIGN_TO((size_t) *rindex, align);
3042 padding = start - *rindex;
3043 end = start + nbytes;
3044
3045 if (end > BUS_MESSAGE_BODY_SIZE(m))
3046 return -EBADMSG;
3047
3048 part = find_part(m, *rindex, padding, (void**) &q);
3049 if (!part)
3050 return -EBADMSG;
3051
3052 if (q) {
3053 /* Verify padding */
3054 for (k = 0; k < padding; k++)
3055 if (q[k] != 0)
3056 return -EBADMSG;
3057 }
3058
3059 part = find_part(m, start, nbytes, (void**) &q);
3060 if (!part || !q)
3061 return -EBADMSG;
3062
3063 *rindex = end;
3064
3065 if (ret)
3066 *ret = q;
3067
18f5b48f 3068 return 0;
9a17484d 3069}
de1c301e 3070
ac89bf1d 3071static bool validate_nul(const char *s, size_t l) {
de1c301e 3072
9a17484d
LP
3073 /* Check for NUL chars in the string */
3074 if (memchr(s, 0, l))
3075 return false;
de1c301e 3076
9a17484d
LP
3077 /* Check for NUL termination */
3078 if (s[l] != 0)
3079 return false;
de1c301e 3080
ac89bf1d
LP
3081 return true;
3082}
3083
3084static bool validate_string(const char *s, size_t l) {
3085
3086 if (!validate_nul(s, l))
3087 return false;
3088
9a17484d
LP
3089 /* Check if valid UTF8 */
3090 if (!utf8_is_valid(s))
3091 return false;
3092
3093 return true;
de1c301e
LP
3094}
3095
9a17484d 3096static bool validate_signature(const char *s, size_t l) {
de1c301e 3097
ac89bf1d 3098 if (!validate_nul(s, l))
9a17484d 3099 return false;
de1c301e 3100
9a17484d
LP
3101 /* Check if valid signature */
3102 if (!signature_is_valid(s, true))
3103 return false;
3104
3105 return true;
3106}
3107
ac89bf1d
LP
3108static bool validate_object_path(const char *s, size_t l) {
3109
3110 if (!validate_nul(s, l))
3111 return false;
3112
3113 if (!object_path_is_valid(s))
3114 return false;
3115
3116 return true;
3117}
3118
d9f644e2 3119_public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
9a17484d 3120 struct bus_container *c;
6647dc66 3121 size_t rindex;
9a17484d 3122 void *q;
0dcd14b9 3123 int r;
9a17484d 3124
9d6c7c82
LP
3125 assert_return(m, -EINVAL);
3126 assert_return(m->sealed, -EPERM);
3127 assert_return(bus_type_is_basic(type), -EINVAL);
de1c301e 3128
7b058942 3129 if (message_end_of_signature(m))
430fb8fa 3130 return -ENXIO;
9a17484d 3131
1daf8121
LP
3132 if (message_end_of_array(m, m->rindex))
3133 return 0;
3134
7b058942 3135 c = message_get_container(m);
9a17484d
LP
3136 if (c->signature[c->index] != type)
3137 return -ENXIO;
3138
6647dc66 3139 rindex = m->rindex;
9a17484d 3140
6647dc66 3141 if (BUS_MESSAGE_IS_GVARIANT(m)) {
9a17484d 3142
6647dc66
LP
3143 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
3144 bool ok;
9a17484d 3145
6647dc66 3146 r = message_peek_body(m, &rindex, 1, c->item_size, &q);
18f5b48f 3147 if (r < 0)
6647dc66
LP
3148 return r;
3149
3150 if (type == SD_BUS_TYPE_STRING)
3151 ok = validate_string(q, c->item_size-1);
3152 else if (type == SD_BUS_TYPE_OBJECT_PATH)
3153 ok = validate_object_path(q, c->item_size-1);
3154 else
3155 ok = validate_signature(q, c->item_size-1);
9a17484d 3156
6647dc66 3157 if (!ok)
ac89bf1d 3158 return -EBADMSG;
6647dc66
LP
3159
3160 if (p)
3161 *(const char**) p = q;
ac89bf1d 3162 } else {
6647dc66
LP
3163 int sz, align;
3164
3165 sz = bus_gvariant_get_size(CHAR_TO_STR(type));
3166 assert(sz > 0);
3167 if ((size_t) sz != c->item_size)
ac89bf1d 3168 return -EBADMSG;
9a17484d 3169
6647dc66
LP
3170 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
3171 assert(align > 0);
0dcd14b9 3172
6647dc66 3173 r = message_peek_body(m, &rindex, align, c->item_size, &q);
18f5b48f 3174 if (r < 0)
6647dc66 3175 return r;
de1c301e 3176
6647dc66 3177 switch (type) {
9a17484d 3178
6647dc66
LP
3179 case SD_BUS_TYPE_BYTE:
3180 if (p)
3181 *(uint8_t*) p = *(uint8_t*) q;
3182 break;
9a17484d 3183
6647dc66
LP
3184 case SD_BUS_TYPE_BOOLEAN:
3185 if (p)
3186 *(int*) p = !!*(uint8_t*) q;
3187 break;
9a17484d 3188
6647dc66
LP
3189 case SD_BUS_TYPE_INT16:
3190 case SD_BUS_TYPE_UINT16:
3191 if (p)
3192 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3193 break;
3194
3195 case SD_BUS_TYPE_INT32:
3196 case SD_BUS_TYPE_UINT32:
3197 if (p)
3198 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3199 break;
9a17484d 3200
6647dc66
LP
3201 case SD_BUS_TYPE_INT64:
3202 case SD_BUS_TYPE_UINT64:
3203 case SD_BUS_TYPE_DOUBLE:
3204 if (p)
3205 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3206 break;
0dcd14b9 3207
6647dc66
LP
3208 case SD_BUS_TYPE_UNIX_FD: {
3209 uint32_t j;
de1c301e 3210
6647dc66
LP
3211 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3212 if (j >= m->n_fds)
3213 return -EBADMSG;
de1c301e 3214
6647dc66
LP
3215 if (p)
3216 *(int*) p = m->fds[j];
de1c301e 3217
6647dc66
LP
3218 break;
3219 }
3220
3221 default:
3222 assert_not_reached("unexpected type");
3223 }
3224 }
3225
3226 r = container_next_item(m, c, &rindex);
3227 if (r < 0)
9a17484d 3228 return r;
6647dc66 3229 } else {
9a17484d 3230
6647dc66 3231 rindex = m->rindex;
9a17484d 3232
6647dc66
LP
3233 if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
3234 uint32_t l;
3235 bool ok;
9a17484d 3236
6647dc66 3237 r = message_peek_body(m, &rindex, 4, 4, &q);
18f5b48f 3238 if (r < 0)
6647dc66 3239 return r;
9a17484d 3240
6647dc66
LP
3241 l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3242 r = message_peek_body(m, &rindex, 1, l+1, &q);
3243 if (r < 0)
3244 return r;
9a17484d 3245
6647dc66
LP
3246 if (type == SD_BUS_TYPE_OBJECT_PATH)
3247 ok = validate_object_path(q, l);
3248 else
3249 ok = validate_string(q, l);
3250 if (!ok)
3251 return -EBADMSG;
9a17484d 3252
0dcd14b9 3253 if (p)
6647dc66 3254 *(const char**) p = q;
9a17484d 3255
6647dc66
LP
3256 } else if (type == SD_BUS_TYPE_SIGNATURE) {
3257 uint8_t l;
3258
3259 r = message_peek_body(m, &rindex, 1, 1, &q);
18f5b48f 3260 if (r < 0)
6647dc66
LP
3261 return r;
3262
3263 l = *(uint8_t*) q;
3264 r = message_peek_body(m, &rindex, 1, l+1, &q);
3265 if (r < 0)
3266 return r;
2c93b4ef 3267
6647dc66 3268 if (!validate_signature(q, l))
2c93b4ef
LP
3269 return -EBADMSG;
3270
0dcd14b9 3271 if (p)
6647dc66 3272 *(const char**) p = q;
2c93b4ef 3273
6647dc66
LP
3274 } else {
3275 ssize_t sz, align;
9a17484d 3276
6647dc66
LP
3277 align = bus_type_get_alignment(type);
3278 assert(align > 0);
2c93b4ef 3279
6647dc66
LP
3280 sz = bus_type_get_size(type);
3281 assert(sz > 0);
3282
3283 r = message_peek_body(m, &rindex, align, sz, &q);
18f5b48f 3284 if (r < 0)
6647dc66
LP
3285 return r;
3286
3287 switch (type) {
3288
3289 case SD_BUS_TYPE_BYTE:
3290 if (p)
3291 *(uint8_t*) p = *(uint8_t*) q;
3292 break;
3293
3294 case SD_BUS_TYPE_BOOLEAN:
3295 if (p)
3296 *(int*) p = !!*(uint32_t*) q;
3297 break;
3298
3299 case SD_BUS_TYPE_INT16:
3300 case SD_BUS_TYPE_UINT16:
3301 if (p)
3302 *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3303 break;
3304
3305 case SD_BUS_TYPE_INT32:
3306 case SD_BUS_TYPE_UINT32:
3307 if (p)
3308 *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3309 break;
3310
3311 case SD_BUS_TYPE_INT64:
3312 case SD_BUS_TYPE_UINT64:
3313 case SD_BUS_TYPE_DOUBLE:
3314 if (p)
3315 *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3316 break;
3317
3318 case SD_BUS_TYPE_UNIX_FD: {
3319 uint32_t j;
3320
3321 j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3322 if (j >= m->n_fds)
3323 return -EBADMSG;
3324
3325 if (p)
3326 *(int*) p = m->fds[j];
3327 break;
3328 }
3329
3330 default:
3331 assert_not_reached("Unknown basic type...");
3332 }
3333 }
9a17484d
LP
3334 }
3335
6647dc66
LP
3336 m->rindex = rindex;
3337
9a17484d
LP
3338 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3339 c->index++;
3340
3341 return 1;
de1c301e
LP
3342}
3343
9a17484d
LP
3344static int bus_message_enter_array(
3345 sd_bus_message *m,
3346 struct bus_container *c,
3347 const char *contents,
6647dc66
LP
3348 uint32_t **array_size,
3349 size_t *item_size,
3350 size_t **offsets,
3351 size_t *n_offsets) {
9a17484d
LP
3352
3353 size_t rindex;
3354 void *q;
3355 int r, alignment;
3356
3357 assert(m);
3358 assert(c);
3359 assert(contents);
3360 assert(array_size);
6647dc66
LP
3361 assert(item_size);
3362 assert(offsets);
3363 assert(n_offsets);
9a17484d 3364
29ddb38f 3365 if (!signature_is_single(contents, true))
de1c301e 3366 return -EINVAL;
9a17484d 3367
9a17484d 3368 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3369 return -ENXIO;
9a17484d
LP
3370
3371 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
3372 return -ENXIO;
3373
3374 if (!startswith(c->signature + c->index + 1, contents))
3375 return -ENXIO;
3376
3377 rindex = m->rindex;
9a17484d 3378
6647dc66
LP
3379 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3380 /* dbus1 */
9a17484d 3381
6647dc66 3382 r = message_peek_body(m, &rindex, 4, 4, &q);
18f5b48f 3383 if (r < 0)
6647dc66 3384 return r;
9a17484d 3385
6647dc66
LP
3386 if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE)
3387 return -EBADMSG;
9a17484d 3388
6647dc66
LP
3389 alignment = bus_type_get_alignment(contents[0]);
3390 if (alignment < 0)
3391 return alignment;
3392
3393 r = message_peek_body(m, &rindex, alignment, 0, NULL);
3394 if (r < 0)
3395 return r;
6647dc66
LP
3396
3397 *array_size = (uint32_t*) q;
3398
3399 } else if (c->item_size <= 0) {
3400
3401 /* gvariant: empty array */
3402 *item_size = 0;
3403 *offsets = NULL;
3404 *n_offsets = 0;
3405
3406 } else if (bus_gvariant_is_fixed_size(contents)) {
3407
3408 /* gvariant: fixed length array */
3409 *item_size = bus_gvariant_get_size(contents);
3410 *offsets = NULL;
3411 *n_offsets = 0;
3412
3413 } else {
3414 size_t where, p = 0, framing, sz;
3415 unsigned i;
3416
3417 /* gvariant: variable length array */
3418 sz = determine_word_size(c->item_size, 0);
3419
3420 where = rindex + c->item_size - sz;
3421 r = message_peek_body(m, &where, 1, sz, &q);
3422 if (r < 0)
3423 return r;
6647dc66
LP
3424
3425 framing = read_word_le(q, sz);
3426 if (framing > c->item_size - sz)
3427 return -EBADMSG;
3428 if ((c->item_size - framing) % sz != 0)
3429 return -EBADMSG;
3430
3431 *n_offsets = (c->item_size - framing) / sz;
3432
3433 where = rindex + framing;
3434 r = message_peek_body(m, &where, 1, *n_offsets * sz, &q);
3435 if (r < 0)
3436 return r;
6647dc66
LP
3437
3438 *offsets = new(size_t, *n_offsets);
3439 if (!*offsets)
3440 return -ENOMEM;
3441
3442 for (i = 0; i < *n_offsets; i++) {
3443 size_t x;
3444
3445 x = read_word_le((uint8_t*) q + i * sz, sz);
3446 if (x > c->item_size - sz)
3447 return -EBADMSG;
3448 if (x < p)
3449 return -EBADMSG;
3450
3451 (*offsets)[i] = rindex + x;
3452 p = x;
3453 }
3454
3455 *item_size = (*offsets)[0] - rindex;
3456 }
3457
3458 m->rindex = rindex;
3459
3460 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3461 c->index += 1 + strlen(contents);
9a17484d
LP
3462
3463 return 1;
3464}
3465
3466static int bus_message_enter_variant(
3467 sd_bus_message *m,
3468 struct bus_container *c,
6647dc66
LP
3469 const char *contents,
3470 size_t *item_size) {
9a17484d
LP
3471
3472 size_t rindex;
3473 uint8_t l;
3474 void *q;
3475 int r;
3476
3477 assert(m);
3478 assert(c);
3479 assert(contents);
6647dc66 3480 assert(item_size);
9a17484d 3481
29ddb38f 3482 if (!signature_is_single(contents, false))
de1c301e 3483 return -EINVAL;
de1c301e 3484
9a17484d
LP
3485 if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
3486 return -EINVAL;
3487
3488 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3489 return -ENXIO;
9a17484d
LP
3490
3491 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
3492 return -ENXIO;
3493
3494 rindex = m->rindex;
9a17484d 3495
6647dc66
LP
3496 if (BUS_MESSAGE_IS_GVARIANT(m)) {
3497 size_t k, where;
3498
3499 k = strlen(contents);
3500 if (1+k > c->item_size)
3501 return -EBADMSG;
3502
3503 where = rindex + c->item_size - (1+k);
3504 r = message_peek_body(m, &where, 1, 1+k, &q);
3505 if (r < 0)
3506 return r;
6647dc66
LP
3507
3508 if (*(char*) q != 0)
3509 return -EBADMSG;
3510
3511 if (memcmp((uint8_t*) q+1, contents, k))
3512 return -ENXIO;
3513
3514 *item_size = c->item_size - (1+k);
3515
3516 } else {
3517 r = message_peek_body(m, &rindex, 1, 1, &q);
3518 if (r < 0)
3519 return r;
6647dc66
LP
3520
3521 l = *(uint8_t*) q;
3522 r = message_peek_body(m, &rindex, 1, l+1, &q);
3523 if (r < 0)
3524 return r;
6647dc66
LP
3525
3526 if (!validate_signature(q, l))
3527 return -EBADMSG;
3528
3529 if (!streq(q, contents))
3530 return -ENXIO;
3531 }
3532
3533 m->rindex = rindex;
3534
3535 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3536 c->index++;
3537
3538 return 1;
3539}
3540
3541static int build_struct_offsets(
3542 sd_bus_message *m,
3543 const char *signature,
3544 size_t size,
3545 size_t *item_size,
3546 size_t **offsets,
3547 size_t *n_offsets) {
3548
3549 unsigned n_variable = 0, n_total = 0, v;
3550 size_t previous = 0, where;
3551 const char *p;
3552 size_t sz;
3553 void *q;
3554 int r;
3555
3556 assert(m);
3557 assert(signature);
3558 assert(item_size);
3559 assert(offsets);
3560 assert(n_offsets);
3561
3562 sz = determine_word_size(size, 0);
3563
3564 /* First, loop over signature and count variable elements and
3565 * elements in general. We use this to know how large the
3566 * offset array is at the end of the structure. Note that
3567 * GVariant only stores offsets for all variable size elements
3568 * that are not the last item. */
3569
3570 p = signature;
3571 while (*p != 0) {
3572 size_t n;
3573
3574 r = signature_element_length(p, &n);
3575 if (r < 0)
3576 return r;
3577 else {
3578 char t[n+1];
3579
3580 memcpy(t, p, n);
3581 t[n] = 0;
3582
3583 r = bus_gvariant_is_fixed_size(t);
3584 }
3585
3586 if (r < 0)
3587 return r;
3588 if (r == 0 && p[n] != 0) /* except the last item */
3589 n_variable ++;
3590 n_total++;
3591
3592 p += n;
3593 }
3594
3595 if (size < n_variable * sz)
3596 return -EBADMSG;
3597
3598 where = m->rindex + size - (n_variable * sz);
3599 r = message_peek_body(m, &where, 1, n_variable * sz, &q);
9a17484d
LP
3600 if (r < 0)
3601 return r;
9a17484d 3602
6647dc66 3603 v = n_variable;
9a17484d 3604
6647dc66
LP
3605 *offsets = new(size_t, n_total);
3606 if (!*offsets)
3607 return -ENOMEM;
9a17484d 3608
6647dc66 3609 *n_offsets = 0;
9a17484d 3610
6647dc66
LP
3611 /* Second, loop again and build an offset table */
3612 p = signature;
3613 while (*p != 0) {
3614 size_t n, offset;
3615 int k;
9a17484d 3616
6647dc66
LP
3617 r = signature_element_length(p, &n);
3618 if (r < 0)
3619 return r;
3620 else {
3621 char t[n+1];
3622
3623 memcpy(t, p, n);
3624 t[n] = 0;
3625
3626 k = bus_gvariant_get_size(t);
3627 if (k < 0) {
3628 size_t x;
3629
3630 /* variable size */
3631 if (v > 0) {
3632 v--;
3633
3634 x = read_word_le((uint8_t*) q + v*sz, sz);
3635 if (x >= size)
3636 return -EBADMSG;
3637 if (m->rindex + x < previous)
3638 return -EBADMSG;
3639 } else
3640 /* The last item's end
3641 * is determined from
3642 * the start of the
3643 * offset array */
3644 x = size - (n_variable * sz);
3645
3646 offset = m->rindex + x;
3647
3648 } else {
3649 size_t align;
3650
3651 /* fixed size */
3652 align = bus_gvariant_get_alignment(t);
3653 assert(align > 0);
3654
3655 offset = (*n_offsets == 0 ? m->rindex : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k;
3656 }
3657 }
3658
3659 previous = (*offsets)[(*n_offsets)++] = offset;
3660 p += n;
3661 }
3662
3663 assert(v == 0);
3664 assert(*n_offsets == n_total);
3665
3666 *item_size = (*offsets)[0] - m->rindex;
3667 return 0;
3668}
3669
3670static int enter_struct_or_dict_entry(
3671 sd_bus_message *m,
3672 struct bus_container *c,
3673 const char *contents,
3674 size_t *item_size,
3675 size_t **offsets,
3676 size_t *n_offsets) {
3677
3678 int r;
3679
3680 assert(m);
3681 assert(c);
3682 assert(contents);
3683 assert(item_size);
3684 assert(offsets);
3685 assert(n_offsets);
3686
3687 if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3688
3689 /* dbus1 */
3690 r = message_peek_body(m, &m->rindex, 8, 0, NULL);
18f5b48f 3691 if (r < 0)
6647dc66
LP
3692 return r;
3693
3694 } else if (c->item_size <= 0) {
3695
3696 /* gvariant empty struct */
3697 *item_size = 0;
3698 *offsets = NULL;
3699 *n_offsets = 0;
3700 } else
3701 /* gvariant with contents */
3702 return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets);
3703
3704 return 0;
de1c301e
LP
3705}
3706
9a17484d
LP
3707static int bus_message_enter_struct(
3708 sd_bus_message *m,
3709 struct bus_container *c,
6647dc66
LP
3710 const char *contents,
3711 size_t *item_size,
3712 size_t **offsets,
3713 size_t *n_offsets) {
9a17484d
LP
3714
3715 size_t l;
3716 int r;
3717
3718 assert(m);
3719 assert(c);
3720 assert(contents);
6647dc66
LP
3721 assert(item_size);
3722 assert(offsets);
3723 assert(n_offsets);
9a17484d
LP
3724
3725 if (!signature_is_valid(contents, false))
3726 return -EINVAL;
3727
3728 if (!c->signature || c->signature[c->index] == 0)
6647dc66 3729 return -ENXIO;
9a17484d
LP
3730
3731 l = strlen(contents);
3732
3733 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
3734 !startswith(c->signature + c->index + 1, contents) ||
3735 c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
3736 return -ENXIO;
3737
6647dc66
LP
3738 r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
3739 if (r < 0)
9a17484d
LP
3740 return r;
3741
3742 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3743 c->index += 1 + l + 1;
3744
3745 return 1;
3746}
3747
3748static int bus_message_enter_dict_entry(
3749 sd_bus_message *m,
3750 struct bus_container *c,
6647dc66
LP
3751 const char *contents,
3752 size_t *item_size,
3753 size_t **offsets,
3754 size_t *n_offsets) {
9a17484d
LP
3755
3756 size_t l;
3757 int r;
3758
3759 assert(m);
3760 assert(c);
3761 assert(contents);
3762
3763 if (!signature_is_pair(contents))
3764 return -EINVAL;
3765
3766 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3767 return -ENXIO;
3768
3769 if (!c->signature || c->signature[c->index] == 0)
3770 return 0;
3771
3772 l = strlen(contents);
3773
3774 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
3775 !startswith(c->signature + c->index + 1, contents) ||
3776 c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
3777 return -ENXIO;
3778
6647dc66
LP
3779 r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
3780 if (r < 0)
9a17484d
LP
3781 return r;
3782
3783 if (c->enclosing != SD_BUS_TYPE_ARRAY)
3784 c->index += 1 + l + 1;
3785
3786 return 1;
3787}
3788
d9f644e2
ZJS
3789_public_ int sd_bus_message_enter_container(sd_bus_message *m,
3790 char type,
3791 const char *contents) {
9a17484d
LP
3792 struct bus_container *c, *w;
3793 uint32_t *array_size = NULL;
3794 char *signature;
b3af9646 3795 size_t before;
6647dc66
LP
3796 size_t *offsets = NULL;
3797 size_t n_offsets = 0, item_size = 0;
9a17484d
LP
3798 int r;
3799
275b39fe
LP
3800 assert_return(m, -EINVAL);
3801 assert_return(m->sealed, -EPERM);
3802 assert_return(type != 0 || !contents, -EINVAL);
3803
3804 if (type == 0 || !contents) {
3805 const char *cc;
3806 char tt;
3807
3808 /* Allow entering into anonymous containers */
3809 r = sd_bus_message_peek_type(m, &tt, &cc);
18f5b48f 3810 if (r < 0)
275b39fe
LP
3811 return r;
3812
3813 if (type != 0 && type != tt)
3814 return -ENXIO;
3815
3816 if (contents && !streq(contents, cc))
3817 return -ENXIO;
3818
3819 type = tt;
3820 contents = cc;
3821 }
9a17484d 3822
ed205a6b
LP
3823 /*
3824 * We enforce a global limit on container depth, that is much
3825 * higher than the 32 structs and 32 arrays the specification
3826 * mandates. This is simpler to implement for us, and we need
3827 * this only to ensure our container array doesn't grow
3828 * without bounds. We are happy to return any data from a
3829 * message as long as the data itself is valid, even if the
3830 * overall message might be not.
3831 *
3832 * Note that the message signature is validated when
3833 * parsing the headers, and that validation does check the
3834 * 32/32 limit.
3835 *
3836 * Note that the specification defines no limits on the depth
3837 * of stacked variants, but we do.
3838 */
3839 if (m->n_containers >= BUS_CONTAINER_DEPTH)
3840 return -EBADMSG;
3841
9a17484d
LP
3842 w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1));
3843 if (!w)
3844 return -ENOMEM;
3845 m->containers = w;
3846
7b058942 3847 if (message_end_of_signature(m))
430fb8fa 3848 return -ENXIO;
9a17484d 3849
1daf8121
LP
3850 if (message_end_of_array(m, m->rindex))
3851 return 0;
3852
7b058942
LP
3853 c = message_get_container(m);
3854
9a17484d
LP
3855 signature = strdup(contents);
3856 if (!signature)
3857 return -ENOMEM;
3858
b3af9646
LP
3859 c->saved_index = c->index;
3860 before = m->rindex;
3861
9a17484d 3862 if (type == SD_BUS_TYPE_ARRAY)
6647dc66 3863 r = bus_message_enter_array(m, c, contents, &array_size, &item_size, &offsets, &n_offsets);
9a17484d 3864 else if (type == SD_BUS_TYPE_VARIANT)
6647dc66 3865 r = bus_message_enter_variant(m, c, contents, &item_size);
9a17484d 3866 else if (type == SD_BUS_TYPE_STRUCT)
6647dc66 3867 r = bus_message_enter_struct(m, c, contents, &item_size, &offsets, &n_offsets);
9a17484d 3868 else if (type == SD_BUS_TYPE_DICT_ENTRY)
6647dc66 3869 r = bus_message_enter_dict_entry(m, c, contents, &item_size, &offsets, &n_offsets);
9a17484d
LP
3870 else
3871 r = -EINVAL;
3872
3873 if (r <= 0) {
3874 free(signature);
6647dc66 3875 free(offsets);
9a17484d
LP
3876 return r;
3877 }
3878
3879 /* OK, let's fill it in */
3880 w += m->n_containers++;
3881 w->enclosing = type;
3882 w->signature = signature;
3883 w->index = 0;
6647dc66 3884
b3af9646 3885 w->before = before;
9a17484d 3886 w->begin = m->rindex;
6647dc66
LP
3887 w->end = m->rindex + c->item_size;
3888
3889 w->array_size = array_size;
3890 w->item_size = item_size;
3891 w->offsets = offsets;
3892 w->n_offsets = n_offsets;
3893 w->offset_index = 0;
9a17484d
LP
3894
3895 return 1;
3896}
3897
d9f644e2 3898_public_ int sd_bus_message_exit_container(sd_bus_message *m) {
9a17484d 3899 struct bus_container *c;
6647dc66 3900 int r;
9a17484d 3901
9d6c7c82
LP
3902 assert_return(m, -EINVAL);
3903 assert_return(m->sealed, -EPERM);
f959af20 3904 assert_return(m->n_containers > 0, -ENXIO);
9a17484d
LP
3905
3906 c = message_get_container(m);
6647dc66
LP
3907
3908 if (c->enclosing != SD_BUS_TYPE_ARRAY) {
3909 if (c->signature && c->signature[c->index] != 0)
3910 return -EBUSY;
3911 }
3912
3913 if (BUS_MESSAGE_IS_GVARIANT(m)) {
3914 if (m->rindex < c->end)
3915 return -EBUSY;
3916
3917 } else if (c->enclosing == SD_BUS_TYPE_ARRAY) {
9a17484d
LP
3918 uint32_t l;
3919
3920 l = BUS_MESSAGE_BSWAP32(m, *c->array_size);
3921 if (c->begin + l != m->rindex)
3922 return -EBUSY;
9a17484d
LP
3923 }
3924
3925 free(c->signature);
6647dc66 3926 free(c->offsets);
9a17484d
LP
3927 m->n_containers--;
3928
6647dc66
LP
3929 c = message_get_container(m);
3930
3931 r = container_next_item(m, c, &m->rindex);
3932 if (r < 0)
3933 return r;
3934
9a17484d
LP
3935 return 1;
3936}
3937
b3af9646
LP
3938static void message_quit_container(sd_bus_message *m) {
3939 struct bus_container *c;
3940
3941 assert(m);
3942 assert(m->sealed);
3943 assert(m->n_containers > 0);
3944
3945 c = message_get_container(m);
3946
3947 /* Undo seeks */
3948 assert(m->rindex >= c->before);
3949 m->rindex = c->before;
3950
3951 /* Free container */
3952 free(c->signature);
6647dc66 3953 free(c->offsets);
b3af9646
LP
3954 m->n_containers--;
3955
3956 /* Correct index of new top-level container */
3957 c = message_get_container(m);
3958 c->index = c->saved_index;
3959}
3960
d9f644e2 3961_public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
9a17484d
LP
3962 struct bus_container *c;
3963 int r;
3964
c430fee6
LP
3965 assert_return(m, -EINVAL);
3966 assert_return(m->sealed, -EPERM);
9a17484d 3967
7b058942 3968 if (message_end_of_signature(m))
9a17484d
LP
3969 goto eof;
3970
3971 if (message_end_of_array(m, m->rindex))
3972 goto eof;
3973
7b058942
LP
3974 c = message_get_container(m);
3975
9a17484d
LP
3976 if (bus_type_is_basic(c->signature[c->index])) {
3977 if (contents)
3978 *contents = NULL;
3979 if (type)
3980 *type = c->signature[c->index];
3981 return 1;
3982 }
3983
3984 if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) {
3985
3986 if (contents) {
3987 size_t l;
3988 char *sig;
3989
3990 r = signature_element_length(c->signature+c->index+1, &l);
3991 if (r < 0)
3992 return r;
3993
80a46c73
LP
3994 assert(l >= 1);
3995
9a17484d
LP
3996 sig = strndup(c->signature + c->index + 1, l);
3997 if (!sig)
3998 return -ENOMEM;
3999
4000 free(m->peeked_signature);
4001 m->peeked_signature = sig;
4002
4003 *contents = sig;
4004 }
4005
4006 if (type)
4007 *type = SD_BUS_TYPE_ARRAY;
4008
4009 return 1;
4010 }
4011
4012 if (c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ||
4013 c->signature[c->index] == SD_BUS_TYPE_DICT_ENTRY_BEGIN) {
4014
4015 if (contents) {
4016 size_t l;
4017 char *sig;
4018
4019 r = signature_element_length(c->signature+c->index, &l);
4020 if (r < 0)
4021 return r;
4022
4023 assert(l >= 2);
4024 sig = strndup(c->signature + c->index + 1, l - 2);
4025 if (!sig)
4026 return -ENOMEM;
4027
4028 free(m->peeked_signature);
4029 m->peeked_signature = sig;
4030
4031 *contents = sig;
4032 }
4033
4034 if (type)
4035 *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
4036
4037 return 1;
4038 }
4039
4040 if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) {
4041 if (contents) {
9a17484d
LP
4042 void *q;
4043
6647dc66
LP
4044 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4045 size_t k;
9a17484d 4046
6647dc66
LP
4047 if (c->item_size < 2)
4048 return -EBADMSG;
9a17484d 4049
6647dc66
LP
4050 /* Look for the NUL delimiter that
4051 separates the payload from the
4052 signature. Since the body might be
4053 in a different part that then the
4054 signature we map byte by byte. */
4055
4056 for (k = 2; k <= c->item_size; k++) {
4057 size_t where;
4058
4059 where = m->rindex + c->item_size - k;
4060 r = message_peek_body(m, &where, 1, k, &q);
4061 if (r < 0)
4062 return r;
6647dc66
LP
4063
4064 if (*(char*) q == 0)
4065 break;
4066 }
4067
4068 if (k > c->item_size)
4069 return -EBADMSG;
4070
4071 free(m->peeked_signature);
4072 m->peeked_signature = strndup((char*) q + 1, k - 1);
4073 if (!m->peeked_signature)
4074 return -ENOMEM;
4075
4076 if (!signature_is_valid(m->peeked_signature, true))
4077 return -EBADMSG;
4078
4079 *contents = m->peeked_signature;
4080 } else {
4081 size_t rindex, l;
4082
4083 rindex = m->rindex;
4084 r = message_peek_body(m, &rindex, 1, 1, &q);
4085 if (r < 0)
4086 return r;
9a17484d 4087
6647dc66
LP
4088 l = *(uint8_t*) q;
4089 r = message_peek_body(m, &rindex, 1, l+1, &q);
4090 if (r < 0)
4091 return r;
6647dc66
LP
4092
4093 if (!validate_signature(q, l))
4094 return -EBADMSG;
4095
4096 *contents = q;
4097 }
9a17484d
LP
4098 }
4099
4100 if (type)
4101 *type = SD_BUS_TYPE_VARIANT;
4102
4103 return 1;
4104 }
4105
4106 return -EINVAL;
4107
4108eof:
4109 if (type)
7b058942 4110 *type = 0;
9a17484d
LP
4111 if (contents)
4112 *contents = NULL;
4113 return 0;
4114}
4115
d9f644e2 4116_public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
9a17484d
LP
4117 struct bus_container *c;
4118
9d6c7c82
LP
4119 assert_return(m, -EINVAL);
4120 assert_return(m->sealed, -EPERM);
9a17484d
LP
4121
4122 if (complete) {
bc7fd8cd 4123 message_reset_containers(m);
9a17484d 4124 m->rindex = 0;
9a17484d
LP
4125
4126 c = message_get_container(m);
4127 } else {
4128 c = message_get_container(m);
4129
6647dc66 4130 c->offset_index = 0;
9a17484d
LP
4131 c->index = 0;
4132 m->rindex = c->begin;
4133 }
4134
4135 return !isempty(c->signature);
4136}
718db961 4137
1b492614
LP
4138static int message_read_ap(
4139 sd_bus_message *m,
4140 const char *types,
4141 va_list ap) {
9a17484d 4142
fe1d424d
LP
4143 unsigned n_array, n_struct;
4144 TypeStack stack[BUS_CONTAINER_DEPTH];
4145 unsigned stack_ptr = 0;
430fb8fa 4146 unsigned n_loop = 0;
9a17484d
LP
4147 int r;
4148
4149 assert(m);
1b492614 4150
430fb8fa 4151 if (isempty(types))
1b492614 4152 return 0;
9a17484d 4153
fe1d424d
LP
4154 /* Ideally, we'd just call ourselves recursively on every
4155 * complex type. However, the state of a va_list that is
4156 * passed to a function is undefined after that function
4157 * returns. This means we need to docode the va_list linearly
4158 * in a single stackframe. We hence implement our own
4159 * home-grown stack in an array. */
4160
430fb8fa
LP
4161 n_array = (unsigned) -1; /* lenght of current array entries */
4162 n_struct = strlen(types); /* length of current struct contents signature */
fe1d424d
LP
4163
4164 for (;;) {
4165 const char *t;
4166
430fb8fa
LP
4167 n_loop++;
4168
1b492614 4169 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
fe1d424d
LP
4170 r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
4171 if (r < 0)
4172 return r;
4173 if (r == 0)
4174 break;
4175
4176 r = sd_bus_message_exit_container(m);
4177 if (r < 0)
4178 return r;
4179
4180 continue;
4181 }
4182
4183 t = types;
4184 if (n_array != (unsigned) -1)
4185 n_array --;
4186 else {
4187 types ++;
4188 n_struct--;
4189 }
4190
9a17484d
LP
4191 switch (*t) {
4192
4193 case SD_BUS_TYPE_BYTE:
4194 case SD_BUS_TYPE_BOOLEAN:
4195 case SD_BUS_TYPE_INT16:
4196 case SD_BUS_TYPE_UINT16:
4197 case SD_BUS_TYPE_INT32:
4198 case SD_BUS_TYPE_UINT32:
4199 case SD_BUS_TYPE_INT64:
4200 case SD_BUS_TYPE_UINT64:
4201 case SD_BUS_TYPE_DOUBLE:
4202 case SD_BUS_TYPE_STRING:
4203 case SD_BUS_TYPE_OBJECT_PATH:
2c93b4ef
LP
4204 case SD_BUS_TYPE_SIGNATURE:
4205 case SD_BUS_TYPE_UNIX_FD: {
9a17484d
LP
4206 void *p;
4207
4208 p = va_arg(ap, void*);
4209 r = sd_bus_message_read_basic(m, *t, p);
fe1d424d
LP
4210 if (r < 0)
4211 return r;
430fb8fa
LP
4212 if (r == 0) {
4213 if (n_loop <= 1)
4214 return 0;
4215
fe1d424d 4216 return -ENXIO;
430fb8fa 4217 }
fe1d424d 4218
9a17484d
LP
4219 break;
4220 }
4221
4222 case SD_BUS_TYPE_ARRAY: {
4223 size_t k;
4224
4225 r = signature_element_length(t + 1, &k);
4226 if (r < 0)
4227 return r;
4228
4229 {
9a17484d 4230 char s[k + 1];
9a17484d
LP
4231 memcpy(s, t + 1, k);
4232 s[k] = 0;
9a17484d
LP
4233
4234 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4235 if (r < 0)
4236 return r;
430fb8fa
LP
4237 if (r == 0) {
4238 if (n_loop <= 1)
4239 return 0;
4240
9a17484d 4241 return -ENXIO;
430fb8fa 4242 }
fe1d424d 4243 }
9a17484d 4244
fe1d424d
LP
4245 if (n_array == (unsigned) -1) {
4246 types += k;
4247 n_struct -= k;
9a17484d
LP
4248 }
4249
fe1d424d
LP
4250 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4251 if (r < 0)
4252 return r;
4253
4254 types = t + 1;
4255 n_struct = k;
4256 n_array = va_arg(ap, unsigned);
4257
9a17484d
LP
4258 break;
4259 }
4260
4261 case SD_BUS_TYPE_VARIANT: {
4262 const char *s;
4263
4264 s = va_arg(ap, const char *);
4265 if (!s)
4266 return -EINVAL;
4267
4268 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s);
4269 if (r < 0)
4270 return r;
430fb8fa
LP
4271 if (r == 0) {
4272 if (n_loop <= 1)
4273 return 0;
4274
9a17484d 4275 return -ENXIO;
430fb8fa 4276 }
9a17484d 4277
fe1d424d 4278 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
9a17484d
LP
4279 if (r < 0)
4280 return r;
9a17484d 4281
fe1d424d
LP
4282 types = s;
4283 n_struct = strlen(s);
4284 n_array = (unsigned) -1;
4285
9a17484d
LP
4286 break;
4287 }
4288
4289 case SD_BUS_TYPE_STRUCT_BEGIN:
4290 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4291 size_t k;
4292
4293 r = signature_element_length(t, &k);
4294 if (r < 0)
4295 return r;
4296
4297 {
4298 char s[k - 1];
4299 memcpy(s, t + 1, k - 2);
4300 s[k - 2] = 0;
4301
4302 r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4303 if (r < 0)
4304 return r;
430fb8fa
LP
4305 if (r == 0) {
4306 if (n_loop <= 1)
4307 return 0;
9a17484d 4308 return -ENXIO;
430fb8fa 4309 }
fe1d424d 4310 }
9a17484d 4311
fe1d424d
LP
4312 if (n_array == (unsigned) -1) {
4313 types += k - 1;
4314 n_struct -= k - 1;
4315 }
9a17484d 4316
fe1d424d
LP
4317 r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4318 if (r < 0)
4319 return r;
9a17484d 4320
fe1d424d
LP
4321 types = t + 1;
4322 n_struct = k - 2;
4323 n_array = (unsigned) -1;
9a17484d
LP
4324
4325 break;
4326 }
4327
4328 default:
fe1d424d 4329 return -EINVAL;
9a17484d 4330 }
9a17484d
LP
4331 }
4332
4333 return 1;
4334}
4335
d9f644e2 4336_public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
9a17484d
LP
4337 va_list ap;
4338 int r;
4339
9b07511d
LP
4340 assert_return(m, -EINVAL);
4341 assert_return(m->sealed, -EPERM);
4342 assert_return(types, -EINVAL);
9a17484d
LP
4343
4344 va_start(ap, types);
4345 r = message_read_ap(m, types, ap);
4346 va_end(ap);
4347
4348 return r;
4349}
4350
d9f644e2 4351_public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
9b07511d
LP
4352 int r;
4353
4354 assert_return(m, -EINVAL);
4355 assert_return(m->sealed, -EPERM);
4356 assert_return(types, -EINVAL);
4357
4358 if (isempty(types))
4359 return 0;
4360
4361 switch (*types) {
4362
4363 case SD_BUS_TYPE_BYTE:
4364 case SD_BUS_TYPE_BOOLEAN:
4365 case SD_BUS_TYPE_INT16:
4366 case SD_BUS_TYPE_UINT16:
4367 case SD_BUS_TYPE_INT32:
4368 case SD_BUS_TYPE_UINT32:
4369 case SD_BUS_TYPE_INT64:
4370 case SD_BUS_TYPE_UINT64:
4371 case SD_BUS_TYPE_DOUBLE:
4372 case SD_BUS_TYPE_STRING:
4373 case SD_BUS_TYPE_OBJECT_PATH:
4374 case SD_BUS_TYPE_SIGNATURE:
4375 case SD_BUS_TYPE_UNIX_FD:
4376
4377 r = sd_bus_message_read_basic(m, *types, NULL);
4378 if (r <= 0)
4379 return r;
4380
4381 r = sd_bus_message_skip(m, types + 1);
4382 if (r < 0)
4383 return r;
4384
4385 return 1;
4386
4387 case SD_BUS_TYPE_ARRAY: {
4388 size_t k;
4389
4390 r = signature_element_length(types + 1, &k);
4391 if (r < 0)
4392 return r;
4393
4394 {
4395 char s[k+1];
4396 memcpy(s, types+1, k);
4397 s[k] = 0;
4398
4399 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4400 if (r <= 0)
4401 return r;
4402
4403 for (;;) {
4404 r = sd_bus_message_skip(m, s);
4405 if (r < 0)
4406 return r;
4407 if (r == 0)
4408 break;
4409 }
4410
4411 r = sd_bus_message_exit_container(m);
4412 if (r < 0)
4413 return r;
4414 }
4415
4416 r = sd_bus_message_skip(m, types + 1 + k);
4417 if (r < 0)
4418 return r;
4419
4420 return 1;
4421 }
4422
4423 case SD_BUS_TYPE_VARIANT: {
4424 const char *contents;
4425 char x;
4426
4427 r = sd_bus_message_peek_type(m, &x, &contents);
4428 if (r <= 0)
4429 return r;
4430
4431 if (x != SD_BUS_TYPE_VARIANT)
4432 return -ENXIO;
4433
4434 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
4435 if (r <= 0)
4436 return r;
4437
4438 r = sd_bus_message_skip(m, contents);
4439 if (r < 0)
4440 return r;
4441 assert(r != 0);
4442
4443 r = sd_bus_message_exit_container(m);
4444 if (r < 0)
4445 return r;
4446
4447 r = sd_bus_message_skip(m, types + 1);
4448 if (r < 0)
4449 return r;
4450
4451 return 1;
4452 }
4453
4454 case SD_BUS_TYPE_STRUCT_BEGIN:
4455 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4456 size_t k;
4457
4458 r = signature_element_length(types, &k);
4459 if (r < 0)
4460 return r;
4461
4462 {
4463 char s[k-1];
4464 memcpy(s, types+1, k-2);
4465 s[k-2] = 0;
4466
4467 r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4468 if (r <= 0)
4469 return r;
4470
4471 r = sd_bus_message_skip(m, s);
4472 if (r < 0)
4473 return r;
4474 assert(r != 0);
4475
4476 r = sd_bus_message_exit_container(m);
4477 if (r < 0)
4478 return r;
4479 }
4480
4481 r = sd_bus_message_skip(m, types + k);
4482 if (r < 0)
4483 return r;
4484
4485 return 1;
4486 }
4487
4488 default:
4489 return -EINVAL;
4490 }
4491}
4492
d9f644e2
ZJS
4493_public_ int sd_bus_message_read_array(sd_bus_message *m,
4494 char type,
4495 const void **ptr,
4496 size_t *size) {
b3af9646
LP
4497 struct bus_container *c;
4498 void *p;
4499 size_t sz;
4500 ssize_t align;
4501 int r;
4502
9d6c7c82
LP
4503 assert_return(m, -EINVAL);
4504 assert_return(m->sealed, -EPERM);
4505 assert_return(bus_type_is_trivial(type), -EINVAL);
4506 assert_return(ptr, -EINVAL);
4507 assert_return(size, -EINVAL);
4508 assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -ENOTSUP);
b3af9646 4509
b3af9646 4510 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
66b26c5c 4511 if (r <= 0)
b3af9646
LP
4512 return r;
4513
4514 c = message_get_container(m);
6647dc66
LP
4515
4516 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4517 align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
4518 if (align < 0)
4519 return align;
4520
18f5b48f 4521 sz = c->end - c->begin;
6647dc66
LP
4522 } else {
4523 align = bus_type_get_alignment(type);
4524 if (align < 0)
4525 return align;
4526
4527 sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
4528 }
b3af9646 4529
5e86fd7b
LP
4530 if (sz == 0)
4531 /* Zero length array, let's return some aligned
4532 * pointer that is not NULL */
4533 p = (uint8_t*) NULL + align;
4534 else {
4535 r = message_peek_body(m, &m->rindex, align, sz, &p);
4536 if (r < 0)
4537 goto fail;
b3af9646
LP
4538 }
4539
4540 r = sd_bus_message_exit_container(m);
4541 if (r < 0)
4542 goto fail;
4543
4544 *ptr = (const void*) p;
4545 *size = sz;
4546
4547 return 1;
4548
4549fail:
4550 message_quit_container(m);
4551 return r;
4552}
4553
80a46c73
LP
4554static int message_peek_fields(
4555 sd_bus_message *m,
4556 size_t *rindex,
4557 size_t align,
4558 size_t nbytes,
4559 void **ret) {
4560
4561 assert(m);
4562 assert(rindex);
4563 assert(align > 0);
4564
c91cb83c 4565 return buffer_peek(BUS_MESSAGE_FIELDS(m), BUS_MESSAGE_FIELDS_SIZE(m), rindex, align, nbytes, ret);
80a46c73
LP
4566}
4567
9f26c90c
LP
4568static int message_peek_field_uint32(
4569 sd_bus_message *m,
4570 size_t *ri,
6647dc66 4571 size_t item_size,
9f26c90c
LP
4572 uint32_t *ret) {
4573
4574 int r;
4575 void *q;
4576
4577 assert(m);
4578 assert(ri);
4579
6647dc66
LP
4580 if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 4)
4581 return -EBADMSG;
4582
4583 /* identical for gvariant and dbus1 */
4584
9f26c90c
LP
4585 r = message_peek_fields(m, ri, 4, 4, &q);
4586 if (r < 0)
4587 return r;
4588
4589 if (ret)
4590 *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
4591
4592 return 0;
4593}
4594
80a46c73
LP
4595static int message_peek_field_string(
4596 sd_bus_message *m,
6693860f 4597 bool (*validate)(const char *p),
80a46c73 4598 size_t *ri,
6647dc66 4599 size_t item_size,
80a46c73
LP
4600 const char **ret) {
4601
9f26c90c 4602 uint32_t l;
80a46c73
LP
4603 int r;
4604 void *q;
4605
9a17484d 4606 assert(m);
80a46c73
LP
4607 assert(ri);
4608
6647dc66 4609 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4610
6647dc66
LP
4611 if (item_size <= 0)
4612 return -EBADMSG;
4613
4614 r = message_peek_fields(m, ri, 1, item_size, &q);
4615 if (r < 0)
4616 return r;
4617
4618 l = item_size - 1;
4619 } else {
4620 r = message_peek_field_uint32(m, ri, 4, &l);
4621 if (r < 0)
4622 return r;
4623
4624 r = message_peek_fields(m, ri, 1, l+1, &q);
4625 if (r < 0)
4626 return r;
4627 }
9a17484d 4628
6693860f
LP
4629 if (validate) {
4630 if (!validate_nul(q, l))
4631 return -EBADMSG;
4632
4633 if (!validate(q))
ac89bf1d
LP
4634 return -EBADMSG;
4635 } else {
4636 if (!validate_string(q, l))
4637 return -EBADMSG;
4638 }
80a46c73
LP
4639
4640 if (ret)
4641 *ret = q;
4642
4643 return 0;
4644}
4645
4646static int message_peek_field_signature(
4647 sd_bus_message *m,
4648 size_t *ri,
6647dc66 4649 size_t item_size,
80a46c73
LP
4650 const char **ret) {
4651
4652 size_t l;
4653 int r;
4654 void *q;
4655
4656 assert(m);
4657 assert(ri);
4658
6647dc66 4659 if (BUS_MESSAGE_IS_GVARIANT(m)) {
80a46c73 4660
6647dc66
LP
4661 if (item_size <= 0)
4662 return -EBADMSG;
4663
4664 r = message_peek_fields(m, ri, 1, item_size, &q);
4665 if (r < 0)
4666 return r;
4667
4668 l = item_size - 1;
4669 } else {
4670 r = message_peek_fields(m, ri, 1, 1, &q);
4671 if (r < 0)
4672 return r;
4673
4674 l = *(uint8_t*) q;
4675 r = message_peek_fields(m, ri, 1, l+1, &q);
4676 if (r < 0)
4677 return r;
4678 }
80a46c73
LP
4679
4680 if (!validate_signature(q, l))
4681 return -EBADMSG;
4682
4683 if (ret)
4684 *ret = q;
4685
4686 return 0;
4687}
4688
80a46c73
LP
4689static int message_skip_fields(
4690 sd_bus_message *m,
4691 size_t *ri,
4692 uint32_t array_size,
4693 const char **signature) {
4694
4695 size_t original_index;
4696 int r;
4697
4698 assert(m);
4699 assert(ri);
4700 assert(signature);
6647dc66 4701 assert(!BUS_MESSAGE_IS_GVARIANT(m));
80a46c73
LP
4702
4703 original_index = *ri;
4704
4705 for (;;) {
4706 char t;
80a46c73
LP
4707 size_t l;
4708
4709 if (array_size != (uint32_t) -1 &&
4710 array_size <= *ri - original_index)
4711 return 0;
4712
4713 t = **signature;
4714 if (!t)
4715 return 0;
4716
6693860f
LP
4717 if (t == SD_BUS_TYPE_STRING) {
4718
6647dc66 4719 r = message_peek_field_string(m, NULL, ri, 0, NULL);
6693860f
LP
4720 if (r < 0)
4721 return r;
4722
4723 (*signature)++;
4724
4725 } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
80a46c73 4726
6647dc66 4727 r = message_peek_field_string(m, object_path_is_valid, ri, 0, NULL);
80a46c73
LP
4728 if (r < 0)
4729 return r;
4730
4731 (*signature)++;
4732
4733 } else if (t == SD_BUS_TYPE_SIGNATURE) {
4734
6647dc66 4735 r = message_peek_field_signature(m, ri, 0, NULL);
80a46c73
LP
4736 if (r < 0)
4737 return r;
4738
4739 (*signature)++;
4740
4741 } else if (bus_type_is_basic(t)) {
27f6e5c7 4742 ssize_t align, k;
80a46c73 4743
c66a2e0c
TG
4744 align = bus_type_get_alignment(t);
4745 k = bus_type_get_size(t);
27f6e5c7 4746 assert(align > 0 && k > 0);
80a46c73
LP
4747
4748 r = message_peek_fields(m, ri, align, k, NULL);
4749 if (r < 0)
4750 return r;
9a17484d 4751
80a46c73
LP
4752 (*signature)++;
4753
4754 } else if (t == SD_BUS_TYPE_ARRAY) {
4755
4756 r = signature_element_length(*signature+1, &l);
4757 if (r < 0)
4758 return r;
4759
4760 assert(l >= 1);
4761 {
4762 char sig[l-1], *s;
9f26c90c 4763 uint32_t nas;
80a46c73
LP
4764 int alignment;
4765
4766 strncpy(sig, *signature + 1, l-1);
4767 s = sig;
4768
4769 alignment = bus_type_get_alignment(sig[0]);
4770 if (alignment < 0)
4771 return alignment;
4772
6647dc66 4773 r = message_peek_field_uint32(m, ri, 0, &nas);
80a46c73
LP
4774 if (r < 0)
4775 return r;
ac89bf1d 4776 if (nas > BUS_ARRAY_MAX_SIZE)
80a46c73
LP
4777 return -EBADMSG;
4778
4779 r = message_peek_fields(m, ri, alignment, 0, NULL);
4780 if (r < 0)
4781 return r;
4782
4783 r = message_skip_fields(m, ri, nas, (const char**) &s);
4784 if (r < 0)
4785 return r;
4786 }
4787
4788 (*signature) += 1 + l;
4789
4790 } else if (t == SD_BUS_TYPE_VARIANT) {
4791 const char *s;
4792
6647dc66 4793 r = message_peek_field_signature(m, ri, 0, &s);
80a46c73
LP
4794 if (r < 0)
4795 return r;
4796
4797 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
4798 if (r < 0)
4799 return r;
4800
4801 (*signature)++;
4802
4803 } else if (t == SD_BUS_TYPE_STRUCT ||
4804 t == SD_BUS_TYPE_DICT_ENTRY) {
4805
4806 r = signature_element_length(*signature, &l);
4807 if (r < 0)
4808 return r;
4809
4810 assert(l >= 2);
4811 {
4812 char sig[l-1], *s;
4813 strncpy(sig, *signature + 1, l-1);
4814 s = sig;
4815
4816 r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
4817 if (r < 0)
4818 return r;
4819 }
4820
4821 *signature += l;
4822 } else
4823 return -EINVAL;
4824 }
4825}
4826
6629161f 4827int bus_message_parse_fields(sd_bus_message *m) {
80a46c73
LP
4828 size_t ri;
4829 int r;
2c93b4ef 4830 uint32_t unix_fds = 0;
6647dc66
LP
4831 void *offsets = NULL;
4832 unsigned n_offsets = 0;
4833 size_t sz;
4834 unsigned i = 0;
80a46c73
LP
4835
4836 assert(m);
4837
6647dc66
LP
4838 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4839 void *q;
4840
4841 sz = determine_word_size(BUS_MESSAGE_FIELDS_SIZE(m), 0);
4842 if (sz > 0) {
4843 size_t framing;
4844
4845 ri = BUS_MESSAGE_FIELDS_SIZE(m) - sz;
4846 r = message_peek_fields(m, &ri, 1, sz, &q);
4847 if (r < 0)
4848 return r;
4849
4850 framing = read_word_le(q, sz);
4851 if (framing >= BUS_MESSAGE_FIELDS_SIZE(m) - sz)
4852 return -EBADMSG;
4853 if ((BUS_MESSAGE_FIELDS_SIZE(m) - framing) % sz != 0)
4854 return -EBADMSG;
4855
4856 ri = framing;
4857 r = message_peek_fields(m, &ri, 1, BUS_MESSAGE_FIELDS_SIZE(m) - framing, &offsets);
4858 if (r < 0)
4859 return r;
4860
4861 n_offsets = (BUS_MESSAGE_FIELDS_SIZE(m) - framing) / sz;
4862 }
4863 }
4864
4865 ri = 0;
4866 while (ri < BUS_MESSAGE_FIELDS_SIZE(m)) {
4867 _cleanup_free_ char *sig = NULL;
80a46c73
LP
4868 const char *signature;
4869 uint8_t *header;
6647dc66
LP
4870 size_t item_size = (size_t) -1;
4871
4872 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4873 if (i >= n_offsets)
4874 break;
4875
4876 if (i == 0)
4877 ri = 0;
4878 else
4879 ri = ALIGN_TO(read_word_le((uint8_t*) offsets + (i-1)*sz, sz), 8);
4880 }
80a46c73
LP
4881
4882 r = message_peek_fields(m, &ri, 8, 1, (void**) &header);
4883 if (r < 0)
4884 return r;
4885
6647dc66
LP
4886 if (BUS_MESSAGE_IS_GVARIANT(m)) {
4887 size_t where, end;
4888 char *b;
4889 void *q;
4890
4891 end = read_word_le((uint8_t*) offsets + i*sz, sz);
4892
4893 if (end < ri)
4894 return -EBADMSG;
4895
4896 where = ri = ALIGN_TO(ri, 8);
4897 item_size = end - ri;
4898 r = message_peek_fields(m, &where, 1, item_size, &q);
4899 if (r < 0)
4900 return r;
4901
4902 b = memrchr(q, 0, item_size);
4903 if (!b)
4904 return -EBADMSG;
4905
4906 sig = strndup(b+1, item_size - (b+1-(char*) q));
4907 if (!sig)
4908 return -ENOMEM;
4909
4910 signature = sig;
4911 item_size = b - (char*) q;
4912 } else {
4913 r = message_peek_field_signature(m, &ri, 0, &signature);
4914 if (r < 0)
4915 return r;
4916 }
80a46c73
LP
4917
4918 switch (*header) {
0461f8cd 4919 case _BUS_MESSAGE_HEADER_INVALID:
80a46c73
LP
4920 return -EBADMSG;
4921
0461f8cd 4922 case BUS_MESSAGE_HEADER_PATH:
2c93b4ef
LP
4923
4924 if (m->path)
4925 return -EBADMSG;
4926
80a46c73
LP
4927 if (!streq(signature, "o"))
4928 return -EBADMSG;
4929
6647dc66 4930 r = message_peek_field_string(m, object_path_is_valid, &ri, item_size, &m->path);
80a46c73
LP
4931 break;
4932
0461f8cd 4933 case BUS_MESSAGE_HEADER_INTERFACE:
2c93b4ef
LP
4934
4935 if (m->interface)
4936 return -EBADMSG;
4937
80a46c73
LP
4938 if (!streq(signature, "s"))
4939 return -EBADMSG;
4940
6647dc66 4941 r = message_peek_field_string(m, interface_name_is_valid, &ri, item_size, &m->interface);
80a46c73
LP
4942 break;
4943
0461f8cd 4944 case BUS_MESSAGE_HEADER_MEMBER:
2c93b4ef
LP
4945
4946 if (m->member)
4947 return -EBADMSG;
4948
80a46c73
LP
4949 if (!streq(signature, "s"))
4950 return -EBADMSG;
4951
6647dc66 4952 r = message_peek_field_string(m, member_name_is_valid, &ri, item_size, &m->member);
80a46c73
LP
4953 break;
4954
0461f8cd 4955 case BUS_MESSAGE_HEADER_ERROR_NAME:
2c93b4ef
LP
4956
4957 if (m->error.name)
4958 return -EBADMSG;
4959
80a46c73
LP
4960 if (!streq(signature, "s"))
4961 return -EBADMSG;
4962
6647dc66 4963 r = message_peek_field_string(m, error_name_is_valid, &ri, item_size, &m->error.name);
79f8d3d2
LP
4964 if (r >= 0)
4965 m->error._need_free = -1;
4966
80a46c73
LP
4967 break;
4968
0461f8cd 4969 case BUS_MESSAGE_HEADER_DESTINATION:
2c93b4ef
LP
4970
4971 if (m->destination)
4972 return -EBADMSG;
4973
80a46c73
LP
4974 if (!streq(signature, "s"))
4975 return -EBADMSG;
4976
6647dc66 4977 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->destination);
80a46c73
LP
4978 break;
4979
0461f8cd 4980 case BUS_MESSAGE_HEADER_SENDER:
2c93b4ef
LP
4981
4982 if (m->sender)
4983 return -EBADMSG;
4984
80a46c73
LP
4985 if (!streq(signature, "s"))
4986 return -EBADMSG;
4987
6647dc66 4988 r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
49b832c5
LP
4989
4990 if (r >= 0 && m->sender[0] == ':' && m->bus && m->bus->bus_client && !m->bus->is_kernel) {
4991 m->creds.unique_name = (char*) m->sender;
4992 m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
4993 }
4994
80a46c73
LP
4995 break;
4996
4997
0461f8cd 4998 case BUS_MESSAGE_HEADER_SIGNATURE: {
80a46c73
LP
4999 const char *s;
5000 char *c;
5001
2c93b4ef
LP
5002 if (m->root_container.signature)
5003 return -EBADMSG;
5004
80a46c73
LP
5005 if (!streq(signature, "g"))
5006 return -EBADMSG;
5007
6647dc66 5008 r = message_peek_field_signature(m, &ri, item_size, &s);
80a46c73
LP
5009 if (r < 0)
5010 return r;
5011
5012 c = strdup(s);
5013 if (!c)
5014 return -ENOMEM;
5015
5016 free(m->root_container.signature);
5017 m->root_container.signature = c;
80a46c73
LP
5018 break;
5019 }
5020
0461f8cd 5021 case BUS_MESSAGE_HEADER_REPLY_SERIAL:
2c93b4ef
LP
5022 if (m->reply_serial != 0)
5023 return -EBADMSG;
5024
80a46c73
LP
5025 if (!streq(signature, "u"))
5026 return -EBADMSG;
5027
6647dc66 5028 r = message_peek_field_uint32(m, &ri, item_size, &m->reply_serial);
6693860f
LP
5029 if (r < 0)
5030 return r;
5031
5032 if (m->reply_serial == 0)
5033 return -EBADMSG;
5034
80a46c73
LP
5035 break;
5036
0461f8cd 5037 case BUS_MESSAGE_HEADER_UNIX_FDS:
2c93b4ef
LP
5038 if (unix_fds != 0)
5039 return -EBADMSG;
5040
5041 if (!streq(signature, "u"))
5042 return -EBADMSG;
5043
6647dc66 5044 r = message_peek_field_uint32(m, &ri, item_size, &unix_fds);
2c93b4ef
LP
5045 if (r < 0)
5046 return -EBADMSG;
5047
5048 if (unix_fds == 0)
5049 return -EBADMSG;
5050
5051 break;
5052
80a46c73 5053 default:
6647dc66
LP
5054 if (!BUS_MESSAGE_IS_GVARIANT(m))
5055 r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
80a46c73
LP
5056 }
5057
5058 if (r < 0)
5059 return r;
6647dc66
LP
5060
5061 i++;
80a46c73
LP
5062 }
5063
2c93b4ef
LP
5064 if (m->n_fds != unix_fds)
5065 return -EBADMSG;
5066
80a46c73
LP
5067 if (isempty(m->root_container.signature) != (BUS_MESSAGE_BODY_SIZE(m) == 0))
5068 return -EBADMSG;
5069
5070 switch (m->header->type) {
5071
40ca29a1 5072 case SD_BUS_MESSAGE_SIGNAL:
80a46c73
LP
5073 if (!m->path || !m->interface || !m->member)
5074 return -EBADMSG;
5075 break;
5076
40ca29a1 5077 case SD_BUS_MESSAGE_METHOD_CALL:
80a46c73
LP
5078
5079 if (!m->path || !m->member)
5080 return -EBADMSG;
5081
5082 break;
5083
40ca29a1 5084 case SD_BUS_MESSAGE_METHOD_RETURN:
80a46c73
LP
5085
5086 if (m->reply_serial == 0)
5087 return -EBADMSG;
5088 break;
5089
40ca29a1 5090 case SD_BUS_MESSAGE_METHOD_ERROR:
80a46c73
LP
5091
5092 if (m->reply_serial == 0 || !m->error.name)
5093 return -EBADMSG;
5094 break;
5095 }
9a17484d 5096
6647dc66
LP
5097 m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
5098
5099 if (BUS_MESSAGE_IS_GVARIANT(m)) {
5100 r = build_struct_offsets(
5101 m,
5102 m->root_container.signature,
5103 BUS_MESSAGE_BODY_SIZE(m),
5104 &m->root_container.item_size,
5105 &m->root_container.offsets,
5106 &m->root_container.n_offsets);
5107 if (r < 0)
5108 return r;
5109 }
5110
89ffcd2a 5111 /* Try to read the error message, but if we can't it's a non-issue */
40ca29a1 5112 if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
89ffcd2a
LP
5113 sd_bus_message_read(m, "s", &m->error.message);
5114
9a17484d
LP
5115 return 0;
5116}
5117
d9f644e2 5118_public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
9d6c7c82
LP
5119 assert_return(m, -EINVAL);
5120 assert_return(destination, -EINVAL);
5121 assert_return(!m->sealed, -EPERM);
5122 assert_return(!m->destination, -EEXIST);
9a17484d 5123
0461f8cd 5124 return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
9a17484d
LP
5125}
5126
de1c301e
LP
5127int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
5128 size_t total;
de1c301e 5129 void *p, *e;
bc7fd8cd
LP
5130 unsigned i;
5131 struct bus_body_part *part;
de1c301e
LP
5132
5133 assert(m);
5134 assert(buffer);
5135 assert(sz);
5136
6629161f 5137 total = BUS_MESSAGE_SIZE(m);
de1c301e
LP
5138
5139 p = malloc(total);
5140 if (!p)
5141 return -ENOMEM;
5142
c91cb83c 5143 e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m));
9b29bb68 5144 MESSAGE_FOREACH_PART(part, i, m)
bc7fd8cd 5145 e = mempcpy(e, part->data, part->size);
2100fa10
LP
5146
5147 assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p));
de1c301e
LP
5148
5149 *buffer = p;
5150 *sz = total;
5151
5152 return 0;
5153}
89ffcd2a
LP
5154
5155int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
5156 int r;
5157
5158 assert(m);
5159 assert(l);
5160
5161 r = sd_bus_message_enter_container(m, 'a', "s");
4686d1b6 5162 if (r <= 0)
89ffcd2a
LP
5163 return r;
5164
5165 for (;;) {
5166 const char *s;
5167
5168 r = sd_bus_message_read_basic(m, 's', &s);
5169 if (r < 0)
5170 return r;
5171 if (r == 0)
5172 break;
5173
5174 r = strv_extend(l, s);
5175 if (r < 0)
5176 return r;
5177 }
5178
5179 r = sd_bus_message_exit_container(m);
5180 if (r < 0)
5181 return r;
5182
405cd3aa 5183 return 1;
89ffcd2a 5184}
392d5b37 5185
ba341e7c 5186_public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
4686d1b6
MAP
5187 char **strv = NULL;
5188 int r;
5189
5190 assert_return(m, -EINVAL);
5191 assert_return(m->sealed, -EPERM);
5192 assert_return(l, -EINVAL);
5193
5194 r = bus_message_read_strv_extend(m, &strv);
5195 if (r <= 0) {
5196 strv_free(strv);
5197 return r;
5198 }
5199
5200 *l = strv;
5201 return 1;
5202}
5203
392d5b37
LP
5204const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
5205 int r;
42c5aaf3
LP
5206 const char *t = NULL;
5207 unsigned j;
392d5b37
LP
5208
5209 assert(m);
5210
5211 r = sd_bus_message_rewind(m, true);
5212 if (r < 0)
5213 return NULL;
5214
42c5aaf3
LP
5215 for (j = 0; j <= i; j++) {
5216 char type;
5217
392d5b37
LP
5218 r = sd_bus_message_peek_type(m, &type, NULL);
5219 if (r < 0)
5220 return NULL;
5221
5222 if (type != SD_BUS_TYPE_STRING &&
5223 type != SD_BUS_TYPE_OBJECT_PATH &&
5224 type != SD_BUS_TYPE_SIGNATURE)
5225 return NULL;
5226
5227 r = sd_bus_message_read_basic(m, type, &t);
5228 if (r < 0)
5229 return NULL;
392d5b37
LP
5230 }
5231
392d5b37
LP
5232 return t;
5233}
2100fa10 5234
c91cb83c
LP
5235bool bus_header_is_complete(struct bus_header *h, size_t size) {
5236 size_t full;
5237
5238 assert(h);
5239 assert(size);
5240
5241 if (size < sizeof(struct bus_header))
5242 return false;
5243
5244 full = sizeof(struct bus_header) +
0461f8cd 5245 (h->endian == BUS_NATIVE_ENDIAN ? h->fields_size : bswap_32(h->fields_size));
c91cb83c
LP
5246
5247 return size >= full;
5248}
5249
5250int bus_header_message_size(struct bus_header *h, size_t *sum) {
6629161f
LP
5251 size_t fs, bs;
5252
5253 assert(h);
5254 assert(sum);
5255
0461f8cd 5256 if (h->endian == BUS_NATIVE_ENDIAN) {
6629161f
LP
5257 fs = h->fields_size;
5258 bs = h->body_size;
0461f8cd 5259 } else if (h->endian == BUS_REVERSE_ENDIAN) {
6629161f
LP
5260 fs = bswap_32(h->fields_size);
5261 bs = bswap_32(h->body_size);
5262 } else
5263 return -EBADMSG;
2100fa10 5264
6629161f
LP
5265 *sum = sizeof(struct bus_header) + ALIGN8(fs) + bs;
5266 return 0;
2100fa10 5267}
eb01ba5d 5268
d9f644e2 5269_public_ int sd_bus_message_get_errno(sd_bus_message *m) {
40ca29a1 5270 assert_return(m, -EINVAL);
eb01ba5d 5271
40ca29a1 5272 if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
eb01ba5d
LP
5273 return 0;
5274
40ca29a1 5275 return sd_bus_error_get_errno(&m->error);
eb01ba5d 5276}
29ddb38f 5277
d9f644e2 5278_public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
29ddb38f
LP
5279 struct bus_container *c;
5280
9d6c7c82 5281 assert_return(m, NULL);
29ddb38f
LP
5282
5283 c = complete ? &m->root_container : message_get_container(m);
40ca29a1 5284 return c->signature ?: "";
29ddb38f 5285}
c430fee6 5286
d9f644e2 5287_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
c430fee6
LP
5288 bool done_something = false;
5289 int r;
5290
80ba3b84
LP
5291 assert_return(m, -EINVAL);
5292 assert_return(source, -EINVAL);
5293 assert_return(!m->sealed, -EPERM);
5294 assert_return(source->sealed, -EPERM);
5295
c430fee6
LP
5296 do {
5297 const char *contents;
5298 char type;
5299 union {
5300 uint8_t u8;
5301 uint16_t u16;
5302 int16_t s16;
5303 uint32_t u32;
5304 int32_t s32;
5305 uint64_t u64;
5306 int64_t s64;
5307 double d64;
5308 const char *string;
5309 int i;
5310 } basic;
5311
5312 r = sd_bus_message_peek_type(source, &type, &contents);
5313 if (r < 0)
5314 return r;
5315 if (r == 0)
5316 break;
5317
5318 done_something = true;
5319
5320 if (bus_type_is_container(type) > 0) {
5321
5322 r = sd_bus_message_enter_container(source, type, contents);
5323 if (r < 0)
5324 return r;
5325
5326 r = sd_bus_message_open_container(m, type, contents);
5327 if (r < 0)
5328 return r;
5329
5330 r = sd_bus_message_copy(m, source, true);
5331 if (r < 0)
5332 return r;
5333
5334 r = sd_bus_message_close_container(m);
5335 if (r < 0)
5336 return r;
5337
5338 r = sd_bus_message_exit_container(source);
5339 if (r < 0)
5340 return r;
5341
5342 continue;
5343 }
5344
5345 r = sd_bus_message_read_basic(source, type, &basic);
5346 if (r < 0)
5347 return r;
5348
5349 assert(r > 0);
5350
5351 if (type == SD_BUS_TYPE_OBJECT_PATH ||
5352 type == SD_BUS_TYPE_SIGNATURE ||
5353 type == SD_BUS_TYPE_STRING)
5354 r = sd_bus_message_append_basic(m, type, basic.string);
5355 else
5356 r = sd_bus_message_append_basic(m, type, &basic);
5357
5358 if (r < 0)
5359 return r;
5360
5361 } while (all);
5362
5363 return done_something;
5364}
5365
d9f644e2 5366_public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
c430fee6
LP
5367 const char *c;
5368 char t;
5369 int r;
5370
5371 assert_return(m, -EINVAL);
5372 assert_return(m->sealed, -EPERM);
5373 assert_return(!type || bus_type_is_valid(type), -EINVAL);
5374 assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
5375 assert_return(type || contents, -EINVAL);
5376 assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
5377
5378 r = sd_bus_message_peek_type(m, &t, &c);
5379 if (r <= 0)
5380 return r;
5381
5382 if (type != 0 && type != t)
5383 return 0;
5384
5385 if (contents && !streq_ptr(contents, c))
5386 return 0;
5387
5388 return 1;
5389}
2be44176
LP
5390
5391_public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) {
5392 assert_return(m, NULL);
5393
5394 return m->bus;
5395}