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