chiark / gitweb /
Prep v233.3: Unmask various functions for future coverage tests.
[elogind.git] / src / libelogind / sd-bus / bus-message.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2013 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <sys/mman.h>
23
24 #include "sd-bus.h"
25
26 #include "alloc-util.h"
27 #include "bus-gvariant.h"
28 #include "bus-internal.h"
29 #include "bus-message.h"
30 #include "bus-signature.h"
31 #include "bus-type.h"
32 #include "bus-util.h"
33 #include "fd-util.h"
34 #include "io-util.h"
35 #include "memfd-util.h"
36 #include "string-util.h"
37 #include "strv.h"
38 #include "time-util.h"
39 #include "utf8.h"
40 #include "util.h"
41
42 static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
43
44 static void *adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) {
45
46         if (p == NULL)
47                 return NULL;
48
49         if (old_base == new_base)
50                 return (void*) p;
51
52         if ((uint8_t*) p < (uint8_t*) old_base)
53                 return (void*) p;
54
55         if ((uint8_t*) p >= (uint8_t*) old_base + sz)
56                 return (void*) p;
57
58         return (uint8_t*) new_base + ((uint8_t*) p - (uint8_t*) old_base);
59 }
60
61 static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
62         assert(m);
63         assert(part);
64
65         if (part->memfd >= 0) {
66                 /* If we can reuse the memfd, try that. For that it
67                  * can't be sealed yet. */
68
69                 if (!part->sealed) {
70                         assert(part->memfd_offset == 0);
71                         assert(part->data == part->mmap_begin);
72                         bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
73                 } else {
74                         if (part->mapped > 0)
75                                 assert_se(munmap(part->mmap_begin, part->mapped) == 0);
76
77                         safe_close(part->memfd);
78                 }
79
80         } else if (part->munmap_this)
81                 munmap(part->mmap_begin, part->mapped);
82         else if (part->free_this)
83                 free(part->data);
84
85         if (part != &m->body)
86                 free(part);
87 }
88
89 static void message_reset_parts(sd_bus_message *m) {
90         struct bus_body_part *part;
91
92         assert(m);
93
94         part = &m->body;
95         while (m->n_body_parts > 0) {
96                 struct bus_body_part *next = part->next;
97                 message_free_part(m, part);
98                 part = next;
99                 m->n_body_parts--;
100         }
101
102         m->body_end = NULL;
103
104         m->cached_rindex_part = NULL;
105         m->cached_rindex_part_begin = 0;
106 }
107
108 static void message_reset_containers(sd_bus_message *m) {
109         unsigned i;
110
111         assert(m);
112
113         for (i = 0; i < m->n_containers; i++) {
114                 free(m->containers[i].signature);
115                 free(m->containers[i].offsets);
116         }
117
118         m->containers = mfree(m->containers);
119
120         m->n_containers = m->containers_allocated = 0;
121         m->root_container.index = 0;
122 }
123
124 static void message_free(sd_bus_message *m) {
125         assert(m);
126
127         if (m->free_header)
128                 free(m->header);
129
130         message_reset_parts(m);
131
132         if (m->release_kdbus)
133                 bus_kernel_cmd_free(m->bus, (uint8_t *) m->kdbus - (uint8_t *) m->bus->kdbus_buffer);
134
135         if (m->free_kdbus)
136                 free(m->kdbus);
137
138         sd_bus_unref(m->bus);
139
140         if (m->free_fds) {
141                 close_many(m->fds, m->n_fds);
142                 free(m->fds);
143         }
144
145         if (m->iovec != m->iovec_fixed)
146                 free(m->iovec);
147
148         m->destination_ptr = mfree(m->destination_ptr);
149         message_reset_containers(m);
150         free(m->root_container.signature);
151         free(m->root_container.offsets);
152
153         free(m->root_container.peeked_signature);
154
155         bus_creds_done(&m->creds);
156         free(m);
157 }
158
159 static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
160         void *op, *np;
161         size_t old_size, new_size, start;
162
163         assert(m);
164
165         if (m->poisoned)
166                 return NULL;
167
168         old_size = sizeof(struct bus_header) + m->fields_size;
169         start = ALIGN_TO(old_size, align);
170         new_size = start + sz;
171
172         if (new_size < start ||
173             new_size > (size_t) ((uint32_t) -1))
174                 goto poison;
175
176         if (old_size == new_size)
177                 return (uint8_t*) m->header + old_size;
178
179         if (m->free_header) {
180                 np = realloc(m->header, ALIGN8(new_size));
181                 if (!np)
182                         goto poison;
183         } else {
184                 /* Initially, the header is allocated as part of
185                  * the sd_bus_message itself, let's replace it by
186                  * dynamic data */
187
188                 np = malloc(ALIGN8(new_size));
189                 if (!np)
190                         goto poison;
191
192                 memcpy(np, m->header, sizeof(struct bus_header));
193         }
194
195         /* Zero out padding */
196         if (start > old_size)
197                 memzero((uint8_t*) np + old_size, start - old_size);
198
199         op = m->header;
200         m->header = np;
201         m->fields_size = new_size - sizeof(struct bus_header);
202
203         /* Adjust quick access pointers */
204         m->path = adjust_pointer(m->path, op, old_size, m->header);
205         m->interface = adjust_pointer(m->interface, op, old_size, m->header);
206         m->member = adjust_pointer(m->member, op, old_size, m->header);
207         m->destination = adjust_pointer(m->destination, op, old_size, m->header);
208         m->sender = adjust_pointer(m->sender, op, old_size, m->header);
209         m->error.name = adjust_pointer(m->error.name, op, old_size, m->header);
210
211         m->free_header = true;
212
213         if (add_offset) {
214                 if (m->n_header_offsets >= ELEMENTSOF(m->header_offsets))
215                         goto poison;
216
217                 m->header_offsets[m->n_header_offsets++] = new_size - sizeof(struct bus_header);
218         }
219
220         return (uint8_t*) np + start;
221
222 poison:
223         m->poisoned = true;
224         return NULL;
225 }
226
227 static int message_append_field_string(
228                 sd_bus_message *m,
229                 uint64_t h,
230                 char type,
231                 const char *s,
232                 const char **ret) {
233
234         size_t l;
235         uint8_t *p;
236
237         assert(m);
238
239         /* dbus1 only allows 8bit header field ids */
240         if (h > 0xFF)
241                 return -EINVAL;
242
243         /* dbus1 doesn't allow strings over 32bit, let's enforce this
244          * globally, to not risk convertability */
245         l = strlen(s);
246         if (l > (size_t) (uint32_t) -1)
247                 return -EINVAL;
248
249         /* Signature "(yv)" where the variant contains "s" */
250
251         if (BUS_MESSAGE_IS_GVARIANT(m)) {
252
253                 /* (field id 64bit, ((string + NUL) + NUL + signature string 's') */
254                 p = message_extend_fields(m, 8, 8 + l + 1 + 1 + 1, true);
255                 if (!p)
256                         return -ENOMEM;
257
258                 *((uint64_t*) p) = h;
259                 memcpy(p+8, s, l);
260                 p[8+l] = 0;
261                 p[8+l+1] = 0;
262                 p[8+l+2] = type;
263
264                 if (ret)
265                         *ret = (char*) p + 8;
266
267         } else {
268                 /* (field id byte + (signature length + signature 's' + NUL) + (string length + string + NUL)) */
269                 p = message_extend_fields(m, 8, 4 + 4 + l + 1, false);
270                 if (!p)
271                         return -ENOMEM;
272
273                 p[0] = (uint8_t) h;
274                 p[1] = 1;
275                 p[2] = type;
276                 p[3] = 0;
277
278                 ((uint32_t*) p)[1] = l;
279                 memcpy(p + 8, s, l + 1);
280
281                 if (ret)
282                         *ret = (char*) p + 8;
283         }
284
285         return 0;
286 }
287
288 static int message_append_field_signature(
289                 sd_bus_message *m,
290                 uint64_t h,
291                 const char *s,
292                 const char **ret) {
293
294         size_t l;
295         uint8_t *p;
296
297         assert(m);
298
299         /* dbus1 only allows 8bit header field ids */
300         if (h > 0xFF)
301                 return -EINVAL;
302
303         /* dbus1 doesn't allow signatures over 8bit, let's enforce
304          * this globally, to not risk convertability */
305         l = strlen(s);
306         if (l > 255)
307                 return -EINVAL;
308
309         /* Signature "(yv)" where the variant contains "g" */
310
311         if (BUS_MESSAGE_IS_GVARIANT(m))
312                 /* For gvariant the serialization is the same as for normal strings */
313                 return message_append_field_string(m, h, 'g', s, ret);
314         else {
315                 /* (field id byte + (signature length + signature 'g' + NUL) + (string length + string + NUL)) */
316                 p = message_extend_fields(m, 8, 4 + 1 + l + 1, false);
317                 if (!p)
318                         return -ENOMEM;
319
320                 p[0] = (uint8_t) h;
321                 p[1] = 1;
322                 p[2] = SD_BUS_TYPE_SIGNATURE;
323                 p[3] = 0;
324                 p[4] = l;
325                 memcpy(p + 5, s, l + 1);
326
327                 if (ret)
328                         *ret = (const char*) p + 5;
329         }
330
331         return 0;
332 }
333
334 static int message_append_field_uint32(sd_bus_message *m, uint64_t h, uint32_t x) {
335         uint8_t *p;
336
337         assert(m);
338
339         /* dbus1 only allows 8bit header field ids */
340         if (h > 0xFF)
341                 return -EINVAL;
342
343         if (BUS_MESSAGE_IS_GVARIANT(m)) {
344                 /* (field id 64bit + ((value + NUL + signature string 'u') */
345
346                 p = message_extend_fields(m, 8, 8 + 4 + 1 + 1, true);
347                 if (!p)
348                         return -ENOMEM;
349
350                 *((uint64_t*) p) = h;
351                 *((uint32_t*) (p + 8)) = x;
352                 p[12] = 0;
353                 p[13] = 'u';
354         } else {
355                 /* (field id byte + (signature length + signature 'u' + NUL) + value) */
356                 p = message_extend_fields(m, 8, 4 + 4, false);
357                 if (!p)
358                         return -ENOMEM;
359
360                 p[0] = (uint8_t) h;
361                 p[1] = 1;
362                 p[2] = 'u';
363                 p[3] = 0;
364
365                 ((uint32_t*) p)[1] = x;
366         }
367
368         return 0;
369 }
370
371 static int message_append_field_uint64(sd_bus_message *m, uint64_t h, uint64_t x) {
372         uint8_t *p;
373
374         assert(m);
375
376         /* dbus1 only allows 8bit header field ids */
377         if (h > 0xFF)
378                 return -EINVAL;
379
380         if (BUS_MESSAGE_IS_GVARIANT(m)) {
381                 /* (field id 64bit + ((value + NUL + signature string 't') */
382
383                 p = message_extend_fields(m, 8, 8 + 8 + 1 + 1, true);
384                 if (!p)
385                         return -ENOMEM;
386
387                 *((uint64_t*) p) = h;
388                 *((uint64_t*) (p + 8)) = x;
389                 p[16] = 0;
390                 p[17] = 't';
391         } else {
392                 /* (field id byte + (signature length + signature 't' + NUL) + 4 byte padding + value) */
393                 p = message_extend_fields(m, 8, 4 + 4 + 8, false);
394                 if (!p)
395                         return -ENOMEM;
396
397                 p[0] = (uint8_t) h;
398                 p[1] = 1;
399                 p[2] = 't';
400                 p[3] = 0;
401                 p[4] = 0;
402                 p[5] = 0;
403                 p[6] = 0;
404                 p[7] = 0;
405
406                 ((uint64_t*) p)[1] = x;
407         }
408
409         return 0;
410 }
411
412 static int message_append_reply_cookie(sd_bus_message *m, uint64_t cookie) {
413         assert(m);
414
415         if (BUS_MESSAGE_IS_GVARIANT(m))
416                 return message_append_field_uint64(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, cookie);
417         else {
418                 /* 64bit cookies are not supported on dbus1 */
419                 if (cookie > 0xffffffffUL)
420                         return -EOPNOTSUPP;
421
422                 return message_append_field_uint32(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, (uint32_t) cookie);
423         }
424 }
425
426 int bus_message_from_header(
427                 sd_bus *bus,
428                 void *header,
429                 size_t header_accessible,
430                 void *footer,
431                 size_t footer_accessible,
432                 size_t message_size,
433                 int *fds,
434                 unsigned n_fds,
435                 const char *label,
436                 size_t extra,
437                 sd_bus_message **ret) {
438
439         _cleanup_free_ sd_bus_message *m = NULL;
440         struct bus_header *h;
441         size_t a, label_sz;
442
443         assert(bus);
444         assert(header || header_accessible <= 0);
445         assert(footer || footer_accessible <= 0);
446         assert(fds || n_fds <= 0);
447         assert(ret);
448
449         if (header_accessible < sizeof(struct bus_header))
450                 return -EBADMSG;
451
452         if (header_accessible > message_size)
453                 return -EBADMSG;
454         if (footer_accessible > message_size)
455                 return -EBADMSG;
456
457         h = header;
458         if (!IN_SET(h->version, 1, 2))
459                 return -EBADMSG;
460
461         if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
462                 return -EBADMSG;
463
464         if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
465                 return -EBADMSG;
466
467         /* Note that we are happy with unknown flags in the flags header! */
468
469         a = ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
470
471         if (label) {
472                 label_sz = strlen(label);
473                 a += label_sz + 1;
474         }
475
476         m = malloc0(a);
477         if (!m)
478                 return -ENOMEM;
479
480         m->n_ref = 1;
481         m->sealed = true;
482         m->header = header;
483         m->header_accessible = header_accessible;
484         m->footer = footer;
485         m->footer_accessible = footer_accessible;
486
487         if (BUS_MESSAGE_IS_GVARIANT(m)) {
488                 size_t ws;
489
490                 if (h->dbus2.cookie == 0)
491                         return -EBADMSG;
492
493                 /* dbus2 derives the sizes from the message size and
494                 the offset table at the end, since it is formatted as
495                 gvariant "yyyyuta{tv}v". Since the message itself is a
496                 structure with precisely to variable sized entries,
497                 there's only one offset in the table, which marks the
498                 end of the fields array. */
499
500                 ws = bus_gvariant_determine_word_size(message_size, 0);
501                 if (footer_accessible < ws)
502                         return -EBADMSG;
503
504                 m->fields_size = bus_gvariant_read_word_le((uint8_t*) footer + footer_accessible - ws, ws);
505                 if (ALIGN8(m->fields_size) > message_size - ws)
506                         return -EBADMSG;
507                 if (m->fields_size < sizeof(struct bus_header))
508                         return -EBADMSG;
509
510                 m->fields_size -= sizeof(struct bus_header);
511                 m->body_size = message_size - (sizeof(struct bus_header) + ALIGN8(m->fields_size));
512         } else {
513                 if (h->dbus1.serial == 0)
514                         return -EBADMSG;
515
516                 /* dbus1 has the sizes in the header */
517                 m->fields_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.fields_size);
518                 m->body_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.body_size);
519
520                 if (sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size != message_size)
521                         return -EBADMSG;
522         }
523
524         m->fds = fds;
525         m->n_fds = n_fds;
526
527         if (label) {
528                 m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
529                 memcpy(m->creds.label, label, label_sz + 1);
530
531                 m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
532         }
533
534         m->bus = sd_bus_ref(bus);
535         *ret = m;
536         m = NULL;
537
538         return 0;
539 }
540
541 int bus_message_from_malloc(
542                 sd_bus *bus,
543                 void *buffer,
544                 size_t length,
545                 int *fds,
546                 unsigned n_fds,
547                 const char *label,
548                 sd_bus_message **ret) {
549
550         sd_bus_message *m;
551         size_t sz;
552         int r;
553
554         r = bus_message_from_header(
555                         bus,
556                         buffer, length, /* in this case the initial bytes and the final bytes are the same */
557                         buffer, length,
558                         length,
559                         fds, n_fds,
560                         label,
561                         0, &m);
562         if (r < 0)
563                 return r;
564
565         sz = length - sizeof(struct bus_header) - ALIGN8(m->fields_size);
566         if (sz > 0) {
567                 m->n_body_parts = 1;
568                 m->body.data = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(m->fields_size);
569                 m->body.size = sz;
570                 m->body.sealed = true;
571                 m->body.memfd = -1;
572         }
573
574         m->n_iovec = 1;
575         m->iovec = m->iovec_fixed;
576         m->iovec[0].iov_base = buffer;
577         m->iovec[0].iov_len = length;
578
579         r = bus_message_parse_fields(m);
580         if (r < 0)
581                 goto fail;
582
583         /* We take possession of the memory and fds now */
584         m->free_header = true;
585         m->free_fds = true;
586
587         *ret = m;
588         return 0;
589
590 fail:
591         message_free(m);
592         return r;
593 }
594
595 static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
596         sd_bus_message *m;
597
598         assert(bus);
599
600         m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
601         if (!m)
602                 return NULL;
603
604         m->n_ref = 1;
605         m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message)));
606         m->header->endian = BUS_NATIVE_ENDIAN;
607         m->header->type = type;
608         m->header->version = bus->message_version;
609         m->allow_fds = bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING);
610         m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m);
611         m->bus = sd_bus_ref(bus);
612
613         if (bus->allow_interactive_authorization)
614                 m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
615
616         return m;
617 }
618
619 _public_ int sd_bus_message_new_signal(
620                 sd_bus *bus,
621                 sd_bus_message **m,
622                 const char *path,
623                 const char *interface,
624                 const char *member) {
625
626         sd_bus_message *t;
627         int r;
628
629         assert_return(bus, -ENOTCONN);
630         assert_return(bus->state != BUS_UNSET, -ENOTCONN);
631         assert_return(object_path_is_valid(path), -EINVAL);
632         assert_return(interface_name_is_valid(interface), -EINVAL);
633         assert_return(member_name_is_valid(member), -EINVAL);
634         assert_return(m, -EINVAL);
635
636         t = message_new(bus, SD_BUS_MESSAGE_SIGNAL);
637         if (!t)
638                 return -ENOMEM;
639
640         t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
641
642         r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
643         if (r < 0)
644                 goto fail;
645         r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
646         if (r < 0)
647                 goto fail;
648         r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
649         if (r < 0)
650                 goto fail;
651
652         *m = t;
653         return 0;
654
655 fail:
656         sd_bus_message_unref(t);
657         return r;
658 }
659
660 _public_ int sd_bus_message_new_method_call(
661                 sd_bus *bus,
662                 sd_bus_message **m,
663                 const char *destination,
664                 const char *path,
665                 const char *interface,
666                 const char *member) {
667
668         sd_bus_message *t;
669         int r;
670
671         assert_return(bus, -ENOTCONN);
672         assert_return(bus->state != BUS_UNSET, -ENOTCONN);
673         assert_return(!destination || service_name_is_valid(destination), -EINVAL);
674         assert_return(object_path_is_valid(path), -EINVAL);
675         assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
676         assert_return(member_name_is_valid(member), -EINVAL);
677         assert_return(m, -EINVAL);
678
679         t = message_new(bus, SD_BUS_MESSAGE_METHOD_CALL);
680         if (!t)
681                 return -ENOMEM;
682
683         r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
684         if (r < 0)
685                 goto fail;
686         r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
687         if (r < 0)
688                 goto fail;
689
690         if (interface) {
691                 r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
692                 if (r < 0)
693                         goto fail;
694         }
695
696         if (destination) {
697                 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination);
698                 if (r < 0)
699                         goto fail;
700         }
701
702         *m = t;
703         return 0;
704
705 fail:
706         message_free(t);
707         return r;
708 }
709
710 static int message_new_reply(
711                 sd_bus_message *call,
712                 uint8_t type,
713                 sd_bus_message **m) {
714
715         sd_bus_message *t;
716         int r;
717
718         assert_return(call, -EINVAL);
719         assert_return(call->sealed, -EPERM);
720         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
721         assert_return(call->bus->state != BUS_UNSET, -ENOTCONN);
722         assert_return(m, -EINVAL);
723
724         t = message_new(call->bus, type);
725         if (!t)
726                 return -ENOMEM;
727
728         t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
729         t->reply_cookie = BUS_MESSAGE_COOKIE(call);
730         if (t->reply_cookie == 0)
731                 return -EOPNOTSUPP;
732
733         r = message_append_reply_cookie(t, t->reply_cookie);
734         if (r < 0)
735                 goto fail;
736
737         if (call->sender) {
738                 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination);
739                 if (r < 0)
740                         goto fail;
741         }
742
743         t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
744         t->enforced_reply_signature = call->enforced_reply_signature;
745
746         *m = t;
747         return 0;
748
749 fail:
750         message_free(t);
751         return r;
752 }
753
754 _public_ int sd_bus_message_new_method_return(
755                 sd_bus_message *call,
756                 sd_bus_message **m) {
757
758         return message_new_reply(call, SD_BUS_MESSAGE_METHOD_RETURN, m);
759 }
760
761 _public_ int sd_bus_message_new_method_error(
762                 sd_bus_message *call,
763                 sd_bus_message **m,
764                 const sd_bus_error *e) {
765
766         sd_bus_message *t;
767         int r;
768
769         assert_return(sd_bus_error_is_set(e), -EINVAL);
770         assert_return(m, -EINVAL);
771
772         r = message_new_reply(call, SD_BUS_MESSAGE_METHOD_ERROR, &t);
773         if (r < 0)
774                 return r;
775
776         r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
777         if (r < 0)
778                 goto fail;
779
780         if (e->message) {
781                 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
782                 if (r < 0)
783                         goto fail;
784         }
785
786         t->error._need_free = -1;
787
788         *m = t;
789         return 0;
790
791 fail:
792         message_free(t);
793         return r;
794 }
795
796 _public_ int sd_bus_message_new_method_errorf(
797                 sd_bus_message *call,
798                 sd_bus_message **m,
799                 const char *name,
800                 const char *format,
801                 ...) {
802
803         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
804         va_list ap;
805
806         assert_return(name, -EINVAL);
807         assert_return(m, -EINVAL);
808
809         va_start(ap, format);
810         bus_error_setfv(&error, name, format, ap);
811         va_end(ap);
812
813         return sd_bus_message_new_method_error(call, m, &error);
814 }
815
816 _public_ int sd_bus_message_new_method_errno(
817                 sd_bus_message *call,
818                 sd_bus_message **m,
819                 int error,
820                 const sd_bus_error *p) {
821
822         _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
823
824         if (sd_bus_error_is_set(p))
825                 return sd_bus_message_new_method_error(call, m, p);
826
827         sd_bus_error_set_errno(&berror, error);
828
829         return sd_bus_message_new_method_error(call, m, &berror);
830 }
831
832 #if 0 /// UNNEEDED by elogind
833 _public_ int sd_bus_message_new_method_errnof(
834                 sd_bus_message *call,
835                 sd_bus_message **m,
836                 int error,
837                 const char *format,
838                 ...) {
839
840         _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
841         va_list ap;
842
843         va_start(ap, format);
844         sd_bus_error_set_errnofv(&berror, error, format, ap);
845         va_end(ap);
846
847         return sd_bus_message_new_method_error(call, m, &berror);
848 }
849 #endif // 0
850
851 void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m) {
852         assert(bus);
853         assert(m);
854
855         m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus.Local";
856         m->creds.well_known_names_local = true;
857         m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
858 }
859
860 void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m) {
861         assert(bus);
862         assert(m);
863
864         m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
865         m->creds.well_known_names_driver = true;
866         m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
867 }
868
869 int bus_message_new_synthetic_error(
870                 sd_bus *bus,
871                 uint64_t cookie,
872                 const sd_bus_error *e,
873                 sd_bus_message **m) {
874
875         sd_bus_message *t;
876         int r;
877
878         assert(bus);
879         assert(sd_bus_error_is_set(e));
880         assert(m);
881
882         t = message_new(bus, SD_BUS_MESSAGE_METHOD_ERROR);
883         if (!t)
884                 return -ENOMEM;
885
886         t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
887         t->reply_cookie = cookie;
888
889         r = message_append_reply_cookie(t, t->reply_cookie);
890         if (r < 0)
891                 goto fail;
892
893         if (bus && bus->unique_name) {
894                 r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination);
895                 if (r < 0)
896                         goto fail;
897         }
898
899         r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
900         if (r < 0)
901                 goto fail;
902
903         if (e->message) {
904                 r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
905                 if (r < 0)
906                         goto fail;
907         }
908
909         t->error._need_free = -1;
910
911         bus_message_set_sender_driver(bus, t);
912
913         *m = t;
914         return 0;
915
916 fail:
917         message_free(t);
918         return r;
919 }
920
921 _public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
922
923         if (!m)
924                 return NULL;
925
926         assert(m->n_ref > 0);
927         m->n_ref++;
928
929         return m;
930 }
931
932 _public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
933
934         if (!m)
935                 return NULL;
936
937         assert(m->n_ref > 0);
938         m->n_ref--;
939
940         if (m->n_ref > 0)
941                 return NULL;
942
943         message_free(m);
944         return NULL;
945 }
946
947 #if 0 /// UNNEEDED by elogind
948 _public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
949         assert_return(m, -EINVAL);
950         assert_return(type, -EINVAL);
951
952         *type = m->header->type;
953         return 0;
954 }
955
956 _public_ int sd_bus_message_get_cookie(sd_bus_message *m, uint64_t *cookie) {
957         uint64_t c;
958
959         assert_return(m, -EINVAL);
960         assert_return(cookie, -EINVAL);
961
962         c = BUS_MESSAGE_COOKIE(m);
963         if (c == 0)
964                 return -ENODATA;
965
966         *cookie = BUS_MESSAGE_COOKIE(m);
967         return 0;
968 }
969
970 _public_ int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie) {
971         assert_return(m, -EINVAL);
972         assert_return(cookie, -EINVAL);
973
974         if (m->reply_cookie == 0)
975                 return -ENODATA;
976
977         *cookie = m->reply_cookie;
978         return 0;
979 }
980
981 _public_ int sd_bus_message_get_expect_reply(sd_bus_message *m) {
982         assert_return(m, -EINVAL);
983
984         return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
985                 !(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
986 }
987
988 _public_ int sd_bus_message_get_auto_start(sd_bus_message *m) {
989         assert_return(m, -EINVAL);
990
991         return !(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
992 }
993 #endif // 0
994
995 _public_ int sd_bus_message_get_allow_interactive_authorization(sd_bus_message *m) {
996         assert_return(m, -EINVAL);
997
998         return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
999                 (m->header->flags & BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION);
1000 }
1001
1002 _public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
1003         assert_return(m, NULL);
1004
1005         return m->path;
1006 }
1007
1008 _public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
1009         assert_return(m, NULL);
1010
1011         return m->interface;
1012 }
1013
1014 _public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
1015         assert_return(m, NULL);
1016
1017         return m->member;
1018 }
1019
1020 _public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
1021         assert_return(m, NULL);
1022
1023         return m->destination;
1024 }
1025
1026 _public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
1027         assert_return(m, NULL);
1028
1029         return m->sender;
1030 }
1031
1032 _public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
1033         assert_return(m, NULL);
1034
1035         if (!sd_bus_error_is_set(&m->error))
1036                 return NULL;
1037
1038         return &m->error;
1039 }
1040
1041 #if 0 /// UNNEEDED by elogind
1042 _public_ int sd_bus_message_get_monotonic_usec(sd_bus_message *m, uint64_t *usec) {
1043         assert_return(m, -EINVAL);
1044         assert_return(usec, -EINVAL);
1045
1046         if (m->monotonic <= 0)
1047                 return -ENODATA;
1048
1049         *usec = m->monotonic;
1050         return 0;
1051 }
1052
1053 _public_ int sd_bus_message_get_realtime_usec(sd_bus_message *m, uint64_t *usec) {
1054         assert_return(m, -EINVAL);
1055         assert_return(usec, -EINVAL);
1056
1057         if (m->realtime <= 0)
1058                 return -ENODATA;
1059
1060         *usec = m->realtime;
1061         return 0;
1062 }
1063
1064 _public_ int sd_bus_message_get_seqnum(sd_bus_message *m, uint64_t *seqnum) {
1065         assert_return(m, -EINVAL);
1066         assert_return(seqnum, -EINVAL);
1067
1068         if (m->seqnum <= 0)
1069                 return -ENODATA;
1070
1071         *seqnum = m->seqnum;
1072         return 0;
1073 }
1074 #endif // 0
1075
1076 _public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) {
1077         assert_return(m, NULL);
1078
1079         if (m->creds.mask == 0)
1080                 return NULL;
1081
1082         return &m->creds;
1083 }
1084
1085 _public_ int sd_bus_message_is_signal(
1086                 sd_bus_message *m,
1087                 const char *interface,
1088                 const char *member) {
1089
1090         assert_return(m, -EINVAL);
1091
1092         if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
1093                 return 0;
1094
1095         if (interface && (!m->interface || !streq(m->interface, interface)))
1096                 return 0;
1097
1098         if (member &&  (!m->member || !streq(m->member, member)))
1099                 return 0;
1100
1101         return 1;
1102 }
1103
1104 _public_ int sd_bus_message_is_method_call(
1105                 sd_bus_message *m,
1106                 const char *interface,
1107                 const char *member) {
1108
1109         assert_return(m, -EINVAL);
1110
1111         if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
1112                 return 0;
1113
1114         if (interface && (!m->interface || !streq(m->interface, interface)))
1115                 return 0;
1116
1117         if (member &&  (!m->member || !streq(m->member, member)))
1118                 return 0;
1119
1120         return 1;
1121 }
1122
1123 _public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
1124         assert_return(m, -EINVAL);
1125
1126         if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
1127                 return 0;
1128
1129         if (name && (!m->error.name || !streq(m->error.name, name)))
1130                 return 0;
1131
1132         return 1;
1133 }
1134
1135 #if 0 /// UNNEEDED by elogind
1136 _public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) {
1137         assert_return(m, -EINVAL);
1138         assert_return(!m->sealed, -EPERM);
1139         assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
1140
1141         SET_FLAG(m->header->flags, BUS_MESSAGE_NO_REPLY_EXPECTED, !b);
1142
1143         return 0;
1144 }
1145
1146 _public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) {
1147         assert_return(m, -EINVAL);
1148         assert_return(!m->sealed, -EPERM);
1149
1150         SET_FLAG(m->header->flags, BUS_MESSAGE_NO_AUTO_START, !b);
1151
1152         return 0;
1153 }
1154
1155 _public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message *m, int b) {
1156         assert_return(m, -EINVAL);
1157         assert_return(!m->sealed, -EPERM);
1158
1159         SET_FLAG(m->header->flags, BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION, b);
1160
1161         return 0;
1162 }
1163 #endif // 0
1164
1165 static struct bus_container *message_get_container(sd_bus_message *m) {
1166         assert(m);
1167
1168         if (m->n_containers == 0)
1169                 return &m->root_container;
1170
1171         assert(m->containers);
1172         return m->containers + m->n_containers - 1;
1173 }
1174
1175 struct bus_body_part *message_append_part(sd_bus_message *m) {
1176         struct bus_body_part *part;
1177
1178         assert(m);
1179
1180         if (m->poisoned)
1181                 return NULL;
1182
1183         if (m->n_body_parts <= 0) {
1184                 part = &m->body;
1185                 zero(*part);
1186         } else {
1187                 assert(m->body_end);
1188
1189                 part = new0(struct bus_body_part, 1);
1190                 if (!part) {
1191                         m->poisoned = true;
1192                         return NULL;
1193                 }
1194
1195                 m->body_end->next = part;
1196         }
1197
1198         part->memfd = -1;
1199         m->body_end = part;
1200         m->n_body_parts++;
1201
1202         return part;
1203 }
1204
1205 static void part_zero(struct bus_body_part *part, size_t sz) {
1206         assert(part);
1207         assert(sz > 0);
1208         assert(sz < 8);
1209
1210         /* All other fields can be left in their defaults */
1211         assert(!part->data);
1212         assert(part->memfd < 0);
1213
1214         part->size = sz;
1215         part->is_zero = true;
1216         part->sealed = true;
1217 }
1218
1219 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         assert(m);
1229         assert(part);
1230         assert(!part->sealed);
1231
1232         if (m->poisoned)
1233                 return -ENOMEM;
1234
1235         if (!part->data && part->memfd < 0) {
1236                 part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated);
1237                 part->mmap_begin = part->data;
1238         }
1239
1240         if (part->memfd >= 0) {
1241
1242                 if (part->allocated == 0 || sz > part->allocated) {
1243                         uint64_t new_allocated;
1244
1245                         new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
1246                         r = memfd_set_size(part->memfd, new_allocated);
1247                         if (r < 0) {
1248                                 m->poisoned = true;
1249                                 return r;
1250                         }
1251
1252                         part->allocated = new_allocated;
1253                 }
1254
1255                 if (!part->data || sz > part->mapped) {
1256                         size_t psz;
1257
1258                         psz = PAGE_ALIGN(sz > 0 ? sz : 1);
1259                         if (part->mapped <= 0)
1260                                 n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
1261                         else
1262                                 n = mremap(part->mmap_begin, part->mapped, psz, MREMAP_MAYMOVE);
1263
1264                         if (n == MAP_FAILED) {
1265                                 m->poisoned = true;
1266                                 return -errno;
1267                         }
1268
1269                         part->mmap_begin = part->data = n;
1270                         part->mapped = psz;
1271                         part->memfd_offset = 0;
1272                 }
1273
1274                 part->munmap_this = true;
1275         } else {
1276                 if (part->allocated == 0 || sz > part->allocated) {
1277                         size_t new_allocated;
1278
1279                         new_allocated = sz > 0 ? 2 * sz : 64;
1280                         n = realloc(part->data, new_allocated);
1281                         if (!n) {
1282                                 m->poisoned = true;
1283                                 return -ENOMEM;
1284                         }
1285
1286                         part->data = n;
1287                         part->allocated = new_allocated;
1288                         part->free_this = true;
1289                 }
1290         }
1291
1292         if (q)
1293                 *q = part->data ? (uint8_t*) part->data + part->size : NULL;
1294
1295         part->size = sz;
1296         return 0;
1297 }
1298
1299 static int message_add_offset(sd_bus_message *m, size_t offset) {
1300         struct bus_container *c;
1301
1302         assert(m);
1303         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         c = message_get_container(m);
1309
1310         if (!c->need_offsets)
1311                 return 0;
1312
1313         if (!GREEDY_REALLOC(c->offsets, c->offsets_allocated, c->n_offsets + 1))
1314                 return -ENOMEM;
1315
1316         c->offsets[c->n_offsets++] = offset;
1317         return 0;
1318 }
1319
1320 static void message_extend_containers(sd_bus_message *m, size_t expand) {
1321         struct bus_container *c;
1322
1323         assert(m);
1324
1325         if (expand <= 0)
1326                 return;
1327
1328         /* Update counters */
1329         for (c = m->containers; c < m->containers + m->n_containers; c++) {
1330
1331                 if (c->array_size)
1332                         *c->array_size += expand;
1333         }
1334 }
1335
1336 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         assert(m);
1348         assert(align > 0);
1349         assert(!m->sealed);
1350
1351         if (m->poisoned)
1352                 return NULL;
1353
1354         start_body = ALIGN_TO((size_t) m->body_size, align);
1355         end_body = start_body + sz;
1356
1357         padding = start_body - m->body_size;
1358         added = padding + sz;
1359
1360         /* Check for 32bit overflows */
1361         if (end_body > (size_t) ((uint32_t) -1) ||
1362             end_body < start_body) {
1363                 m->poisoned = true;
1364                 return NULL;
1365         }
1366
1367         if (added > 0) {
1368                 struct bus_body_part *part = NULL;
1369                 bool add_new_part;
1370
1371                 add_new_part =
1372                         m->n_body_parts <= 0 ||
1373                         m->body_end->sealed ||
1374                         (padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size) ||
1375                         (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                 if (add_new_part) {
1378                         if (padding > 0) {
1379                                 part = message_append_part(m);
1380                                 if (!part)
1381                                         return NULL;
1382
1383                                 part_zero(part, padding);
1384                         }
1385
1386                         part = message_append_part(m);
1387                         if (!part)
1388                                 return NULL;
1389
1390                         r = part_make_space(m, part, sz, &p);
1391                         if (r < 0)
1392                                 return NULL;
1393                 } else {
1394                         struct bus_container *c;
1395                         void *op;
1396                         size_t os, start_part, end_part;
1397
1398                         part = m->body_end;
1399                         op = part->data;
1400                         os = part->size;
1401
1402                         start_part = ALIGN_TO(part->size, align);
1403                         end_part = start_part + sz;
1404
1405                         r = part_make_space(m, part, end_part, &p);
1406                         if (r < 0)
1407                                 return NULL;
1408
1409                         if (padding > 0) {
1410                                 memzero(p, padding);
1411                                 p = (uint8_t*) p + padding;
1412                         }
1413
1414                         /* Readjust pointers */
1415                         for (c = m->containers; c < m->containers + m->n_containers; c++)
1416                                 c->array_size = adjust_pointer(c->array_size, op, os, part->data);
1417
1418                         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                 p = (uint8_t *) NULL + align;
1423
1424         m->body_size = end_body;
1425         message_extend_containers(m, added);
1426
1427         if (add_offset) {
1428                 r = message_add_offset(m, end_body);
1429                 if (r < 0) {
1430                         m->poisoned = true;
1431                         return NULL;
1432                 }
1433         }
1434
1435         return p;
1436 }
1437
1438 static int message_push_fd(sd_bus_message *m, int fd) {
1439         int *f, copy;
1440
1441         assert(m);
1442
1443         if (fd < 0)
1444                 return -EINVAL;
1445
1446         if (!m->allow_fds)
1447                 return -EOPNOTSUPP;
1448
1449         copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
1450         if (copy < 0)
1451                 return -errno;
1452
1453         f = realloc(m->fds, sizeof(int) * (m->n_fds + 1));
1454         if (!f) {
1455                 m->poisoned = true;
1456                 safe_close(copy);
1457                 return -ENOMEM;
1458         }
1459
1460         m->fds = f;
1461         m->fds[m->n_fds] = copy;
1462         m->free_fds = true;
1463
1464         return copy;
1465 }
1466
1467 int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
1468         _cleanup_close_ int fd = -1;
1469         struct bus_container *c;
1470         ssize_t align, sz;
1471         void *a;
1472
1473         assert_return(m, -EINVAL);
1474         assert_return(!m->sealed, -EPERM);
1475         assert_return(bus_type_is_basic(type), -EINVAL);
1476         assert_return(!m->poisoned, -ESTALE);
1477
1478         c = message_get_container(m);
1479
1480         if (c->signature && c->signature[c->index]) {
1481                 /* Container signature is already set */
1482
1483                 if (c->signature[c->index] != type)
1484                         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                 if (c->enclosing != 0)
1490                         return -ENXIO;
1491
1492                 e = strextend(&c->signature, CHAR_TO_STR(type), NULL);
1493                 if (!e) {
1494                         m->poisoned = true;
1495                         return -ENOMEM;
1496                 }
1497         }
1498
1499         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1500                 uint8_t u8;
1501                 uint32_t u32;
1502
1503                 switch (type) {
1504
1505                 case SD_BUS_TYPE_SIGNATURE:
1506                 case SD_BUS_TYPE_STRING:
1507                         p = strempty(p);
1508
1509                         /* Fall through... */
1510                 case SD_BUS_TYPE_OBJECT_PATH:
1511                         if (!p)
1512                                 return -EINVAL;
1513
1514                         align = 1;
1515                         sz = strlen(p) + 1;
1516                         break;
1517
1518                 case SD_BUS_TYPE_BOOLEAN:
1519
1520                         u8 = p && *(int*) p;
1521                         p = &u8;
1522
1523                         align = sz = 1;
1524                         break;
1525
1526                 case SD_BUS_TYPE_UNIX_FD:
1527
1528                         if (!p)
1529                                 return -EINVAL;
1530
1531                         fd = message_push_fd(m, *(int*) p);
1532                         if (fd < 0)
1533                                 return fd;
1534
1535                         u32 = m->n_fds;
1536                         p = &u32;
1537
1538                         align = sz = 4;
1539                         break;
1540
1541                 default:
1542                         align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
1543                         sz = bus_gvariant_get_size(CHAR_TO_STR(type));
1544                         break;
1545                 }
1546
1547                 assert(align > 0);
1548                 assert(sz > 0);
1549
1550                 a = message_extend_body(m, align, sz, true, false);
1551                 if (!a)
1552                         return -ENOMEM;
1553
1554                 memcpy(a, p, sz);
1555
1556                 if (stored)
1557                         *stored = (const uint8_t*) a;
1558
1559         } else {
1560                 uint32_t u32;
1561
1562                 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                         p = strempty(p);
1568
1569                         /* Fall through... */
1570                 case SD_BUS_TYPE_OBJECT_PATH:
1571
1572                         if (!p)
1573                                 return -EINVAL;
1574
1575                         align = 4;
1576                         sz = 4 + strlen(p) + 1;
1577                         break;
1578
1579                 case SD_BUS_TYPE_SIGNATURE:
1580
1581                         p = strempty(p);
1582
1583                         align = 1;
1584                         sz = 1 + strlen(p) + 1;
1585                         break;
1586
1587                 case SD_BUS_TYPE_BOOLEAN:
1588
1589                         u32 = p && *(int*) p;
1590                         p = &u32;
1591
1592                         align = sz = 4;
1593                         break;
1594
1595                 case SD_BUS_TYPE_UNIX_FD:
1596
1597                         if (!p)
1598                                 return -EINVAL;
1599
1600                         fd = message_push_fd(m, *(int*) p);
1601                         if (fd < 0)
1602                                 return fd;
1603
1604                         u32 = m->n_fds;
1605                         p = &u32;
1606
1607                         align = sz = 4;
1608                         break;
1609
1610                 default:
1611                         align = bus_type_get_alignment(type);
1612                         sz = bus_type_get_size(type);
1613                         break;
1614                 }
1615
1616                 assert(align > 0);
1617                 assert(sz > 0);
1618
1619                 a = message_extend_body(m, align, sz, false, false);
1620                 if (!a)
1621                         return -ENOMEM;
1622
1623                 if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) {
1624                         *(uint32_t*) a = sz - 5;
1625                         memcpy((uint8_t*) a + 4, p, sz - 4);
1626
1627                         if (stored)
1628                                 *stored = (const uint8_t*) a + 4;
1629
1630                 } else if (type == SD_BUS_TYPE_SIGNATURE) {
1631                         *(uint8_t*) a = sz - 2;
1632                         memcpy((uint8_t*) a + 1, p, sz - 1);
1633
1634                         if (stored)
1635                                 *stored = (const uint8_t*) a + 1;
1636                 } else {
1637                         memcpy(a, p, sz);
1638
1639                         if (stored)
1640                                 *stored = a;
1641                 }
1642         }
1643
1644         if (type == SD_BUS_TYPE_UNIX_FD)
1645                 m->n_fds++;
1646
1647         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1648                 c->index++;
1649
1650         fd = -1;
1651         return 0;
1652 }
1653
1654 _public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) {
1655         return message_append_basic(m, type, p, NULL);
1656 }
1657
1658 #if 0 /// UNNEEDED by elogind
1659 _public_ int sd_bus_message_append_string_space(
1660                 sd_bus_message *m,
1661                 size_t size,
1662                 char **s) {
1663
1664         struct bus_container *c;
1665         void *a;
1666
1667         assert_return(m, -EINVAL);
1668         assert_return(s, -EINVAL);
1669         assert_return(!m->sealed, -EPERM);
1670         assert_return(!m->poisoned, -ESTALE);
1671
1672         c = message_get_container(m);
1673
1674         if (c->signature && c->signature[c->index]) {
1675                 /* Container signature is already set */
1676
1677                 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
1678                         return -ENXIO;
1679         } else {
1680                 char *e;
1681
1682                 /* Maybe we can append to the signature? But only if this is the top-level container */
1683                 if (c->enclosing != 0)
1684                         return -ENXIO;
1685
1686                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
1687                 if (!e) {
1688                         m->poisoned = true;
1689                         return -ENOMEM;
1690                 }
1691         }
1692
1693         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1694                 a = message_extend_body(m, 1, size + 1, true, false);
1695                 if (!a)
1696                         return -ENOMEM;
1697
1698                 *s = a;
1699         } else {
1700                 a = message_extend_body(m, 4, 4 + size + 1, false, false);
1701                 if (!a)
1702                         return -ENOMEM;
1703
1704                 *(uint32_t*) a = size;
1705                 *s = (char*) a + 4;
1706         }
1707
1708         (*s)[size] = 0;
1709
1710         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1711                 c->index++;
1712
1713         return 0;
1714 }
1715
1716 _public_ int sd_bus_message_append_string_iovec(
1717                 sd_bus_message *m,
1718                 const struct iovec *iov,
1719                 unsigned n) {
1720
1721         size_t size;
1722         unsigned i;
1723         char *p;
1724         int r;
1725
1726         assert_return(m, -EINVAL);
1727         assert_return(!m->sealed, -EPERM);
1728         assert_return(iov || n == 0, -EINVAL);
1729         assert_return(!m->poisoned, -ESTALE);
1730
1731         size = IOVEC_TOTAL_SIZE(iov, n);
1732
1733         r = sd_bus_message_append_string_space(m, size, &p);
1734         if (r < 0)
1735                 return r;
1736
1737         for (i = 0; i < n; i++) {
1738
1739                 if (iov[i].iov_base)
1740                         memcpy(p, iov[i].iov_base, iov[i].iov_len);
1741                 else
1742                         memset(p, ' ', iov[i].iov_len);
1743
1744                 p += iov[i].iov_len;
1745         }
1746
1747         return 0;
1748 }
1749 #endif // 0
1750
1751 static int bus_message_open_array(
1752                 sd_bus_message *m,
1753                 struct bus_container *c,
1754                 const char *contents,
1755                 uint32_t **array_size,
1756                 size_t *begin,
1757                 bool *need_offsets) {
1758
1759         unsigned nindex;
1760         int alignment, r;
1761
1762         assert(m);
1763         assert(c);
1764         assert(contents);
1765         assert(array_size);
1766         assert(begin);
1767         assert(need_offsets);
1768
1769         if (!signature_is_single(contents, true))
1770                 return -EINVAL;
1771
1772         if (c->signature && c->signature[c->index]) {
1773
1774                 /* Verify the existing signature */
1775
1776                 if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
1777                         return -ENXIO;
1778
1779                 if (!startswith(c->signature + c->index + 1, contents))
1780                         return -ENXIO;
1781
1782                 nindex = c->index + 1 + strlen(contents);
1783         } else {
1784                 char *e;
1785
1786                 if (c->enclosing != 0)
1787                         return -ENXIO;
1788
1789                 /* Extend the existing signature */
1790
1791                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL);
1792                 if (!e) {
1793                         m->poisoned = true;
1794                         return -ENOMEM;
1795                 }
1796
1797                 nindex = e - c->signature;
1798         }
1799
1800         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1801                 alignment = bus_gvariant_get_alignment(contents);
1802                 if (alignment < 0)
1803                         return alignment;
1804
1805                 /* Add alignment padding and add to offset list */
1806                 if (!message_extend_body(m, alignment, 0, false, false))
1807                         return -ENOMEM;
1808
1809                 r = bus_gvariant_is_fixed_size(contents);
1810                 if (r < 0)
1811                         return r;
1812
1813                 *begin = m->body_size;
1814                 *need_offsets = r == 0;
1815         } else {
1816                 void *a, *op;
1817                 size_t os;
1818                 struct bus_body_part *o;
1819
1820                 alignment = bus_type_get_alignment(contents[0]);
1821                 if (alignment < 0)
1822                         return alignment;
1823
1824                 a = message_extend_body(m, 4, 4, false, false);
1825                 if (!a)
1826                         return -ENOMEM;
1827
1828                 o = m->body_end;
1829                 op = m->body_end->data;
1830                 os = m->body_end->size;
1831
1832                 /* Add alignment between size and first element */
1833                 if (!message_extend_body(m, alignment, 0, false, false))
1834                         return -ENOMEM;
1835
1836                 /* location of array size might have changed so let's readjust a */
1837                 if (o == m->body_end)
1838                         a = adjust_pointer(a, op, os, m->body_end->data);
1839
1840                 *(uint32_t*) a = 0;
1841                 *array_size = a;
1842         }
1843
1844         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1845                 c->index = nindex;
1846
1847         return 0;
1848 }
1849
1850 static int bus_message_open_variant(
1851                 sd_bus_message *m,
1852                 struct bus_container *c,
1853                 const char *contents) {
1854
1855         assert(m);
1856         assert(c);
1857         assert(contents);
1858
1859         if (!signature_is_single(contents, false))
1860                 return -EINVAL;
1861
1862         if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
1863                 return -EINVAL;
1864
1865         if (c->signature && c->signature[c->index]) {
1866
1867                 if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
1868                         return -ENXIO;
1869
1870         } else {
1871                 char *e;
1872
1873                 if (c->enclosing != 0)
1874                         return -ENXIO;
1875
1876                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL);
1877                 if (!e) {
1878                         m->poisoned = true;
1879                         return -ENOMEM;
1880                 }
1881         }
1882
1883         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1884                 /* Variants are always aligned to 8 */
1885
1886                 if (!message_extend_body(m, 8, 0, false, false))
1887                         return -ENOMEM;
1888
1889         } else {
1890                 size_t l;
1891                 void *a;
1892
1893                 l = strlen(contents);
1894                 a = message_extend_body(m, 1, 1 + l + 1, false, false);
1895                 if (!a)
1896                         return -ENOMEM;
1897
1898                 *(uint8_t*) a = l;
1899                 memcpy((uint8_t*) a + 1, contents, l + 1);
1900         }
1901
1902         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1903                 c->index++;
1904
1905         return 0;
1906 }
1907
1908 static int bus_message_open_struct(
1909                 sd_bus_message *m,
1910                 struct bus_container *c,
1911                 const char *contents,
1912                 size_t *begin,
1913                 bool *need_offsets) {
1914
1915         size_t nindex;
1916         int r;
1917
1918         assert(m);
1919         assert(c);
1920         assert(contents);
1921         assert(begin);
1922         assert(need_offsets);
1923
1924         if (!signature_is_valid(contents, false))
1925                 return -EINVAL;
1926
1927         if (c->signature && c->signature[c->index]) {
1928                 size_t l;
1929
1930                 l = strlen(contents);
1931
1932                 if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
1933                     !startswith(c->signature + c->index + 1, contents) ||
1934                     c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
1935                         return -ENXIO;
1936
1937                 nindex = c->index + 1 + l + 1;
1938         } else {
1939                 char *e;
1940
1941                 if (c->enclosing != 0)
1942                         return -ENXIO;
1943
1944                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL);
1945                 if (!e) {
1946                         m->poisoned = true;
1947                         return -ENOMEM;
1948                 }
1949
1950                 nindex = e - c->signature;
1951         }
1952
1953         if (BUS_MESSAGE_IS_GVARIANT(m)) {
1954                 int alignment;
1955
1956                 alignment = bus_gvariant_get_alignment(contents);
1957                 if (alignment < 0)
1958                         return alignment;
1959
1960                 if (!message_extend_body(m, alignment, 0, false, false))
1961                         return -ENOMEM;
1962
1963                 r = bus_gvariant_is_fixed_size(contents);
1964                 if (r < 0)
1965                         return r;
1966
1967                 *begin = m->body_size;
1968                 *need_offsets = r == 0;
1969         } else {
1970                 /* Align contents to 8 byte boundary */
1971                 if (!message_extend_body(m, 8, 0, false, false))
1972                         return -ENOMEM;
1973         }
1974
1975         if (c->enclosing != SD_BUS_TYPE_ARRAY)
1976                 c->index = nindex;
1977
1978         return 0;
1979 }
1980
1981 static int bus_message_open_dict_entry(
1982                 sd_bus_message *m,
1983                 struct bus_container *c,
1984                 const char *contents,
1985                 size_t *begin,
1986                 bool *need_offsets) {
1987
1988         int r;
1989
1990         assert(m);
1991         assert(c);
1992         assert(contents);
1993         assert(begin);
1994         assert(need_offsets);
1995
1996         if (!signature_is_pair(contents))
1997                 return -EINVAL;
1998
1999         if (c->enclosing != SD_BUS_TYPE_ARRAY)
2000                 return -ENXIO;
2001
2002         if (c->signature && c->signature[c->index]) {
2003                 size_t l;
2004
2005                 l = strlen(contents);
2006
2007                 if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
2008                     !startswith(c->signature + c->index + 1, contents) ||
2009                     c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
2010                         return -ENXIO;
2011         } else
2012                 return -ENXIO;
2013
2014         if (BUS_MESSAGE_IS_GVARIANT(m)) {
2015                 int alignment;
2016
2017                 alignment = bus_gvariant_get_alignment(contents);
2018                 if (alignment < 0)
2019                         return alignment;
2020
2021                 if (!message_extend_body(m, alignment, 0, false, false))
2022                         return -ENOMEM;
2023
2024                 r = bus_gvariant_is_fixed_size(contents);
2025                 if (r < 0)
2026                         return r;
2027
2028                 *begin = m->body_size;
2029                 *need_offsets = r == 0;
2030         } else {
2031                 /* Align contents to 8 byte boundary */
2032                 if (!message_extend_body(m, 8, 0, false, false))
2033                         return -ENOMEM;
2034         }
2035
2036         return 0;
2037 }
2038
2039 _public_ int sd_bus_message_open_container(
2040                 sd_bus_message *m,
2041                 char type,
2042                 const char *contents) {
2043
2044         struct bus_container *c, *w;
2045         uint32_t *array_size = NULL;
2046         char *signature;
2047         size_t before, begin = 0;
2048         bool need_offsets = false;
2049         int r;
2050
2051         assert_return(m, -EINVAL);
2052         assert_return(!m->sealed, -EPERM);
2053         assert_return(contents, -EINVAL);
2054         assert_return(!m->poisoned, -ESTALE);
2055
2056         /* Make sure we have space for one more container */
2057         if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1)) {
2058                 m->poisoned = true;
2059                 return -ENOMEM;
2060         }
2061
2062         c = message_get_container(m);
2063
2064         signature = strdup(contents);
2065         if (!signature) {
2066                 m->poisoned = true;
2067                 return -ENOMEM;
2068         }
2069
2070         /* Save old index in the parent container, in case we have to
2071          * abort this container */
2072         c->saved_index = c->index;
2073         before = m->body_size;
2074
2075         if (type == SD_BUS_TYPE_ARRAY)
2076                 r = bus_message_open_array(m, c, contents, &array_size, &begin, &need_offsets);
2077         else if (type == SD_BUS_TYPE_VARIANT)
2078                 r = bus_message_open_variant(m, c, contents);
2079         else if (type == SD_BUS_TYPE_STRUCT)
2080                 r = bus_message_open_struct(m, c, contents, &begin, &need_offsets);
2081         else if (type == SD_BUS_TYPE_DICT_ENTRY)
2082                 r = bus_message_open_dict_entry(m, c, contents, &begin, &need_offsets);
2083         else
2084                 r = -EINVAL;
2085
2086         if (r < 0) {
2087                 free(signature);
2088                 return r;
2089         }
2090
2091         /* OK, let's fill it in */
2092         w = m->containers + m->n_containers++;
2093         w->enclosing = type;
2094         w->signature = signature;
2095         w->index = 0;
2096         w->array_size = array_size;
2097         w->before = before;
2098         w->begin = begin;
2099         w->n_offsets = w->offsets_allocated = 0;
2100         w->offsets = NULL;
2101         w->need_offsets = need_offsets;
2102
2103         return 0;
2104 }
2105
2106 static int bus_message_close_array(sd_bus_message *m, struct bus_container *c) {
2107
2108         assert(m);
2109         assert(c);
2110
2111         if (!BUS_MESSAGE_IS_GVARIANT(m))
2112                 return 0;
2113
2114         if (c->need_offsets) {
2115                 size_t payload, sz, i;
2116                 uint8_t *a;
2117
2118                 /* Variable-width arrays */
2119
2120                 payload = c->n_offsets > 0 ? c->offsets[c->n_offsets-1] - c->begin : 0;
2121                 sz = bus_gvariant_determine_word_size(payload, c->n_offsets);
2122
2123                 a = message_extend_body(m, 1, sz * c->n_offsets, true, false);
2124                 if (!a)
2125                         return -ENOMEM;
2126
2127                 for (i = 0; i < c->n_offsets; i++)
2128                         bus_gvariant_write_word_le(a + sz*i, sz, c->offsets[i] - c->begin);
2129         } else {
2130                 void *a;
2131
2132                 /* Fixed-width or empty arrays */
2133
2134                 a = message_extend_body(m, 1, 0, true, false); /* let's add offset to parent */
2135                 if (!a)
2136                         return -ENOMEM;
2137         }
2138
2139         return 0;
2140 }
2141
2142 static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c) {
2143         uint8_t *a;
2144         size_t l;
2145
2146         assert(m);
2147         assert(c);
2148         assert(c->signature);
2149
2150         if (!BUS_MESSAGE_IS_GVARIANT(m))
2151                 return 0;
2152
2153         l = strlen(c->signature);
2154
2155         a = message_extend_body(m, 1, 1 + l, true, false);
2156         if (!a)
2157                 return -ENOMEM;
2158
2159         a[0] = 0;
2160         memcpy(a+1, c->signature, l);
2161
2162         return 0;
2163 }
2164
2165 static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, bool add_offset) {
2166         bool fixed_size = true;
2167         size_t n_variable = 0;
2168         unsigned i = 0;
2169         const char *p;
2170         uint8_t *a;
2171         int r;
2172
2173         assert(m);
2174         assert(c);
2175
2176         if (!BUS_MESSAGE_IS_GVARIANT(m))
2177                 return 0;
2178
2179         p = strempty(c->signature);
2180         while (*p != 0) {
2181                 size_t n;
2182
2183                 r = signature_element_length(p, &n);
2184                 if (r < 0)
2185                         return r;
2186                 else {
2187                         char t[n+1];
2188
2189                         memcpy(t, p, n);
2190                         t[n] = 0;
2191
2192                         r = bus_gvariant_is_fixed_size(t);
2193                         if (r < 0)
2194                                 return r;
2195                 }
2196
2197                 assert(!c->need_offsets || i <= c->n_offsets);
2198
2199                 /* We need to add an offset for each item that has a
2200                  * variable size and that is not the last one in the
2201                  * list */
2202                 if (r == 0)
2203                         fixed_size = false;
2204                 if (r == 0 && p[n] != 0)
2205                         n_variable++;
2206
2207                 i++;
2208                 p += n;
2209         }
2210
2211         assert(!c->need_offsets || i == c->n_offsets);
2212         assert(c->need_offsets || n_variable == 0);
2213
2214         if (isempty(c->signature)) {
2215                 /* The unary type is encoded as fixed 1 byte padding */
2216                 a = message_extend_body(m, 1, 1, add_offset, false);
2217                 if (!a)
2218                         return -ENOMEM;
2219
2220                 *a = 0;
2221         } else if (n_variable <= 0) {
2222                 int alignment = 1;
2223
2224                 /* Structures with fixed-size members only have to be
2225                  * fixed-size themselves. But gvariant requires all fixed-size
2226                  * elements to be sized a multiple of their alignment. Hence,
2227                  * we must *always* add final padding after the last member so
2228                  * the overall size of the structure is properly aligned. */
2229                 if (fixed_size)
2230                         alignment = bus_gvariant_get_alignment(strempty(c->signature));
2231
2232                 assert(alignment > 0);
2233
2234                 a = message_extend_body(m, alignment, 0, add_offset, false);
2235                 if (!a)
2236                         return -ENOMEM;
2237         } else {
2238                 size_t sz;
2239                 unsigned j;
2240
2241                 assert(c->offsets[c->n_offsets-1] == m->body_size);
2242
2243                 sz = bus_gvariant_determine_word_size(m->body_size - c->begin, n_variable);
2244
2245                 a = message_extend_body(m, 1, sz * n_variable, add_offset, false);
2246                 if (!a)
2247                         return -ENOMEM;
2248
2249                 p = strempty(c->signature);
2250                 for (i = 0, j = 0; i < c->n_offsets; i++) {
2251                         unsigned k;
2252                         size_t n;
2253
2254                         r = signature_element_length(p, &n);
2255                         if (r < 0)
2256                                 return r;
2257                         else {
2258                                 char t[n+1];
2259
2260                                 memcpy(t, p, n);
2261                                 t[n] = 0;
2262
2263                                 p += n;
2264
2265                                 r = bus_gvariant_is_fixed_size(t);
2266                                 if (r < 0)
2267                                         return r;
2268                                 if (r > 0 || p[0] == 0)
2269                                         continue;
2270                         }
2271
2272                         k = n_variable - 1 - j;
2273
2274                         bus_gvariant_write_word_le(a + k * sz, sz, c->offsets[i] - c->begin);
2275
2276                         j++;
2277                 }
2278         }
2279
2280         return 0;
2281 }
2282
2283 _public_ int sd_bus_message_close_container(sd_bus_message *m) {
2284         struct bus_container *c;
2285         int r;
2286
2287         assert_return(m, -EINVAL);
2288         assert_return(!m->sealed, -EPERM);
2289         assert_return(m->n_containers > 0, -EINVAL);
2290         assert_return(!m->poisoned, -ESTALE);
2291
2292         c = message_get_container(m);
2293
2294         if (c->enclosing != SD_BUS_TYPE_ARRAY)
2295                 if (c->signature && c->signature[c->index] != 0)
2296                         return -EINVAL;
2297
2298         m->n_containers--;
2299
2300         if (c->enclosing == SD_BUS_TYPE_ARRAY)
2301                 r = bus_message_close_array(m, c);
2302         else if (c->enclosing == SD_BUS_TYPE_VARIANT)
2303                 r = bus_message_close_variant(m, c);
2304         else if (c->enclosing == SD_BUS_TYPE_STRUCT || c->enclosing == SD_BUS_TYPE_DICT_ENTRY)
2305                 r = bus_message_close_struct(m, c, true);
2306         else
2307                 assert_not_reached("Unknown container type");
2308
2309         free(c->signature);
2310         free(c->offsets);
2311
2312         return r;
2313 }
2314
2315 typedef struct {
2316         const char *types;
2317         unsigned n_struct;
2318         unsigned n_array;
2319 } TypeStack;
2320
2321 static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) {
2322         assert(stack);
2323         assert(max > 0);
2324
2325         if (*i >= max)
2326                 return -EINVAL;
2327
2328         stack[*i].types = types;
2329         stack[*i].n_struct = n_struct;
2330         stack[*i].n_array = n_array;
2331         (*i)++;
2332
2333         return 0;
2334 }
2335
2336 static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) {
2337         assert(stack);
2338         assert(max > 0);
2339         assert(types);
2340         assert(n_struct);
2341         assert(n_array);
2342
2343         if (*i <= 0)
2344                 return 0;
2345
2346         (*i)--;
2347         *types = stack[*i].types;
2348         *n_struct = stack[*i].n_struct;
2349         *n_array = stack[*i].n_array;
2350
2351         return 1;
2352 }
2353
2354 int bus_message_append_ap(
2355                 sd_bus_message *m,
2356                 const char *types,
2357                 va_list ap) {
2358
2359         unsigned n_array, n_struct;
2360         TypeStack stack[BUS_CONTAINER_DEPTH];
2361         unsigned stack_ptr = 0;
2362         int r;
2363
2364         assert(m);
2365
2366         if (!types)
2367                 return 0;
2368
2369         n_array = (unsigned) -1;
2370         n_struct = strlen(types);
2371
2372         for (;;) {
2373                 const char *t;
2374
2375                 if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
2376                         r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
2377                         if (r < 0)
2378                                 return r;
2379                         if (r == 0)
2380                                 break;
2381
2382                         r = sd_bus_message_close_container(m);
2383                         if (r < 0)
2384                                 return r;
2385
2386                         continue;
2387                 }
2388
2389                 t = types;
2390                 if (n_array != (unsigned) -1)
2391                         n_array--;
2392                 else {
2393                         types++;
2394                         n_struct--;
2395                 }
2396
2397                 switch (*t) {
2398
2399                 case SD_BUS_TYPE_BYTE: {
2400                         uint8_t x;
2401
2402                         x = (uint8_t) va_arg(ap, int);
2403                         r = sd_bus_message_append_basic(m, *t, &x);
2404                         break;
2405                 }
2406
2407                 case SD_BUS_TYPE_BOOLEAN:
2408                 case SD_BUS_TYPE_INT32:
2409                 case SD_BUS_TYPE_UINT32:
2410                 case SD_BUS_TYPE_UNIX_FD: {
2411                         uint32_t x;
2412
2413                         /* We assume a boolean is the same as int32_t */
2414                         assert_cc(sizeof(int32_t) == sizeof(int));
2415
2416                         x = va_arg(ap, uint32_t);
2417                         r = sd_bus_message_append_basic(m, *t, &x);
2418                         break;
2419                 }
2420
2421                 case SD_BUS_TYPE_INT16:
2422                 case SD_BUS_TYPE_UINT16: {
2423                         uint16_t x;
2424
2425                         x = (uint16_t) va_arg(ap, int);
2426                         r = sd_bus_message_append_basic(m, *t, &x);
2427                         break;
2428                 }
2429
2430                 case SD_BUS_TYPE_INT64:
2431                 case SD_BUS_TYPE_UINT64: {
2432                         uint64_t x;
2433
2434                         x = va_arg(ap, uint64_t);
2435                         r = sd_bus_message_append_basic(m, *t, &x);
2436                         break;
2437                 }
2438
2439                 case SD_BUS_TYPE_DOUBLE: {
2440                         double x;
2441
2442                         x = va_arg(ap, double);
2443                         r = sd_bus_message_append_basic(m, *t, &x);
2444                         break;
2445                 }
2446
2447                 case SD_BUS_TYPE_STRING:
2448                 case SD_BUS_TYPE_OBJECT_PATH:
2449                 case SD_BUS_TYPE_SIGNATURE: {
2450                         const char *x;
2451
2452                         x = va_arg(ap, const char*);
2453                         r = sd_bus_message_append_basic(m, *t, x);
2454                         break;
2455                 }
2456
2457                 case SD_BUS_TYPE_ARRAY: {
2458                         size_t k;
2459
2460                         r = signature_element_length(t + 1, &k);
2461                         if (r < 0)
2462                                 return r;
2463
2464                         {
2465                                 char s[k + 1];
2466                                 memcpy(s, t + 1, k);
2467                                 s[k] = 0;
2468
2469                                 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
2470                                 if (r < 0)
2471                                         return r;
2472                         }
2473
2474                         if (n_array == (unsigned) -1) {
2475                                 types += k;
2476                                 n_struct -= k;
2477                         }
2478
2479                         r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2480                         if (r < 0)
2481                                 return r;
2482
2483                         types = t + 1;
2484                         n_struct = k;
2485                         n_array = va_arg(ap, unsigned);
2486
2487                         break;
2488                 }
2489
2490                 case SD_BUS_TYPE_VARIANT: {
2491                         const char *s;
2492
2493                         s = va_arg(ap, const char*);
2494                         if (!s)
2495                                 return -EINVAL;
2496
2497                         r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, s);
2498                         if (r < 0)
2499                                 return r;
2500
2501                         r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2502                         if (r < 0)
2503                                 return r;
2504
2505                         types = s;
2506                         n_struct = strlen(s);
2507                         n_array = (unsigned) -1;
2508
2509                         break;
2510                 }
2511
2512                 case SD_BUS_TYPE_STRUCT_BEGIN:
2513                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
2514                         size_t k;
2515
2516                         r = signature_element_length(t, &k);
2517                         if (r < 0)
2518                                 return r;
2519
2520                         {
2521                                 char s[k - 1];
2522
2523                                 memcpy(s, t + 1, k - 2);
2524                                 s[k - 2] = 0;
2525
2526                                 r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
2527                                 if (r < 0)
2528                                         return r;
2529                         }
2530
2531                         if (n_array == (unsigned) -1) {
2532                                 types += k - 1;
2533                                 n_struct -= k - 1;
2534                         }
2535
2536                         r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2537                         if (r < 0)
2538                                 return r;
2539
2540                         types = t + 1;
2541                         n_struct = k - 2;
2542                         n_array = (unsigned) -1;
2543
2544                         break;
2545                 }
2546
2547                 default:
2548                         r = -EINVAL;
2549                 }
2550
2551                 if (r < 0)
2552                         return r;
2553         }
2554
2555         return 1;
2556 }
2557
2558 _public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
2559         va_list ap;
2560         int r;
2561
2562         assert_return(m, -EINVAL);
2563         assert_return(types, -EINVAL);
2564         assert_return(!m->sealed, -EPERM);
2565         assert_return(!m->poisoned, -ESTALE);
2566
2567         va_start(ap, types);
2568         r = bus_message_append_ap(m, types, ap);
2569         va_end(ap);
2570
2571         return r;
2572 }
2573
2574 _public_ int sd_bus_message_append_array_space(
2575                 sd_bus_message *m,
2576                 char type,
2577                 size_t size,
2578                 void **ptr) {
2579
2580         ssize_t align, sz;
2581         void *a;
2582         int r;
2583
2584         assert_return(m, -EINVAL);
2585         assert_return(!m->sealed, -EPERM);
2586         assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL);
2587         assert_return(ptr || size == 0, -EINVAL);
2588         assert_return(!m->poisoned, -ESTALE);
2589
2590         /* alignment and size of the trivial types (except bool) is
2591          * identical for gvariant and dbus1 marshalling */
2592         align = bus_type_get_alignment(type);
2593         sz = bus_type_get_size(type);
2594
2595         assert_se(align > 0);
2596         assert_se(sz > 0);
2597
2598         if (size % sz != 0)
2599                 return -EINVAL;
2600
2601         r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2602         if (r < 0)
2603                 return r;
2604
2605         a = message_extend_body(m, align, size, false, false);
2606         if (!a)
2607                 return -ENOMEM;
2608
2609         r = sd_bus_message_close_container(m);
2610         if (r < 0)
2611                 return r;
2612
2613         *ptr = a;
2614         return 0;
2615 }
2616
2617 #if 0 /// UNNEEDED by elogind
2618 _public_ int sd_bus_message_append_array(
2619                 sd_bus_message *m,
2620                 char type,
2621                 const void *ptr,
2622                 size_t size) {
2623         int r;
2624         void *p;
2625
2626         assert_return(m, -EINVAL);
2627         assert_return(!m->sealed, -EPERM);
2628         assert_return(bus_type_is_trivial(type), -EINVAL);
2629         assert_return(ptr || size == 0, -EINVAL);
2630         assert_return(!m->poisoned, -ESTALE);
2631
2632         r = sd_bus_message_append_array_space(m, type, size, &p);
2633         if (r < 0)
2634                 return r;
2635
2636         memcpy_safe(p, ptr, size);
2637
2638         return 0;
2639 }
2640
2641 _public_ int sd_bus_message_append_array_iovec(
2642                 sd_bus_message *m,
2643                 char type,
2644                 const struct iovec *iov,
2645                 unsigned n) {
2646
2647         size_t size;
2648         unsigned i;
2649         void *p;
2650         int r;
2651
2652         assert_return(m, -EINVAL);
2653         assert_return(!m->sealed, -EPERM);
2654         assert_return(bus_type_is_trivial(type), -EINVAL);
2655         assert_return(iov || n == 0, -EINVAL);
2656         assert_return(!m->poisoned, -ESTALE);
2657
2658         size = IOVEC_TOTAL_SIZE(iov, n);
2659
2660         r = sd_bus_message_append_array_space(m, type, size, &p);
2661         if (r < 0)
2662                 return r;
2663
2664         for (i = 0; i < n; i++) {
2665
2666                 if (iov[i].iov_base)
2667                         memcpy(p, iov[i].iov_base, iov[i].iov_len);
2668                 else
2669                         memzero(p, iov[i].iov_len);
2670
2671                 p = (uint8_t*) p + iov[i].iov_len;
2672         }
2673
2674         return 0;
2675 }
2676
2677 _public_ int sd_bus_message_append_array_memfd(
2678                 sd_bus_message *m,
2679                 char type,
2680                 int memfd,
2681                 uint64_t offset,
2682                 uint64_t size) {
2683
2684         _cleanup_close_ int copy_fd = -1;
2685         struct bus_body_part *part;
2686         ssize_t align, sz;
2687         uint64_t real_size;
2688         void *a;
2689         int r;
2690
2691         assert_return(m, -EINVAL);
2692         assert_return(memfd >= 0, -EBADF);
2693         assert_return(bus_type_is_trivial(type), -EINVAL);
2694         assert_return(size > 0, -EINVAL);
2695         assert_return(!m->sealed, -EPERM);
2696         assert_return(!m->poisoned, -ESTALE);
2697
2698         r = memfd_set_sealed(memfd);
2699         if (r < 0)
2700                 return r;
2701
2702         copy_fd = dup(memfd);
2703         if (copy_fd < 0)
2704                 return copy_fd;
2705
2706         r = memfd_get_size(memfd, &real_size);
2707         if (r < 0)
2708                 return r;
2709
2710         if (offset == 0 && size == (uint64_t) -1)
2711                 size = real_size;
2712         else if (offset + size > real_size)
2713                 return -EMSGSIZE;
2714
2715         align = bus_type_get_alignment(type);
2716         sz = bus_type_get_size(type);
2717
2718         assert_se(align > 0);
2719         assert_se(sz > 0);
2720
2721         if (offset % align != 0)
2722                 return -EINVAL;
2723
2724         if (size % sz != 0)
2725                 return -EINVAL;
2726
2727         if (size > (uint64_t) (uint32_t) -1)
2728                 return -EINVAL;
2729
2730         r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2731         if (r < 0)
2732                 return r;
2733
2734         a = message_extend_body(m, align, 0, false, false);
2735         if (!a)
2736                 return -ENOMEM;
2737
2738         part = message_append_part(m);
2739         if (!part)
2740                 return -ENOMEM;
2741
2742         part->memfd = copy_fd;
2743         part->memfd_offset = offset;
2744         part->sealed = true;
2745         part->size = size;
2746         copy_fd = -1;
2747
2748         m->body_size += size;
2749         message_extend_containers(m, size);
2750
2751         return sd_bus_message_close_container(m);
2752 }
2753
2754 _public_ int sd_bus_message_append_string_memfd(
2755                 sd_bus_message *m,
2756                 int memfd,
2757                 uint64_t offset,
2758                 uint64_t size) {
2759
2760         _cleanup_close_ int copy_fd = -1;
2761         struct bus_body_part *part;
2762         struct bus_container *c;
2763         uint64_t real_size;
2764         void *a;
2765         int r;
2766
2767         assert_return(m, -EINVAL);
2768         assert_return(memfd >= 0, -EBADF);
2769         assert_return(size > 0, -EINVAL);
2770         assert_return(!m->sealed, -EPERM);
2771         assert_return(!m->poisoned, -ESTALE);
2772
2773         r = memfd_set_sealed(memfd);
2774         if (r < 0)
2775                 return r;
2776
2777         copy_fd = dup(memfd);
2778         if (copy_fd < 0)
2779                 return copy_fd;
2780
2781         r = memfd_get_size(memfd, &real_size);
2782         if (r < 0)
2783                 return r;
2784
2785         if (offset == 0 && size == (uint64_t) -1)
2786                 size = real_size;
2787         else if (offset + size > real_size)
2788                 return -EMSGSIZE;
2789
2790         /* We require this to be NUL terminated */
2791         if (size == 0)
2792                 return -EINVAL;
2793
2794         if (size > (uint64_t) (uint32_t) -1)
2795                 return -EINVAL;
2796
2797         c = message_get_container(m);
2798         if (c->signature && c->signature[c->index]) {
2799                 /* Container signature is already set */
2800
2801                 if (c->signature[c->index] != SD_BUS_TYPE_STRING)
2802                         return -ENXIO;
2803         } else {
2804                 char *e;
2805
2806                 /* Maybe we can append to the signature? But only if this is the top-level container */
2807                 if (c->enclosing != 0)
2808                         return -ENXIO;
2809
2810                 e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
2811                 if (!e) {
2812                         m->poisoned = true;
2813                         return -ENOMEM;
2814                 }
2815         }
2816
2817         if (!BUS_MESSAGE_IS_GVARIANT(m)) {
2818                 a = message_extend_body(m, 4, 4, false, false);
2819                 if (!a)
2820                         return -ENOMEM;
2821
2822                 *(uint32_t*) a = size - 1;
2823         }
2824
2825         part = message_append_part(m);
2826         if (!part)
2827                 return -ENOMEM;
2828
2829         part->memfd = copy_fd;
2830         part->memfd_offset = offset;
2831         part->sealed = true;
2832         part->size = size;
2833         copy_fd = -1;
2834
2835         m->body_size += size;
2836         message_extend_containers(m, size);
2837
2838         if (BUS_MESSAGE_IS_GVARIANT(m)) {
2839                 r = message_add_offset(m, m->body_size);
2840                 if (r < 0) {
2841                         m->poisoned = true;
2842                         return -ENOMEM;
2843                 }
2844         }
2845
2846         if (c->enclosing != SD_BUS_TYPE_ARRAY)
2847                 c->index++;
2848
2849         return 0;
2850 }
2851 #endif // 0
2852
2853 _public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) {
2854         char **i;
2855         int r;
2856
2857         assert_return(m, -EINVAL);
2858         assert_return(!m->sealed, -EPERM);
2859         assert_return(!m->poisoned, -ESTALE);
2860
2861         r = sd_bus_message_open_container(m, 'a', "s");
2862         if (r < 0)
2863                 return r;
2864
2865         STRV_FOREACH(i, l) {
2866                 r = sd_bus_message_append_basic(m, 's', *i);
2867                 if (r < 0)
2868                         return r;
2869         }
2870
2871         return sd_bus_message_close_container(m);
2872 }
2873
2874 static int bus_message_close_header(sd_bus_message *m) {
2875
2876         assert(m);
2877
2878         /* The actual user data is finished now, we just complete the
2879            variant and struct now (at least on gvariant). Remember
2880            this position, so that during parsing we know where to
2881            put the outer container end. */
2882         m->user_body_size = m->body_size;
2883
2884         if (BUS_MESSAGE_IS_GVARIANT(m)) {
2885                 const char *signature;
2886                 size_t sz, l;
2887                 void *d;
2888
2889                 /* Add offset table to end of fields array */
2890                 if (m->n_header_offsets >= 1) {
2891                         uint8_t *a;
2892                         unsigned i;
2893
2894                         assert(m->fields_size == m->header_offsets[m->n_header_offsets-1]);
2895
2896                         sz = bus_gvariant_determine_word_size(m->fields_size, m->n_header_offsets);
2897                         a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
2898                         if (!a)
2899                                 return -ENOMEM;
2900
2901                         for (i = 0; i < m->n_header_offsets; i++)
2902                                 bus_gvariant_write_word_le(a + sz*i, sz, m->header_offsets[i]);
2903                 }
2904
2905                 /* Add gvariant NUL byte plus signature to the end of
2906                  * the body, followed by the final offset pointing to
2907                  * the end of the fields array */
2908
2909                 signature = strempty(m->root_container.signature);
2910                 l = strlen(signature);
2911
2912                 sz = bus_gvariant_determine_word_size(sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size + 1 + l + 2, 1);
2913                 d = message_extend_body(m, 1, 1 + l + 2 + sz, false, true);
2914                 if (!d)
2915                         return -ENOMEM;
2916
2917                 *(uint8_t*) d = 0;
2918                 *((uint8_t*) d + 1) = SD_BUS_TYPE_STRUCT_BEGIN;
2919                 memcpy((uint8_t*) d + 2, signature, l);
2920                 *((uint8_t*) d + 1 + l + 1) = SD_BUS_TYPE_STRUCT_END;
2921
2922                 bus_gvariant_write_word_le((uint8_t*) d + 1 + l + 2, sz, sizeof(struct bus_header) + m->fields_size);
2923
2924                 m->footer = d;
2925                 m->footer_accessible = 1 + l + 2 + sz;
2926         } else {
2927                 m->header->dbus1.fields_size = m->fields_size;
2928                 m->header->dbus1.body_size = m->body_size;
2929         }
2930
2931         return 0;
2932 }
2933
2934 int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
2935         struct bus_body_part *part;
2936         size_t a;
2937         unsigned i;
2938         int r;
2939
2940         assert(m);
2941
2942         if (m->sealed)
2943                 return -EPERM;
2944
2945         if (m->n_containers > 0)
2946                 return -EBADMSG;
2947
2948         if (m->poisoned)
2949                 return -ESTALE;
2950
2951         if (cookie > 0xffffffffULL &&
2952             !BUS_MESSAGE_IS_GVARIANT(m))
2953                 return -EOPNOTSUPP;
2954
2955         /* In vtables the return signature of method calls is listed,
2956          * let's check if they match if this is a response */
2957         if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
2958             m->enforced_reply_signature &&
2959             !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
2960                 return -ENOMSG;
2961
2962         /* If gvariant marshalling is used we need to close the body structure */
2963         r = bus_message_close_struct(m, &m->root_container, false);
2964         if (r < 0)
2965                 return r;
2966
2967         /* If there's a non-trivial signature set, then add it in
2968          * here, but only on dbus1 */
2969         if (!isempty(m->root_container.signature) && !BUS_MESSAGE_IS_GVARIANT(m)) {
2970                 r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
2971                 if (r < 0)
2972                         return r;
2973         }
2974
2975         if (m->n_fds > 0) {
2976                 r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
2977                 if (r < 0)
2978                         return r;
2979         }
2980
2981         r = bus_message_close_header(m);
2982         if (r < 0)
2983                 return r;
2984
2985         if (BUS_MESSAGE_IS_GVARIANT(m))
2986                 m->header->dbus2.cookie = cookie;
2987         else
2988                 m->header->dbus1.serial = (uint32_t) cookie;
2989
2990         m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout;
2991
2992         /* Add padding at the end of the fields part, since we know
2993          * the body needs to start at an 8 byte alignment. We made
2994          * sure we allocated enough space for this, so all we need to
2995          * do here is to zero it out. */
2996         a = ALIGN8(m->fields_size) - m->fields_size;
2997         if (a > 0)
2998                 memzero((uint8_t*) BUS_MESSAGE_FIELDS(m) + m->fields_size, a);
2999
3000         /* If this is something we can send as memfd, then let's seal
3001         the memfd now. Note that we can send memfds as payload only
3002         for directed messages, and not for broadcasts. */
3003         if (m->destination && m->bus->use_memfd) {
3004                 MESSAGE_FOREACH_PART(part, i, m)
3005                         if (part->memfd >= 0 &&
3006                             !part->sealed &&
3007                             (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0) &&
3008                             part != m->body_end) { /* The last part may never be sent as memfd */
3009                                 uint64_t sz;
3010
3011                                 /* Try to seal it if that makes
3012                                  * sense. First, unmap our own map to
3013                                  * make sure we don't keep it busy. */
3014                                 bus_body_part_unmap(part);
3015
3016                                 /* Then, sync up real memfd size */
3017                                 sz = part->size;
3018                                 r = memfd_set_size(part->memfd, sz);
3019                                 if (r < 0)
3020                                         return r;
3021
3022                                 /* Finally, try to seal */
3023                                 if (memfd_set_sealed(part->memfd) >= 0)
3024                                         part->sealed = true;
3025                         }
3026         }
3027
3028         m->root_container.end = m->user_body_size;
3029         m->root_container.index = 0;
3030         m->root_container.offset_index = 0;
3031         m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
3032
3033         m->sealed = true;
3034
3035         return 0;
3036 }
3037
3038 int bus_body_part_map(struct bus_body_part *part) {
3039         void *p;
3040         size_t psz, shift;
3041
3042         assert_se(part);
3043
3044         if (part->data)
3045                 return 0;
3046
3047         if (part->size <= 0)
3048                 return 0;
3049
3050         /* For smaller zero parts (as used for padding) we don't need to map anything... */
3051         if (part->memfd < 0 && part->is_zero && part->size < 8) {
3052                 static const uint8_t zeroes[7] = { };
3053                 part->data = (void*) zeroes;
3054                 return 0;
3055         }
3056
3057         shift = part->memfd_offset - ((part->memfd_offset / page_size()) * page_size());
3058         psz = PAGE_ALIGN(part->size + shift);
3059
3060         if (part->memfd >= 0)
3061                 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE, part->memfd, part->memfd_offset - shift);
3062         else if (part->is_zero)
3063                 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
3064         else
3065                 return -EINVAL;
3066
3067         if (p == MAP_FAILED)
3068                 return -errno;
3069
3070         part->mapped = psz;
3071         part->mmap_begin = p;
3072         part->data = (uint8_t*) p + shift;
3073         part->munmap_this = true;
3074
3075         return 0;
3076 }
3077
3078 void bus_body_part_unmap(struct bus_body_part *part) {
3079
3080         assert_se(part);
3081
3082         if (part->memfd < 0)
3083                 return;
3084
3085         if (!part->mmap_begin)
3086                 return;
3087
3088         if (!part->munmap_this)
3089                 return;
3090
3091         assert_se(munmap(part->mmap_begin, part->mapped) == 0);
3092
3093         part->mmap_begin = NULL;
3094         part->data = NULL;
3095         part->mapped = 0;
3096         part->munmap_this = false;
3097
3098         return;
3099 }
3100
3101 static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
3102         size_t k, start, end;
3103
3104         assert(rindex);
3105         assert(align > 0);
3106
3107         start = ALIGN_TO((size_t) *rindex, align);
3108         end = start + nbytes;
3109
3110         if (end > sz)
3111                 return -EBADMSG;
3112
3113         /* Verify that padding is 0 */
3114         for (k = *rindex; k < start; k++)
3115                 if (((const uint8_t*) p)[k] != 0)
3116                         return -EBADMSG;
3117
3118         if (r)
3119                 *r = (uint8_t*) p + start;
3120
3121         *rindex = end;
3122
3123         return 1;
3124 }
3125
3126 static bool message_end_of_signature(sd_bus_message *m) {
3127         struct bus_container *c;
3128
3129         assert(m);
3130
3131         c = message_get_container(m);
3132         return !c->signature || c->signature[c->index] == 0;
3133 }
3134
3135 static bool message_end_of_array(sd_bus_message *m, size_t index) {
3136         struct bus_container *c;
3137
3138         assert(m);
3139
3140         c = message_get_container(m);
3141         if (c->enclosing != SD_BUS_TYPE_ARRAY)
3142                 return false;
3143
3144         if (BUS_MESSAGE_IS_GVARIANT(m))
3145                 return index >= c->end;
3146         else {
3147                 assert(c->array_size);
3148                 return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
3149         }
3150 }
3151
3152 #if 0 /// UNNEEDED by elogind
3153 _public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
3154         assert_return(m, -EINVAL);
3155         assert_return(m->sealed, -EPERM);
3156
3157         if (complete && m->n_containers > 0)
3158                 return false;
3159
3160         if (message_end_of_signature(m))
3161                 return true;
3162
3163         if (message_end_of_array(m, m->rindex))
3164                 return true;
3165
3166         return false;
3167 }
3168 #endif // 0
3169
3170 static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
3171         struct bus_body_part *part;
3172         size_t begin;
3173         int r;
3174
3175         assert(m);
3176
3177         if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) {
3178                 part = m->cached_rindex_part;
3179                 begin = m->cached_rindex_part_begin;
3180         } else {
3181                 part = &m->body;
3182                 begin = 0;
3183         }
3184
3185         while (part) {
3186                 if (index < begin)
3187                         return NULL;
3188
3189                 if (index + sz <= begin + part->size) {
3190