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