LCOV - code coverage report
Current view: top level - libsystemd/sd-bus - bus-message.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 2251 3185 70.7 %
Date: 2015-07-29 18:47:03 Functions: 105 134 78.4 %

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

Generated by: LCOV version 1.11