LCOV - code coverage report
Current view: top level - libsystemd/sd-bus - bus-message.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 2142 3239 66.1 %
Date: 2019-08-22 15:41:25 Functions: 105 139 75.5 %

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

Generated by: LCOV version 1.14