sssd_dbus_interface.c revision b742179ac0790068380618ab72a06af18544f09c
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor/*
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor Authors:
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor Pavel Březina <pbrezina@redhat.com>
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor Copyright (C) 2014 Red Hat
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor This program is free software; you can redistribute it and/or modify
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor it under the terms of the GNU General Public License as published by
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor the Free Software Foundation; either version 3 of the License, or
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor (at your option) any later version.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen
2e545ce2450a9953665f701bb05350f0d3f26275nd This program is distributed in the hope that it will be useful,
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen but WITHOUT ANY WARRANTY; without even the implied warranty of
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor GNU General Public License for more details.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor You should have received a copy of the GNU General Public License
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen along with this program. If not, see <http://www.gnu.org/licenses/>.
3f08db06526d6901aa08c110b5bc7dde6bc39905nd*/
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor#include <talloc.h>
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor#include <dbus/dbus.h>
3f08db06526d6901aa08c110b5bc7dde6bc39905nd#include <dhash.h>
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor#include "util/util.h"
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor#include "sbus/sssd_dbus.h"
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor#include "sbus/sssd_dbus_meta.h"
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung#include "sbus/sssd_dbus_private.h"
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorstatic struct sbus_interface *
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorsbus_iface_list_lookup(struct sbus_interface_list *list,
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *iface)
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor{
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor struct sbus_interface_list *item;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor DLIST_FOR_EACH(item, list) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor if (strcmp(item->interface->vtable->meta->name, iface) == 0) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor return item->interface;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor return NULL;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor}
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorstatic errno_t
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorsbus_iface_list_copy(TALLOC_CTX *mem_ctx,
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor struct sbus_interface_list *list,
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor struct sbus_interface_list **_copy)
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor{
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor TALLOC_CTX *list_ctx;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor struct sbus_interface_list *new_list = NULL;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor struct sbus_interface_list *new_item;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor struct sbus_interface_list *item;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor errno_t ret;
e40d2af13fd7ff120eda49cd327c68fbc16443e8sf
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor if (list == NULL) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor *_copy = NULL;
df135dbebadfdf65d0c45e181d6c19b84d17b7c6sf return EOK;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
7e9c796f2dc0dba993a817b3a58cfd56b4e511edwrowe list_ctx = talloc_new(mem_ctx);
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor if (list_ctx == NULL) {
ffb01336be79c64046b636e59fa8ddca8ec029edsf return ENOMEM;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor DLIST_FOR_EACH(item, list) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor if (sbus_iface_list_lookup(new_list,
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor item->interface->vtable->meta->name) != NULL) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor /* already in list */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor continue;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor new_item = talloc_zero(list_ctx, struct sbus_interface_list);
df135dbebadfdf65d0c45e181d6c19b84d17b7c6sf if (new_item == NULL) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor ret = ENOMEM;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor goto done;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor new_item->interface = item->interface;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor DLIST_ADD(new_list, new_item);
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh *_copy = new_list;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor ret = EOK;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzordone:
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor if (ret != EOK) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor talloc_free(list_ctx);
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
48c64aeceef385e19025b384bd719b2a9789592dnd return ret;
48c64aeceef385e19025b384bd719b2a9789592dnd}
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor/**
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * Object paths that represent all objects under the path:
1462ff536f1b939bb337766b2056109c29664c4erbowen * /org/object/path/~* (without tilda)
1462ff536f1b939bb337766b2056109c29664c4erbowen */
1462ff536f1b939bb337766b2056109c29664c4erbowenstatic bool sbus_opath_is_subtree(const char *path)
1462ff536f1b939bb337766b2056109c29664c4erbowen{
1462ff536f1b939bb337766b2056109c29664c4erbowen size_t len;
1462ff536f1b939bb337766b2056109c29664c4erbowen
1462ff536f1b939bb337766b2056109c29664c4erbowen len = strlen(path);
1462ff536f1b939bb337766b2056109c29664c4erbowen
25f8d56998acb95d39c62c489d72b92d8d29b765humbedooh if (len < 2) {
25f8d56998acb95d39c62c489d72b92d8d29b765humbedooh return false;
25f8d56998acb95d39c62c489d72b92d8d29b765humbedooh }
25f8d56998acb95d39c62c489d72b92d8d29b765humbedooh
25f8d56998acb95d39c62c489d72b92d8d29b765humbedooh return path[len - 2] == '/' && path[len - 1] == '*';
25f8d56998acb95d39c62c489d72b92d8d29b765humbedooh}
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
65a611af7093423efb91e5794b8887a527d4cf63trawick/**
65a611af7093423efb91e5794b8887a527d4cf63trawick * If the path represents a subtree object path, this function will
65a611af7093423efb91e5794b8887a527d4cf63trawick * remove /~* from the end.
65a611af7093423efb91e5794b8887a527d4cf63trawick */
65a611af7093423efb91e5794b8887a527d4cf63trawickstatic char *sbus_opath_get_base_path(TALLOC_CTX *mem_ctx,
65a611af7093423efb91e5794b8887a527d4cf63trawick const char *object_path)
65a611af7093423efb91e5794b8887a527d4cf63trawick{
65a611af7093423efb91e5794b8887a527d4cf63trawick char *tree_path;
65a611af7093423efb91e5794b8887a527d4cf63trawick size_t len;
65a611af7093423efb91e5794b8887a527d4cf63trawick
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor tree_path = talloc_strdup(mem_ctx, object_path);
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor if (tree_path == NULL) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor return NULL;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor if (!sbus_opath_is_subtree(tree_path)) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor return tree_path;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor /* replace / only if it is not a root path (only slash) */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor len = strlen(tree_path);
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor tree_path[len - 1] = '\0';
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor tree_path[len - 2] = (len - 2 != 0) ? '\0' : '/';
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor return tree_path;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor}
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzorstatic char *sbus_opath_parent_subtree(TALLOC_CTX *mem_ctx,
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor const char *path)
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor{
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor char *subtree;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor char *slash;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor /* first remove /~* from the end, stop when we have reached the root i.e.
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor * subtree == "/" */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor subtree = sbus_opath_get_base_path(mem_ctx, path);
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor if (subtree == NULL || subtree[1] == '\0') {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor return NULL;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor /* Find the first separator and replace the part with asterisk. */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor slash = strrchr(subtree, '/');
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor if (slash == NULL) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor /* we cannot continue up */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor talloc_free(subtree);
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor return NULL;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor }
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor if (*(slash + 1) == '\0') {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor /* this object path is invalid since it cannot end with slash */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor DEBUG(SSSDBG_CRIT_FAILURE, "Invalid object path '%s'?\n", path);
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor talloc_free(subtree);
e40d2af13fd7ff120eda49cd327c68fbc16443e8sf return NULL;
e40d2af13fd7ff120eda49cd327c68fbc16443e8sf }
e40d2af13fd7ff120eda49cd327c68fbc16443e8sf
1462ff536f1b939bb337766b2056109c29664c4erbowen /* because object path cannot end with / there is enough space for
1462ff536f1b939bb337766b2056109c29664c4erbowen * asterisk and terminating zero */
e40d2af13fd7ff120eda49cd327c68fbc16443e8sf *(slash + 1) = '*';
e40d2af13fd7ff120eda49cd327c68fbc16443e8sf *(slash + 2) = '\0';
e40d2af13fd7ff120eda49cd327c68fbc16443e8sf
e40d2af13fd7ff120eda49cd327c68fbc16443e8sf return subtree;
1462ff536f1b939bb337766b2056109c29664c4erbowen}
1462ff536f1b939bb337766b2056109c29664c4erbowen
1462ff536f1b939bb337766b2056109c29664c4erbowenstatic void
1462ff536f1b939bb337766b2056109c29664c4erbowensbus_opath_hash_delete_cb(hash_entry_t *item,
25f8d56998acb95d39c62c489d72b92d8d29b765humbedooh hash_destroy_enum deltype,
25f8d56998acb95d39c62c489d72b92d8d29b765humbedooh void *pvt)
1462ff536f1b939bb337766b2056109c29664c4erbowen{
1462ff536f1b939bb337766b2056109c29664c4erbowen struct sbus_connection *conn;
1462ff536f1b939bb337766b2056109c29664c4erbowen char *path;
1462ff536f1b939bb337766b2056109c29664c4erbowen
1462ff536f1b939bb337766b2056109c29664c4erbowen conn = talloc_get_type(pvt, struct sbus_connection);
1462ff536f1b939bb337766b2056109c29664c4erbowen path = sbus_opath_get_base_path(NULL, item->key.str);
1462ff536f1b939bb337766b2056109c29664c4erbowen
1462ff536f1b939bb337766b2056109c29664c4erbowen dbus_connection_unregister_object_path(conn->dbus.conn, path);
1462ff536f1b939bb337766b2056109c29664c4erbowen}
1462ff536f1b939bb337766b2056109c29664c4erbowen
1462ff536f1b939bb337766b2056109c29664c4erbowenerrno_t
1462ff536f1b939bb337766b2056109c29664c4erbowensbus_opath_hash_init(TALLOC_CTX *mem_ctx,
1462ff536f1b939bb337766b2056109c29664c4erbowen struct sbus_connection *conn,
1462ff536f1b939bb337766b2056109c29664c4erbowen hash_table_t **_table)
1462ff536f1b939bb337766b2056109c29664c4erbowen{
737a1f4117ce00c29a1b78b93db08e4a273ab2edtrawick return sss_hash_create_ex(mem_ctx, 10, _table, 0, 0, 0, 0,
737a1f4117ce00c29a1b78b93db08e4a273ab2edtrawick sbus_opath_hash_delete_cb, conn);
1462ff536f1b939bb337766b2056109c29664c4erbowen}
1462ff536f1b939bb337766b2056109c29664c4erbowen
1462ff536f1b939bb337766b2056109c29664c4erbowenstatic errno_t
1462ff536f1b939bb337766b2056109c29664c4erbowensbus_opath_hash_add_iface(hash_table_t *table,
1462ff536f1b939bb337766b2056109c29664c4erbowen const char *object_path,
1462ff536f1b939bb337766b2056109c29664c4erbowen struct sbus_interface *iface,
1462ff536f1b939bb337766b2056109c29664c4erbowen bool *_path_known)
1462ff536f1b939bb337766b2056109c29664c4erbowen{
1462ff536f1b939bb337766b2056109c29664c4erbowen TALLOC_CTX *tmp_ctx = NULL;
1462ff536f1b939bb337766b2056109c29664c4erbowen struct sbus_interface_list *list = NULL;
1462ff536f1b939bb337766b2056109c29664c4erbowen struct sbus_interface_list *item = NULL;
1462ff536f1b939bb337766b2056109c29664c4erbowen const char *iface_name = iface->vtable->meta->name;
1462ff536f1b939bb337766b2056109c29664c4erbowen hash_key_t key;
1462ff536f1b939bb337766b2056109c29664c4erbowen hash_value_t value;
1462ff536f1b939bb337766b2056109c29664c4erbowen bool path_known;
1462ff536f1b939bb337766b2056109c29664c4erbowen errno_t ret;
1462ff536f1b939bb337766b2056109c29664c4erbowen int hret;
1462ff536f1b939bb337766b2056109c29664c4erbowen
1462ff536f1b939bb337766b2056109c29664c4erbowen tmp_ctx = talloc_new(NULL);
1462ff536f1b939bb337766b2056109c29664c4erbowen if (tmp_ctx == NULL) {
1462ff536f1b939bb337766b2056109c29664c4erbowen return ENOMEM;
1462ff536f1b939bb337766b2056109c29664c4erbowen }
1462ff536f1b939bb337766b2056109c29664c4erbowen
1462ff536f1b939bb337766b2056109c29664c4erbowen DEBUG(SSSDBG_TRACE_FUNC, "Registering interface %s with path %s\n",
1462ff536f1b939bb337766b2056109c29664c4erbowen iface_name, object_path);
1462ff536f1b939bb337766b2056109c29664c4erbowen
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor /* create new list item */
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor item = talloc_zero(tmp_ctx, struct sbus_interface_list);
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung if (item == NULL) {
727872d18412fc021f03969b8641810d8896820bhumbedooh return ENOMEM;
0d0ba3a410038e179b695446bb149cce6264e0abnd }
727872d18412fc021f03969b8641810d8896820bhumbedooh
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh item->interface = iface;
0d0ba3a410038e179b695446bb149cce6264e0abnd
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh /* first lookup existing list in hash table */
727872d18412fc021f03969b8641810d8896820bhumbedooh
0d0ba3a410038e179b695446bb149cce6264e0abnd key.type = HASH_KEY_STRING;
0d0ba3a410038e179b695446bb149cce6264e0abnd key.str = talloc_strdup(tmp_ctx, object_path);
0d0ba3a410038e179b695446bb149cce6264e0abnd if (key.str == NULL) {
ac082aefa89416cbdc9a1836eaf3bed9698201c8humbedooh ret = ENOMEM;
0d0ba3a410038e179b695446bb149cce6264e0abnd goto done;
0d0ba3a410038e179b695446bb149cce6264e0abnd }
0d0ba3a410038e179b695446bb149cce6264e0abnd
727872d18412fc021f03969b8641810d8896820bhumbedooh hret = hash_lookup(table, &key, &value);
0d0ba3a410038e179b695446bb149cce6264e0abnd if (hret == HASH_SUCCESS) {
0d0ba3a410038e179b695446bb149cce6264e0abnd /* This object path has already some interface registered. We will
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh * check for existence of the interface currently being added and
07dc96d063d49299da433f84b5c5681da9bbdf68rbowen * add it if missing. */
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen
0d0ba3a410038e179b695446bb149cce6264e0abnd path_known = true;
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd list = talloc_get_type(value.ptr, struct sbus_interface_list);
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd if (sbus_iface_list_lookup(list, iface_name) != NULL) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor DEBUG(SSSDBG_MINOR_FAILURE, "Trying to register the same interface"
" twice: iface=%s, opath=%s\n", iface_name, object_path);
ret = EEXIST;
goto done;
}
DLIST_ADD_END(list, item, struct sbus_interface_list *);
ret = EOK;
goto done;
} else if (hret != HASH_ERROR_KEY_NOT_FOUND) {
ret = EIO;
goto done;
}
/* otherwise create new hash entry and new list */
path_known = false;
list = item;
value.type = HASH_VALUE_PTR;
value.ptr = list;
hret = hash_enter(table, &key, &value);
if (hret != HASH_SUCCESS) {
ret = EIO;
goto done;
}
talloc_steal(table, key.str);
ret = EOK;
done:
if (ret == EOK) {
talloc_steal(item, iface);
talloc_steal(table, item);
*_path_known = path_known;
} else {
talloc_free(item);
}
return ret;
}
static bool
sbus_opath_hash_has_path(hash_table_t *table,
const char *object_path)
{
hash_key_t key;
key.type = HASH_KEY_STRING;
key.str = discard_const(object_path);
return hash_has_key(table, &key);
}
/**
* First @object_path is looked up in @table, if it is not found it steps up
* in the path hierarchy and try to lookup the parent node. This continues
* until the root is reached.
*/
struct sbus_interface *
sbus_opath_hash_lookup_iface(hash_table_t *table,
const char *object_path,
const char *iface_name)
{
TALLOC_CTX *tmp_ctx = NULL;
struct sbus_interface_list *list = NULL;
struct sbus_interface *iface = NULL;
char *lookup_path = NULL;
hash_key_t key;
hash_value_t value;
int hret;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
return NULL;
}
lookup_path = talloc_strdup(tmp_ctx, object_path);
if (lookup_path == NULL) {
goto done;
}
while (lookup_path != NULL) {
key.type = HASH_KEY_STRING;
key.str = lookup_path;
hret = hash_lookup(table, &key, &value);
if (hret == HASH_SUCCESS) {
list = talloc_get_type(value.ptr, struct sbus_interface_list);
iface = sbus_iface_list_lookup(list, iface_name);
if (iface != NULL) {
goto done;
}
} else if (hret != HASH_ERROR_KEY_NOT_FOUND) {
DEBUG(SSSDBG_OP_FAILURE,
"Unable to search hash table: hret=%d\n", hret);
iface = NULL;
goto done;
}
/* we will not free lookup path since it is freed with tmp_ctx
* and the object paths are supposed to be small */
lookup_path = sbus_opath_parent_subtree(tmp_ctx, lookup_path);
}
done:
talloc_free(tmp_ctx);
return iface;
}
/**
* Acquire list of all interfaces that are supported on given object path.
*/
errno_t
sbus_opath_hash_lookup_supported(TALLOC_CTX *mem_ctx,
hash_table_t *table,
const char *object_path,
struct sbus_interface_list **_list)
{
TALLOC_CTX *tmp_ctx = NULL;
TALLOC_CTX *list_ctx = NULL;
struct sbus_interface_list *copy = NULL;
struct sbus_interface_list *list = NULL;
char *lookup_path = NULL;
hash_key_t key;
hash_value_t value;
errno_t ret;
int hret;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
return ENOMEM;
}
list_ctx = talloc_new(tmp_ctx);
if (list_ctx == NULL) {
ret = ENOMEM;
goto done;
}
lookup_path = talloc_strdup(tmp_ctx, object_path);
if (lookup_path == NULL) {
ret = ENOMEM;
goto done;
}
while (lookup_path != NULL) {
key.type = HASH_KEY_STRING;
key.str = lookup_path;
hret = hash_lookup(table, &key, &value);
if (hret == HASH_SUCCESS) {
ret = sbus_iface_list_copy(list_ctx, value.ptr, &copy);
if (ret != EOK) {
goto done;
}
DLIST_CONCATENATE(list, copy, struct sbus_interface_list *);
} else if (hret != HASH_ERROR_KEY_NOT_FOUND) {
DEBUG(SSSDBG_OP_FAILURE,
"Unable to search hash table: hret=%d\n", hret);
ret = EIO;
goto done;
}
/* we will not free lookup path since it is freed with tmp_ctx
* and the object paths are supposed to be small */
lookup_path = sbus_opath_parent_subtree(tmp_ctx, lookup_path);
}
talloc_steal(mem_ctx, list_ctx);
*_list = list;
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
static struct sbus_interface *
sbus_new_interface(TALLOC_CTX *mem_ctx,
const char *object_path,
struct sbus_vtable *iface_vtable,
void *instance_data)
{
struct sbus_interface *intf;
intf = talloc_zero(mem_ctx, struct sbus_interface);
if (intf == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE, "Cannot allocate a new sbus_interface.\n");
return NULL;
}
intf->path = talloc_strdup(intf, object_path);
if (intf->path == NULL) {
DEBUG(SSSDBG_FATAL_FAILURE, "Cannot duplicate object path.\n");
talloc_free(intf);
return NULL;
}
intf->vtable = iface_vtable;
intf->instance_data = instance_data;
return intf;
}
static DBusHandlerResult
sbus_message_handler(DBusConnection *dbus_conn,
DBusMessage *message,
void *user_data);
static errno_t
sbus_conn_register_path(struct sbus_connection *conn,
const char *path)
{
static DBusObjectPathVTable vtable = {NULL, sbus_message_handler,
NULL, NULL, NULL, NULL};
DBusError error;
char *reg_path = NULL;
dbus_bool_t dbret;
DEBUG(SSSDBG_TRACE_FUNC, "Registering object path %s with D-Bus "
"connection\n", path);
if (sbus_opath_is_subtree(path)) {
reg_path = sbus_opath_get_base_path(conn, path);
if (reg_path == NULL) {
return ENOMEM;
}
/* D-Bus does not allow to have both object path and fallback
* registered. Since we handle the real message handlers ourselves
* we will register fallback only in this case. */
if (sbus_opath_hash_has_path(conn->managed_paths, reg_path)) {
dbus_connection_unregister_object_path(conn->dbus.conn, reg_path);
}
dbret = dbus_connection_register_fallback(conn->dbus.conn, reg_path,
&vtable, conn);
talloc_free(reg_path);
} else {
dbus_error_init(&error);
dbret = dbus_connection_try_register_object_path(conn->dbus.conn, path,
&vtable, conn, &error);
if (dbus_error_is_set(&error) &&
strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0) {
/* A fallback is probably already registered. Just return. */
dbus_error_free(&error);
return EOK;
}
}
if (!dbret) {
DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register object path "
"%s with D-Bus connection.\n", path);
return ENOMEM;
}
return EOK;
}
errno_t
sbus_conn_register_iface(struct sbus_connection *conn,
struct sbus_vtable *iface_vtable,
const char *object_path,
void *pvt)
{
struct sbus_interface *iface = NULL;
bool path_known;
errno_t ret;
if (conn == NULL || iface_vtable == NULL || object_path == NULL) {
return EINVAL;
}
iface = sbus_new_interface(conn, object_path, iface_vtable, pvt);
if (iface == NULL) {
return ENOMEM;
}
ret = sbus_opath_hash_add_iface(conn->managed_paths, object_path, iface,
&path_known);
if (ret != EOK) {
talloc_free(iface);
return ret;
}
if (path_known) {
/* this object path is already registered */
return EOK;
}
/* if ret != EOK we will still leave iface in the table, since
* we probably don't have enough memory to remove it correctly anyway */
ret = sbus_conn_register_path(conn, object_path);
if (ret != EOK) {
return ret;
}
/* register standard interfaces with this object path as well */
ret = sbus_conn_register_iface(conn, sbus_properties_vtable(),
object_path, conn);
if (ret != EOK) {
return ret;
}
ret = sbus_conn_register_iface(conn, sbus_introspect_vtable(),
object_path, conn);
if (ret != EOK) {
return ret;
}
return ret;
}
errno_t
sbus_conn_reregister_paths(struct sbus_connection *conn)
{
hash_key_t *keys = NULL;
unsigned long count;
unsigned long i;
errno_t ret;
int hret;
hret = hash_keys(conn->managed_paths, &count, &keys);
if (hret != HASH_SUCCESS) {
ret = ENOMEM;
goto done;
}
for (i = 0; i < count; i++) {
ret = sbus_conn_register_path(conn, keys[i].str);
if (ret != EOK) {
goto done;
}
}
ret = EOK;
done:
talloc_free(keys);
return ret;
}
static void
sbus_message_handler_got_caller_id(struct tevent_req *req);
static DBusHandlerResult
sbus_message_handler(DBusConnection *dbus_conn,
DBusMessage *message,
void *user_data)
{
struct tevent_req *req;
struct sbus_connection *conn;
struct sbus_interface *iface;
struct sbus_request *sbus_req;
const struct sbus_method_meta *method;
const char *iface_name;
const char *method_name;
const char *path;
const char *sender;
conn = talloc_get_type(user_data, struct sbus_connection);
/* header information */
iface_name = dbus_message_get_interface(message);
method_name = dbus_message_get_member(message);
path = dbus_message_get_path(message);
sender = dbus_message_get_sender(message);
DEBUG(SSSDBG_TRACE_INTERNAL, "Received SBUS method %s.%s on path %s\n",
iface_name, method_name, path);
/* try to find the interface */
iface = sbus_opath_hash_lookup_iface(conn->managed_paths,
path, iface_name);
if (iface == NULL) {
goto fail;
}
method = sbus_meta_find_method(iface->vtable->meta, method_name);
if (method == NULL || method->vtable_offset == 0) {
goto fail;
}
/* we have a valid handler, create D-Bus request */
sbus_req = sbus_new_request(conn, iface, message);
if (sbus_req == NULL) {
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
sbus_req->method = method;
/* now get the sender ID */
req = sbus_get_sender_id_send(sbus_req, conn->ev, conn, sender);
if (req == NULL) {
talloc_free(sbus_req);
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
tevent_req_set_callback(req, sbus_message_handler_got_caller_id, sbus_req);
return DBUS_HANDLER_RESULT_HANDLED;
fail: ;
DBusMessage *reply;
DEBUG(SSSDBG_CRIT_FAILURE, "No matching handler found for method %s.%s "
"on path %s\n", iface_name, method_name, path);
reply = dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, NULL);
sbus_conn_send_reply(conn, reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
static void
sbus_message_handler_got_caller_id(struct tevent_req *req)
{
struct sbus_request *sbus_req;
const struct sbus_method_meta *method;
sbus_msg_handler_fn handler;
sbus_method_invoker_fn invoker;
void *pvt;
DBusError *error;
errno_t ret;
sbus_req = tevent_req_callback_data(req, struct sbus_request);
method = sbus_req->method;
ret = sbus_get_sender_id_recv(req, &sbus_req->client);
if (ret != EOK) {
error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to "
"resolve caller's ID: %s\n", sss_strerror(ret));
sbus_request_fail_and_finish(sbus_req, error);
return;
}
handler = VTABLE_FUNC(sbus_req->intf->vtable, method->vtable_offset);
invoker = method->invoker;
pvt = sbus_req->intf->instance_data;
sbus_request_invoke_or_finish(sbus_req, handler, pvt, invoker);
return;
}