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