+ if (ret)
+ *ret = q;
+
+ return 0;
+}
+
+static int message_skip_fields(
+ sd_bus_message *m,
+ size_t *ri,
+ uint32_t array_size,
+ const char **signature) {
+
+ size_t original_index;
+ int r;
+
+ assert(m);
+ assert(ri);
+ assert(signature);
+
+ original_index = *ri;
+
+ for (;;) {
+ char t;
+ size_t l;
+
+ if (array_size != (uint32_t) -1 &&
+ array_size <= *ri - original_index)
+ return 0;
+
+ t = **signature;
+ if (!t)
+ return 0;
+
+ if (t == SD_BUS_TYPE_STRING) {
+
+ r = message_peek_field_string(m, NULL, ri, NULL);
+ if (r < 0)
+ return r;
+
+ (*signature)++;
+
+ } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
+
+ r = message_peek_field_string(m, object_path_is_valid, ri, NULL);
+ if (r < 0)
+ return r;
+
+ (*signature)++;
+
+ } else if (t == SD_BUS_TYPE_SIGNATURE) {
+
+ r = message_peek_field_signature(m, ri, NULL);
+ if (r < 0)
+ return r;
+
+ (*signature)++;
+
+ } else if (bus_type_is_basic(t)) {
+ ssize_t align, k;
+
+ align = bus_type_get_alignment(t);
+ k = bus_type_get_size(t);
+ assert(align > 0 && k > 0);
+
+ r = message_peek_fields(m, ri, align, k, NULL);
+ if (r < 0)
+ return r;
+
+ (*signature)++;
+
+ } else if (t == SD_BUS_TYPE_ARRAY) {
+
+ r = signature_element_length(*signature+1, &l);
+ if (r < 0)
+ return r;
+
+ assert(l >= 1);
+ {
+ char sig[l-1], *s;
+ uint32_t nas;
+ int alignment;
+
+ strncpy(sig, *signature + 1, l-1);
+ s = sig;
+
+ alignment = bus_type_get_alignment(sig[0]);
+ if (alignment < 0)
+ return alignment;
+
+ r = message_peek_field_uint32(m, ri, &nas);
+ if (r < 0)
+ return r;
+ if (nas > BUS_ARRAY_MAX_SIZE)
+ return -EBADMSG;
+
+ r = message_peek_fields(m, ri, alignment, 0, NULL);
+ if (r < 0)
+ return r;
+
+ r = message_skip_fields(m, ri, nas, (const char**) &s);
+ if (r < 0)
+ return r;
+ }
+
+ (*signature) += 1 + l;
+
+ } else if (t == SD_BUS_TYPE_VARIANT) {
+ const char *s;
+
+ r = message_peek_field_signature(m, ri, &s);
+ if (r < 0)
+ return r;
+
+ r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
+ if (r < 0)
+ return r;
+
+ (*signature)++;
+
+ } else if (t == SD_BUS_TYPE_STRUCT ||
+ t == SD_BUS_TYPE_DICT_ENTRY) {
+
+ r = signature_element_length(*signature, &l);
+ if (r < 0)
+ return r;
+
+ assert(l >= 2);
+ {
+ char sig[l-1], *s;
+ strncpy(sig, *signature + 1, l-1);
+ s = sig;
+
+ r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
+ if (r < 0)
+ return r;
+ }
+
+ *signature += l;
+ } else
+ return -EINVAL;
+ }
+}
+
+static int message_parse_fields(sd_bus_message *m) {
+ size_t ri;
+ int r;
+ uint32_t unix_fds = 0;
+
+ assert(m);
+
+ for (ri = 0; ri < BUS_MESSAGE_FIELDS_SIZE(m); ) {
+ const char *signature;
+ uint8_t *header;
+
+ r = message_peek_fields(m, &ri, 8, 1, (void**) &header);
+ if (r < 0)
+ return r;
+
+ r = message_peek_field_signature(m, &ri, &signature);
+ if (r < 0)
+ return r;
+
+ switch (*header) {
+ case _SD_BUS_MESSAGE_HEADER_INVALID:
+ return -EBADMSG;
+
+ case SD_BUS_MESSAGE_HEADER_PATH:
+
+ if (m->path)
+ return -EBADMSG;
+
+ if (!streq(signature, "o"))
+ return -EBADMSG;
+
+ r = message_peek_field_string(m, object_path_is_valid, &ri, &m->path);
+ break;
+
+ case SD_BUS_MESSAGE_HEADER_INTERFACE:
+
+ if (m->interface)
+ return -EBADMSG;
+
+ if (!streq(signature, "s"))
+ return -EBADMSG;
+
+ r = message_peek_field_string(m, interface_name_is_valid, &ri, &m->interface);
+ break;
+
+ case SD_BUS_MESSAGE_HEADER_MEMBER:
+
+ if (m->member)
+ return -EBADMSG;
+
+ if (!streq(signature, "s"))
+ return -EBADMSG;
+
+ r = message_peek_field_string(m, member_name_is_valid, &ri, &m->member);
+ break;
+
+ case SD_BUS_MESSAGE_HEADER_ERROR_NAME:
+
+ if (m->error.name)
+ return -EBADMSG;
+
+ if (!streq(signature, "s"))
+ return -EBADMSG;
+
+ r = message_peek_field_string(m, error_name_is_valid, &ri, &m->error.name);
+ break;
+
+ case SD_BUS_MESSAGE_HEADER_DESTINATION:
+
+ if (m->destination)
+ return -EBADMSG;
+
+ if (!streq(signature, "s"))
+ return -EBADMSG;
+
+ r = message_peek_field_string(m, service_name_is_valid, &ri, &m->destination);
+ break;
+
+ case SD_BUS_MESSAGE_HEADER_SENDER:
+
+ if (m->sender)
+ return -EBADMSG;
+
+ if (!streq(signature, "s"))
+ return -EBADMSG;
+
+ r = message_peek_field_string(m, service_name_is_valid, &ri, &m->sender);
+ break;
+
+
+ case SD_BUS_MESSAGE_HEADER_SIGNATURE: {
+ const char *s;
+ char *c;
+
+ if (m->root_container.signature)
+ return -EBADMSG;
+
+ if (!streq(signature, "g"))
+ return -EBADMSG;
+
+ r = message_peek_field_signature(m, &ri, &s);
+ if (r < 0)
+ return r;
+
+ c = strdup(s);
+ if (!c)
+ return -ENOMEM;
+
+ free(m->root_container.signature);
+ m->root_container.signature = c;
+ break;
+ }
+
+ case SD_BUS_MESSAGE_HEADER_REPLY_SERIAL:
+ if (m->reply_serial != 0)
+ return -EBADMSG;
+
+ if (!streq(signature, "u"))
+ return -EBADMSG;
+
+ r = message_peek_field_uint32(m, &ri, &m->reply_serial);
+ if (r < 0)
+ return r;
+
+ if (m->reply_serial == 0)
+ return -EBADMSG;
+
+ break;
+
+ case SD_BUS_MESSAGE_HEADER_UNIX_FDS:
+ if (unix_fds != 0)
+ return -EBADMSG;
+
+ if (!streq(signature, "u"))
+ return -EBADMSG;
+
+ r = message_peek_field_uint32(m, &ri, &unix_fds);
+ if (r < 0)
+ return -EBADMSG;
+
+ if (unix_fds == 0)
+ return -EBADMSG;
+
+ break;
+
+ default:
+ r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
+ }
+
+ if (r < 0)
+ return r;
+ }
+
+ if (m->n_fds != unix_fds)
+ return -EBADMSG;
+
+ if (isempty(m->root_container.signature) != (BUS_MESSAGE_BODY_SIZE(m) == 0))
+ return -EBADMSG;
+
+ switch (m->header->type) {
+
+ case SD_BUS_MESSAGE_TYPE_SIGNAL:
+ if (!m->path || !m->interface || !m->member)
+ return -EBADMSG;
+ break;
+
+ case SD_BUS_MESSAGE_TYPE_METHOD_CALL:
+
+ if (!m->path || !m->member)
+ return -EBADMSG;
+
+ break;
+
+ case SD_BUS_MESSAGE_TYPE_METHOD_RETURN:
+
+ if (m->reply_serial == 0)
+ return -EBADMSG;
+ break;
+
+ case SD_BUS_MESSAGE_TYPE_METHOD_ERROR:
+
+ if (m->reply_serial == 0 || !m->error.name)
+ return -EBADMSG;
+ break;
+ }
+
+ /* Try to read the error message, but if we can't it's a non-issue */
+ if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_ERROR)
+ sd_bus_message_read(m, "s", &m->error.message);