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