summaryrefslogtreecommitdiffstats
path: root/src/sbus/interface
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
commit74aa0bc6779af38018a03fd2cf4419fe85917904 (patch)
tree9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/sbus/interface
parentInitial commit. (diff)
downloadsssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz
sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/sbus/interface')
-rw-r--r--src/sbus/interface/sbus_interface.c464
-rw-r--r--src/sbus/interface/sbus_introspection.c679
-rw-r--r--src/sbus/interface/sbus_iterator_readers.c414
-rw-r--r--src/sbus/interface/sbus_iterator_readers.h126
-rw-r--r--src/sbus/interface/sbus_iterator_writers.c365
-rw-r--r--src/sbus/interface/sbus_iterator_writers.h126
-rw-r--r--src/sbus/interface/sbus_properties.c894
-rw-r--r--src/sbus/interface/sbus_properties_parser.c198
-rw-r--r--src/sbus/interface/sbus_std_signals.c65
9 files changed, 3331 insertions, 0 deletions
diff --git a/src/sbus/interface/sbus_interface.c b/src/sbus/interface/sbus_interface.c
new file mode 100644
index 0000000..e7fc05d
--- /dev/null
+++ b/src/sbus/interface/sbus_interface.c
@@ -0,0 +1,464 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <talloc.h>
+#include <string.h>
+
+#include "sbus/sbus_annotations.h"
+#include "sbus/sbus_interface_declarations.h"
+
+static struct sbus_handler
+sbus_sync_handler(sbus_handler_sync_fn handler,
+ sbus_handler_data data)
+{
+ struct sbus_handler object = {
+ .type = SBUS_HANDLER_SYNC,
+ .sync = handler,
+ .data = data
+ };
+
+ return object;
+}
+
+static struct sbus_handler
+sbus_async_handler(sbus_handler_send_fn handler_send,
+ sbus_handler_recv_fn handler_recv,
+ sbus_handler_data data)
+{
+ struct sbus_handler object = {
+ .type = SBUS_HANDLER_ASYNC,
+ .async_send = handler_send,
+ .async_recv = handler_recv,
+ .data = data
+ };
+
+ return object;
+}
+
+struct sbus_method
+sbus_method_sync(const char *name,
+ const struct sbus_method_arguments *arguments,
+ const struct sbus_annotation *annotations,
+ sbus_invoker_issue invoker_issue,
+ sbus_invoker_keygen invoker_keygen,
+ sbus_handler_sync_fn handler,
+ sbus_handler_data data)
+{
+ struct sbus_method object = {
+ .name = name,
+ .annotations = annotations,
+ .invoker = {.issue = invoker_issue, .keygen = invoker_keygen},
+ .handler = sbus_sync_handler(handler, data),
+ .arguments = arguments
+ };
+
+ return object;
+}
+
+struct sbus_method
+sbus_method_async(const char *name,
+ const struct sbus_method_arguments *arguments,
+ const struct sbus_annotation *annotations,
+ sbus_invoker_issue invoker_issue,
+ sbus_invoker_keygen invoker_keygen,
+ sbus_handler_send_fn handler_send,
+ sbus_handler_recv_fn handler_recv,
+ sbus_handler_data data)
+{
+ struct sbus_method object = {
+ .name = name,
+ .annotations = annotations,
+ .invoker = {.issue = invoker_issue, .keygen = invoker_keygen},
+ .handler = sbus_async_handler(handler_send, handler_recv, data),
+ .arguments = arguments
+ };
+
+ return object;
+}
+
+static struct sbus_method *
+sbus_method_copy(TALLOC_CTX *mem_ctx,
+ const struct sbus_method *input)
+{
+ struct sbus_method *copy;
+ size_t count;
+
+ for (count = 0; input[count].name != NULL; count++);
+
+ copy = talloc_zero_array(mem_ctx, struct sbus_method, count + 1);
+ if (copy == NULL) {
+ return NULL;
+ }
+
+ /* All data is either pointer to a static data or it is not a pointer.
+ * We can just copy it. */
+ memcpy(copy, input, sizeof(struct sbus_method) * (count + 1));
+
+ return copy;
+}
+
+struct sbus_signal
+sbus_signal(const char *name,
+ const struct sbus_argument *arguments,
+ const struct sbus_annotation *annotations)
+{
+ struct sbus_signal object = {
+ .name = name,
+ .arguments = arguments,
+ .annotations = annotations
+ };
+
+ return object;
+}
+
+static struct sbus_signal *
+sbus_signal_copy(TALLOC_CTX *mem_ctx,
+ const struct sbus_signal *input)
+{
+ struct sbus_signal *copy;
+ size_t count;
+
+ for (count = 0; input[count].name != NULL; count++);
+
+ copy = talloc_zero_array(mem_ctx, struct sbus_signal, count + 1);
+ if (copy == NULL) {
+ return NULL;
+ }
+
+ /* All data is either pointer to a static data or it is not a pointer.
+ * We can just copy it. */
+ memcpy(copy, input, sizeof(struct sbus_signal) * (count + 1));
+
+ return copy;
+}
+
+struct sbus_property
+sbus_property_sync(const char *name,
+ const char *type,
+ enum sbus_property_access access,
+ const struct sbus_annotation *annotations,
+ sbus_invoker_issue invoker_issue,
+ sbus_handler_sync_fn handler,
+ sbus_handler_data data)
+{
+ struct sbus_property object = {
+ .name = name,
+ .type = type,
+ .access = access,
+ .annotations = annotations,
+ .invoker = {.issue = invoker_issue, .keygen = NULL},
+ .handler = sbus_sync_handler(handler, data)
+ };
+
+ return object;
+}
+
+struct sbus_property
+sbus_property_async(const char *name,
+ const char *type,
+ enum sbus_property_access access,
+ const struct sbus_annotation *annotations,
+ sbus_invoker_issue invoker_issue,
+ sbus_handler_send_fn handler_send,
+ sbus_handler_recv_fn handler_recv,
+ sbus_handler_data data)
+{
+ struct sbus_property object = {
+ .name = name,
+ .type = type,
+ .access = access,
+ .annotations = annotations,
+ .invoker = {.issue = invoker_issue, .keygen = NULL},
+ .handler = sbus_async_handler(handler_send, handler_recv, data)
+ };
+
+ return object;
+}
+
+static struct sbus_property *
+sbus_property_copy(TALLOC_CTX *mem_ctx,
+ const struct sbus_property *input)
+{
+ struct sbus_property *copy;
+ size_t count;
+
+ for (count = 0; input[count].name != NULL; count++);
+
+ copy = talloc_zero_array(mem_ctx, struct sbus_property, count + 1);
+ if (copy == NULL) {
+ return NULL;
+ }
+
+ /* All data is either pointer to a static data or it is not a pointer.
+ * We can just copy it. */
+ memcpy(copy, input, sizeof(struct sbus_property) * (count + 1));
+
+ return copy;
+}
+
+struct sbus_interface
+sbus_interface(const char *name,
+ const struct sbus_annotation *annotations,
+ const struct sbus_method *methods,
+ const struct sbus_signal *signals,
+ const struct sbus_property *properties)
+{
+ struct sbus_interface object = {
+ .name = name,
+ .annotations = annotations,
+ .methods = methods,
+ .signals = signals,
+ .properties = properties
+ };
+
+ return object;
+}
+
+struct sbus_interface *
+sbus_interface_copy(TALLOC_CTX *mem_ctx,
+ const struct sbus_interface *input)
+{
+ struct sbus_interface *copy;
+
+ copy = talloc_zero(mem_ctx, struct sbus_interface);
+ if (copy == NULL) {
+ return NULL;
+ }
+
+ /* Name and annotations are pointer to static data, no need to copy them. */
+ copy->name = input->name;
+ copy->annotations = input->annotations;
+
+ copy->methods = sbus_method_copy(copy, input->methods);
+ copy->signals = sbus_signal_copy(copy, input->signals);
+ copy->properties = sbus_property_copy(copy, input->properties);
+
+ if (copy->methods == NULL || copy->signals == NULL
+ || copy->properties == NULL) {
+ talloc_free(copy);
+ return NULL;
+ }
+
+ return copy;
+}
+
+const struct sbus_method *
+sbus_interface_find_method(struct sbus_interface *iface,
+ const char *method_name)
+{
+ unsigned int i;
+
+ for (i = 0; iface->methods[i].name != NULL; i++) {
+ if (strcmp(iface->methods[i].name, method_name) == 0) {
+ return &iface->methods[i];
+ }
+ }
+
+ return NULL;
+}
+
+const struct sbus_property *
+sbus_interface_find_property(struct sbus_interface *iface,
+ enum sbus_property_access access,
+ const char *property_name)
+{
+ unsigned int i;
+
+ for (i = 0; iface->properties[i].name != NULL; i++) {
+ if (iface->properties[i].access != access) {
+ continue;
+ }
+
+ if (strcmp(iface->properties[i].name, property_name) == 0) {
+ return &iface->properties[i];
+ }
+ }
+
+ return NULL;
+}
+
+struct sbus_listener
+sbus_listener_sync(const char *interface,
+ const char *signal_name,
+ const char *object_path,
+ sbus_invoker_issue invoker_issue,
+ sbus_invoker_keygen invoker_keygen,
+ sbus_handler_sync_fn handler,
+ sbus_handler_data data)
+{
+ struct sbus_listener object = {
+ .interface = interface,
+ .signal_name = signal_name,
+ .object_path = object_path,
+ .invoker = {.issue = invoker_issue, .keygen = invoker_keygen},
+ .handler = sbus_sync_handler(handler, data)
+ };
+
+ return object;
+}
+
+struct sbus_listener
+sbus_listener_async(const char *interface,
+ const char *signal_name,
+ const char *object_path,
+ sbus_invoker_issue invoker_issue,
+ sbus_invoker_keygen invoker_keygen,
+ sbus_handler_send_fn handler_send,
+ sbus_handler_recv_fn handler_recv,
+ sbus_handler_data data)
+{
+ struct sbus_listener object = {
+ .interface = interface,
+ .signal_name = signal_name,
+ .object_path = object_path,
+ .invoker = {.issue = invoker_issue, .keygen = invoker_keygen},
+ .handler = sbus_async_handler(handler_send, handler_recv, data)
+ };
+
+ return object;
+}
+
+struct sbus_listener *
+sbus_listener_copy(TALLOC_CTX *mem_ctx,
+ const struct sbus_listener *input)
+{
+ /* All data is either pointer to a static data or it is not a pointer.
+ * We can just copy it. */
+ return talloc_memdup(mem_ctx, input, sizeof(struct sbus_listener));
+}
+
+struct sbus_node
+sbus_node_sync(const char *path,
+ sbus_handler_sync_fn factory,
+ sbus_handler_data data)
+{
+ struct sbus_node object = {
+ .path = path,
+ .factory = sbus_sync_handler(factory, data)
+ };
+
+ return object;
+}
+
+struct sbus_node
+sbus_node_async(const char *path,
+ sbus_handler_send_fn factory_send,
+ sbus_handler_recv_fn factory_recv,
+ sbus_handler_data data)
+{
+ struct sbus_node object = {
+ .path = path,
+ .factory = sbus_async_handler(factory_send, factory_recv, data)
+ };
+
+ return object;
+}
+
+struct sbus_node *
+sbus_node_copy(TALLOC_CTX *mem_ctx,
+ struct sbus_node *input)
+{
+ struct sbus_node *copy;
+
+ copy = talloc_zero(mem_ctx, struct sbus_node);
+ if (copy == NULL) {
+ return NULL;
+ }
+
+ copy->path = talloc_strdup(copy, input->path);
+ if (copy->path == NULL) {
+ talloc_free(copy);
+ return NULL;
+ }
+
+ copy->factory = input->factory;
+
+ return copy;
+}
+
+const char *
+sbus_annotation_find(const struct sbus_annotation *annotations,
+ const char *name)
+{
+ int i;
+
+ if (annotations == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; annotations[i].name != NULL; i++) {
+ if (strcmp(annotations[i].name, name) == 0) {
+ return annotations[i].value;
+ }
+ }
+
+ return NULL;
+}
+
+bool
+sbus_annotation_find_as_bool(const struct sbus_annotation *annotations,
+ const char *name)
+{
+ const char *value;
+
+ value = sbus_annotation_find(annotations, name);
+
+ if (value != NULL && strcasecmp(value, "true") == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+static void
+sbus_warn_deprecated(const struct sbus_annotation *annotations,
+ const char *iface_name,
+ const char *method_name)
+{
+ const char *by;
+ const char *member;
+ const char *dot;
+
+ if (annotations == NULL) {
+ return;
+ }
+
+ if (sbus_annotation_find_as_bool(annotations, SBUS_ANNOTATION_DEPRECATED)) {
+ member = method_name == NULL ? "" : method_name;
+ dot = method_name == NULL ? "" : ".";
+
+ by = sbus_annotation_find(annotations, SBUS_ANNOTATION_DEPRECATED_BY);
+ if (by != NULL) {
+ DEBUG(SSSDBG_IMPORTANT_INFO, "%s%s%s is deprecated by %s\n",
+ iface_name, dot, member, by);
+ } else {
+ DEBUG(SSSDBG_IMPORTANT_INFO, "%s%s%s is deprecated\n",
+ iface_name, dot, member);
+ }
+ }
+}
+
+void
+sbus_annotation_warn(const struct sbus_interface *iface,
+ const struct sbus_method *method)
+{
+ sbus_warn_deprecated(iface->annotations, iface->name, NULL);
+ sbus_warn_deprecated(method->annotations, iface->name, method->name);
+}
diff --git a/src/sbus/interface/sbus_introspection.c b/src/sbus/interface/sbus_introspection.c
new file mode 100644
index 0000000..8633837
--- /dev/null
+++ b/src/sbus/interface/sbus_introspection.c
@@ -0,0 +1,679 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+#include <stdio.h>
+
+#include "util/util.h"
+#include "util/dlinklist.h"
+#include "sbus/sbus_request.h"
+#include "sbus/sbus_private.h"
+#include "sbus/sbus_interface.h"
+#include "sbus/interface_dbus/sbus_dbus_server.h"
+
+#define FMT_DOCTYPE \
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" \
+ " \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+
+#define FMT_NODE "<node name=\"%s\">\n"
+#define FMT_IFACE " <interface name=\"%s\">\n"
+#define FMT_ANNOTATION " %s<annotation name=\"%s\" value=\"%s\" />\n"
+#define FMT_METHOD_EMPTY " <method name=\"%s\" />\n"
+#define FMT_METHOD_OPEN " <method name=\"%s\">\n"
+#define FMT_METHOD_ARG " <arg type=\"%s\" name=\"%s\" direction=\"%s\" />\n"
+#define FMT_METHOD_CLOSE " </method>\n"
+#define FMT_SIGNAL_EMPTY " <signal name=\"%s\" />\n"
+#define FMT_SIGNAL_OPEN " <signal name=\"%s\">\n"
+#define FMT_SIGNAL_ARG " <arg type=\"%s\" name=\"%s\" />\n"
+#define FMT_SIGNAL_CLOSE " </signal>\n"
+#define FMT_PROPERTY_EMPTY " <property name=\"%s\" type=\"%s\" access=\"%s\" />\n"
+#define FMT_PROPERTY_OPEN " <property name=\"%s\" type=\"%s\" access=\"%s\">\n"
+#define FMT_PROPERTY_CLOSE " </property>\n"
+#define FMT_IFACE_CLOSE " </interface>\n"
+#define FMT_CHILD_NODE " <node name=\"%s\" />\n"
+#define FMT_NODE_CLOSE "</node>\n"
+
+#define WRITE_OR_FAIL(file, ret, label, fmt, ...) do { \
+ ret = fprintf(file, fmt, ##__VA_ARGS__); \
+ if (ret < 0) { \
+ ret = EIO; \
+ goto label; \
+ } \
+} while (0)
+
+#define EMPTY(field) ((field) == NULL || (field)[0].name == NULL)
+
+enum sbus_arg_type {
+ SBUS_ARG_IN,
+ SBUS_ARG_OUT,
+ SBUS_ARG_SIGNAL
+};
+
+static errno_t
+sbus_introspect_annotations(FILE *file,
+ bool inside,
+ const struct sbus_annotation *annotations)
+{
+ errno_t ret;
+ const char *indent = inside ? " " : "";
+ int i;
+
+ if (annotations == NULL) {
+ return EOK;
+ }
+
+ for (i = 0; annotations[i].name != NULL; i++) {
+ WRITE_OR_FAIL(file, ret, done, FMT_ANNOTATION, indent,
+ annotations[i].name, annotations[i].value);
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t
+sbus_introspect_args(FILE *file,
+ enum sbus_arg_type type,
+ const struct sbus_argument *args)
+{
+ errno_t ret;
+ int i;
+
+ if (args == NULL) {
+ return EOK;
+ }
+
+ for (i = 0; args[i].name != NULL; i++) {
+ switch (type) {
+ case SBUS_ARG_SIGNAL:
+ WRITE_OR_FAIL(file, ret, done, FMT_SIGNAL_ARG,
+ args[i].type, args[i].name);
+ break;
+ case SBUS_ARG_IN:
+ WRITE_OR_FAIL(file, ret, done, FMT_METHOD_ARG,
+ args[i].type, args[i].name, "in");
+ break;
+ case SBUS_ARG_OUT:
+ WRITE_OR_FAIL(file, ret, done, FMT_METHOD_ARG,
+ args[i].type, args[i].name, "out");
+ break;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t
+sbus_introspect_methods(FILE *file,
+ const struct sbus_method *methods)
+{
+ errno_t ret;
+ int i;
+
+ if (methods == NULL) {
+ return EOK;
+ }
+
+ for (i = 0; methods[i].name != NULL; i++) {
+ if (EMPTY(methods[i].annotations)
+ && EMPTY(methods[i].arguments->input)
+ && EMPTY(methods[i].arguments->output)) {
+ WRITE_OR_FAIL(file, ret, done, FMT_METHOD_EMPTY, methods[i].name);
+ continue;
+ }
+
+ WRITE_OR_FAIL(file, ret, done, FMT_METHOD_OPEN, methods[i].name);
+
+ ret = sbus_introspect_annotations(file, true, methods[i].annotations);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sbus_introspect_args(file, SBUS_ARG_IN,
+ methods[i].arguments->input);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sbus_introspect_args(file, SBUS_ARG_OUT,
+ methods[i].arguments->output);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ WRITE_OR_FAIL(file, ret, done, FMT_METHOD_CLOSE);
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static errno_t
+sbus_introspect_signals(FILE *file,
+ const struct sbus_signal *signals)
+{
+ errno_t ret;
+ int i;
+
+ if (signals == NULL) {
+ return EOK;
+ }
+
+ for (i = 0; signals[i].name != NULL; i++) {
+ if (EMPTY(signals[i].annotations) && EMPTY(signals[i].arguments)) {
+ WRITE_OR_FAIL(file, ret, done, FMT_SIGNAL_EMPTY, signals[i].name);
+ continue;
+ }
+
+ WRITE_OR_FAIL(file, ret, done, FMT_SIGNAL_OPEN, signals[i].name);
+
+ ret = sbus_introspect_annotations(file, true, signals[i].annotations);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sbus_introspect_args(file, SBUS_ARG_SIGNAL, signals[i].arguments);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ WRITE_OR_FAIL(file, ret, done, FMT_SIGNAL_CLOSE);
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+struct sbus_introspect_property {
+ const char *name;
+ const char *type;
+ const struct sbus_annotation *annotations;
+ enum sbus_property_access access;
+};
+
+static void
+sbus_introspect_property_set(struct sbus_introspect_property *properties,
+ const struct sbus_property *property)
+{
+ int i;
+
+ for (i = 0; properties[i].name != NULL; i++) {
+ if (strcmp(properties[i].name, property->name) == 0) {
+ break;
+ }
+ }
+
+ /* Name, type and annotation is the same for both getter and setter.
+ * We just need to update access mode. */
+ properties[i].name = property->name;
+ properties[i].type = property->type;
+ properties[i].annotations = property->annotations;
+ properties[i].access |= property->access;
+}
+
+static const char *
+sbus_introspect_property_mode(struct sbus_introspect_property *property)
+{
+ switch (property->access) {
+ case SBUS_PROPERTY_READABLE:
+ return "read";
+ case SBUS_PROPERTY_WRITABLE:
+ return "write";
+ default:
+ return "readwrite";
+ }
+}
+
+static errno_t
+sbus_introspect_properties(FILE *file,
+ const struct sbus_property *properties)
+{
+ struct sbus_introspect_property *props;
+ const char *mode;
+ errno_t ret;
+ int len;
+ int i;
+
+ if (properties == NULL) {
+ return EOK;
+ }
+
+ for (len = 0; properties[len].name != NULL ; len++);
+
+ props = talloc_zero_array(NULL, struct sbus_introspect_property, len + 1);
+ if (props == NULL) {
+ return ENOMEM;
+ }
+
+ for (i = 0; properties[i].name != NULL; i++) {
+ sbus_introspect_property_set(props, &properties[i]);
+ }
+
+ for (i = 0; props[i].name != NULL; i++) {
+ mode = sbus_introspect_property_mode(&props[i]);
+
+ if (EMPTY(props[i].annotations)) {
+ WRITE_OR_FAIL(file, ret, done, FMT_PROPERTY_EMPTY,
+ props[i].name, props[i].type, mode);
+ continue;
+ }
+
+ WRITE_OR_FAIL(file, ret, done, FMT_PROPERTY_OPEN,
+ props[i].name, props[i].type, mode);
+
+ ret = sbus_introspect_annotations(file, true, props[i].annotations);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ WRITE_OR_FAIL(file, ret, done, FMT_PROPERTY_CLOSE);
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(props);
+ return ret;
+}
+
+static int
+sbus_introspect_iface(FILE *file, struct sbus_interface *iface)
+{
+ errno_t ret;
+
+ WRITE_OR_FAIL(file, ret, done, FMT_IFACE, iface->name);
+
+ ret = sbus_introspect_annotations(file, false, iface->annotations);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sbus_introspect_methods(file, iface->methods);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sbus_introspect_signals(file, iface->signals);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sbus_introspect_properties(file, iface->properties);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ WRITE_OR_FAIL(file, ret, done, FMT_IFACE_CLOSE);
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static int
+sbus_introspect_nodes(FILE *file, const char **nodes)
+{
+ errno_t ret;
+ int i;
+
+ if (nodes == NULL) {
+ return EOK;
+ }
+
+ for (i = 0; nodes[i] != NULL; i++) {
+ WRITE_OR_FAIL(file, ret, done, FMT_CHILD_NODE, nodes[i]);
+ }
+
+ ret = EOK;
+
+done:
+ return ret;
+}
+
+static char *
+sbus_introspect(TALLOC_CTX *mem_ctx,
+ const char *node,
+ const char **nodes,
+ struct sbus_interface_list *list)
+{
+ struct sbus_interface_list *item;
+ char *introspection = NULL;
+ FILE *memstream;
+ char *buffer;
+ size_t size;
+ errno_t ret;
+
+ memstream = open_memstream(&buffer, &size);
+ if (memstream == NULL) {
+ goto done;
+ }
+
+ WRITE_OR_FAIL(memstream, ret, done, FMT_DOCTYPE);
+ WRITE_OR_FAIL(memstream, ret, done, FMT_NODE, node);
+
+ DLIST_FOR_EACH(item, list) {
+ ret = sbus_introspect_iface(memstream, item->interface);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ ret = sbus_introspect_nodes(memstream, nodes);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ WRITE_OR_FAIL(memstream, ret, done, FMT_NODE_CLOSE);
+
+ fflush(memstream);
+ introspection = talloc_memdup(mem_ctx, buffer, size + 1);
+
+done:
+ if (memstream != NULL) {
+ fclose(memstream);
+ free(buffer);
+ }
+
+ return introspection;
+}
+
+typedef errno_t
+(*sbus_node_factory_sync)(TALLOC_CTX *, const char *, void *, const char ***);
+
+typedef struct tevent_req *
+(*sbus_node_factory_send)(TALLOC_CTX *, struct tevent_context *,
+ const char *, void *);
+
+typedef errno_t
+(*sbus_node_factory_recv)(TALLOC_CTX *, struct tevent_req *, const char ***);
+
+struct sbus_acquire_nodes_state {
+ const char **nodes;
+ struct sbus_handler *handler;
+};
+
+static void sbus_acquire_nodes_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+sbus_acquire_nodes_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sbus_router *router,
+ const char *path)
+{
+ struct sbus_acquire_nodes_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ struct sbus_node *node;
+ sbus_node_factory_sync handler_sync;
+ sbus_node_factory_send handler_send;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct sbus_acquire_nodes_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
+ return NULL;
+ }
+
+ node = sbus_router_nodes_lookup(router->nodes, path);
+ if (node == NULL) {
+ /* If there is no node factory registered and it is a root path,
+ * we return all known paths to the router. */
+ if (strcmp(path, "/") == 0) {
+ state->nodes = sbus_router_paths_nodes(state, router->paths);
+ } else {
+ state->nodes = NULL;
+ }
+ ret = EOK;
+ goto done;
+ }
+
+ state->handler = &node->factory;
+
+ switch (node->factory.type) {
+ case SBUS_HANDLER_SYNC:
+ handler_sync = node->factory.sync;
+ if (handler_sync == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: sync handler is not specified!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ ret = handler_sync(state, path, node->factory.data, &state->nodes);
+ goto done;
+ case SBUS_HANDLER_ASYNC:
+ handler_send = node->factory.async_send;
+ if (handler_send == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: async handler is not specified!\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ subreq = handler_send(state, ev, path, node->factory.data);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, sbus_acquire_nodes_done, req);
+ break;
+ }
+
+ ret = EAGAIN;
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ } else if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void sbus_acquire_nodes_done(struct tevent_req *subreq)
+{
+ struct sbus_acquire_nodes_state *state;
+ sbus_node_factory_recv handler_recv;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sbus_acquire_nodes_state);
+
+ handler_recv = state->handler->async_recv;
+ if (handler_recv == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: async handler is not specified!\n");
+ tevent_req_error(req, ERR_INTERNAL);
+ return;
+ }
+
+ ret = handler_recv(state, subreq, &state->nodes);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+}
+
+static errno_t
+sbus_acquire_nodes_recv(struct tevent_req *req,
+ const char ***_nodes)
+{
+ struct sbus_acquire_nodes_state *state;
+ state = tevent_req_data(req, struct sbus_acquire_nodes_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ /* We keep the nodes allocated on this request state, so we do not have
+ * to expect that state->nodes is a talloc context. This way, it may
+ * be static array. */
+
+ *_nodes = state->nodes;
+
+ return EOK;
+}
+
+struct sbus_introspection_state {
+ struct sbus_interface_list *list;
+ const char *introspection;
+ const char *path;
+};
+
+static void sbus_introspection_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+sbus_introspection_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sbus_request *sbus_req,
+ struct sbus_router *router)
+{
+ struct sbus_introspection_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct sbus_introspection_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
+ return NULL;
+ }
+
+ state->path = sbus_req->path;
+ state->introspection = NULL;
+
+ ret = sbus_router_paths_supported(state, router->paths,
+ sbus_req->path, &state->list);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to acquire interface list "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+
+ subreq = sbus_acquire_nodes_send(mem_ctx, ev, router, sbus_req->path);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, sbus_introspection_done, req);
+
+ ret = EAGAIN;
+
+done:
+ if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void sbus_introspection_done(struct tevent_req *subreq)
+{
+ struct sbus_introspection_state *state;
+ struct tevent_req *req;
+ const char **nodes;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sbus_introspection_state);
+
+ /* We keep the nodes allocated on subrequest state, so we do not have
+ * to expect that it is a talloc context and allow it also as a static
+ * array. Therefore we must free subreq later. */
+
+ ret = sbus_acquire_nodes_recv(subreq, &nodes);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ state->introspection = sbus_introspect(state, state->path,
+ nodes, state->list);
+ if (state->introspection == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+done:
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+}
+
+static errno_t
+sbus_introspection_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ const char **_introspection)
+{
+ struct sbus_introspection_state *state;
+ state = tevent_req_data(req, struct sbus_introspection_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_introspection = talloc_steal(mem_ctx, state->introspection);
+
+ return EOK;
+}
+
+errno_t
+sbus_register_introspection(struct sbus_router *router)
+{
+
+ SBUS_INTERFACE(iface,
+ org_freedesktop_DBus_Introspectable,
+ SBUS_METHODS(
+ SBUS_ASYNC(METHOD, org_freedesktop_DBus_Introspectable, Introspect,
+ sbus_introspection_send, sbus_introspection_recv,
+ router)
+ ),
+ SBUS_WITHOUT_SIGNALS,
+ SBUS_WITHOUT_PROPERTIES
+ );
+
+ struct sbus_path paths[] = {
+ {"/", &iface},
+ {"/*", &iface},
+ {NULL, NULL}
+ };
+
+ return sbus_router_add_path_map(router, paths);
+}
diff --git a/src/sbus/interface/sbus_iterator_readers.c b/src/sbus/interface/sbus_iterator_readers.c
new file mode 100644
index 0000000..6113f6d
--- /dev/null
+++ b/src/sbus/interface/sbus_iterator_readers.c
@@ -0,0 +1,414 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+#include <dbus/dbus.h>
+
+#include "util/util.h"
+#include "sbus/interface/sbus_iterator_readers.h"
+
+static errno_t
+sbus_iterator_read_basic(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ int dbus_type,
+ void *_value_ptr)
+{
+ int arg_type;
+ char **strptr;
+ char *str;
+
+ arg_type = dbus_message_iter_get_arg_type(iterator);
+ if (arg_type != dbus_type) {
+ return ERR_SBUS_INVALID_TYPE;
+ }
+
+ dbus_message_iter_get_basic(iterator, _value_ptr);
+ dbus_message_iter_next(iterator);
+
+ switch (dbus_type) {
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ strptr = (char**)_value_ptr;
+ str = talloc_strdup(mem_ctx, *strptr);
+ if (str == NULL) {
+ return ENOMEM;
+ }
+ *strptr = str;
+ break;
+ default:
+ break;
+ }
+
+ return EOK;
+}
+
+static errno_t
+_sbus_iterator_read_basic_array(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ int dbus_type,
+ int element_size,
+ void **_value_ptr)
+{
+ DBusMessageIter subiter;
+ uint8_t *arrayptr;
+ void *array = NULL;
+ int arg_type;
+ int count;
+ errno_t ret;
+ int i;
+
+ arg_type = dbus_message_iter_get_arg_type(iterator);
+ if (arg_type != DBUS_TYPE_ARRAY) {
+ ret = ERR_SBUS_INVALID_TYPE;
+ goto done;
+ }
+
+ count = dbus_message_iter_get_element_count(iterator);
+ dbus_message_iter_recurse(iterator, &subiter);
+
+ /* NULL-terminated array for pointer types */
+ switch (dbus_type) {
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ array = talloc_zero_size(mem_ctx, (size_t)(count + 1) * element_size);
+ if (array == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (count == 0) {
+ array = NULL;
+ ret = EOK;
+ goto done;
+ }
+ break;
+ default:
+ if (count == 0) {
+ array = NULL;
+ ret = EOK;
+ goto done;
+ }
+
+ array = talloc_zero_size(mem_ctx, (size_t)count * element_size);
+ if (array == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ break;
+ }
+
+ arrayptr = array;
+ for (i = 0; i < count; i++) {
+ ret = sbus_iterator_read_basic(array, &subiter, dbus_type, arrayptr);
+ if (ret != EOK) {
+ talloc_free(array);
+ goto done;
+ }
+
+ arrayptr += element_size;
+ }
+
+ ret = EOK;
+
+done:
+ /* Always step past the array. */
+ dbus_message_iter_next(iterator);
+
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_value_ptr = array;
+
+ return ret;
+}
+
+#define sbus_iterator_read_basic_array(mem_ctx, iterator, dbus_type, c_type, dest) \
+ _sbus_iterator_read_basic_array((mem_ctx), (iterator), (dbus_type), \
+ sizeof(c_type), (void**)(dest))
+
+errno_t sbus_iterator_read_y(DBusMessageIter *iterator,
+ uint8_t *_value)
+{
+ return sbus_iterator_read_basic(NULL, iterator, DBUS_TYPE_BYTE, _value);
+}
+
+errno_t sbus_iterator_read_b(DBusMessageIter *iterator,
+ bool *_value)
+{
+ dbus_bool_t dbus_value;
+ errno_t ret;
+
+ ret = sbus_iterator_read_basic(NULL, iterator, DBUS_TYPE_BOOLEAN, &dbus_value);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_value = dbus_value;
+
+ return EOK;
+}
+
+errno_t sbus_iterator_read_n(DBusMessageIter *iterator,
+ int16_t *_value)
+{
+ dbus_int16_t dbus_value;
+ errno_t ret;
+
+ ret = sbus_iterator_read_basic(NULL, iterator, DBUS_TYPE_INT16, &dbus_value);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_value = dbus_value;
+
+ return EOK;
+}
+
+errno_t sbus_iterator_read_q(DBusMessageIter *iterator,
+ uint16_t *_value)
+{
+ dbus_uint16_t dbus_value;
+ errno_t ret;
+
+ ret = sbus_iterator_read_basic(NULL, iterator, DBUS_TYPE_UINT16, &dbus_value);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_value = dbus_value;
+
+ return EOK;
+}
+
+errno_t sbus_iterator_read_i(DBusMessageIter *iterator,
+ int32_t *_value)
+{
+ dbus_int32_t dbus_value;
+ errno_t ret;
+
+ ret = sbus_iterator_read_basic(NULL, iterator, DBUS_TYPE_INT32, &dbus_value);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_value = dbus_value;
+
+ return EOK;
+}
+
+errno_t sbus_iterator_read_u(DBusMessageIter *iterator,
+ uint32_t *_value)
+{
+ dbus_uint32_t dbus_value;
+ errno_t ret;
+
+ ret = sbus_iterator_read_basic(NULL, iterator, DBUS_TYPE_UINT32, &dbus_value);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_value = dbus_value;
+
+ return EOK;
+}
+
+errno_t sbus_iterator_read_x(DBusMessageIter *iterator,
+ int64_t *_value)
+{
+ dbus_int64_t dbus_value;
+ errno_t ret;
+
+ ret = sbus_iterator_read_basic(NULL, iterator, DBUS_TYPE_INT64, &dbus_value);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_value = dbus_value;
+
+ return EOK;
+}
+
+errno_t sbus_iterator_read_t(DBusMessageIter *iterator,
+ uint64_t *_value)
+{
+ dbus_uint64_t dbus_value;
+ errno_t ret;
+
+ ret = sbus_iterator_read_basic(NULL, iterator, DBUS_TYPE_UINT64, &dbus_value);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_value = dbus_value;
+
+ return EOK;
+}
+
+errno_t sbus_iterator_read_d(DBusMessageIter *iterator,
+ double *_value)
+{
+ return sbus_iterator_read_basic(NULL, iterator, DBUS_TYPE_DOUBLE, _value);
+}
+
+errno_t sbus_iterator_read_s(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ const char **_value)
+{
+ return sbus_iterator_read_basic(mem_ctx, iterator, DBUS_TYPE_STRING, _value);
+}
+
+errno_t sbus_iterator_read_S(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ char **_value)
+{
+ return sbus_iterator_read_basic(mem_ctx, iterator, DBUS_TYPE_STRING, _value);
+}
+
+errno_t sbus_iterator_read_o(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ const char **_value)
+{
+ return sbus_iterator_read_basic(mem_ctx, iterator, DBUS_TYPE_OBJECT_PATH, _value);
+}
+
+errno_t sbus_iterator_read_O(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ char **_value)
+{
+ return sbus_iterator_read_basic(mem_ctx, iterator, DBUS_TYPE_OBJECT_PATH, _value);
+}
+
+errno_t sbus_iterator_read_ay(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ uint8_t **_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_BYTE,
+ uint8_t, _value);
+}
+
+errno_t sbus_iterator_read_ab(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ bool **_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_BOOLEAN,
+ uint8_t, _value);
+}
+
+errno_t sbus_iterator_read_an(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ int16_t **_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_INT16,
+ int16_t, _value);
+}
+
+errno_t sbus_iterator_read_aq(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ uint16_t **_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_UINT16,
+ uint16_t, _value);
+}
+
+errno_t sbus_iterator_read_ai(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ int32_t **_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_INT32,
+ int32_t, _value);
+}
+
+errno_t sbus_iterator_read_au(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ uint32_t **_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_UINT32,
+ uint32_t, _value);
+}
+
+errno_t sbus_iterator_read_ax(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ int64_t **_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_INT64,
+ int64_t, _value);
+}
+
+errno_t sbus_iterator_read_at(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ uint64_t **_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_UINT64,
+ uint64_t, _value);
+}
+
+errno_t sbus_iterator_read_ad(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ double **_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_DOUBLE,
+ double, _value);
+}
+
+errno_t sbus_iterator_read_as(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ const char ***_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_STRING,
+ const char *, _value);
+}
+
+errno_t sbus_iterator_read_aS(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ char ***_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_STRING,
+ char *, _value);
+}
+
+errno_t sbus_iterator_read_ao(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ const char ***_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_OBJECT_PATH,
+ const char *, _value);
+}
+
+errno_t sbus_iterator_read_aO(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ char ***_value)
+{
+ return sbus_iterator_read_basic_array(mem_ctx, iterator,
+ DBUS_TYPE_OBJECT_PATH,
+ char *, _value);
+}
diff --git a/src/sbus/interface/sbus_iterator_readers.h b/src/sbus/interface/sbus_iterator_readers.h
new file mode 100644
index 0000000..6785243
--- /dev/null
+++ b/src/sbus/interface/sbus_iterator_readers.h
@@ -0,0 +1,126 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SBUS_ITERATOR_READERS_H_
+#define _SBUS_ITERATOR_READERS_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <talloc.h>
+#include <dbus/dbus.h>
+
+#include "util/util.h"
+
+errno_t sbus_iterator_read_y(DBusMessageIter *iterator,
+ uint8_t *_value);
+
+errno_t sbus_iterator_read_b(DBusMessageIter *iterator,
+ bool *_value);
+
+errno_t sbus_iterator_read_n(DBusMessageIter *iterator,
+ int16_t *_value);
+
+errno_t sbus_iterator_read_q(DBusMessageIter *iterator,
+ uint16_t *_value);
+
+errno_t sbus_iterator_read_i(DBusMessageIter *iterator,
+ int32_t *_value);
+
+errno_t sbus_iterator_read_u(DBusMessageIter *iterator,
+ uint32_t *_value);
+
+errno_t sbus_iterator_read_x(DBusMessageIter *iterator,
+ int64_t *_value);
+
+errno_t sbus_iterator_read_t(DBusMessageIter *iterator,
+ uint64_t *_value);
+
+errno_t sbus_iterator_read_d(DBusMessageIter *iterator,
+ double *_value);
+
+errno_t sbus_iterator_read_s(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ const char **_value);
+
+errno_t sbus_iterator_read_S(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ char **_value);
+
+errno_t sbus_iterator_read_o(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ const char **_value);
+
+errno_t sbus_iterator_read_O(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ char **_value);
+
+errno_t sbus_iterator_read_ay(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ uint8_t **_value);
+
+errno_t sbus_iterator_read_ab(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ bool **_value);
+
+errno_t sbus_iterator_read_an(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ int16_t **_value);
+
+errno_t sbus_iterator_read_aq(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ uint16_t **_value);
+
+errno_t sbus_iterator_read_ai(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ int32_t **_value);
+
+errno_t sbus_iterator_read_au(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ uint32_t **_value);
+
+errno_t sbus_iterator_read_ax(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ int64_t **_value);
+
+errno_t sbus_iterator_read_at(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ uint64_t **_value);
+
+errno_t sbus_iterator_read_ad(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ double **_value);
+
+errno_t sbus_iterator_read_as(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ const char ***_value);
+
+errno_t sbus_iterator_read_aS(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ char ***_value);
+
+errno_t sbus_iterator_read_ao(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ const char ***_value);
+
+errno_t sbus_iterator_read_aO(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *iterator,
+ char ***_value);
+
+#endif /* _SBUS_ITERATOR_READERS_H_ */
diff --git a/src/sbus/interface/sbus_iterator_writers.c b/src/sbus/interface/sbus_iterator_writers.c
new file mode 100644
index 0000000..3becc8f
--- /dev/null
+++ b/src/sbus/interface/sbus_iterator_writers.c
@@ -0,0 +1,365 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <talloc.h>
+#include <dbus/dbus.h>
+
+#include "util/util.h"
+#include "util/sss_utf8.h"
+#include "sbus/interface/sbus_iterator_writers.h"
+
+static errno_t
+sbus_iterator_write_basic(DBusMessageIter *iterator,
+ int dbus_type,
+ void *value_ptr)
+{
+ dbus_bool_t ret;
+
+ ret = dbus_message_iter_append_basic(iterator, dbus_type, value_ptr);
+
+ return ret ? EOK : EIO;
+}
+
+static errno_t
+sbus_iterator_write_string(DBusMessageIter *iterator,
+ int dbus_type,
+ const char *value,
+ const char *default_value)
+{
+ dbus_bool_t ret;
+ bool is_valid;
+
+ /* If the value is not set, we will provide a correct default value. */
+ value = value == NULL ? default_value : value;
+
+ /* D-Bus is not capable of sending NULL string. If even the default value
+ * was not set, we return an error. */
+ if (value == NULL) {
+ return ERR_SBUS_EMPTY_STRING;
+ }
+
+ /* D-Bus can send only correct UTF-8 strings. */
+ is_valid = sss_utf8_check((const uint8_t *)value, strlen(value));
+ if (!is_valid) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "String with non-utf8 characters was "
+ "given [%s]\n", value);
+ return ERR_SBUS_INVALID_STRING;
+ }
+
+ ret = dbus_message_iter_append_basic(iterator, dbus_type, &value);
+
+ return ret ? EOK : EIO;
+}
+
+static errno_t
+sbus_iterator_write_string_elements(DBusMessageIter *iterator,
+ int dbus_type,
+ const char **values)
+{
+ errno_t ret;
+ int i;
+
+ if (values == NULL) {
+ return EOK;
+ }
+
+ /* String arrays are NULL-terminated. */
+ for (i = 0; values[i] != NULL; i++) {
+ ret = sbus_iterator_write_string(iterator, dbus_type, values[i], NULL);
+ if (ret != EOK) {
+ return ret;
+ }
+ }
+
+ return EOK;
+}
+
+static errno_t
+sbus_iterator_write_fixed_elements(DBusMessageIter *iterator,
+ int dbus_type,
+ int element_size,
+ int array_length,
+ void *value_ptr)
+{
+ errno_t ret;
+ uint8_t *element_ptr;
+ int count;
+ int i;
+
+ element_ptr = value_ptr;
+ if (array_length < 0) {
+ count = talloc_get_size(value_ptr) / element_size;
+ } else {
+ count = array_length;
+ }
+
+
+ for (i = 0; i < count; i++) {
+ ret = sbus_iterator_write_basic(iterator, dbus_type, element_ptr);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ element_ptr += element_size;
+ }
+
+ return EOK;
+}
+
+errno_t
+_sbus_iterator_write_basic_array(DBusMessageIter *iterator,
+ int dbus_type,
+ int element_size,
+ int array_length,
+ void *value_ptr)
+{
+ const char array_type[2] = {dbus_type, '\0'};
+ DBusMessageIter arrayiter;
+ dbus_bool_t dbret;
+ errno_t ret;
+
+ dbret = dbus_message_iter_open_container(iterator, DBUS_TYPE_ARRAY,
+ array_type, &arrayiter);
+ if (!dbret) {
+ return EIO;
+ }
+
+ switch (dbus_type) {
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ ret = sbus_iterator_write_string_elements(&arrayiter, dbus_type,
+ (const char **)value_ptr);
+ if (ret != EOK) {
+ goto done;
+ }
+ break;
+ default:
+ ret = sbus_iterator_write_fixed_elements(&arrayiter, dbus_type,
+ element_size, array_length,
+ value_ptr);
+ if (ret != EOK) {
+ goto done;
+ }
+ break;
+ }
+
+ dbret = dbus_message_iter_close_container(iterator, &arrayiter);
+ if (!dbret) {
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ dbus_message_iter_abandon_container(iterator, &arrayiter);
+ }
+
+ return ret;
+}
+
+errno_t sbus_iterator_write_y(DBusMessageIter *iterator,
+ uint8_t value)
+{
+ return sbus_iterator_write_basic(iterator, DBUS_TYPE_BYTE, &value);
+}
+
+errno_t sbus_iterator_write_b(DBusMessageIter *iterator,
+ bool value)
+{
+ dbus_bool_t dbus_value = value;
+
+ return sbus_iterator_write_basic(iterator, DBUS_TYPE_BOOLEAN, &dbus_value);
+}
+
+errno_t sbus_iterator_write_n(DBusMessageIter *iterator,
+ int16_t value)
+{
+ dbus_int16_t dbus_value = value;
+
+ return sbus_iterator_write_basic(iterator, DBUS_TYPE_INT16, &dbus_value);
+}
+
+errno_t sbus_iterator_write_q(DBusMessageIter *iterator,
+ uint16_t value)
+{
+ dbus_uint16_t dbus_value = value;
+
+ return sbus_iterator_write_basic(iterator, DBUS_TYPE_UINT16, &dbus_value);
+}
+
+errno_t sbus_iterator_write_i(DBusMessageIter *iterator,
+ int32_t value)
+{
+ dbus_int32_t dbus_value = value;
+
+ return sbus_iterator_write_basic(iterator, DBUS_TYPE_INT32, &dbus_value);
+}
+
+errno_t sbus_iterator_write_u(DBusMessageIter *iterator,
+ uint32_t value)
+{
+ dbus_uint32_t dbus_value = value;
+
+ return sbus_iterator_write_basic(iterator, DBUS_TYPE_UINT32, &dbus_value);
+}
+
+errno_t sbus_iterator_write_x(DBusMessageIter *iterator,
+ int64_t value)
+{
+ dbus_int64_t dbus_value = value;
+
+ return sbus_iterator_write_basic(iterator, DBUS_TYPE_INT64, &dbus_value);
+}
+
+errno_t sbus_iterator_write_t(DBusMessageIter *iterator,
+ uint64_t value)
+{
+ dbus_uint64_t dbus_value = value;
+
+ return sbus_iterator_write_basic(iterator, DBUS_TYPE_UINT64, &dbus_value);
+}
+
+errno_t sbus_iterator_write_d(DBusMessageIter *iterator,
+ double value)
+{
+ return sbus_iterator_write_basic(iterator, DBUS_TYPE_DOUBLE, &value);
+}
+
+errno_t sbus_iterator_write_s(DBusMessageIter *iterator,
+ const char *value)
+{
+ return sbus_iterator_write_string(iterator, DBUS_TYPE_STRING, value, "");
+}
+
+errno_t sbus_iterator_write_S(DBusMessageIter *iterator,
+ char *value)
+{
+ return sbus_iterator_write_string(iterator, DBUS_TYPE_STRING, value, "");
+}
+
+errno_t sbus_iterator_write_o(DBusMessageIter *iterator,
+ const char *value)
+{
+ return sbus_iterator_write_string(iterator, DBUS_TYPE_OBJECT_PATH,
+ value, "/");
+}
+
+errno_t sbus_iterator_write_O(DBusMessageIter *iterator,
+ char *value)
+{
+ return sbus_iterator_write_string(iterator, DBUS_TYPE_OBJECT_PATH,
+ value, "/");
+}
+
+errno_t sbus_iterator_write_ay(DBusMessageIter *iterator,
+ uint8_t *value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_BYTE,
+ uint8_t, value);
+}
+
+errno_t sbus_iterator_write_ab(DBusMessageIter *iterator,
+ bool *value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_BOOLEAN,
+ bool, value);
+}
+
+errno_t sbus_iterator_write_an(DBusMessageIter *iterator,
+ int16_t *value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_INT16,
+ int16_t, value);
+}
+
+errno_t sbus_iterator_write_aq(DBusMessageIter *iterator,
+ uint16_t *value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_UINT16,
+ uint16_t, value);
+}
+
+errno_t sbus_iterator_write_ai(DBusMessageIter *iterator,
+ int32_t *value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_INT32,
+ int32_t, value);
+}
+
+errno_t sbus_iterator_write_au(DBusMessageIter *iterator,
+ uint32_t *value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_UINT32,
+ uint32_t, value);
+}
+
+errno_t sbus_iterator_write_ax(DBusMessageIter *iterator,
+ int64_t *value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_INT64,
+ int64_t, value);
+}
+
+errno_t sbus_iterator_write_at(DBusMessageIter *iterator,
+ uint64_t *value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_UINT64,
+ uint64_t, value);
+}
+
+errno_t sbus_iterator_write_ad(DBusMessageIter *iterator,
+ double *value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_DOUBLE,
+ double, value);
+}
+
+errno_t sbus_iterator_write_as(DBusMessageIter *iterator,
+ const char **value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_STRING,
+ const char *, value);
+}
+
+errno_t sbus_iterator_write_aS(DBusMessageIter *iterator,
+ char **value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_STRING,
+ char *, value);
+}
+
+errno_t sbus_iterator_write_ao(DBusMessageIter *iterator,
+ const char **value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_OBJECT_PATH,
+ const char *, value);
+}
+
+errno_t sbus_iterator_write_aO(DBusMessageIter *iterator,
+ char **value)
+{
+ return sbus_iterator_write_basic_array(iterator, DBUS_TYPE_OBJECT_PATH,
+ char *, value);
+}
diff --git a/src/sbus/interface/sbus_iterator_writers.h b/src/sbus/interface/sbus_iterator_writers.h
new file mode 100644
index 0000000..ec0662e
--- /dev/null
+++ b/src/sbus/interface/sbus_iterator_writers.h
@@ -0,0 +1,126 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SBUS_ITERATOR_WRITERS_H_
+#define _SBUS_ITERATOR_WRITERS_H_
+
+#include <stdint.h>
+#include <dbus/dbus.h>
+
+#include "util/util.h"
+
+/* Generic writers to be used in custom type handlers. */
+
+errno_t
+_sbus_iterator_write_basic_array(DBusMessageIter *iterator,
+ int dbus_type,
+ int element_size,
+ int array_length,
+ void *value_ptr);
+
+#define sbus_iterator_write_basic_array(iterator, dbus_type, c_type, source) \
+ _sbus_iterator_write_basic_array((iterator), (dbus_type), \
+ sizeof(c_type), -1, (void*)(source))
+
+#define sbus_iterator_write_basic_array_len(iterator, dbus_type, c_type, source, length) \
+ _sbus_iterator_write_basic_array((iterator), (dbus_type), \
+ sizeof(c_type), (length), (void*)(source))
+
+/* Basic types. */
+
+errno_t sbus_iterator_write_y(DBusMessageIter *iterator,
+ uint8_t value);
+
+errno_t sbus_iterator_write_b(DBusMessageIter *iterator,
+ bool value);
+
+errno_t sbus_iterator_write_n(DBusMessageIter *iterator,
+ int16_t value);
+
+errno_t sbus_iterator_write_q(DBusMessageIter *iterator,
+ uint16_t value);
+
+errno_t sbus_iterator_write_i(DBusMessageIter *iterator,
+ int32_t value);
+
+errno_t sbus_iterator_write_u(DBusMessageIter *iterator,
+ uint32_t value);
+
+errno_t sbus_iterator_write_x(DBusMessageIter *iterator,
+ int64_t value);
+
+errno_t sbus_iterator_write_t(DBusMessageIter *iterator,
+ uint64_t value);
+
+errno_t sbus_iterator_write_d(DBusMessageIter *iterator,
+ double value);
+
+errno_t sbus_iterator_write_s(DBusMessageIter *iterator,
+ const char *value);
+
+errno_t sbus_iterator_write_S(DBusMessageIter *iterator,
+ char *value);
+
+errno_t sbus_iterator_write_o(DBusMessageIter *iterator,
+ const char *value);
+
+errno_t sbus_iterator_write_O(DBusMessageIter *iterator,
+ char *value);
+
+errno_t sbus_iterator_write_ay(DBusMessageIter *iterator,
+ uint8_t *value);
+
+errno_t sbus_iterator_write_ab(DBusMessageIter *iterator,
+ bool *value);
+
+errno_t sbus_iterator_write_an(DBusMessageIter *iterator,
+ int16_t *value);
+
+errno_t sbus_iterator_write_aq(DBusMessageIter *iterator,
+ uint16_t *value);
+
+errno_t sbus_iterator_write_ai(DBusMessageIter *iterator,
+ int32_t *value);
+
+errno_t sbus_iterator_write_au(DBusMessageIter *iterator,
+ uint32_t *value);
+
+errno_t sbus_iterator_write_ax(DBusMessageIter *iterator,
+ int64_t *value);
+
+errno_t sbus_iterator_write_at(DBusMessageIter *iterator,
+ uint64_t *value);
+
+errno_t sbus_iterator_write_ad(DBusMessageIter *iterator,
+ double *value);
+
+errno_t sbus_iterator_write_as(DBusMessageIter *iterator,
+ const char **value);
+
+errno_t sbus_iterator_write_aS(DBusMessageIter *iterator,
+ char **value);
+
+errno_t sbus_iterator_write_ao(DBusMessageIter *iterator,
+ const char **value);
+
+errno_t sbus_iterator_write_aO(DBusMessageIter *iterator,
+ char **value);
+
+#endif /* _SBUS_ITERATOR_WRITERS_H_ */
diff --git a/src/sbus/interface/sbus_properties.c b/src/sbus/interface/sbus_properties.c
new file mode 100644
index 0000000..8be933c
--- /dev/null
+++ b/src/sbus/interface/sbus_properties.c
@@ -0,0 +1,894 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <dbus/dbus.h>
+
+#include "util/util.h"
+#include "sbus/sbus_request.h"
+#include "sbus/sbus_private.h"
+#include "sbus/interface/sbus_iterator_readers.h"
+#include "sbus/interface/sbus_iterator_writers.h"
+#include "sbus/interface_dbus/sbus_dbus_server.h"
+
+static errno_t
+sbus_open_variant(DBusMessageIter *parent,
+ DBusMessageIter *sub,
+ const char *type)
+{
+ dbus_bool_t dbret;
+
+ dbret = dbus_message_iter_open_container(parent, DBUS_TYPE_VARIANT,
+ type, sub);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ return EOK;
+}
+
+static errno_t
+sbus_open_dict(DBusMessageIter *parent,
+ DBusMessageIter *sub)
+{
+ dbus_bool_t dbret;
+
+ dbret = dbus_message_iter_open_container(parent, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ sub);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ return EOK;
+}
+
+static errno_t
+sbus_open_dict_entry(DBusMessageIter *parent,
+ DBusMessageIter *sub)
+{
+ dbus_bool_t dbret;
+
+ dbret = dbus_message_iter_open_container(parent, DBUS_TYPE_DICT_ENTRY,
+ NULL, sub);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ return EOK;
+}
+
+static errno_t
+sbus_close_iterator(DBusMessageIter *parent,
+ DBusMessageIter *sub)
+{
+ dbus_bool_t dbret;
+
+ dbret = dbus_message_iter_close_container(parent, sub);
+ if (!dbret) {
+ return EIO;
+ }
+
+ return EOK;
+}
+
+static errno_t
+sbus_create_dummy_message(TALLOC_CTX *mem_ctx,
+ DBusMessage **_msg,
+ DBusMessageIter *_write_iter)
+{
+ DBusMessage *msg;
+ errno_t ret;
+
+ msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
+ if (msg == NULL) {
+ return ENOMEM;
+ }
+
+ /* Set fake serial number for reply. */
+ dbus_message_set_serial(msg, 1);
+
+ ret = sbus_message_bound(mem_ctx, msg);
+ if (ret != EOK) {
+ dbus_message_unref(msg);
+ return ret;
+ }
+
+ dbus_message_iter_init_append(msg, _write_iter);
+
+ *_msg = msg;
+
+ return EOK;
+}
+
+static errno_t
+sbus_copy_iterator_value(DBusMessageIter *from,
+ DBusMessageIter *to);
+
+static errno_t
+sbus_copy_iterator_fixed_array(DBusMessageIter *from,
+ DBusMessageIter *to,
+ int type)
+{
+ DBusMessageIter from_sub;
+ DBusMessageIter to_sub;
+ dbus_bool_t dbret;
+ const char *typestr;
+ void *fixed;
+ int count;
+
+ typestr = dbus_message_type_to_string(type);
+ if (typestr == NULL) {
+ return ERR_INTERNAL;
+ }
+
+ dbret = dbus_message_iter_open_container(to, DBUS_TYPE_ARRAY,
+ typestr, &to_sub);
+ if (!dbret) {
+ return EIO;
+ }
+
+ dbus_message_iter_recurse(from, &from_sub);
+ dbus_message_iter_get_fixed_array(&from_sub, &fixed, &count);
+
+ dbret = dbus_message_iter_append_fixed_array(&to_sub, type, &fixed, count);
+ if (!dbret) {
+ goto fail;
+ }
+
+ dbret = dbus_message_iter_close_container(to, &to_sub);
+ if (!dbret) {
+ goto fail;
+ }
+
+ return EOK;
+
+fail:
+ dbus_message_iter_abandon_container(to, &to_sub);
+ return EIO;
+}
+
+static errno_t
+sbus_copy_iterator_container(DBusMessageIter *from,
+ DBusMessageIter *to,
+ int type)
+{
+ DBusMessageIter from_sub;
+ DBusMessageIter to_sub;
+ const char *signature;
+ dbus_bool_t dbret;
+ errno_t ret;
+
+ dbus_message_iter_recurse(from, &from_sub);
+
+ if (type == DBUS_TYPE_DICT_ENTRY) {
+ /* This is a special case. Dictionary entries do not have any specific
+ * signature when we open their container. */
+ signature = NULL;
+ } else {
+ signature = dbus_message_iter_get_signature(&from_sub);
+ if (signature == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ dbret = dbus_message_iter_open_container(to, type, signature, &to_sub);
+ if (!dbret) {
+ return EIO;
+ }
+
+ ret = sbus_copy_iterator_value(&from_sub, &to_sub);
+ if (ret != EOK) {
+ ret = EIO;
+ goto done;
+ }
+
+ dbret = dbus_message_iter_close_container(to, &to_sub);
+ if (!dbret) {
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ dbus_message_iter_abandon_container(to, &to_sub);
+ }
+
+ return ret;
+}
+
+static errno_t
+sbus_copy_iterator_value(DBusMessageIter *from,
+ DBusMessageIter *to)
+{
+ void *basic;
+ dbus_bool_t dbret;
+ int element_type;
+ int type;
+ errno_t ret;
+
+ do {
+ type = dbus_message_iter_get_arg_type(from);
+
+ if (type == DBUS_TYPE_INVALID) {
+ /* We have reached the end of the message. */
+ return EOK;
+ }
+
+ /* If this is a basic type, we just write it to its destination. */
+ if (dbus_type_is_basic(type)) {
+ dbus_message_iter_get_basic(from, &basic);
+ dbret = dbus_message_iter_append_basic(to, type, &basic);
+ if (!dbret) {
+ return EIO;
+ }
+
+ continue;
+ }
+
+ if (type == DBUS_TYPE_ARRAY) {
+ element_type = dbus_message_iter_get_element_type(from);
+
+ /* Fixed types can be copied at once. Otherwise we treat it
+ * as any other container. */
+ if (dbus_type_is_fixed(element_type)) {
+ ret = sbus_copy_iterator_fixed_array(from, to, element_type);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ continue;
+ }
+ }
+
+ /* If this is a container, we need to descend into it and open
+ * this container in the destination iterator. */
+ if (dbus_type_is_container(type)) {
+ ret = sbus_copy_iterator_container(from, to, type);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ continue;
+ }
+
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected type [%d]\n", type);
+ return ERR_INTERNAL;
+ } while (dbus_message_iter_next(from));
+
+ return EOK;
+}
+
+static errno_t
+sbus_copy_message_to_dictionary(const char *name,
+ DBusMessage *msg,
+ DBusMessageIter *to)
+{
+ DBusMessageIter entry;
+ DBusMessageIter from;
+ dbus_bool_t dbret;
+ errno_t ret;
+
+ /* Open dictionary entry iterator. */
+ ret = sbus_open_dict_entry(to, &entry);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ /* Append property name as key. */
+ ret = sbus_iterator_write_s(&entry, name);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Open message iterator for reading. */
+ dbret = dbus_message_iter_init(msg, &from);
+ if (!dbret) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sbus_copy_iterator_value(&from, &entry);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sbus_close_iterator(to, &entry);
+
+done:
+ if (ret != EOK) {
+ dbus_message_iter_abandon_container(to, &entry);
+ }
+
+ return ret;
+}
+
+static errno_t
+sbus_request_property(TALLOC_CTX *mem_ctx,
+ struct sbus_connection *conn,
+ struct sbus_router *router,
+ const struct sbus_sender *sender,
+ enum sbus_property_access access,
+ const char *destination,
+ const char *path,
+ const char *interface_name,
+ const char *property_name,
+ struct sbus_request **_sbus_req,
+ const struct sbus_property **_property)
+{
+ const struct sbus_property *property;
+ struct sbus_request *sbus_req;
+ struct sbus_interface *iface;
+ enum sbus_request_type type;
+
+ iface = sbus_router_paths_lookup(router->paths, path, interface_name);
+ if (iface == NULL) {
+ return ERR_SBUS_UNKNOWN_INTERFACE;
+ }
+
+ property = sbus_interface_find_property(iface, access, property_name);
+ if (property == NULL) {
+ return ERR_SBUS_UNKNOWN_PROPERTY;
+ }
+
+ switch (access) {
+ case SBUS_PROPERTY_READABLE:
+ type = SBUS_REQUEST_PROPERTY_GET;
+ break;
+ case SBUS_PROPERTY_WRITABLE:
+ type = SBUS_REQUEST_PROPERTY_SET;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ sbus_req = sbus_request_create(mem_ctx, conn, type, destination,
+ interface_name, property_name, path);
+ if (sbus_req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create request data!\n");
+ return ENOMEM;
+ }
+
+ sbus_req->sender = sbus_sender_copy(sbus_req, sender);
+ if (sbus_req->sender == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to copy sender data!\n");
+ talloc_free(sbus_req);
+ return ENOMEM;
+ }
+
+ *_sbus_req = sbus_req;
+ *_property = property;
+
+ return EOK;
+}
+
+struct sbus_properties_get_state {
+ struct {
+ DBusMessageIter *root;
+ DBusMessageIter variant;
+ } iter;
+};
+
+static void sbus_properties_get_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+sbus_properties_get_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sbus_request *sbus_req,
+ struct sbus_router *router,
+ const char *interface_name,
+ const char *property_name,
+ DBusMessageIter *write_iterator)
+{
+ struct sbus_properties_get_state *state;
+ const struct sbus_property *property;
+ struct sbus_request *property_req;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ errno_t ret;
+
+ DEBUG(SSSDBG_TRACE_ALL, "Requesting property: %s.%s of %s\n",
+ interface_name, property_name, sbus_req->path);
+
+ req = tevent_req_create(mem_ctx, &state, struct sbus_properties_get_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
+ return NULL;
+ }
+
+ ret = sbus_request_property(state, sbus_req->conn, router, sbus_req->sender,
+ SBUS_PROPERTY_READABLE, sbus_req->destination,
+ sbus_req->path, interface_name, property_name,
+ &property_req, &property);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot request property %s.%s [%d]: %s\n",
+ interface_name, property_name, ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = sbus_check_access(router->conn, property_req);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ state->iter.root = write_iterator;
+ ret = sbus_open_variant(state->iter.root, &state->iter.variant,
+ property->type);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ subreq = property->invoker.issue(state, ev, property_req,
+ NULL, /* no keygen */
+ &property->handler,
+ NULL, /* no read iterator*/
+ &state->iter.variant,
+ NULL /* no key */);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, sbus_properties_get_done, req);
+
+ ret = EAGAIN;
+
+done:
+ if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void
+sbus_properties_get_done(struct tevent_req *subreq)
+{
+ struct sbus_properties_get_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sbus_properties_get_state);
+
+ ret = sbus_invoker_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ dbus_message_iter_abandon_container(state->iter.root,
+ &state->iter.variant);
+ goto done;
+ }
+
+ ret = sbus_close_iterator(state->iter.root, &state->iter.variant);
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static errno_t
+sbus_properties_get_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+struct sbus_properties_getall_state {
+ struct tevent_context *ev;
+ struct sbus_router *router;
+ struct sbus_request *sbus_req;
+ const char *interface_name;
+
+ struct {
+ DBusMessageIter *root;
+ DBusMessageIter dict;
+ DBusMessageIter entry;
+ } iter;
+
+ struct {
+ DBusMessage *msg;
+ DBusMessageIter write_iter;
+ } dummy;
+
+ const struct sbus_property *properties;
+ struct {
+ const struct sbus_property *current;
+ size_t index;
+ } property;
+};
+
+static errno_t sdap_properties_getall_next(struct tevent_req *req);
+static void sbus_properties_getall_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+sbus_properties_getall_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sbus_request *sbus_req,
+ struct sbus_router *router,
+ const char *interface_name,
+ DBusMessageIter *write_iterator)
+{
+ struct sbus_properties_getall_state *state;
+ struct sbus_interface *iface;
+ struct tevent_req *req;
+ errno_t ret;
+
+ DEBUG(SSSDBG_TRACE_ALL, "Requesting all properties: %s of %s\n",
+ interface_name, sbus_req->path);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct sbus_properties_getall_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
+ return NULL;
+ }
+
+ iface = sbus_router_paths_lookup(router->paths, sbus_req->path,
+ interface_name);
+ if (iface == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unknown interface: %s\n", interface_name);
+ ret = ERR_SBUS_UNKNOWN_INTERFACE;
+ goto done;
+ }
+
+ state->ev = ev;
+ state->router = router;
+ state->sbus_req = sbus_req;
+ state->interface_name = interface_name;
+ state->properties = iface->properties;
+ state->iter.root = write_iterator;
+
+ /* Open array of <key, value> pairs. */
+ ret = sbus_open_dict(state->iter.root, &state->iter.dict);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sdap_properties_getall_next(req);
+ if (ret == EOK) {
+ /* There were no properties to return, we must close the container
+ * so an empty result is sent back to the caller. */
+ ret = sbus_close_iterator(state->iter.root, &state->iter.dict);
+ goto done;
+ } else if (ret != EAGAIN) {
+ dbus_message_iter_abandon_container(state->iter.root,
+ &state->iter.dict);
+ }
+
+ ret = EAGAIN;
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ } else if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static errno_t
+sdap_properties_getall_next(struct tevent_req *req)
+{
+ struct sbus_properties_getall_state *state;
+ const struct sbus_property *property;
+ struct tevent_req *subreq;
+ errno_t ret;
+
+ state = tevent_req_data(req, struct sbus_properties_getall_state);
+
+ /* There are no properties available. */
+ if (state->properties == NULL) {
+ return EOK;
+ }
+
+ do {
+ property = &state->properties[state->property.index];
+ state->property.current = property;
+ state->property.index++;
+
+ /* There are no more properties available. */
+ if (property->name == NULL) {
+ return EOK;
+ }
+
+ /* We are interested only in readable properties. */
+ } while (property->access != SBUS_PROPERTY_READABLE);
+
+ /* Create new message that we will use to fake an Get method request.
+ * We will then copy its reply to the GetAll dictionary. */
+ ret = sbus_create_dummy_message(state, &state->dummy.msg,
+ &state->dummy.write_iter);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ subreq = sbus_properties_get_send(state, state->ev, state->sbus_req,
+ state->router, state->interface_name,
+ property->name, &state->dummy.write_iter);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+
+ tevent_req_set_callback(subreq, sbus_properties_getall_done, req);
+
+ return EAGAIN;
+}
+
+static void sbus_properties_getall_done(struct tevent_req *subreq)
+{
+ struct sbus_properties_getall_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sbus_properties_getall_state);
+
+ ret = sbus_properties_get_recv(state, subreq);
+ talloc_zfree(subreq);
+ switch (ret) {
+ case EOK:
+ ret = sbus_copy_message_to_dictionary(state->property.current->name,
+ state->dummy.msg,
+ &state->iter.dict);
+ if (ret != EOK) {
+ goto done;
+ }
+ break;
+ case ENOENT:
+ case EACCES:
+ case EPERM:
+ /* These errors are not fatal. We will just skip this property. */
+ DEBUG(SSSDBG_TRACE_FUNC, "Unable to get property %s.%s [%d]: %s\n",
+ state->interface_name, state->property.current->name,
+ ret, sss_strerror(ret));
+ break;
+ default:
+ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get property %s.%s [%d]: %s\n",
+ state->interface_name, state->property.current->name,
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ dbus_message_unref(state->dummy.msg);
+ ret = sdap_properties_getall_next(req);
+ if (ret == EAGAIN) {
+ /* Continue with next property. */
+ return;
+ } else if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sbus_close_iterator(state->iter.root, &state->iter.dict);
+ if (ret != EOK) {
+ goto done;
+ }
+
+done:
+ if (ret != EOK) {
+ dbus_message_iter_abandon_container(state->iter.root,
+ &state->iter.dict);
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static errno_t
+sbus_properties_getall_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+static errno_t
+sbus_properties_set_parse(TALLOC_CTX *mem_ctx,
+ DBusMessageIter *read_iter,
+ const char **_interface_name,
+ const char **_property_name)
+{
+ const char *interface_name;
+ const char *property_name;
+ errno_t ret;
+
+ ret = sbus_iterator_read_s(mem_ctx, read_iter, &interface_name);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sbus_iterator_read_s(mem_ctx, read_iter, &property_name);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_interface_name = interface_name;
+ *_property_name = property_name;
+
+ return EOK;
+}
+
+struct sbus_properties_set_state {
+ DBusMessageIter variant_iterator;
+};
+
+static void sbus_properties_set_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+sbus_properties_set_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sbus_request *sbus_req,
+ struct sbus_router *router,
+ DBusMessageIter *read_iterator)
+{
+ struct sbus_properties_set_state *state;
+ const struct sbus_property *property;
+ struct sbus_request *property_req;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ const char *interface_name;
+ const char *property_name;
+ char *signature;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct sbus_properties_set_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
+ return NULL;
+ }
+
+ ret = sbus_properties_set_parse(state, read_iterator, &interface_name,
+ &property_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to parse input message [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_ALL, "Setting property: %s.%s of %s\n",
+ interface_name, property_name, sbus_req->path);
+
+ ret = sbus_request_property(state, sbus_req->conn, router, sbus_req->sender,
+ SBUS_PROPERTY_WRITABLE, sbus_req->destination,
+ sbus_req->path, interface_name, property_name,
+ &property_req, &property);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sbus_check_access(router->conn, property_req);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ if (dbus_message_iter_get_arg_type(read_iterator) != DBUS_TYPE_VARIANT) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Setter argument is not inside variant!\n");
+ ret = ERR_SBUS_INVALID_TYPE;
+ goto done;
+ }
+
+ /* Recurse into variant to get iterator for new property value. */
+ dbus_message_iter_recurse(read_iterator, &state->variant_iterator);
+ signature = dbus_message_iter_get_signature(&state->variant_iterator);
+ if (strcmp(property->type, signature) != 0) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ subreq = property->invoker.issue(state, ev, property_req,
+ NULL, /* no keygen */
+ &property->handler,
+ &state->variant_iterator,
+ NULL, /* no write iterator*/
+ NULL /* no key */);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, sbus_properties_set_done, req);
+
+ ret = EAGAIN;
+
+done:
+ if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void
+sbus_properties_set_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ ret = sbus_invoker_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static errno_t
+sbus_properties_set_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+errno_t
+sbus_register_properties(struct sbus_router *router)
+{
+
+ SBUS_INTERFACE(iface,
+ org_freedesktop_DBus_Properties,
+ SBUS_METHODS(
+ SBUS_ASYNC(METHOD, org_freedesktop_DBus_Properties, Get,
+ sbus_properties_get_send, sbus_properties_get_recv,
+ router),
+ SBUS_ASYNC(METHOD, org_freedesktop_DBus_Properties, Set,
+ sbus_properties_set_send, sbus_properties_set_recv,
+ router),
+ SBUS_ASYNC(METHOD, org_freedesktop_DBus_Properties, GetAll,
+ sbus_properties_getall_send, sbus_properties_getall_recv,
+ router)
+ ),
+ SBUS_WITHOUT_SIGNALS,
+ SBUS_WITHOUT_PROPERTIES
+ );
+
+ struct sbus_path paths[] = {
+ {"/", &iface},
+ {"/*", &iface},
+ {NULL, NULL}
+ };
+
+ return sbus_router_add_path_map(router, paths);
+}
diff --git a/src/sbus/interface/sbus_properties_parser.c b/src/sbus/interface/sbus_properties_parser.c
new file mode 100644
index 0000000..2a94493
--- /dev/null
+++ b/src/sbus/interface/sbus_properties_parser.c
@@ -0,0 +1,198 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+#include <talloc.h>
+
+#include "sbus/sbus_private.h"
+#include "sbus/interface/sbus_iterator_readers.h"
+#include "sbus/interface/sbus_iterator_writers.h"
+
+static errno_t
+sbus_parse_get_value(TALLOC_CTX *mem_ctx,
+ sbus_value_reader_fn reader,
+ sbus_value_reader_talloc_fn reader_talloc,
+ DBusMessageIter *iter,
+ void *_value_ptr)
+{
+ DBusMessageIter variant;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
+ return ERR_SBUS_INVALID_TYPE;
+ }
+
+ dbus_message_iter_recurse(iter, &variant);
+
+ if (reader != NULL) {
+ return reader(&variant, _value_ptr);
+ }
+
+ return reader_talloc(mem_ctx, &variant, _value_ptr);
+}
+
+errno_t
+sbus_parse_get_message(TALLOC_CTX *mem_ctx,
+ sbus_value_reader_fn reader,
+ sbus_value_reader_talloc_fn reader_talloc,
+ DBusMessage *msg,
+ void *_value_ptr)
+{
+ DBusMessageIter iterator;
+
+ dbus_message_iter_init(msg, &iterator);
+
+ return sbus_parse_get_value(mem_ctx, reader, reader_talloc,
+ &iterator, _value_ptr);
+}
+
+static errno_t
+sbus_parse_getall_name(struct sbus_parse_getall_table *table,
+ DBusMessageIter *dict_iter,
+ struct sbus_parse_getall_table **_property)
+{
+ const char *name;
+ int type;
+ int i;
+
+ type = dbus_message_iter_get_arg_type(dict_iter);
+ if (type != DBUS_TYPE_STRING) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected type [%d]\n", type);
+ return ERR_SBUS_INVALID_TYPE;
+ }
+
+ dbus_message_iter_get_basic(dict_iter, &name);
+
+ for (i = 0; table[i].name != NULL; i++) {
+ if (strcmp(table[i].name, name) == 0) {
+ *_property = &table[i];
+ return EOK;
+ }
+ }
+
+ DEBUG(SSSDBG_MINOR_FAILURE, "Unknown property [%s], skipping...\n", name);
+ *_property = NULL;
+
+ return EOK;
+}
+
+static errno_t
+sbus_parse_getall_dict_entry(TALLOC_CTX *mem_ctx,
+ struct sbus_parse_getall_table *table,
+ DBusMessageIter *dict_iter)
+{
+ struct sbus_parse_getall_table *property;
+ dbus_bool_t dbret;
+ errno_t ret;
+
+ ret = sbus_parse_getall_name(table, dict_iter, &property);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ dbret = dbus_message_iter_next(dict_iter);
+ if (!dbret) {
+ return ERR_SBUS_INVALID_TYPE;
+ }
+
+ if (property == NULL) {
+ return EOK;
+ }
+
+ ret = sbus_parse_get_value(mem_ctx, property->reader,
+ property->reader_talloc, dict_iter,
+ property->destination);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *(property->is_set) = true;
+
+ return EOK;
+}
+
+static errno_t
+sbus_parse_getall_array(TALLOC_CTX *mem_ctx,
+ struct sbus_parse_getall_table *table,
+ DBusMessageIter *array_iter)
+{
+ DBusMessageIter dict_iter;
+ errno_t ret;
+ int type;
+
+ do {
+ type = dbus_message_iter_get_arg_type(array_iter);
+
+ switch (type) {
+ case DBUS_TYPE_INVALID:
+ /* We have reached the end of the array. */
+ return EOK;
+ case DBUS_TYPE_DICT_ENTRY:
+ dbus_message_iter_recurse(array_iter, &dict_iter);
+ ret = sbus_parse_getall_dict_entry(mem_ctx, table, &dict_iter);
+ if (ret != EOK) {
+ return ret;
+ }
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected type [%d]\n", type);
+ return ERR_SBUS_INVALID_TYPE;
+ }
+ } while (dbus_message_iter_next(array_iter));
+
+ return EOK;
+}
+
+errno_t
+sbus_parse_getall_message(TALLOC_CTX *mem_ctx,
+ struct sbus_parse_getall_table *table,
+ DBusMessage *msg)
+{
+ DBusMessageIter array_iter;
+ DBusMessageIter iter;
+ errno_t ret;
+ int type;
+
+ dbus_message_iter_init(msg, &iter);
+
+ type = dbus_message_iter_get_arg_type(&iter);
+
+ switch (type) {
+ case DBUS_TYPE_INVALID:
+ /* Empty message. */
+ return EOK;
+ case DBUS_TYPE_ARRAY:
+ dbus_message_iter_recurse(&iter, &array_iter);
+ ret = sbus_parse_getall_array(mem_ctx, table, &array_iter);
+ if (ret != EOK) {
+ return ret;
+ }
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected type [%d]\n", type);
+ return ERR_SBUS_INVALID_TYPE;
+ }
+
+ if (dbus_message_iter_has_next(&iter)) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid GetAll reply\n");
+ return ERR_SBUS_INVALID_TYPE;
+ }
+
+ return EOK;
+}
diff --git a/src/sbus/interface/sbus_std_signals.c b/src/sbus/interface/sbus_std_signals.c
new file mode 100644
index 0000000..c9afe44
--- /dev/null
+++ b/src/sbus/interface/sbus_std_signals.c
@@ -0,0 +1,65 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2017 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "sbus/sbus_request.h"
+#include "sbus/sbus_private.h"
+#include "sbus/interface_dbus/sbus_dbus_server.h"
+
+static errno_t
+sbus_name_owner_changed(TALLOC_CTX *mem_ctx,
+ struct sbus_request *sbus_req,
+ struct sbus_connection *conn,
+ const char *name,
+ const char *new_owner,
+ const char *old_owner)
+{
+ DEBUG(SSSDBG_TRACE_ALL, "Name of owner %s has changed from "
+ "[%s] to [%s]\n", name, old_owner, new_owner);
+
+ /* Delete any existing sender information since it is now obsolete. */
+ sbus_senders_delete(conn->senders, name);
+
+ return EOK;
+}
+
+static errno_t
+sbus_name_acquired(TALLOC_CTX *mem_ctx,
+ struct sbus_request *sbus_req,
+ struct sbus_connection *conn,
+ const char *name)
+{
+ DEBUG(SSSDBG_TRACE_FUNC, "D-Bus name acquired: %s\n", name);
+
+ return EOK;
+}
+
+errno_t
+sbus_register_standard_signals(struct sbus_connection *conn)
+{
+ struct sbus_listener listeners[] = SBUS_LISTENERS(
+ SBUS_LISTEN_SYNC(org_freedesktop_DBus, NameOwnerChanged,
+ DBUS_PATH_DBUS, sbus_name_owner_changed, conn),
+ SBUS_LISTEN_SYNC(org_freedesktop_DBus, NameAcquired,
+ DBUS_PATH_DBUS, sbus_name_acquired, conn)
+ );
+
+ return sbus_router_listen_map(conn, listeners);
+}