summaryrefslogtreecommitdiffstats
path: root/src/sbus/interface/sbus_properties.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sbus/interface/sbus_properties.c')
-rw-r--r--src/sbus/interface/sbus_properties.c894
1 files changed, 894 insertions, 0 deletions
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);
+}