LCOV - code coverage report
Current view: top level - sbus - sssd_dbus_interface.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 110 478 23.0 %
Date: 2016-06-29 Functions: 8 30 26.7 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Pavel Březina <pbrezina@redhat.com>
       4             : 
       5             :     Copyright (C) 2014 Red Hat
       6             : 
       7             :     This program is free software; you can redistribute it and/or modify
       8             :     it under the terms of the GNU General Public License as published by
       9             :     the Free Software Foundation; either version 3 of the License, or
      10             :     (at your option) any later version.
      11             : 
      12             :     This program is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :     GNU General Public License for more details.
      16             : 
      17             :     You should have received a copy of the GNU General Public License
      18             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include <talloc.h>
      22             : #include <dbus/dbus.h>
      23             : #include <dhash.h>
      24             : 
      25             : #include "util/util.h"
      26             : #include "sbus/sssd_dbus.h"
      27             : #include "sbus/sssd_dbus_meta.h"
      28             : #include "sbus/sssd_dbus_private.h"
      29             : 
      30             : static struct sbus_interface *
      31           0 : sbus_iface_list_lookup(struct sbus_interface_list *list,
      32             :                        const char *iface)
      33             : {
      34             :     struct sbus_interface_list *item;
      35             : 
      36           0 :     DLIST_FOR_EACH(item, list) {
      37           0 :         if (strcmp(item->interface->vtable->meta->name, iface) == 0) {
      38           0 :             return item->interface;
      39             :         }
      40             :     }
      41             : 
      42           0 :     return NULL;
      43             : }
      44             : 
      45             : static errno_t
      46           0 : sbus_iface_list_copy(TALLOC_CTX *mem_ctx,
      47             :                      struct sbus_interface_list *list,
      48             :                      struct sbus_interface_list **_copy)
      49             : {
      50             :     TALLOC_CTX *list_ctx;
      51           0 :     struct sbus_interface_list *new_list = NULL;
      52             :     struct sbus_interface_list *new_item;
      53             :     struct sbus_interface_list *item;
      54             :     errno_t ret;
      55             : 
      56           0 :     if (list == NULL) {
      57           0 :         *_copy = NULL;
      58           0 :         return EOK;
      59             :     }
      60             : 
      61           0 :     list_ctx = talloc_new(mem_ctx);
      62           0 :     if (list_ctx == NULL) {
      63           0 :         return ENOMEM;
      64             :     }
      65             : 
      66           0 :     DLIST_FOR_EACH(item, list) {
      67           0 :         if (sbus_iface_list_lookup(new_list,
      68           0 :                item->interface->vtable->meta->name) != NULL) {
      69             :             /* already in list */
      70           0 :             continue;
      71             :         }
      72             : 
      73           0 :         new_item = talloc_zero(list_ctx, struct sbus_interface_list);
      74           0 :         if (new_item == NULL) {
      75           0 :             ret = ENOMEM;
      76           0 :             goto done;
      77             :         }
      78             : 
      79           0 :         new_item->interface = item->interface;
      80           0 :         DLIST_ADD(new_list, new_item);
      81             :     }
      82             : 
      83           0 :     *_copy = new_list;
      84           0 :     ret = EOK;
      85             : 
      86             : done:
      87           0 :     if (ret != EOK) {
      88           0 :         talloc_free(list_ctx);
      89             :     }
      90             : 
      91           0 :     return ret;
      92             : }
      93             : 
      94             : /**
      95             :  * Object paths that represent all objects under the path:
      96             :  * /org/object/path/~* (without tilda)
      97             :  */
      98           0 : static bool sbus_opath_is_subtree(const char *path)
      99             : {
     100             :     size_t len;
     101             : 
     102           0 :     len = strlen(path);
     103             : 
     104           0 :     if (len < 2) {
     105           0 :         return false;
     106             :     }
     107             : 
     108           0 :     return path[len - 2] == '/' && path[len - 1] == '*';
     109             : }
     110             : 
     111             : /**
     112             :  * If the path represents a subtree object path, this function will
     113             :  * remove /~* from the end.
     114             :  */
     115           0 : static char *sbus_opath_get_base_path(TALLOC_CTX *mem_ctx,
     116             :                                       const char *object_path)
     117             : {
     118             :     char *tree_path;
     119             :     size_t len;
     120             : 
     121           0 :     tree_path = talloc_strdup(mem_ctx, object_path);
     122           0 :     if (tree_path == NULL) {
     123           0 :         return NULL;
     124             :     }
     125             : 
     126           0 :     if (!sbus_opath_is_subtree(tree_path)) {
     127           0 :         return tree_path;
     128             :     }
     129             : 
     130             :     /* replace / only if it is not a root path (only slash) */
     131           0 :     len = strlen(tree_path);
     132           0 :     tree_path[len - 1] = '\0';
     133           0 :     tree_path[len - 2] = (len - 2 != 0) ? '\0' : '/';
     134             : 
     135           0 :     return tree_path;
     136             : }
     137             : 
     138           0 : static char *sbus_opath_parent_subtree(TALLOC_CTX *mem_ctx,
     139             :                                        const char *path)
     140             : {
     141             :     char *subtree;
     142             :     char *slash;
     143             : 
     144             :     /* first remove /~* from the end, stop when we have reached the root i.e.
     145             :      * subtree == "/" */
     146           0 :     subtree = sbus_opath_get_base_path(mem_ctx, path);
     147           0 :     if (subtree == NULL || subtree[1] == '\0') {
     148           0 :         return NULL;
     149             :     }
     150             : 
     151             :     /* Find the first separator and replace the part with asterisk. */
     152           0 :     slash = strrchr(subtree, '/');
     153           0 :     if (slash == NULL) {
     154             :         /* we cannot continue up */
     155           0 :         talloc_free(subtree);
     156           0 :         return NULL;
     157             :     }
     158             : 
     159           0 :     if (*(slash + 1) == '\0') {
     160             :         /* this object path is invalid since it cannot end with slash */
     161           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid object path '%s'?\n", path);
     162           0 :         talloc_free(subtree);
     163           0 :         return NULL;
     164             :     }
     165             : 
     166             :     /* because object path cannot end with / there is enough space for
     167             :      * asterisk and terminating zero */
     168           0 :     *(slash + 1) = '*';
     169           0 :     *(slash + 2) = '\0';
     170             : 
     171           0 :     return subtree;
     172             : }
     173             : 
     174             : /**
     175             :  * The following path related functions are based on similar code in
     176             :  * storaged, just tailored to use talloc instead of glib
     177             :  */
     178             : char *
     179           7 : sbus_opath_escape_part(TALLOC_CTX *mem_ctx,
     180             :                        const char *object_path_part)
     181             : {
     182             :     size_t n;
     183           7 :     char *safe_path = NULL;
     184           7 :     TALLOC_CTX *tmp_ctx = NULL;
     185             : 
     186             :     /* The path must be valid */
     187           7 :     if (object_path_part == NULL) {
     188           1 :         return NULL;
     189             :     }
     190             : 
     191           6 :     tmp_ctx = talloc_new(NULL);
     192           6 :     if (tmp_ctx == NULL) {
     193           0 :         return NULL;
     194             :     }
     195             : 
     196           6 :     safe_path = talloc_strdup(tmp_ctx, "");
     197           6 :     if (safe_path == NULL) {
     198           0 :         goto done;
     199             :     }
     200             : 
     201             :     /* Special case for an empty string */
     202           6 :     if (strcmp(object_path_part, "") == 0) {
     203             :         /* the for loop would just fall through */
     204           1 :         safe_path = talloc_asprintf_append_buffer(safe_path, "_");
     205           1 :         if (safe_path == NULL) {
     206           0 :             goto done;
     207             :         }
     208             :     }
     209             : 
     210          61 :     for (n = 0; object_path_part[n]; n++) {
     211          55 :         int c = object_path_part[n];
     212             :         /* D-Bus spec says:
     213             :          * *
     214             :          * * Each element must only contain the ASCII characters
     215             :          * "[A-Z][a-z][0-9]_"
     216             :          * */
     217          55 :         if ((c >= 'A' && c <= 'Z')
     218          55 :                 || (c >= 'a' && c <= 'z')
     219           4 :                 || (c >= '0' && c <= '9')) {
     220          51 :             safe_path = talloc_asprintf_append_buffer(safe_path, "%c", c);
     221         102 :             if (safe_path == NULL) {
     222           0 :                 goto done;
     223             :             }
     224             :         } else {
     225           4 :             safe_path = talloc_asprintf_append_buffer(safe_path, "_%02x", c);
     226           4 :             if (safe_path == NULL) {
     227           0 :                 goto done;
     228             :             }
     229             :         }
     230             :     }
     231             : 
     232           6 :     safe_path = talloc_steal(mem_ctx, safe_path);
     233             : 
     234             : done:
     235           6 :     talloc_free(tmp_ctx);
     236           6 :     return safe_path;
     237             : }
     238             : 
     239          12 : static inline int unhexchar(char c)
     240             : {
     241          12 :     if (c >= '0' && c <= '9') {
     242           6 :         return c - '0';
     243             :     }
     244             : 
     245           6 :     if (c >= 'a' && c <= 'f') {
     246           6 :         return c - 'a' + 10;
     247             :     }
     248             : 
     249           0 :     if (c >= 'A' && c <= 'F') {
     250           0 :         return c - 'A' + 10;
     251             :     }
     252             : 
     253           0 :     return -1;
     254             : }
     255             : 
     256             : char *
     257          20 : sbus_opath_unescape_part(TALLOC_CTX *mem_ctx,
     258             :                          const char *object_path_part)
     259             : {
     260             :     char *safe_path;
     261             :     const char *p;
     262             :     int a, b, c;
     263          20 :     TALLOC_CTX *tmp_ctx = NULL;
     264             : 
     265          20 :     tmp_ctx = talloc_new(NULL);
     266          20 :     if (tmp_ctx == NULL) {
     267           0 :         return NULL;
     268             :     }
     269             : 
     270          20 :     safe_path = talloc_strdup(tmp_ctx, "");
     271          20 :     if (safe_path == NULL) {
     272           0 :         goto done;
     273             :     }
     274             : 
     275             :     /* Special case for the empty string */
     276          20 :     if (strcmp(object_path_part, "_") == 0) {
     277           1 :         safe_path = talloc_steal(mem_ctx, safe_path);
     278           1 :         goto done;
     279             :     }
     280             : 
     281         157 :     for (p = object_path_part; *p; p++) {
     282         139 :         if (*p == '_') {
     283             :             /* There must be at least two more chars after underscore */
     284           7 :             if (p[1] == '\0' || p[2] == '\0') {
     285           1 :                 safe_path = NULL;
     286           1 :                 goto done;
     287             :             }
     288             : 
     289           6 :             if ((a = unhexchar(p[1])) < 0
     290           6 :                     || (b = unhexchar(p[2])) < 0) {
     291             :                 /* Invalid escape code, let's take it literal then */
     292           0 :                 c = '_';
     293             :             } else {
     294           6 :                 c = ((a << 4) | b);
     295           6 :                 p += 2;
     296             :             }
     297             :         } else  {
     298         132 :             c = *p;
     299             :         }
     300             : 
     301         138 :         safe_path = talloc_asprintf_append_buffer(safe_path, "%c", c);
     302         138 :         if (safe_path == NULL) {
     303           0 :             goto done;
     304             :         }
     305             :     }
     306             : 
     307          18 :     safe_path = talloc_steal(mem_ctx, safe_path);
     308             : 
     309             : done:
     310          20 :     talloc_free(tmp_ctx);
     311          20 :     return safe_path;
     312             : }
     313             : 
     314             : char *
     315           2 : _sbus_opath_compose(TALLOC_CTX *mem_ctx,
     316             :                     const char *base,
     317             :                     const char *part, ...)
     318             : {
     319             :     char *safe_part;
     320           2 :     char *path = NULL;
     321             :     va_list va;
     322             : 
     323           2 :     if (base == NULL) {
     324           0 :         DEBUG(SSSDBG_OP_FAILURE, "Wrong object path base!\n");
     325           0 :         return NULL;
     326             :     }
     327             : 
     328           2 :     path = talloc_strdup(mem_ctx, base);
     329           2 :     if (path == NULL) return NULL;
     330             : 
     331           2 :     va_start(va, part);
     332           6 :     while (part != NULL) {
     333           2 :         safe_part = sbus_opath_escape_part(mem_ctx, part);
     334           2 :         if (safe_part == NULL) {
     335           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not add [%s] to objpath\n", part);
     336           0 :             goto fail;
     337             :         }
     338             : 
     339           2 :         path = talloc_asprintf_append(path, "/%s", safe_part);
     340           2 :         talloc_free(safe_part);
     341           2 :         if (path == NULL) {
     342           0 :             goto fail;
     343             :         }
     344             : 
     345           2 :         part = va_arg(va, const char *);
     346             :     }
     347           2 :     va_end(va);
     348             : 
     349           2 :     return path;
     350             : 
     351             : fail:
     352           0 :     va_end(va);
     353           0 :     talloc_free(path);
     354           0 :     return NULL;
     355             : }
     356             : 
     357             : errno_t
     358           7 : sbus_opath_decompose(TALLOC_CTX *mem_ctx,
     359             :                      const char *object_path,
     360             :                      const char *prefix,
     361             :                      char ***_components,
     362             :                      size_t *_len)
     363             : {
     364             :     TALLOC_CTX *tmp_ctx;
     365             :     const char *path;
     366             :     char **decomposed;
     367             :     char **unescaped;
     368             :     errno_t ret;
     369             :     int len;
     370             :     int i;
     371             : 
     372           7 :     tmp_ctx = talloc_new(NULL);
     373           7 :     if (tmp_ctx == NULL) {
     374           0 :         return ENOMEM;
     375             :     }
     376             : 
     377             :     /* Strip prefix from the path. */
     378           7 :     if (prefix != NULL) {
     379           3 :         path = sbus_opath_strip_prefix(object_path, prefix);
     380           3 :         if (path == NULL) {
     381           1 :             ret = ERR_SBUS_INVALID_PATH;
     382           1 :             goto done;
     383             :         }
     384             :     } else {
     385           4 :         path = object_path;
     386             :     }
     387             : 
     388             :     /* Split the string using / as delimiter. */
     389           6 :     split_on_separator(tmp_ctx, path, '/', true, true, &decomposed, &len);
     390             : 
     391             :     /* Unescape parts. */
     392           6 :     unescaped = talloc_zero_array(tmp_ctx, char *, len + 1);
     393           6 :     if (unescaped == NULL) {
     394           0 :         ret = ENOMEM;
     395           0 :         goto done;
     396             :     }
     397             : 
     398          19 :     for (i = 0; i < len; i++) {
     399          13 :         unescaped[i] = sbus_opath_unescape_part(unescaped, decomposed[i]);
     400          13 :         if (unescaped[i] == NULL) {
     401           0 :             ret = ENOMEM;
     402           0 :             goto done;
     403             :         }
     404             :     }
     405             : 
     406           6 :     if (_components != NULL) {
     407           6 :         *_components = talloc_steal(mem_ctx, unescaped);
     408             :     }
     409             : 
     410           6 :     if (_len != NULL) {
     411           6 :         *_len = len;
     412             :     }
     413             : 
     414           6 :     ret = EOK;
     415             : 
     416             : done:
     417           7 :     talloc_free(tmp_ctx);
     418           7 :     return ret;
     419             : }
     420             : 
     421             : errno_t
     422           2 : sbus_opath_decompose_exact(TALLOC_CTX *mem_ctx,
     423             :                            const char *object_path,
     424             :                            const char *prefix,
     425             :                            size_t expected,
     426             :                            char ***_components)
     427             : {
     428             :     char **components;
     429             :     size_t len;
     430             :     errno_t ret;
     431             : 
     432           2 :     ret = sbus_opath_decompose(mem_ctx, object_path, prefix,
     433             :                                &components, &len);
     434           2 :     if (ret != EOK) {
     435           0 :         return ret;
     436             :     }
     437             : 
     438           2 :     if (len != expected) {
     439           1 :         talloc_free(components);
     440           1 :         return ERR_SBUS_INVALID_PATH;
     441             :     }
     442             : 
     443           1 :     if (_components != NULL) {
     444           1 :         *_components = components;
     445             :     }
     446             : 
     447           1 :     return EOK;
     448             : }
     449             : 
     450             : const char *
     451           9 : sbus_opath_strip_prefix(const char *object_path,
     452             :                         const char *prefix)
     453             : {
     454           9 :     if (strncmp(object_path, prefix, strlen(prefix)) == 0) {
     455           6 :         return object_path + strlen(prefix);
     456             :     }
     457             : 
     458           3 :     return NULL;
     459             : }
     460             : 
     461             : char *
     462           4 : sbus_opath_get_object_name(TALLOC_CTX *mem_ctx,
     463             :                            const char *object_path,
     464             :                            const char *base_path)
     465             : {
     466             :     const char *name;
     467             : 
     468           4 :     name = sbus_opath_strip_prefix(object_path, base_path);
     469           4 :     if (name == NULL || name[0] == '\0') {
     470           2 :         return NULL;
     471             :     }
     472             : 
     473             :     /* if base_path did not end with / */
     474           2 :     if (name[0] == '/') {
     475           1 :         name = name + 1;
     476             :     }
     477             : 
     478           2 :     return sbus_opath_unescape_part(mem_ctx, name);
     479             : }
     480             : 
     481             : static void
     482           0 : sbus_opath_hash_delete_cb(hash_entry_t *item,
     483             :                           hash_destroy_enum deltype,
     484             :                           void *pvt)
     485             : {
     486             :     struct sbus_connection *conn;
     487             :     char *path;
     488             : 
     489           0 :     conn = talloc_get_type(pvt, struct sbus_connection);
     490           0 :     path = sbus_opath_get_base_path(NULL, item->key.str);
     491             : 
     492           0 :     dbus_connection_unregister_object_path(conn->dbus.conn, path);
     493           0 : }
     494             : 
     495             : errno_t
     496           0 : sbus_opath_hash_init(TALLOC_CTX *mem_ctx,
     497             :                      struct sbus_connection *conn,
     498             :                      hash_table_t **_table)
     499             : {
     500           0 :     return sss_hash_create_ex(mem_ctx, 10, _table, 0, 0, 0, 0,
     501             :                               sbus_opath_hash_delete_cb, conn);
     502             : }
     503             : 
     504             : static errno_t
     505           0 : sbus_opath_hash_add_iface(hash_table_t *table,
     506             :                           const char *object_path,
     507             :                           struct sbus_interface *iface,
     508             :                           bool *_path_known)
     509             : {
     510           0 :     TALLOC_CTX *tmp_ctx = NULL;
     511           0 :     struct sbus_interface_list *list = NULL;
     512           0 :     struct sbus_interface_list *item = NULL;
     513           0 :     const char *iface_name = iface->vtable->meta->name;
     514             :     hash_key_t key;
     515             :     hash_value_t value;
     516             :     bool path_known;
     517             :     errno_t ret;
     518             :     int hret;
     519             : 
     520           0 :     tmp_ctx = talloc_new(NULL);
     521           0 :     if (tmp_ctx == NULL) {
     522           0 :         return ENOMEM;
     523             :     }
     524             : 
     525           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Registering interface %s with path %s\n",
     526             :           iface_name, object_path);
     527             : 
     528             :     /* create new list item */
     529             : 
     530           0 :     item = talloc_zero(tmp_ctx, struct sbus_interface_list);
     531           0 :     if (item == NULL) {
     532           0 :         return ENOMEM;
     533             :     }
     534             : 
     535           0 :     item->interface = iface;
     536             : 
     537             :     /* first lookup existing list in hash table */
     538             : 
     539           0 :     key.type = HASH_KEY_STRING;
     540           0 :     key.str = talloc_strdup(tmp_ctx, object_path);
     541           0 :     if (key.str == NULL) {
     542           0 :         ret = ENOMEM;
     543           0 :         goto done;
     544             :     }
     545             : 
     546           0 :     hret = hash_lookup(table, &key, &value);
     547           0 :     if (hret == HASH_SUCCESS) {
     548             :         /* This object path has already some interface registered. We will
     549             :          * check for existence of the interface currently being added and
     550             :          * add it if missing. */
     551             : 
     552           0 :         path_known = true;
     553             : 
     554           0 :         list = talloc_get_type(value.ptr, struct sbus_interface_list);
     555           0 :         if (sbus_iface_list_lookup(list, iface_name) != NULL) {
     556           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Trying to register the same interface"
     557             :                   " twice: iface=%s, opath=%s\n", iface_name, object_path);
     558           0 :             ret = EEXIST;
     559           0 :             goto done;
     560             :         }
     561             : 
     562           0 :         DLIST_ADD_END(list, item, struct sbus_interface_list *);
     563           0 :         ret = EOK;
     564           0 :         goto done;
     565           0 :     } else if (hret != HASH_ERROR_KEY_NOT_FOUND) {
     566           0 :         ret = EIO;
     567           0 :         goto done;
     568             :     }
     569             : 
     570             :     /* otherwise create new hash entry and new list */
     571             : 
     572           0 :     path_known = false;
     573           0 :     list = item;
     574             : 
     575           0 :     value.type = HASH_VALUE_PTR;
     576           0 :     value.ptr = list;
     577             : 
     578           0 :     hret = hash_enter(table, &key, &value);
     579           0 :     if (hret != HASH_SUCCESS) {
     580           0 :         ret = EIO;
     581           0 :         goto done;
     582             :     }
     583             : 
     584           0 :     talloc_steal(table, key.str);
     585           0 :     ret = EOK;
     586             : 
     587             : done:
     588           0 :     if (ret == EOK) {
     589           0 :         talloc_steal(item, iface);
     590           0 :         talloc_steal(table, item);
     591           0 :         *_path_known = path_known;
     592             :     }
     593             : 
     594           0 :     talloc_free(tmp_ctx);
     595           0 :     return ret;
     596             : }
     597             : 
     598             : static bool
     599           0 : sbus_opath_hash_has_path(hash_table_t *table,
     600             :                          const char *object_path)
     601             : {
     602             :     hash_key_t key;
     603             : 
     604           0 :     key.type = HASH_KEY_STRING;
     605           0 :     key.str = discard_const(object_path);
     606             : 
     607           0 :     return hash_has_key(table, &key);
     608             : }
     609             : 
     610             : /**
     611             :  * First @object_path is looked up in @table, if it is not found it steps up
     612             :  * in the path hierarchy and try to lookup the parent node. This continues
     613             :  * until the root is reached.
     614             :  */
     615             : struct sbus_interface *
     616           0 : sbus_opath_hash_lookup_iface(hash_table_t *table,
     617             :                              const char *object_path,
     618             :                              const char *iface_name)
     619             : {
     620           0 :     TALLOC_CTX *tmp_ctx = NULL;
     621           0 :     struct sbus_interface_list *list = NULL;
     622           0 :     struct sbus_interface *iface = NULL;
     623           0 :     char *lookup_path = NULL;
     624             :     hash_key_t key;
     625             :     hash_value_t value;
     626             :     int hret;
     627             : 
     628           0 :     tmp_ctx = talloc_new(NULL);
     629           0 :     if (tmp_ctx == NULL) {
     630           0 :         return NULL;
     631             :     }
     632             : 
     633           0 :     lookup_path = talloc_strdup(tmp_ctx, object_path);
     634           0 :     if (lookup_path == NULL) {
     635           0 :         goto done;
     636             :     }
     637             : 
     638           0 :     while (lookup_path != NULL) {
     639           0 :         key.type = HASH_KEY_STRING;
     640           0 :         key.str = lookup_path;
     641             : 
     642           0 :         hret = hash_lookup(table, &key, &value);
     643           0 :         if (hret == HASH_SUCCESS) {
     644           0 :             list = talloc_get_type(value.ptr, struct sbus_interface_list);
     645           0 :             iface = sbus_iface_list_lookup(list, iface_name);
     646           0 :             if (iface != NULL) {
     647           0 :                 goto done;
     648             :             }
     649           0 :         } else if (hret != HASH_ERROR_KEY_NOT_FOUND) {
     650           0 :             DEBUG(SSSDBG_OP_FAILURE,
     651             :                   "Unable to search hash table: hret=%d\n", hret);
     652           0 :             iface = NULL;
     653           0 :             goto done;
     654             :         }
     655             : 
     656             :         /* we will not free lookup path since it is freed with tmp_ctx
     657             :          * and the object paths are supposed to be small */
     658           0 :         lookup_path = sbus_opath_parent_subtree(tmp_ctx, lookup_path);
     659             :     }
     660             : 
     661             : done:
     662           0 :     talloc_free(tmp_ctx);
     663           0 :     return iface;
     664             : }
     665             : 
     666             : /**
     667             :  * Acquire list of all interfaces that are supported on given object path.
     668             :  */
     669             : errno_t
     670           0 : sbus_opath_hash_lookup_supported(TALLOC_CTX *mem_ctx,
     671             :                                  hash_table_t *table,
     672             :                                  const char *object_path,
     673             :                                  struct sbus_interface_list **_list)
     674             : {
     675           0 :     TALLOC_CTX *tmp_ctx = NULL;
     676           0 :     TALLOC_CTX *list_ctx = NULL;
     677           0 :     struct sbus_interface_list *copy = NULL;
     678           0 :     struct sbus_interface_list *list = NULL;
     679           0 :     char *lookup_path = NULL;
     680             :     hash_key_t key;
     681             :     hash_value_t value;
     682             :     errno_t ret;
     683             :     int hret;
     684             : 
     685           0 :     tmp_ctx = talloc_new(NULL);
     686           0 :     if (tmp_ctx == NULL) {
     687           0 :         return ENOMEM;
     688             :     }
     689             : 
     690           0 :     list_ctx = talloc_new(tmp_ctx);
     691           0 :     if (list_ctx == NULL) {
     692           0 :         ret = ENOMEM;
     693           0 :         goto done;
     694             :     }
     695             : 
     696           0 :     lookup_path = talloc_strdup(tmp_ctx, object_path);
     697           0 :     if (lookup_path == NULL) {
     698           0 :         ret = ENOMEM;
     699           0 :         goto done;
     700             :     }
     701             : 
     702           0 :     while (lookup_path != NULL) {
     703           0 :         key.type = HASH_KEY_STRING;
     704           0 :         key.str = lookup_path;
     705             : 
     706           0 :         hret = hash_lookup(table, &key, &value);
     707           0 :         if (hret == HASH_SUCCESS) {
     708           0 :             ret = sbus_iface_list_copy(list_ctx, value.ptr, &copy);
     709           0 :             if (ret != EOK) {
     710           0 :                 goto done;
     711             :             }
     712             : 
     713           0 :             DLIST_CONCATENATE(list, copy, struct sbus_interface_list *);
     714           0 :         } else if (hret != HASH_ERROR_KEY_NOT_FOUND) {
     715           0 :             DEBUG(SSSDBG_OP_FAILURE,
     716             :                   "Unable to search hash table: hret=%d\n", hret);
     717           0 :             ret = EIO;
     718           0 :             goto done;
     719             :         }
     720             : 
     721             :         /* we will not free lookup path since it is freed with tmp_ctx
     722             :          * and the object paths are supposed to be small */
     723           0 :         lookup_path = sbus_opath_parent_subtree(tmp_ctx, lookup_path);
     724             :     }
     725             : 
     726           0 :     talloc_steal(mem_ctx, list_ctx);
     727           0 :     *_list = list;
     728           0 :     ret = EOK;
     729             : 
     730             : done:
     731           0 :     talloc_free(tmp_ctx);
     732           0 :     return ret;
     733             : }
     734             : 
     735             : errno_t
     736           0 : sbus_nodes_hash_init(TALLOC_CTX *mem_ctx,
     737             :                      struct sbus_connection *conn,
     738             :                      hash_table_t **_table)
     739             : {
     740           0 :     return sss_hash_create_ex(mem_ctx, 10, _table, 0, 0, 0, 0,
     741             :                               NULL, conn);
     742             : }
     743             : 
     744             : struct sbus_nodes_data {
     745             :     sbus_nodes_fn nodes_fn;
     746             :     void *handler_data;
     747             : };
     748             : 
     749             : static errno_t
     750           0 : sbus_nodes_hash_add(hash_table_t *table,
     751             :                     const char *object_path,
     752             :                     sbus_nodes_fn nodes_fn,
     753             :                     void *handler_data)
     754             : {
     755             :     TALLOC_CTX *tmp_ctx;
     756             :     struct sbus_nodes_data *data;
     757             :     hash_key_t key;
     758             :     hash_value_t value;
     759             :     errno_t ret;
     760             :     bool has_key;
     761             :     int hret;
     762             : 
     763           0 :     tmp_ctx = talloc_new(NULL);
     764           0 :     if (tmp_ctx == NULL) {
     765           0 :         return ENOMEM;
     766             :     }
     767             : 
     768           0 :     key.type = HASH_KEY_STRING;
     769           0 :     key.str = talloc_strdup(tmp_ctx, object_path);
     770           0 :     if (key.str == NULL) {
     771           0 :         return ENOMEM;
     772             :     }
     773             : 
     774           0 :     has_key = hash_has_key(table, &key);
     775           0 :     if (has_key) {
     776           0 :         ret = EEXIST;
     777           0 :         goto done;
     778             :     }
     779             : 
     780           0 :     data = talloc_zero(tmp_ctx, struct sbus_nodes_data);
     781           0 :     if (data == NULL) {
     782           0 :         ret = ENOMEM;
     783           0 :         goto done;
     784             :     }
     785             : 
     786           0 :     data->handler_data = handler_data;
     787           0 :     data->nodes_fn = nodes_fn;
     788             : 
     789           0 :     value.type = HASH_VALUE_PTR;
     790           0 :     value.ptr = data;
     791             : 
     792           0 :     hret = hash_enter(table, &key, &value);
     793           0 :     if (hret != HASH_SUCCESS) {
     794           0 :         ret = EIO;
     795           0 :         goto done;
     796             :     }
     797             : 
     798           0 :     talloc_steal(table, key.str);
     799           0 :     talloc_steal(table, data);
     800             : 
     801           0 :     ret = EOK;
     802             : 
     803             : done:
     804           0 :     talloc_free(tmp_ctx);
     805           0 :     return ret;
     806             : }
     807             : 
     808             : const char **
     809           0 : sbus_nodes_hash_lookup(TALLOC_CTX *mem_ctx,
     810             :                        hash_table_t *table,
     811             :                        const char *object_path)
     812             : {
     813             :     struct sbus_nodes_data *data;
     814             :     hash_key_t key;
     815             :     hash_value_t value;
     816             :     int hret;
     817             : 
     818           0 :     key.type = HASH_KEY_STRING;
     819           0 :     key.str = discard_const(object_path);
     820             : 
     821           0 :     hret = hash_lookup(table, &key, &value);
     822           0 :     if (hret == HASH_ERROR_KEY_NOT_FOUND) {
     823           0 :         return NULL;
     824           0 :     } else if (hret != HASH_SUCCESS) {
     825           0 :         DEBUG(SSSDBG_OP_FAILURE,
     826             :               "Unable to search hash table: hret=%d\n", hret);
     827           0 :         return NULL;
     828             :     }
     829             : 
     830           0 :     data = talloc_get_type(value.ptr, struct sbus_nodes_data);
     831             : 
     832           0 :     return data->nodes_fn(mem_ctx, object_path, data->handler_data);
     833             : }
     834             : 
     835             : static struct sbus_interface *
     836           0 : sbus_new_interface(TALLOC_CTX *mem_ctx,
     837             :                    const char *object_path,
     838             :                    struct sbus_vtable *iface_vtable,
     839             :                    void *handler_data)
     840             : {
     841             :     struct sbus_interface *intf;
     842             : 
     843           0 :     intf = talloc_zero(mem_ctx, struct sbus_interface);
     844           0 :     if (intf == NULL) {
     845           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Cannot allocate a new sbus_interface.\n");
     846           0 :         return NULL;
     847             :     }
     848             : 
     849           0 :     intf->path = talloc_strdup(intf, object_path);
     850           0 :     if (intf->path == NULL) {
     851           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Cannot duplicate object path.\n");
     852           0 :         talloc_free(intf);
     853           0 :         return NULL;
     854             :     }
     855             : 
     856           0 :     intf->vtable = iface_vtable;
     857           0 :     intf->handler_data = handler_data;
     858           0 :     return intf;
     859             : }
     860             : 
     861             : static DBusHandlerResult
     862             : sbus_message_handler(DBusConnection *dbus_conn,
     863             :                      DBusMessage *message,
     864             :                      void *user_data);
     865             : 
     866             : static errno_t
     867           0 : sbus_conn_register_path(struct sbus_connection *conn,
     868             :                         const char *path)
     869             : {
     870             :     static DBusObjectPathVTable vtable = {NULL, sbus_message_handler,
     871             :                                           NULL, NULL, NULL, NULL};
     872             :     DBusError error;
     873           0 :     char *reg_path = NULL;
     874             :     dbus_bool_t dbret;
     875             : 
     876           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Registering object path %s with D-Bus "
     877             :           "connection\n", path);
     878             : 
     879           0 :     if (sbus_opath_is_subtree(path)) {
     880           0 :         reg_path = sbus_opath_get_base_path(conn, path);
     881           0 :         if (reg_path == NULL) {
     882           0 :             return ENOMEM;
     883             :         }
     884             : 
     885             :         /* D-Bus does not allow to have both object path and fallback
     886             :          * registered. Since we handle the real message handlers ourselves
     887             :          * we will register fallback only in this case. */
     888           0 :         if (sbus_opath_hash_has_path(conn->managed_paths, reg_path)) {
     889           0 :             dbus_connection_unregister_object_path(conn->dbus.conn, reg_path);
     890             :         }
     891             : 
     892           0 :         dbret = dbus_connection_register_fallback(conn->dbus.conn, reg_path,
     893             :                                                   &vtable, conn);
     894           0 :         talloc_free(reg_path);
     895             :     } else {
     896           0 :         dbus_error_init(&error);
     897             : 
     898           0 :         dbret = dbus_connection_try_register_object_path(conn->dbus.conn, path,
     899             :                                                          &vtable, conn, &error);
     900             : 
     901           0 :         if (dbus_error_is_set(&error) &&
     902           0 :                 strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0) {
     903             :             /* A fallback is probably already registered. Just return. */
     904           0 :             dbus_error_free(&error);
     905           0 :             return EOK;
     906             :         }
     907             :     }
     908             : 
     909           0 :     if (!dbret) {
     910           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register object path "
     911             :               "%s with D-Bus connection.\n", path);
     912           0 :         return ENOMEM;
     913             :     }
     914             : 
     915           0 :     return EOK;
     916             : }
     917             : 
     918             : errno_t
     919           0 : sbus_conn_register_iface(struct sbus_connection *conn,
     920             :                          struct sbus_vtable *iface_vtable,
     921             :                          const char *object_path,
     922             :                          void *handler_data)
     923             : {
     924           0 :     struct sbus_interface *iface = NULL;
     925             :     bool path_known;
     926             :     errno_t ret;
     927             : 
     928           0 :     if (conn == NULL || iface_vtable == NULL || object_path == NULL) {
     929           0 :         return EINVAL;
     930             :     }
     931             : 
     932           0 :     iface = sbus_new_interface(conn, object_path, iface_vtable, handler_data);
     933           0 :     if (iface == NULL) {
     934           0 :         return ENOMEM;
     935             :     }
     936             : 
     937           0 :     ret = sbus_opath_hash_add_iface(conn->managed_paths, object_path, iface,
     938             :                                     &path_known);
     939           0 :     if (ret != EOK) {
     940           0 :         talloc_free(iface);
     941           0 :         return ret;
     942             :     }
     943             : 
     944           0 :     if (path_known) {
     945             :         /* this object path is already registered */
     946           0 :         return EOK;
     947             :     }
     948             : 
     949             :     /* if ret != EOK we will still leave iface in the table, since
     950             :      * we probably don't have enough memory to remove it correctly anyway */
     951             : 
     952           0 :     ret = sbus_conn_register_path(conn, object_path);
     953           0 :     if (ret != EOK) {
     954           0 :         return ret;
     955             :     }
     956             : 
     957             :     /* register standard interfaces with this object path as well */
     958           0 :     ret = sbus_conn_register_iface(conn, sbus_properties_vtable(),
     959             :                                    object_path, conn);
     960           0 :     if (ret != EOK) {
     961           0 :         return ret;
     962             :     }
     963             : 
     964           0 :     ret = sbus_conn_register_iface(conn, sbus_introspect_vtable(),
     965             :                                    object_path, conn);
     966           0 :     if (ret != EOK) {
     967           0 :         return ret;
     968             :     }
     969             : 
     970           0 :     return ret;
     971             : }
     972             : 
     973             : errno_t
     974           0 : sbus_conn_register_iface_map(struct sbus_connection *conn,
     975             :                              struct sbus_iface_map *map,
     976             :                              void *pvt)
     977             : {
     978             :     errno_t ret;
     979             :     int i;
     980             : 
     981           0 :     for (i = 0; map[i].path != NULL; i++) {
     982           0 :         ret = sbus_conn_register_iface(conn, map[i].vtable, map[i].path, pvt);
     983           0 :         if (ret != EOK) {
     984           0 :             return ret;
     985             :         }
     986             :     }
     987             : 
     988           0 :     return EOK;
     989             : }
     990             : 
     991             : void
     992           0 : sbus_conn_register_nodes(struct sbus_connection *conn,
     993             :                          const char *path,
     994             :                          sbus_nodes_fn nodes_fn,
     995             :                          void *data)
     996             : {
     997             :     errno_t ret;
     998             : 
     999           0 :     ret = sbus_nodes_hash_add(conn->nodes_fns, path, nodes_fn, data);
    1000           0 :     if (ret != EOK && ret != EEXIST) {
    1001           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Unable to register node function with "
    1002             :               "%s. Introspection may not work correctly.\n", path);
    1003             :     }
    1004           0 : }
    1005             : 
    1006             : errno_t
    1007           0 : sbus_conn_reregister_paths(struct sbus_connection *conn)
    1008             : {
    1009           0 :     hash_key_t *keys = NULL;
    1010             :     unsigned long count;
    1011             :     unsigned long i;
    1012             :     errno_t ret;
    1013             :     int hret;
    1014             : 
    1015           0 :     hret = hash_keys(conn->managed_paths, &count, &keys);
    1016           0 :     if (hret != HASH_SUCCESS) {
    1017           0 :         ret = ENOMEM;
    1018           0 :         goto done;
    1019             :     }
    1020             : 
    1021           0 :     for (i = 0; i < count; i++) {
    1022           0 :         ret = sbus_conn_register_path(conn, keys[i].str);
    1023           0 :         if (ret != EOK) {
    1024           0 :             goto done;
    1025             :         }
    1026             :     }
    1027             : 
    1028           0 :     ret = EOK;
    1029             : 
    1030             : done:
    1031           0 :     talloc_free(keys);
    1032           0 :     return ret;
    1033             : }
    1034             : 
    1035             : static void
    1036             : sbus_message_handler_got_caller_id(struct tevent_req *req);
    1037             : 
    1038             : static DBusHandlerResult
    1039           0 : sbus_message_handler(DBusConnection *dbus_conn,
    1040             :                      DBusMessage *message,
    1041             :                      void *handler_data)
    1042             : {
    1043             :     struct tevent_req *req;
    1044             :     struct sbus_connection *conn;
    1045             :     struct sbus_interface *iface;
    1046             :     struct sbus_request *sbus_req;
    1047             :     const struct sbus_method_meta *method;
    1048             :     const char *iface_name;
    1049             :     const char *method_name;
    1050             :     const char *path;
    1051             :     const char *sender;
    1052             : 
    1053           0 :     conn = talloc_get_type(handler_data, struct sbus_connection);
    1054             : 
    1055             :     /* header information */
    1056           0 :     iface_name = dbus_message_get_interface(message);
    1057           0 :     method_name = dbus_message_get_member(message);
    1058           0 :     path = dbus_message_get_path(message);
    1059           0 :     sender = dbus_message_get_sender(message);
    1060             : 
    1061           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Received SBUS method %s.%s on path %s\n",
    1062             :           iface_name, method_name, path);
    1063             : 
    1064             :     /* try to find the interface */
    1065           0 :     iface = sbus_opath_hash_lookup_iface(conn->managed_paths,
    1066             :                                          path, iface_name);
    1067           0 :     if (iface == NULL) {
    1068           0 :         goto fail;
    1069             :     }
    1070             : 
    1071           0 :     method = sbus_meta_find_method(iface->vtable->meta, method_name);
    1072           0 :     if (method == NULL || method->vtable_offset == 0) {
    1073             :         goto fail;
    1074             :     }
    1075             : 
    1076             :     /* we have a valid handler, create D-Bus request */
    1077           0 :     sbus_req = sbus_new_request(conn, iface, message);
    1078           0 :     if (sbus_req == NULL) {
    1079           0 :         return DBUS_HANDLER_RESULT_NEED_MEMORY;
    1080             :     }
    1081             : 
    1082           0 :     sbus_req->method = method;
    1083             : 
    1084             :     /* now get the sender ID */
    1085           0 :     req = sbus_get_sender_id_send(sbus_req, conn->ev, conn, sender);
    1086           0 :     if (req == NULL) {
    1087           0 :         talloc_free(sbus_req);
    1088           0 :         return DBUS_HANDLER_RESULT_NEED_MEMORY;
    1089             :     }
    1090           0 :     tevent_req_set_callback(req, sbus_message_handler_got_caller_id, sbus_req);
    1091             : 
    1092           0 :     return DBUS_HANDLER_RESULT_HANDLED;
    1093             : 
    1094             : fail: ;
    1095             :     DBusMessage *reply;
    1096             : 
    1097           0 :     DEBUG(SSSDBG_CRIT_FAILURE, "No matching handler found for method %s.%s "
    1098             :           "on path %s\n", iface_name, method_name, path);
    1099             : 
    1100           0 :     reply = dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, NULL);
    1101           0 :     sbus_conn_send_reply(conn, reply);
    1102             : 
    1103           0 :     return DBUS_HANDLER_RESULT_HANDLED;
    1104             : }
    1105             : 
    1106             : static void
    1107           0 : sbus_message_handler_got_caller_id(struct tevent_req *req)
    1108             : {
    1109             :     struct sbus_request *sbus_req;
    1110             :     const struct sbus_method_meta *method;
    1111             :     sbus_msg_handler_fn handler;
    1112             :     sbus_method_invoker_fn invoker;
    1113             :     void *pvt;
    1114             :     DBusError *error;
    1115             :     errno_t ret;
    1116             : 
    1117           0 :     sbus_req = tevent_req_callback_data(req, struct sbus_request);
    1118           0 :     method = sbus_req->method;
    1119             : 
    1120           0 :     ret = sbus_get_sender_id_recv(req, &sbus_req->client);
    1121           0 :     if (ret != EOK) {
    1122           0 :         error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to "
    1123             :                                "resolve caller's ID: %s\n", sss_strerror(ret));
    1124           0 :         sbus_request_fail_and_finish(sbus_req, error);
    1125           0 :         return;
    1126             :     }
    1127             : 
    1128           0 :     handler = VTABLE_FUNC(sbus_req->intf->vtable, method->vtable_offset);
    1129           0 :     invoker = method->invoker;
    1130           0 :     pvt = sbus_req->intf->handler_data;
    1131             : 
    1132           0 :     sbus_request_invoke_or_finish(sbus_req, handler, pvt, invoker);
    1133           0 :     return;
    1134             : }

Generated by: LCOV version 1.10