LCOV - code coverage report
Current view: top level - db - sysdb_subdomains.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 341 538 63.4 %
Date: 2015-10-19 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    System Database - Sub-domain related calls
       5             : 
       6             :    Copyright (C) 2012 Jan Zeleny <jzeleny@redhat.com>
       7             :    Copyright (C) 2012 Sumit Bose <sbose@redhat.com>
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "util/util.h"
      24             : #include "db/sysdb_private.h"
      25             : 
      26          47 : struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
      27             :                                       struct sss_domain_info *parent,
      28             :                                       const char *name,
      29             :                                       const char *realm,
      30             :                                       const char *flat_name,
      31             :                                       const char *id,
      32             :                                       bool mpg,
      33             :                                       bool enumerate,
      34             :                                       const char *forest,
      35             :                                       uint32_t trust_direction)
      36             : {
      37             :     struct sss_domain_info *dom;
      38             :     bool inherit_option;
      39             : 
      40          47 :     DEBUG(SSSDBG_TRACE_FUNC,
      41             :           "Creating [%s] as subdomain of [%s]!\n", name, parent->name);
      42             : 
      43          47 :     dom = talloc_zero(mem_ctx, struct sss_domain_info);
      44          47 :     if (dom == NULL) {
      45           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
      46           0 :         return NULL;
      47             :     }
      48             : 
      49          47 :     dom->parent = parent;
      50             : 
      51             :     /* Sub-domains always have the same view as the parent */
      52          47 :     dom->has_views = parent->has_views;
      53          47 :     if (parent->view_name != NULL) {
      54           5 :         dom->view_name = talloc_strdup(dom, parent->view_name);
      55           5 :         if (dom->view_name == NULL) {
      56           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy parent's view name.\n");
      57           0 :             goto fail;
      58             :         }
      59             :     }
      60             : 
      61          47 :     dom->name = talloc_strdup(dom, name);
      62          47 :     if (dom->name == NULL) {
      63           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to copy domain name.\n");
      64           0 :         goto fail;
      65             :     }
      66             : 
      67          47 :     dom->provider = talloc_strdup(dom, parent->provider);
      68          47 :     if (dom->provider == NULL) {
      69           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to copy provider name.\n");
      70           0 :         goto fail;
      71             :     }
      72             : 
      73          47 :     dom->conn_name = talloc_strdup(dom, parent->conn_name);
      74          47 :     if (dom->conn_name == NULL) {
      75           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to copy connection name.\n");
      76           0 :         goto fail;
      77             :     }
      78             : 
      79          47 :     if (realm != NULL) {
      80          40 :         dom->realm = talloc_strdup(dom, realm);
      81          40 :         if (dom->realm == NULL) {
      82           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy realm name.\n");
      83           0 :             goto fail;
      84             :         }
      85             :     }
      86             : 
      87          47 :     if (flat_name != NULL) {
      88          40 :         dom->flat_name = talloc_strdup(dom, flat_name);
      89          40 :         if (dom->flat_name == NULL) {
      90           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy flat name.\n");
      91           0 :             goto fail;
      92             :         }
      93             :     }
      94             : 
      95          47 :     if (id != NULL) {
      96          40 :         dom->domain_id = talloc_strdup(dom, id);
      97          40 :         if (dom->domain_id == NULL) {
      98           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy id.\n");
      99           0 :             goto fail;
     100             :         }
     101             :     }
     102             : 
     103          47 :     if (forest != NULL) {
     104          23 :         dom->forest = talloc_strdup(dom, forest);
     105          23 :         if (dom->forest == NULL) {
     106           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy forest.\n");
     107           0 :             goto fail;
     108             :         }
     109             :     }
     110             : 
     111          47 :     dom->enumerate = enumerate;
     112          47 :     dom->fqnames = true;
     113          47 :     dom->mpg = mpg;
     114          47 :     dom->state = DOM_ACTIVE;
     115             : 
     116             :     /* If the parent domain filters out group members, the subdomain should
     117             :      * as well if configured */
     118          47 :     inherit_option = string_in_list(CONFDB_DOMAIN_IGNORE_GROUP_MEMBERS,
     119             :                                     parent->sd_inherit, false);
     120          47 :     if (inherit_option) {
     121           0 :         dom->ignore_group_members = parent->ignore_group_members;
     122             :     }
     123             : 
     124          47 :     dom->trust_direction = trust_direction;
     125             :     /* If the parent domain explicitly limits ID ranges, the subdomain
     126             :      * should honour the limits as well.
     127             :      */
     128          47 :     dom->id_min = parent->id_min ? parent->id_min : 0;
     129          47 :     dom->id_max = parent->id_max ? parent->id_max : 0xffffffff;
     130          47 :     dom->pwd_expiration_warning = parent->pwd_expiration_warning;
     131          47 :     dom->cache_credentials = parent->cache_credentials;
     132          47 :     dom->cache_credentials_min_ff_length =
     133          47 :                                         parent->cache_credentials_min_ff_length;
     134          47 :     dom->case_sensitive = false;
     135          47 :     dom->user_timeout = parent->user_timeout;
     136          47 :     dom->group_timeout = parent->group_timeout;
     137          47 :     dom->netgroup_timeout = parent->netgroup_timeout;
     138          47 :     dom->service_timeout = parent->service_timeout;
     139          47 :     dom->names = parent->names;
     140             : 
     141          47 :     dom->override_homedir = parent->override_homedir;
     142          47 :     dom->fallback_homedir = parent->fallback_homedir;
     143          47 :     dom->subdomain_homedir = parent->subdomain_homedir;
     144          47 :     dom->override_shell = parent->override_shell;
     145          47 :     dom->default_shell = parent->default_shell;
     146          47 :     dom->homedir_substr = parent->homedir_substr;
     147             : 
     148          47 :     if (parent->sysdb == NULL) {
     149           0 :         DEBUG(SSSDBG_OP_FAILURE, "Missing sysdb context in parent domain.\n");
     150           0 :         goto fail;
     151             :     }
     152          47 :     dom->sysdb = parent->sysdb;
     153             : 
     154          47 :     return dom;
     155             : 
     156             : fail:
     157           0 :     talloc_free(dom);
     158           0 :     return NULL;
     159             : }
     160             : 
     161          50 : static bool is_forest_root(struct sss_domain_info *d)
     162             : {
     163          50 :     if (d->forest == NULL) {
     164             :         /* IPA subdomain provider saves/saved trusted forest root domains
     165             :          * without the forest attribute. Those are automatically forest
     166             :          * roots
     167             :          */
     168          37 :         return true;
     169             :     }
     170             : 
     171          13 :     if (d->realm && (strcasecmp(d->forest, d->realm) == 0)) {
     172          13 :         return true;
     173             :     }
     174             : 
     175           0 :     return false;
     176             : }
     177             : 
     178          62 : static bool is_same_forest(struct sss_domain_info *root,
     179             :                            struct sss_domain_info *member)
     180             : {
     181          62 :     if (member->forest != NULL
     182          34 :             && root->realm != NULL
     183          30 :             && strcasecmp(member->forest, root->realm) == 0) {
     184          14 :         return true;
     185             :     }
     186             : 
     187          48 :     return false;
     188             : }
     189             : 
     190          22 : static void link_forest_roots(struct sss_domain_info *domain)
     191             : {
     192             :     struct sss_domain_info *d;
     193             :     struct sss_domain_info *dd;
     194             : 
     195          86 :     for (d = domain; d; d = get_next_domain(d, true)) {
     196          64 :         d->forest_root = NULL;
     197             :     }
     198             : 
     199          86 :     for (d = domain; d; d = get_next_domain(d, true)) {
     200          64 :         if (d->forest_root != NULL) {
     201          14 :             continue;
     202             :         }
     203             : 
     204          50 :         if (is_forest_root(d) == true) {
     205          50 :             d->forest_root = d;
     206          50 :             DEBUG(SSSDBG_TRACE_INTERNAL, "[%s] is a forest root\n", d->name);
     207             : 
     208         207 :             for (dd = domain; dd; dd = get_next_domain(dd, true)) {
     209         157 :                 if (dd->forest_root != NULL) {
     210          95 :                     continue;
     211             :                 }
     212             : 
     213          62 :                 if (is_same_forest(d, dd) == true) {
     214          14 :                     dd->forest_root = d;
     215          14 :                     DEBUG(SSSDBG_TRACE_INTERNAL,
     216             :                           "[%s] is a forest root of [%s]\n",
     217             :                           d->forest_root->name,
     218             :                           dd->name);
     219             :                 }
     220             :             }
     221             :         }
     222             :     }
     223          22 : }
     224             : 
     225          29 : errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
     226             : {
     227             :     int i;
     228             :     errno_t ret;
     229             :     TALLOC_CTX *tmp_ctx;
     230             :     struct ldb_result *res;
     231          29 :     const char *attrs[] = {"cn",
     232             :                            SYSDB_SUBDOMAIN_REALM,
     233             :                            SYSDB_SUBDOMAIN_FLAT,
     234             :                            SYSDB_SUBDOMAIN_ID,
     235             :                            SYSDB_SUBDOMAIN_MPG,
     236             :                            SYSDB_SUBDOMAIN_ENUM,
     237             :                            SYSDB_SUBDOMAIN_FOREST,
     238             :                            SYSDB_SUBDOMAIN_TRUST_DIRECTION,
     239             :                            NULL};
     240             :     struct sss_domain_info *dom;
     241             :     struct ldb_dn *basedn;
     242             :     const char *name;
     243             :     const char *realm;
     244             :     const char *flat;
     245             :     const char *id;
     246             :     const char *forest;
     247             :     bool mpg;
     248             :     bool enumerate;
     249             :     uint32_t trust_direction;
     250             : 
     251          29 :     tmp_ctx = talloc_new(NULL);
     252          29 :     if (tmp_ctx == NULL) {
     253           0 :         ret = ENOMEM;
     254           0 :         goto done;
     255             :     }
     256             : 
     257          29 :     basedn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, SYSDB_BASE);
     258          29 :     if (basedn == NULL) {
     259           0 :         ret = EIO;
     260           0 :         goto done;
     261             :     }
     262          29 :     ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
     263             :                      basedn, LDB_SCOPE_ONELEVEL,
     264             :                      attrs, "objectclass=%s", SYSDB_SUBDOMAIN_CLASS);
     265          29 :     if (ret != LDB_SUCCESS) {
     266           0 :         ret = EIO;
     267           0 :         goto done;
     268             :     }
     269             : 
     270             :     /* disable all domains,
     271             :      * let the search result refresh any that are still valid */
     272          34 :     for (dom = domain->subdomains; dom; dom = get_next_domain(dom, false)) {
     273           5 :         sss_domain_set_state(dom, DOM_DISABLED);
     274             :     }
     275             : 
     276          29 :     if (res->count == 0) {
     277           7 :         ret = EOK;
     278           7 :         goto done;
     279             :     }
     280             : 
     281          57 :     for (i = 0; i < res->count; i++) {
     282             : 
     283          35 :         name = ldb_msg_find_attr_as_string(res->msgs[i], "cn", NULL);
     284          35 :         if (name == NULL) {
     285           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     286             :                   "The object [%s] doesn't have a name\n",
     287             :                    ldb_dn_get_linearized(res->msgs[i]->dn));
     288           0 :             ret = EINVAL;
     289           0 :             goto done;
     290             :         }
     291             : 
     292          35 :         realm = ldb_msg_find_attr_as_string(res->msgs[i],
     293             :                                             SYSDB_SUBDOMAIN_REALM, NULL);
     294             : 
     295          35 :         flat = ldb_msg_find_attr_as_string(res->msgs[i],
     296             :                                            SYSDB_SUBDOMAIN_FLAT, NULL);
     297             : 
     298          35 :         id = ldb_msg_find_attr_as_string(res->msgs[i],
     299             :                                          SYSDB_SUBDOMAIN_ID, NULL);
     300             : 
     301          35 :         mpg = ldb_msg_find_attr_as_bool(res->msgs[i],
     302             :                                         SYSDB_SUBDOMAIN_MPG, false);
     303             : 
     304          35 :         enumerate = ldb_msg_find_attr_as_bool(res->msgs[i],
     305             :                                               SYSDB_SUBDOMAIN_ENUM, false);
     306             : 
     307          35 :         forest = ldb_msg_find_attr_as_string(res->msgs[i],
     308             :                                              SYSDB_SUBDOMAIN_FOREST, NULL);
     309             : 
     310          35 :         trust_direction = ldb_msg_find_attr_as_int(res->msgs[i],
     311             :                                              SYSDB_SUBDOMAIN_TRUST_DIRECTION,
     312             :                                              0);
     313             : 
     314             :         /* explicitly use dom->next as we need to check 'disabled' domains */
     315          51 :         for (dom = domain->subdomains; dom; dom = dom->next) {
     316          19 :             if (strcasecmp(dom->name, name) == 0) {
     317           3 :                 sss_domain_set_state(dom, DOM_ACTIVE);
     318             : 
     319             :                 /* in theory these may change, but it should never happen */
     320           3 :                 if (strcasecmp(dom->realm, realm) != 0) {
     321           0 :                     DEBUG(SSSDBG_TRACE_INTERNAL,
     322             :                           "Realm name changed from [%s] to [%s]!\n",
     323             :                            dom->realm, realm);
     324           0 :                     talloc_zfree(dom->realm);
     325           0 :                     dom->realm = talloc_strdup(dom, realm);
     326           0 :                     if (dom->realm == NULL) {
     327           0 :                         ret = ENOMEM;
     328           0 :                         goto done;
     329             :                     }
     330             :                 }
     331           3 :                 if (strcasecmp(dom->flat_name, flat) != 0) {
     332           0 :                     DEBUG(SSSDBG_TRACE_INTERNAL,
     333             :                           "Flat name changed from [%s] to [%s]!\n",
     334             :                            dom->flat_name, flat);
     335           0 :                     talloc_zfree(dom->flat_name);
     336           0 :                     dom->flat_name = talloc_strdup(dom, flat);
     337           0 :                     if (dom->flat_name == NULL) {
     338           0 :                         ret = ENOMEM;
     339           0 :                         goto done;
     340             :                     }
     341             :                 }
     342           3 :                 if (strcasecmp(dom->domain_id, id) != 0) {
     343           0 :                     DEBUG(SSSDBG_TRACE_INTERNAL,
     344             :                           "Domain changed from [%s] to [%s]!\n",
     345             :                            dom->domain_id, id);
     346           0 :                     talloc_zfree(dom->domain_id);
     347           0 :                     dom->domain_id = talloc_strdup(dom, id);
     348           0 :                     if (dom->domain_id == NULL) {
     349           0 :                         ret = ENOMEM;
     350           0 :                         goto done;
     351             :                     }
     352             :                 }
     353             : 
     354           3 :                 if (dom->mpg != mpg) {
     355           0 :                     DEBUG(SSSDBG_TRACE_INTERNAL,
     356             :                           "MPG state change from [%s] to [%s]!\n",
     357             :                            dom->mpg ? "true" : "false",
     358             :                            mpg ? "true" : "false");
     359           0 :                     dom->mpg = mpg;
     360             :                 }
     361             : 
     362           3 :                 if (dom->enumerate != enumerate) {
     363           0 :                     DEBUG(SSSDBG_TRACE_INTERNAL,
     364             :                           "enumerate state change from [%s] to [%s]!\n",
     365             :                            dom->enumerate ? "true" : "false",
     366             :                            enumerate ? "true" : "false");
     367           0 :                     dom->enumerate = enumerate;
     368             :                 }
     369             : 
     370           3 :                 if ((dom->forest == NULL && forest != NULL)
     371           3 :                         || (dom->forest != NULL && forest != NULL
     372           0 :                             && strcasecmp(dom->forest, forest) != 0)) {
     373           0 :                     DEBUG(SSSDBG_TRACE_INTERNAL,
     374             :                           "Forest changed from [%s] to [%s]!\n",
     375             :                            dom->forest, forest);
     376           0 :                     talloc_zfree(dom->forest);
     377           0 :                     dom->forest = talloc_strdup(dom, forest);
     378           0 :                     if (dom->forest == NULL) {
     379           0 :                         ret = ENOMEM;
     380           0 :                         goto done;
     381             :                     }
     382             :                 }
     383             : 
     384           3 :                 if (!dom->has_views && dom->view_name == NULL) {
     385             :                     /* maybe views are not initialized, copy from parent */
     386           3 :                     dom->has_views = dom->parent->has_views;
     387           6 :                     if (dom->parent->view_name != NULL) {
     388           0 :                         dom->view_name = talloc_strdup(dom,
     389           0 :                                                        dom->parent->view_name);
     390           0 :                         if (dom->view_name == NULL) {
     391           0 :                             DEBUG(SSSDBG_OP_FAILURE,
     392             :                                   "Failed to copy parent's view name.\n");
     393           0 :                             ret = ENOMEM;
     394           0 :                             goto done;
     395             :                         }
     396             :                     }
     397             :                 } else {
     398           0 :                     if (dom->has_views != dom->parent->has_views
     399           0 :                             || strcmp(dom->view_name,
     400           0 :                                       dom->parent->view_name) != 0) {
     401           0 :                         DEBUG(SSSDBG_CRIT_FAILURE,
     402             :                             "Sub-domain [%s][%s] and parent [%s][%s] " \
     403             :                             "views are different.\n",
     404             :                             dom->has_views ? "has view" : "has no view",
     405             :                             dom->view_name,
     406             :                             dom->parent->has_views ? "has view" : "has no view",
     407             :                             dom->parent->view_name);
     408           0 :                         ret = EINVAL;
     409           0 :                         goto done;
     410             :                     }
     411             :                 }
     412             : 
     413           3 :                 if (dom->trust_direction != trust_direction) {
     414           2 :                     DEBUG(SSSDBG_TRACE_INTERNAL,
     415             :                           "Trust direction change from [%d] to [%d]!\n",
     416             :                            dom->trust_direction, trust_direction);
     417           2 :                     dom->trust_direction = trust_direction;
     418             :                 }
     419             : 
     420           3 :                 break;
     421             :             }
     422             :         }
     423             :         /* If not found in loop it is a new subdomain */
     424          35 :         if (dom == NULL) {
     425          32 :             dom = new_subdomain(domain, domain, name, realm,
     426             :                                 flat, id, mpg, enumerate, forest,
     427             :                                 trust_direction);
     428          32 :             if (dom == NULL) {
     429           0 :                 ret = ENOMEM;
     430           0 :                 goto done;
     431             :             }
     432          32 :             DLIST_ADD_END(domain->subdomains, dom, struct sss_domain_info *);
     433             :         }
     434             :     }
     435             : 
     436          22 :     link_forest_roots(domain);
     437             : 
     438          22 :     ret = EOK;
     439             : 
     440             : done:
     441          29 :     talloc_free(tmp_ctx);
     442          29 :     return ret;
     443             : }
     444             : 
     445          21 : errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
     446             : {
     447             :     errno_t ret;
     448             :     TALLOC_CTX *tmp_ctx;
     449             :     const char *tmp_str;
     450             :     struct ldb_dn *basedn;
     451             :     struct ldb_result *res;
     452          21 :     const char *attrs[] = {"cn",
     453             :                            SYSDB_SUBDOMAIN_REALM,
     454             :                            SYSDB_SUBDOMAIN_FLAT,
     455             :                            SYSDB_SUBDOMAIN_ID,
     456             :                            SYSDB_SUBDOMAIN_FOREST,
     457             :                            NULL};
     458          21 :     char *view_name = NULL;
     459             : 
     460          21 :     tmp_ctx = talloc_new(NULL);
     461          21 :     if (tmp_ctx == NULL) {
     462           0 :         return ENOMEM;
     463             :     }
     464             : 
     465          21 :     basedn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
     466             :                             SYSDB_DOM_BASE, domain->name);
     467          21 :     if (basedn == NULL) {
     468           0 :         ret = EIO;
     469           0 :         goto done;
     470             :     }
     471          21 :     ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
     472             :                      basedn, LDB_SCOPE_BASE, attrs, NULL);
     473          21 :     if (ret != LDB_SUCCESS) {
     474           0 :         ret = EIO;
     475           0 :         goto done;
     476             :     }
     477             : 
     478          21 :     if (res->count == 0) {
     479           0 :         ret = ENOENT;
     480           0 :         goto done;
     481             :     }
     482             : 
     483          21 :     if (res->count > 1) {
     484           0 :         DEBUG(SSSDBG_OP_FAILURE, "Base search returned [%d] results, "
     485             :                                  "expected 1.\n", res->count);
     486           0 :         ret = EINVAL;
     487           0 :         goto done;
     488             :     }
     489             : 
     490          21 :     tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SUBDOMAIN_REALM,
     491             :                                           NULL);
     492          32 :     if (tmp_str != NULL &&
     493          17 :         (domain->realm == NULL || strcasecmp(tmp_str, domain->realm) != 0)) {
     494           7 :         talloc_free(domain->realm);
     495           7 :         domain->realm = talloc_strdup(domain, tmp_str);
     496           7 :         if (domain->realm == NULL) {
     497           0 :             ret = ENOMEM;
     498           0 :             goto done;
     499             :         }
     500             :     }
     501             : 
     502          21 :     tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SUBDOMAIN_FLAT,
     503             :                                           NULL);
     504          32 :     if (tmp_str != NULL &&
     505          17 :         (domain->flat_name == NULL ||
     506           6 :          strcasecmp(tmp_str, domain->flat_name) != 0)) {
     507           7 :         talloc_free(domain->flat_name);
     508           7 :         domain->flat_name = talloc_strdup(domain, tmp_str);
     509           7 :         if (domain->flat_name == NULL) {
     510           0 :             ret = ENOMEM;
     511           0 :             goto done;
     512             :         }
     513             :     }
     514             : 
     515          21 :     tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SUBDOMAIN_ID,
     516             :                                           NULL);
     517          32 :     if (tmp_str != NULL &&
     518          17 :         (domain->domain_id == NULL ||
     519           6 :          strcasecmp(tmp_str, domain->domain_id) != 0)) {
     520           7 :         talloc_free(domain->domain_id);
     521           7 :         domain->domain_id = talloc_strdup(domain, tmp_str);
     522           7 :         if (domain->domain_id == NULL) {
     523           0 :             ret = ENOMEM;
     524           0 :             goto done;
     525             :         }
     526             :     }
     527             : 
     528          21 :     tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SUBDOMAIN_FOREST,
     529             :                                           NULL);
     530          32 :     if (tmp_str != NULL &&
     531          17 :         (domain->forest == NULL ||
     532           6 :          strcasecmp(tmp_str, domain->forest) != 0)) {
     533           6 :         talloc_free(domain->forest);
     534           6 :         domain->forest = talloc_strdup(domain, tmp_str);
     535           6 :         if (domain->forest == NULL) {
     536           0 :             ret = ENOMEM;
     537           0 :             goto done;
     538             :         }
     539             :     }
     540             : 
     541          21 :     ret = sysdb_get_view_name(tmp_ctx, domain->sysdb, &view_name);
     542          21 :     if (ret != EOK && ret != ENOENT) {
     543           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name failed.\n");
     544           0 :         goto done;
     545             :     }
     546             : 
     547             :     /* If no view is defined the default view will be used. In this case
     548             :      * domain->has_views is FALSE and
     549             :      * domain->view_name is set to SYSDB_DEFAULT_VIEW_NAME
     550             :      *
     551             :      * If there is a view defined
     552             :      * domain->has_views is TRUE and
     553             :      * domain->view_name is set to the given view name
     554             :      *
     555             :      * Currently changing the view is not supported hence we have to check for
     556             :      * changes and error out accordingly.
     557             :      */
     558          21 :     if (ret == ENOENT || is_default_view(view_name)) {
     559             :         /* handle default view */
     560          42 :         if (domain->has_views) {
     561           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     562             :                   "View name change is currently not supported. " \
     563             :                   "New view is the default view while current view is [%s]. " \
     564             :                   "View name is not changed!\n", domain->view_name);
     565             :         } else {
     566          21 :             if (domain->view_name == NULL) {
     567          12 :                 domain->view_name = talloc_strdup(domain,
     568             :                                                   SYSDB_DEFAULT_VIEW_NAME);
     569          12 :                 if (domain->view_name == NULL) {
     570           0 :                     DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
     571           0 :                     ret = ENOMEM;
     572           0 :                     goto done;
     573             :                 }
     574             :             } else {
     575           9 :                 if (strcmp(domain->view_name, SYSDB_DEFAULT_VIEW_NAME) != 0) {
     576           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
     577             :                           "Domain [%s] has no view but view name [%s] " \
     578             :                           "is not the default view name [%s].\n",
     579             :                           domain->name, domain->view_name,
     580             :                           SYSDB_DEFAULT_VIEW_NAME);
     581           0 :                     ret = EINVAL;
     582           0 :                     goto done;
     583             :                 }
     584             :             }
     585             :         }
     586             :     } else {
     587             :         /* handle view other than default */
     588           0 :         if (domain->has_views) {
     589           0 :             if (strcmp(domain->view_name, view_name) != 0) {
     590           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     591             :                       "View name change is currently not supported. " \
     592             :                       "New view is [%s] while current view is [%s]. " \
     593             :                       "View name is not changed!\n",
     594             :                       view_name, domain->view_name);
     595             :             }
     596             :         } else {
     597           0 :             if (domain->view_name == NULL) {
     598           0 :                 domain->has_views = true;
     599           0 :                 domain->view_name = talloc_steal(domain, view_name);
     600           0 :                 if (domain->view_name == NULL) {
     601           0 :                     DEBUG(SSSDBG_OP_FAILURE, "talloc_steal failed.\n");
     602           0 :                     ret = ENOMEM;
     603           0 :                     goto done;
     604             :                 }
     605             :             } else {
     606           0 :                 if (strcmp(domain->view_name, SYSDB_DEFAULT_VIEW_NAME) == 0) {
     607           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
     608             :                         "View name change is currently not supported. " \
     609             :                         "New view is [%s] while current is the default view. " \
     610             :                         "View name is not changed!\n", view_name);
     611             :                 } else {
     612           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
     613             :                           "Domain currently has no views, " \
     614             :                           "but current view name is set to [%s] " \
     615             :                           "and new view name is [%s].\n",
     616             :                           domain->view_name, view_name);
     617           0 :                     ret = EINVAL;
     618           0 :                     goto done;
     619             :                 }
     620             :             }
     621             :         }
     622             :     }
     623             : 
     624          21 :     ret = EOK;
     625             : 
     626             : done:
     627          21 :     talloc_free(tmp_ctx);
     628          21 :     return ret;
     629             : }
     630             : 
     631           6 : errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
     632             :                                      const char *realm,
     633             :                                      const char *flat,
     634             :                                      const char *id,
     635             :                                      const char* forest)
     636             : {
     637             :     TALLOC_CTX *tmp_ctx;
     638             :     struct ldb_message *msg;
     639             :     int ret;
     640           6 :     bool do_update = false;
     641             : 
     642           6 :     tmp_ctx = talloc_new(NULL);
     643           6 :     if (tmp_ctx == NULL) {
     644           0 :         return ENOMEM;
     645             :     }
     646             : 
     647           6 :     msg = ldb_msg_new(tmp_ctx);
     648           6 :     if (msg == NULL) {
     649           0 :         ret = ENOMEM;
     650           0 :         goto done;
     651             :     }
     652             : 
     653           6 :     msg->dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
     654             :                              SYSDB_DOM_BASE, domain->name);
     655           6 :     if (msg->dn == NULL) {
     656           0 :         ret = EIO;
     657           0 :         goto done;
     658             :     }
     659             : 
     660           7 :     if (flat != NULL && (domain->flat_name == NULL ||
     661           1 :                          strcmp(domain->flat_name, flat) != 0)) {
     662           6 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_FLAT,
     663             :                                 LDB_FLAG_MOD_REPLACE, NULL);
     664           6 :         if (ret != LDB_SUCCESS) {
     665           0 :             ret = sysdb_error_to_errno(ret);
     666           0 :             goto done;
     667             :         }
     668             : 
     669           6 :         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_FLAT, flat);
     670           6 :         if (ret != LDB_SUCCESS) {
     671           0 :             ret = sysdb_error_to_errno(ret);
     672           0 :             goto done;
     673             :         }
     674             : 
     675           6 :         do_update = true;
     676             :     }
     677             : 
     678           7 :     if (id != NULL && (domain->domain_id == NULL ||
     679           1 :                        strcmp(domain->domain_id, id) != 0)) {
     680           6 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_ID,
     681             :                                 LDB_FLAG_MOD_REPLACE, NULL);
     682           6 :         if (ret != LDB_SUCCESS) {
     683           0 :             ret = sysdb_error_to_errno(ret);
     684           0 :             goto done;
     685             :         }
     686             : 
     687           6 :         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_ID, id);
     688           6 :         if (ret != LDB_SUCCESS) {
     689           0 :             ret = sysdb_error_to_errno(ret);
     690           0 :             goto done;
     691             :         }
     692             : 
     693           6 :         do_update = true;
     694             :     }
     695             : 
     696           7 :    if (forest != NULL && (domain->forest == NULL ||
     697           1 :                        strcmp(domain->forest, forest) != 0)) {
     698           6 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_FOREST,
     699             :                                 LDB_FLAG_MOD_REPLACE, NULL);
     700           6 :         if (ret != LDB_SUCCESS) {
     701           0 :             ret = sysdb_error_to_errno(ret);
     702           0 :             goto done;
     703             :         }
     704             : 
     705           6 :         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_FOREST, forest);
     706           6 :         if (ret != LDB_SUCCESS) {
     707           0 :             ret = sysdb_error_to_errno(ret);
     708           0 :             goto done;
     709             :         }
     710             : 
     711           6 :         do_update = true;
     712             :     }
     713             : 
     714           7 :    if (realm != NULL && (domain->realm == NULL ||
     715           1 :                        strcmp(domain->realm, realm) != 0)) {
     716           6 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_REALM,
     717             :                                 LDB_FLAG_MOD_REPLACE, NULL);
     718           6 :         if (ret != LDB_SUCCESS) {
     719           0 :             ret = sysdb_error_to_errno(ret);
     720           0 :             goto done;
     721             :         }
     722             : 
     723           6 :         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_REALM, realm);
     724           6 :         if (ret != LDB_SUCCESS) {
     725           0 :             ret = sysdb_error_to_errno(ret);
     726           0 :             goto done;
     727             :         }
     728             : 
     729           6 :         do_update = true;
     730             :     }
     731             : 
     732           6 :     if (do_update == false) {
     733           0 :         ret = EOK;
     734           0 :         goto done;
     735             :     }
     736             : 
     737           6 :     ret = ldb_modify(domain->sysdb->ldb, msg);
     738           6 :     if (ret != LDB_SUCCESS) {
     739           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to add subdomain attributes to "
     740             :                                      "[%s]: [%d][%s]!\n", domain->name, ret,
     741             :                                      ldb_errstring(domain->sysdb->ldb));
     742           0 :         ret = sysdb_error_to_errno(ret);
     743           0 :         goto done;
     744             :     }
     745             : 
     746           6 :     ret = sysdb_master_domain_update(domain);
     747           6 :     if (ret != EOK) {
     748           0 :         goto done;
     749             :     }
     750             : 
     751           6 :     ret = EOK;
     752             : 
     753             : done:
     754           6 :     talloc_free(tmp_ctx);
     755             : 
     756           6 :     return ret;
     757             : }
     758             : 
     759          35 : errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
     760             :                               const char *name, const char *realm,
     761             :                               const char *flat_name, const char *domain_id,
     762             :                               bool mpg, bool enumerate, const char *forest,
     763             :                               uint32_t trust_direction)
     764             : {
     765             :     TALLOC_CTX *tmp_ctx;
     766             :     struct ldb_message *msg;
     767             :     struct ldb_dn *dn;
     768             :     struct ldb_result *res;
     769          35 :     const char *attrs[] = {"cn",
     770             :                            SYSDB_SUBDOMAIN_REALM,
     771             :                            SYSDB_SUBDOMAIN_FLAT,
     772             :                            SYSDB_SUBDOMAIN_ID,
     773             :                            SYSDB_SUBDOMAIN_MPG,
     774             :                            SYSDB_SUBDOMAIN_ENUM,
     775             :                            SYSDB_SUBDOMAIN_FOREST,
     776             :                            SYSDB_SUBDOMAIN_TRUST_DIRECTION,
     777             :                            NULL};
     778             :     const char *tmp_str;
     779             :     bool tmp_bool;
     780          35 :     bool store = false;
     781          35 :     int realm_flags = 0;
     782          35 :     int flat_flags = 0;
     783          35 :     int id_flags = 0;
     784          35 :     int mpg_flags = 0;
     785          35 :     int enum_flags = 0;
     786          35 :     int forest_flags = 0;
     787          35 :     int td_flags = 0;
     788             :     uint32_t tmp_td;
     789             :     int ret;
     790             : 
     791          35 :     tmp_ctx = talloc_new(NULL);
     792          35 :     if (tmp_ctx == NULL) {
     793           0 :         return ENOMEM;
     794             :     }
     795             : 
     796          35 :     dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, name);
     797          35 :     if (dn == NULL) {
     798           0 :         ret = EIO;
     799           0 :         goto done;
     800             :     }
     801          35 :     ret = ldb_search(sysdb->ldb, tmp_ctx, &res,
     802             :                      dn, LDB_SCOPE_BASE, attrs, NULL);
     803          35 :     if (ret != LDB_SUCCESS) {
     804           0 :         ret = EIO;
     805           0 :         goto done;
     806             :     }
     807             : 
     808          35 :     if (res->count == 0) {
     809          15 :         ret = sysdb_domain_create(sysdb, name);
     810          15 :         if (ret) {
     811           0 :             goto done;
     812             :         }
     813          15 :         store = true;
     814          15 :         if (realm) realm_flags = LDB_FLAG_MOD_ADD;
     815          15 :         if (flat_name) flat_flags = LDB_FLAG_MOD_ADD;
     816          15 :         if (domain_id) id_flags = LDB_FLAG_MOD_ADD;
     817          15 :         mpg_flags = LDB_FLAG_MOD_ADD;
     818          15 :         enum_flags = LDB_FLAG_MOD_ADD;
     819          15 :         if (forest) forest_flags = LDB_FLAG_MOD_ADD;
     820          15 :         if (trust_direction) td_flags = LDB_FLAG_MOD_ADD;
     821          20 :     } else if (res->count != 1) {
     822           0 :         ret = EINVAL;
     823           0 :         goto done;
     824             :     } else { /* 1 found */
     825          20 :         if (realm) {
     826          20 :             tmp_str = ldb_msg_find_attr_as_string(res->msgs[0],
     827             :                                                   SYSDB_SUBDOMAIN_REALM, NULL);
     828          20 :             if (!tmp_str || strcasecmp(tmp_str, realm) != 0) {
     829           1 :                 realm_flags = LDB_FLAG_MOD_REPLACE;
     830             :             }
     831             :         }
     832          20 :         if (flat_name) {
     833          14 :             tmp_str = ldb_msg_find_attr_as_string(res->msgs[0],
     834             :                                                   SYSDB_SUBDOMAIN_FLAT, NULL);
     835          14 :             if (!tmp_str || strcasecmp(tmp_str, flat_name) != 0) {
     836           1 :                 flat_flags = LDB_FLAG_MOD_REPLACE;
     837             :             }
     838             :         }
     839          20 :         if (domain_id) {
     840          20 :             tmp_str = ldb_msg_find_attr_as_string(res->msgs[0],
     841             :                                                   SYSDB_SUBDOMAIN_ID, NULL);
     842          20 :             if (!tmp_str || strcasecmp(tmp_str, domain_id) != 0) {
     843           1 :                 id_flags = LDB_FLAG_MOD_REPLACE;
     844             :             }
     845             :         }
     846             : 
     847          20 :         tmp_bool = ldb_msg_find_attr_as_bool(res->msgs[0], SYSDB_SUBDOMAIN_MPG,
     848          20 :                                              !mpg);
     849          20 :         if (tmp_bool != mpg) {
     850           1 :             mpg_flags = LDB_FLAG_MOD_REPLACE;
     851             :         }
     852          20 :         tmp_bool = ldb_msg_find_attr_as_bool(res->msgs[0], SYSDB_SUBDOMAIN_ENUM,
     853          20 :                                              !enumerate);
     854          20 :         if (tmp_bool != enumerate) {
     855           1 :             enum_flags = LDB_FLAG_MOD_REPLACE;
     856             :         }
     857             : 
     858          20 :         if (forest) {
     859          13 :             tmp_str = ldb_msg_find_attr_as_string(res->msgs[0],
     860             :                                                   SYSDB_SUBDOMAIN_FOREST, NULL);
     861          13 :             if (!tmp_str || strcasecmp(tmp_str, forest) != 0) {
     862           0 :                 forest_flags = LDB_FLAG_MOD_REPLACE;
     863             :             }
     864             :         }
     865             : 
     866          20 :         tmp_td = ldb_msg_find_attr_as_uint(res->msgs[0],
     867             :                                            SYSDB_SUBDOMAIN_TRUST_DIRECTION,
     868             :                                            0);
     869          20 :         if (tmp_td != trust_direction) {
     870           4 :             td_flags = LDB_FLAG_MOD_REPLACE;
     871             :         }
     872             :     }
     873             : 
     874          35 :     if (!store && realm_flags == 0 && flat_flags == 0 && id_flags == 0
     875          19 :             && mpg_flags == 0 && enum_flags == 0 && forest_flags == 0
     876          19 :             && td_flags == 0) {
     877          15 :         ret = EOK;
     878          15 :         goto done;
     879             :     }
     880             : 
     881          20 :     msg = ldb_msg_new(tmp_ctx);
     882          20 :     if (msg == NULL) {
     883           0 :         ret = ENOMEM;
     884           0 :         goto done;
     885             :     }
     886          20 :     msg->dn = dn;
     887             : 
     888          20 :     if (store) {
     889          15 :         ret = ldb_msg_add_empty(msg, SYSDB_OBJECTCLASS, LDB_FLAG_MOD_ADD, NULL);
     890          15 :         if (ret != LDB_SUCCESS) {
     891           0 :             ret = sysdb_error_to_errno(ret);
     892           0 :             goto done;
     893             :         }
     894             : 
     895          15 :         ret = ldb_msg_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_SUBDOMAIN_CLASS);
     896          15 :         if (ret != LDB_SUCCESS) {
     897           0 :             ret = sysdb_error_to_errno(ret);
     898           0 :             goto done;
     899             :         }
     900             :     }
     901             : 
     902          20 :     if (realm_flags) {
     903          16 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_REALM, realm_flags, NULL);
     904          16 :         if (ret != LDB_SUCCESS) {
     905           0 :             ret = sysdb_error_to_errno(ret);
     906           0 :             goto done;
     907             :         }
     908             : 
     909          16 :         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_REALM, realm);
     910          16 :         if (ret != LDB_SUCCESS) {
     911           0 :             ret = sysdb_error_to_errno(ret);
     912           0 :             goto done;
     913             :         }
     914             :     }
     915             : 
     916          20 :     if (flat_flags) {
     917          15 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_FLAT, flat_flags, NULL);
     918          15 :         if (ret != LDB_SUCCESS) {
     919           0 :             ret = sysdb_error_to_errno(ret);
     920           0 :             goto done;
     921             :         }
     922             : 
     923          15 :         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_FLAT, flat_name);
     924          15 :         if (ret != LDB_SUCCESS) {
     925           0 :             ret = sysdb_error_to_errno(ret);
     926           0 :             goto done;
     927             :         }
     928             :     }
     929             : 
     930          20 :     if (id_flags) {
     931          16 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_ID, id_flags, NULL);
     932          16 :         if (ret != LDB_SUCCESS) {
     933           0 :             ret = sysdb_error_to_errno(ret);
     934           0 :             goto done;
     935             :         }
     936             : 
     937          16 :         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_ID, domain_id);
     938          16 :         if (ret != LDB_SUCCESS) {
     939           0 :             ret = sysdb_error_to_errno(ret);
     940           0 :             goto done;
     941             :         }
     942             :     }
     943             : 
     944          20 :     if (mpg_flags) {
     945          16 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_MPG, mpg_flags, NULL);
     946          16 :         if (ret != LDB_SUCCESS) {
     947           0 :             ret = sysdb_error_to_errno(ret);
     948           0 :             goto done;
     949             :         }
     950             : 
     951          16 :         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_MPG,
     952             :                                  mpg ? "TRUE" : "FALSE");
     953          16 :         if (ret != LDB_SUCCESS) {
     954           0 :             ret = sysdb_error_to_errno(ret);
     955           0 :             goto done;
     956             :         }
     957             :     }
     958             : 
     959          20 :     if (enum_flags) {
     960          16 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_ENUM, enum_flags, NULL);
     961          16 :         if (ret != LDB_SUCCESS) {
     962           0 :             ret = sysdb_error_to_errno(ret);
     963           0 :             goto done;
     964             :         }
     965             : 
     966          16 :         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_ENUM,
     967             :                                  enumerate ? "TRUE" : "FALSE");
     968          16 :         if (ret != LDB_SUCCESS) {
     969           0 :             ret = sysdb_error_to_errno(ret);
     970           0 :             goto done;
     971             :         }
     972             :     }
     973             : 
     974          20 :     if (forest_flags) {
     975          11 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_FOREST, forest_flags,
     976             :                                 NULL);
     977          11 :         if (ret != LDB_SUCCESS) {
     978           0 :             ret = sysdb_error_to_errno(ret);
     979           0 :             goto done;
     980             :         }
     981             : 
     982          11 :         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_FOREST, forest);
     983          11 :         if (ret != LDB_SUCCESS) {
     984           0 :             ret = sysdb_error_to_errno(ret);
     985           0 :             goto done;
     986             :         }
     987             :     }
     988             : 
     989          20 :     if (td_flags) {
     990           7 :         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_TRUST_DIRECTION,
     991             :                                 td_flags, NULL);
     992           7 :         if (ret != LDB_SUCCESS) {
     993           0 :             ret = sysdb_error_to_errno(ret);
     994           0 :             goto done;
     995             :         }
     996             : 
     997           7 :         ret = ldb_msg_add_fmt(msg, SYSDB_SUBDOMAIN_TRUST_DIRECTION,
     998             :                               "%u", trust_direction);
     999           7 :         if (ret != LDB_SUCCESS) {
    1000           0 :             ret = sysdb_error_to_errno(ret);
    1001           0 :             goto done;
    1002             :         }
    1003             :     }
    1004             : 
    1005          20 :     ret = ldb_modify(sysdb->ldb, msg);
    1006          20 :     if (ret != LDB_SUCCESS) {
    1007           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to add subdomain attributes to "
    1008             :                                      "[%s]: [%d][%s]!\n", name, ret,
    1009             :                                      ldb_errstring(sysdb->ldb));
    1010           0 :         ret = sysdb_error_to_errno(ret);
    1011           0 :         goto done;
    1012             :     }
    1013             : 
    1014          20 :     ret = EOK;
    1015             : 
    1016             : done:
    1017          35 :     talloc_free(tmp_ctx);
    1018             : 
    1019          35 :     return ret;
    1020             : }
    1021             : 
    1022           3 : errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name)
    1023             : {
    1024           3 :     TALLOC_CTX *tmp_ctx = NULL;
    1025             :     struct ldb_dn *dn;
    1026             :     int ret;
    1027             : 
    1028           3 :     tmp_ctx = talloc_new(NULL);
    1029           3 :     if (tmp_ctx == NULL) {
    1030           0 :         ret = ENOMEM;
    1031           0 :         goto done;
    1032             :     }
    1033             : 
    1034           3 :     DEBUG(SSSDBG_TRACE_FUNC, "Removing sub-domain [%s] from db.\n", name);
    1035           3 :     dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, name);
    1036           3 :     if (dn == NULL) {
    1037           0 :         ret = ENOMEM;
    1038           0 :         goto done;
    1039             :     }
    1040             : 
    1041           3 :     ret = sysdb_delete_recursive(sysdb, dn, true);
    1042           3 :     if (ret != EOK) {
    1043           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_recursive failed.\n");
    1044           0 :         goto done;
    1045             :     }
    1046             : 
    1047             : done:
    1048           3 :     talloc_free(tmp_ctx);
    1049           3 :     return ret;
    1050             : }

Generated by: LCOV version 1.10