LCOV - code coverage report
Current view: top level - providers/ad - ad_subdomains.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 556 0.0 %
Date: 2015-10-19 Functions: 0 23 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     AD Subdomains Module
       5             : 
       6             :     Authors:
       7             :         Sumit Bose <sbose@redhat.com>
       8             : 
       9             :     Copyright (C) 2013 Red Hat
      10             : 
      11             :     This program is free software; you can redistribute it and/or modify
      12             :     it under the terms of the GNU General Public License as published by
      13             :     the Free Software Foundation; either version 3 of the License, or
      14             :     (at your option) any later version.
      15             : 
      16             :     This program is distributed in the hope that it will be useful,
      17             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :     GNU General Public License for more details.
      20             : 
      21             :     You should have received a copy of the GNU General Public License
      22             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "providers/ldap/sdap_async.h"
      26             : #include "providers/ad/ad_subdomains.h"
      27             : #include "providers/ad/ad_domain_info.h"
      28             : #include "providers/ad/ad_srv.h"
      29             : #include "providers/ad/ad_common.h"
      30             : 
      31             : #include "providers/ldap/sdap_idmap.h"
      32             : #include "util/util_sss_idmap.h"
      33             : #include <ctype.h>
      34             : #include <ndr.h>
      35             : #include <ndr/ndr_nbt.h>
      36             : 
      37             : /* Attributes of AD trusted domains */
      38             : #define AD_AT_FLATNAME      "flatName"
      39             : #define AD_AT_SID           "securityIdentifier"
      40             : #define AD_AT_TRUST_TYPE    "trustType"
      41             : #define AD_AT_TRUST_PARTNER "trustPartner"
      42             : #define AD_AT_TRUST_ATTRS   "trustAttributes"
      43             : 
      44             : /* trustType=2 denotes uplevel (NT5 and later) trusted domains. See
      45             :  * http://msdn.microsoft.com/en-us/library/windows/desktop/ms680342%28v=vs.85%29.aspx
      46             :  * for example.
      47             :  *
      48             :  * The absence of msDS-TrustForestTrustInfo attribute denotes a domain from
      49             :  * the same forest. See http://msdn.microsoft.com/en-us/library/cc223786.aspx
      50             :  * for more information.
      51             :  */
      52             : #define SLAVE_DOMAIN_FILTER_BASE "(objectclass=trustedDomain)(trustType=2)(!(msDS-TrustForestTrustInfo=*))"
      53             : #define SLAVE_DOMAIN_FILTER      "(&"SLAVE_DOMAIN_FILTER_BASE")"
      54             : #define FOREST_ROOT_FILTER_FMT   "(&"SLAVE_DOMAIN_FILTER_BASE"(cn=%s))"
      55             : 
      56             : /* do not refresh more often than every 5 seconds for now */
      57             : #define AD_SUBDOMAIN_REFRESH_LIMIT 5
      58             : 
      59             : struct ad_subdomains_ctx {
      60             :     struct be_ctx *be_ctx;
      61             :     struct sdap_id_ctx *sdap_id_ctx;
      62             :     struct sdap_domain *sdom;
      63             :     struct sdap_id_conn_ctx *ldap_ctx;
      64             :     struct sss_idmap_ctx *idmap_ctx;
      65             :     char *domain_name;
      66             : 
      67             :     time_t last_refreshed;
      68             :     struct tevent_timer *timer_event;
      69             :     struct ad_id_ctx *ad_id_ctx;
      70             : };
      71             : 
      72             : struct ad_subdomains_req_ctx {
      73             :     struct be_req *be_req;
      74             :     struct ad_subdomains_ctx *sd_ctx;
      75             :     struct sdap_id_op *sdap_op;
      76             : 
      77             :     char *current_filter;
      78             :     size_t base_iter;
      79             : 
      80             :     struct ad_id_ctx *root_id_ctx;
      81             :     struct sdap_id_op *root_op;
      82             :     size_t root_base_iter;
      83             :     struct sysdb_attrs *root_domain_attrs;
      84             :     struct sss_domain_info *root_domain;
      85             : 
      86             :     size_t reply_count;
      87             :     struct sysdb_attrs **reply;
      88             : 
      89             :     char *master_sid;
      90             :     char *flat_name;
      91             :     char *site;
      92             :     char *forest;
      93             : };
      94             : 
      95             : static errno_t
      96           0 : ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
      97             :                      struct ad_id_ctx *id_ctx,
      98             :                      struct sss_domain_info *subdom,
      99             :                      struct ad_id_ctx **_subdom_id_ctx)
     100             : {
     101             :     struct ad_options *ad_options;
     102             :     struct ad_id_ctx *ad_id_ctx;
     103             :     const char *gc_service_name;
     104             :     struct ad_srv_plugin_ctx *srv_ctx;
     105             :     char *ad_domain;
     106             :     char *ad_site_override;
     107             :     struct sdap_domain *sdom;
     108             :     errno_t ret;
     109             :     const char *realm;
     110             :     const char *hostname;
     111             : 
     112           0 :     realm = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_KRB5_REALM);
     113           0 :     hostname = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_HOSTNAME);
     114           0 :     ad_domain = subdom->name;
     115           0 :     if (realm == NULL || hostname == NULL || ad_domain == NULL) {
     116           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm or hostname.\n");
     117           0 :         return EINVAL;
     118             :     }
     119             : 
     120           0 :     ad_options = ad_create_2way_trust_options(id_ctx, realm,
     121             :                                               ad_domain, hostname);
     122           0 :     if (ad_options == NULL) {
     123           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
     124           0 :         talloc_free(ad_options);
     125           0 :         return ENOMEM;
     126             :     }
     127             : 
     128           0 :     ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
     129             : 
     130           0 :     gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->name);
     131           0 :     if (gc_service_name == NULL) {
     132           0 :         talloc_free(ad_options);
     133           0 :         return ENOMEM;
     134             :     }
     135             : 
     136           0 :     ret = ad_failover_init(ad_options, be_ctx, NULL, NULL, realm,
     137           0 :                            subdom->name, gc_service_name,
     138           0 :                            subdom->name, &ad_options->service);
     139           0 :     if (ret != EOK) {
     140           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
     141           0 :         talloc_free(ad_options);
     142           0 :         return ret;
     143             :     }
     144             : 
     145           0 :     ad_id_ctx = ad_id_ctx_init(ad_options, be_ctx);
     146           0 :     if (ad_id_ctx == NULL) {
     147           0 :         talloc_free(ad_options);
     148           0 :         return ENOMEM;
     149             :     }
     150           0 :     ad_id_ctx->sdap_id_ctx->opts = ad_options->id;
     151           0 :     ad_options->id_ctx = ad_id_ctx;
     152             : 
     153             :     /* use AD plugin */
     154           0 :     srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res,
     155             :                                      default_host_dbs,
     156           0 :                                      ad_id_ctx->ad_options->id,
     157             :                                      hostname,
     158             :                                      ad_domain,
     159             :                                      ad_site_override);
     160           0 :     if (srv_ctx == NULL) {
     161           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
     162           0 :         return ENOMEM;
     163             :     }
     164           0 :     be_fo_set_srv_lookup_plugin(be_ctx, ad_srv_plugin_send,
     165             :                                 ad_srv_plugin_recv, srv_ctx, "AD");
     166             : 
     167           0 :     ret = sdap_domain_subdom_add(ad_id_ctx->sdap_id_ctx,
     168           0 :                                  ad_id_ctx->sdap_id_ctx->opts->sdom,
     169             :                                  subdom->parent);
     170           0 :     if (ret != EOK) {
     171           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize sdap domain\n");
     172           0 :         talloc_free(ad_options);
     173           0 :         return ret;
     174             :     }
     175             : 
     176           0 :     sdom = sdap_domain_get(ad_id_ctx->sdap_id_ctx->opts, subdom);
     177           0 :     if (sdom == NULL) {
     178           0 :         return EFAULT;
     179             :     }
     180             : 
     181           0 :     sdap_inherit_options(subdom->parent->sd_inherit,
     182           0 :                          id_ctx->sdap_id_ctx->opts,
     183           0 :                          ad_id_ctx->sdap_id_ctx->opts);
     184             : 
     185             :     /* Set up the ID mapping object */
     186           0 :     ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
     187           0 :         id_ctx->sdap_id_ctx->opts->idmap_ctx;
     188             : 
     189           0 :     *_subdom_id_ctx = ad_id_ctx;
     190           0 :     return EOK;
     191             : }
     192             : 
     193             : static errno_t
     194           0 : ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
     195             :                       struct sss_domain_info *parent)
     196             : {
     197             :     int ret;
     198             :     struct sdap_domain *sditer;
     199             :     struct ad_id_ctx *subdom_id_ctx;
     200             : 
     201           0 :     ret = sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent);
     202           0 :     if (ret != EOK) {
     203           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_domain_subdom_add failed.\n");
     204           0 :         return ret;
     205             :     }
     206             : 
     207           0 :     DLIST_FOR_EACH(sditer, ctx->sdom) {
     208           0 :         if (IS_SUBDOMAIN(sditer->dom) && sditer->pvt == NULL) {
     209           0 :             ret = ad_subdom_ad_ctx_new(ctx->be_ctx, ctx->ad_id_ctx,
     210             :                                        sditer->dom, &subdom_id_ctx);
     211           0 :             if (ret != EOK) {
     212           0 :                 DEBUG(SSSDBG_OP_FAILURE, "ad_subdom_ad_ctx_new failed.\n");
     213             :             } else {
     214           0 :                 sditer->pvt = subdom_id_ctx;
     215             :             }
     216             :         }
     217             :     }
     218             : 
     219           0 :     return EOK;
     220             : }
     221             : 
     222           0 : static errno_t ad_subdom_enumerates(struct sss_domain_info *parent,
     223             :                                     struct sysdb_attrs *attrs,
     224             :                                     bool *_enumerates)
     225             : {
     226             :     errno_t ret;
     227             :     const char *name;
     228             : 
     229           0 :     ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name);
     230           0 :     if (ret != EOK) {
     231           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
     232           0 :         return ret;
     233             :     }
     234             : 
     235           0 :     *_enumerates = subdomain_enumerates(parent, name);
     236           0 :     return EOK;
     237             : }
     238             : 
     239             : static errno_t
     240           0 : ad_subdom_store(struct ad_subdomains_ctx *ctx,
     241             :                 struct sss_domain_info *domain,
     242             :                 struct sysdb_attrs *subdom_attrs,
     243             :                 bool enumerate)
     244             : {
     245             :     TALLOC_CTX *tmp_ctx;
     246             :     const char *name;
     247             :     char *realm;
     248             :     const char *flat;
     249             :     errno_t ret;
     250             :     enum idmap_error_code err;
     251             :     struct ldb_message_element *el;
     252           0 :     char *sid_str = NULL;
     253             :     uint32_t trust_type;
     254             :     bool mpg;
     255             : 
     256           0 :     tmp_ctx = talloc_new(NULL);
     257           0 :     if (tmp_ctx == NULL) {
     258           0 :         ret = ENOMEM;
     259           0 :         goto done;
     260             :     }
     261             : 
     262           0 :     ret = sysdb_attrs_get_uint32_t(subdom_attrs, AD_AT_TRUST_TYPE,
     263             :                                    &trust_type);
     264           0 :     if (ret != EOK) {
     265           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_uint32_t failed.\n");
     266           0 :         goto done;
     267             :     }
     268             : 
     269           0 :     ret = sysdb_attrs_get_string(subdom_attrs, AD_AT_TRUST_PARTNER, &name);
     270           0 :     if (ret != EOK) {
     271           0 :         DEBUG(SSSDBG_OP_FAILURE, "failed to get subdomain name\n");
     272           0 :         goto done;
     273             :     }
     274             : 
     275           0 :     realm = get_uppercase_realm(tmp_ctx, name);
     276           0 :     if (!realm) {
     277           0 :         ret = ENOMEM;
     278           0 :         goto done;
     279             :     }
     280             : 
     281           0 :     ret = sysdb_attrs_get_string(subdom_attrs, AD_AT_FLATNAME, &flat);
     282           0 :     if (ret) {
     283           0 :         DEBUG(SSSDBG_OP_FAILURE, "failed to get flat name of subdomain %s\n",
     284             :                                   name);
     285           0 :         goto done;
     286             :     }
     287             : 
     288           0 :     ret = sysdb_attrs_get_el(subdom_attrs, AD_AT_SID, &el);
     289           0 :     if (ret != EOK || el->num_values != 1) {
     290           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_attrs_get_el failed.\n");
     291           0 :         goto done;
     292             :     }
     293             : 
     294           0 :     err = sss_idmap_bin_sid_to_sid(ctx->idmap_ctx,
     295           0 :                                    el->values[0].data,
     296           0 :                                    el->values[0].length,
     297             :                                    &sid_str);
     298           0 :     if (err != IDMAP_SUCCESS) {
     299           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     300             :               "Could not convert SID: [%s].\n", idmap_error_string(err));
     301           0 :         ret = EFAULT;
     302           0 :         goto done;
     303             :     }
     304             : 
     305           0 :     mpg = sdap_idmap_domain_has_algorithmic_mapping(
     306           0 :                                              ctx->sdap_id_ctx->opts->idmap_ctx,
     307             :                                              name,
     308             :                                              sid_str);
     309             : 
     310           0 :     ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
     311           0 :                                 mpg, enumerate, domain->forest, 0);
     312           0 :     if (ret != EOK) {
     313           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_subdomain_store failed.\n");
     314           0 :         goto done;
     315             :     }
     316             : 
     317           0 :     ret = EOK;
     318             : done:
     319           0 :     sss_idmap_free_sid(ctx->sdap_id_ctx->opts->idmap_ctx->map, sid_str);
     320           0 :     talloc_free(tmp_ctx);
     321             : 
     322           0 :     return ret;
     323             : }
     324             : 
     325           0 : static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
     326             :                                      int count, bool root_domain,
     327             :                                      struct sysdb_attrs **reply,
     328             :                                      bool *changes)
     329           0 : {
     330             :     struct sdap_domain *sdom;
     331             :     struct sss_domain_info *domain, *dom;
     332           0 :     bool handled[count];
     333             :     const char *value;
     334           0 :     const char *root_name = NULL;
     335             :     int c, h;
     336             :     int ret;
     337             :     bool enumerate;
     338             : 
     339           0 :     domain = ctx->be_ctx->domain;
     340           0 :     memset(handled, 0, sizeof(bool) * count);
     341           0 :     h = 0;
     342             : 
     343           0 :     if (root_domain) {
     344           0 :         ret = sysdb_attrs_get_string(reply[0], AD_AT_TRUST_PARTNER,
     345             :                                      &root_name);
     346           0 :         if (ret != EOK) {
     347           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
     348           0 :             goto done;
     349             :         }
     350             :     }
     351             : 
     352             :     /* check existing subdomains */
     353           0 :     for (dom = get_next_domain(domain, true);
     354           0 :          dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
     355           0 :          dom = get_next_domain(dom, false)) {
     356             : 
     357             :         /* If we are handling root domain, skip all the other domains. We don't
     358             :          * want to accidentally remove non-root domains
     359             :          */
     360           0 :         if (root_name && strcmp(root_name, dom->name) != 0) {
     361           0 :             continue;
     362             :         }
     363             : 
     364           0 :         for (c = 0; c < count; c++) {
     365           0 :             if (handled[c]) {
     366           0 :                 continue;
     367             :             }
     368           0 :             ret = sysdb_attrs_get_string(reply[c], AD_AT_TRUST_PARTNER, &value);
     369           0 :             if (ret != EOK) {
     370           0 :                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
     371           0 :                 goto done;
     372             :             }
     373           0 :             if (strcmp(value, dom->name) == 0) {
     374           0 :                 break;
     375             :             }
     376             :         }
     377             : 
     378           0 :         if (c >= count) {
     379             :             /* ok this subdomain does not exist anymore, let's clean up */
     380           0 :             sss_domain_set_state(dom, DOM_DISABLED);
     381           0 :             ret = sysdb_subdomain_delete(dom->sysdb, dom->name);
     382           0 :             if (ret != EOK) {
     383           0 :                 goto done;
     384             :             }
     385             : 
     386           0 :             sdom = sdap_domain_get(ctx->sdap_id_ctx->opts, dom);
     387           0 :             if (sdom == NULL) {
     388           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Domain does not exist?\n");
     389           0 :                 continue;
     390             :             }
     391             : 
     392             :             /* Remove the subdomain from the list of LDAP domains */
     393           0 :             sdap_domain_remove(ctx->sdap_id_ctx->opts, dom);
     394             : 
     395           0 :             be_ptask_destroy(&sdom->enum_task);
     396           0 :             be_ptask_destroy(&sdom->cleanup_task);
     397             : 
     398             :             /* terminate all requests for this subdomain so we can free it */
     399           0 :             be_terminate_domain_requests(ctx->be_ctx, dom->name);
     400           0 :             talloc_zfree(sdom);
     401             :         } else {
     402             :             /* ok let's try to update it */
     403           0 :             ret = ad_subdom_enumerates(domain, reply[c], &enumerate);
     404           0 :             if (ret != EOK) {
     405           0 :                 goto done;
     406             :             }
     407             : 
     408           0 :             ret = ad_subdom_store(ctx, domain, reply[c], enumerate);
     409           0 :             if (ret) {
     410             :                 /* Nothing we can do about the error. Let's at least try
     411             :                  * to reuse the existing domains
     412             :                  */
     413           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Failed to parse subdom data, "
     414             :                       "will try to use cached subdomain\n");
     415             :             }
     416           0 :             handled[c] = true;
     417           0 :             h++;
     418             :         }
     419             :     }
     420             : 
     421           0 :     if (count == h) {
     422             :         /* all domains were already accounted for and have been updated */
     423           0 :         ret = EOK;
     424           0 :         *changes = false;
     425           0 :         goto done;
     426             :     }
     427             : 
     428             :     /* if we get here it means we have changes to the subdomains list */
     429           0 :     *changes = true;
     430             : 
     431           0 :     for (c = 0; c < count; c++) {
     432           0 :         if (handled[c]) {
     433           0 :             continue;
     434             :         }
     435             :         /* Nothing we can do about the error. Let's at least try
     436             :          * to reuse the existing domains.
     437             :          */
     438           0 :         ret = ad_subdom_enumerates(domain, reply[c], &enumerate);
     439           0 :         if (ret != EOK) {
     440           0 :             goto done;
     441             :         }
     442             : 
     443           0 :         ret = ad_subdom_store(ctx, domain, reply[c], enumerate);
     444           0 :         if (ret) {
     445           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Failed to parse subdom data, "
     446             :                   "will try to use cached subdomain\n");
     447             :         }
     448             :     }
     449             : 
     450           0 :     ret = EOK;
     451             : 
     452             : done:
     453           0 :     if (ret != EOK) {
     454           0 :         ctx->last_refreshed = 0;
     455             :     } else {
     456           0 :         ctx->last_refreshed = time(NULL);
     457             :     }
     458             : 
     459           0 :     return ret;
     460             : }
     461             : 
     462           0 : static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx)
     463             : {
     464             :     errno_t ret;
     465             : 
     466           0 :     ret = sss_write_krb5_conf_snippet(
     467           0 :                             dp_opt_get_string(ctx->ad_id_ctx->ad_options->basic,
     468             :                                               AD_KRB5_CONFD_PATH));
     469           0 :     if (ret != EOK) {
     470           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n");
     471             :         /* Just continue */
     472             :     }
     473             : 
     474           0 :     ret = sysdb_update_subdomains(ctx->be_ctx->domain);
     475           0 :     if (ret != EOK) {
     476           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
     477           0 :         return ret;
     478             :     }
     479             : 
     480           0 :     ret = sss_write_domain_mappings(ctx->be_ctx->domain);
     481           0 :     if (ret != EOK) {
     482           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "sss_krb5_write_mappings failed.\n");
     483             :         /* Just continue */
     484             :     }
     485             : 
     486           0 :     ret = ads_store_sdap_subdom(ctx, ctx->be_ctx->domain);
     487           0 :     if (ret != EOK) {
     488           0 :         DEBUG(SSSDBG_OP_FAILURE, "ads_store_sdap_subdom failed.\n");
     489           0 :         return ret;
     490             :     }
     491             : 
     492           0 :     return EOK;
     493             : }
     494             : 
     495             : static void ad_subdomains_get_conn_done(struct tevent_req *req);
     496             : static void ad_subdomains_master_dom_done(struct tevent_req *req);
     497             : static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx);
     498             : static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx);
     499             : 
     500           0 : static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx,
     501             :                                    struct be_req *be_req)
     502             : {
     503           0 :     struct ad_subdomains_req_ctx *req_ctx = NULL;
     504             :     struct tevent_req *req;
     505           0 :     int dp_error = DP_ERR_FATAL;
     506             :     int ret;
     507             : 
     508           0 :     req_ctx = talloc_zero(be_req, struct ad_subdomains_req_ctx);
     509           0 :     if (req_ctx == NULL) {
     510           0 :         ret = ENOMEM;
     511           0 :         goto done;
     512             :     }
     513             : 
     514           0 :     req_ctx->be_req = be_req;
     515           0 :     req_ctx->sd_ctx = ctx;
     516           0 :     req_ctx->current_filter = NULL;
     517           0 :     req_ctx->base_iter = 0;
     518           0 :     req_ctx->root_base_iter = 0;
     519           0 :     req_ctx->root_id_ctx = NULL;
     520           0 :     req_ctx->root_op = NULL;
     521           0 :     req_ctx->root_domain = NULL;
     522           0 :     req_ctx->root_domain_attrs = NULL;
     523           0 :     req_ctx->reply_count = 0;
     524           0 :     req_ctx->reply = NULL;
     525             : 
     526           0 :     req_ctx->sdap_op = sdap_id_op_create(req_ctx,
     527           0 :                                          ctx->ldap_ctx->conn_cache);
     528           0 :     if (req_ctx->sdap_op == NULL) {
     529           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
     530           0 :         ret = ENOMEM;
     531           0 :         goto done;
     532             :     }
     533             : 
     534           0 :     req = sdap_id_op_connect_send(req_ctx->sdap_op, req_ctx, &ret);
     535           0 :     if (req == NULL) {
     536           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
     537             :                                   ret, strerror(ret));
     538           0 :         goto done;
     539             :     }
     540             : 
     541           0 :     tevent_req_set_callback(req, ad_subdomains_get_conn_done, req_ctx);
     542             : 
     543           0 :     return;
     544             : 
     545             : done:
     546           0 :     talloc_free(req_ctx);
     547           0 :     if (ret == EOK) {
     548           0 :         dp_error = DP_ERR_OK;
     549             :     }
     550           0 :     be_req_terminate(be_req, dp_error, ret, NULL);
     551             : }
     552             : 
     553           0 : static void ad_subdomains_get_conn_done(struct tevent_req *req)
     554             : {
     555             :     int ret;
     556           0 :     int dp_error = DP_ERR_FATAL;
     557             :     struct ad_subdomains_req_ctx *ctx;
     558             : 
     559           0 :     ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
     560             : 
     561           0 :     ret = sdap_id_op_connect_recv(req, &dp_error);
     562           0 :     talloc_zfree(req);
     563           0 :     if (ret) {
     564           0 :         if (dp_error == DP_ERR_OFFLINE) {
     565           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     566             :                   "No AD server is available, cannot get the "
     567             :                    "subdomain list while offline\n");
     568             :         } else {
     569           0 :             DEBUG(SSSDBG_OP_FAILURE,
     570             :                   "Failed to connect to AD server: [%d](%s)\n",
     571             :                    ret, strerror(ret));
     572             :         }
     573             : 
     574           0 :         goto fail;
     575             :     }
     576             : 
     577           0 :     req = ad_master_domain_send(ctx, ctx->sd_ctx->be_ctx->ev,
     578           0 :                                 ctx->sd_ctx->ldap_ctx,
     579             :                                 ctx->sdap_op,
     580           0 :                                 ctx->sd_ctx->domain_name);
     581           0 :     if (req == NULL) {
     582           0 :         DEBUG(SSSDBG_OP_FAILURE, "ad_master_domain_send failed.\n");
     583           0 :         ret = ENOMEM;
     584           0 :         goto fail;
     585             :     }
     586           0 :     tevent_req_set_callback(req, ad_subdomains_master_dom_done, ctx);
     587           0 :     return;
     588             : 
     589             : fail:
     590           0 :     be_req_terminate(ctx->be_req, dp_error, ret, NULL);
     591             : }
     592             : 
     593           0 : static void ad_subdomains_master_dom_done(struct tevent_req *req)
     594             : {
     595             :     struct ad_subdomains_req_ctx *ctx;
     596             :     errno_t ret;
     597             :     const char *realm;
     598             : 
     599           0 :     ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
     600             : 
     601           0 :     ret = ad_master_domain_recv(req, ctx,
     602             :                                 &ctx->flat_name, &ctx->master_sid,
     603             :                                 &ctx->site, &ctx->forest);
     604           0 :     talloc_zfree(req);
     605           0 :     if (ret != EOK) {
     606           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve master domain info\n");
     607           0 :         goto done;
     608             :     }
     609             : 
     610           0 :     realm = dp_opt_get_cstring(ctx->sd_ctx->ad_id_ctx->ad_options->basic,
     611             :                                AD_KRB5_REALM);
     612           0 :     if (realm == NULL) {
     613           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm.\n");
     614           0 :         ret = EINVAL;
     615           0 :         goto done;
     616             :     }
     617             : 
     618           0 :     ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain,
     619             :                                        realm,
     620           0 :                                        ctx->flat_name, ctx->master_sid,
     621           0 :                                        ctx->forest);
     622           0 :     if (ret != EOK) {
     623           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info\n");
     624           0 :         goto done;
     625             :     }
     626             : 
     627           0 :     if (ctx->forest == NULL ||
     628           0 :           strcasecmp(ctx->sd_ctx->be_ctx->domain->name, ctx->forest) != 0) {
     629           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     630             :               "SSSD needs to look up the forest root domain\n");
     631           0 :         ret = ad_subdomains_get_root(ctx);
     632             :     } else {
     633           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     634             :               "Connected to forest root, looking up child domains..\n");
     635             : 
     636           0 :         ctx->root_op = ctx->sdap_op;
     637           0 :         ctx->root_id_ctx = ctx->sd_ctx->ad_id_ctx;
     638             : 
     639           0 :         ret = ad_subdomains_get_slave(ctx);
     640             :     }
     641             : 
     642           0 :     if (ret == EAGAIN) {
     643           0 :         return;
     644           0 :     } else if (ret != EOK) {
     645           0 :         goto done;
     646             :     }
     647             : 
     648             : done:
     649           0 :     be_req_terminate(ctx->be_req, DP_ERR_FATAL, ret, NULL);
     650             : }
     651             : 
     652             : static void ad_subdomains_get_root_domain_done(struct tevent_req *req);
     653             : 
     654           0 : static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx)
     655             : {
     656             :     struct tevent_req *req;
     657             :     struct sdap_search_base *base;
     658             :     struct sdap_id_ctx *sdap_id_ctx;
     659             :     char *filter;
     660           0 :     const char *forest_root_attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
     661             :                                         AD_AT_SID, AD_AT_TRUST_TYPE,
     662             :                                         AD_AT_TRUST_ATTRS, NULL };
     663             : 
     664           0 :     sdap_id_ctx = ctx->sd_ctx->sdap_id_ctx;
     665           0 :     base = sdap_id_ctx->opts->sdom->search_bases[ctx->root_base_iter];
     666           0 :     if (base == NULL) {
     667           0 :         return EOK;
     668             :     }
     669             : 
     670           0 :     filter = talloc_asprintf(ctx, FOREST_ROOT_FILTER_FMT, ctx->forest);
     671           0 :     if (filter == NULL) {
     672           0 :         return ENOMEM;
     673             :     }
     674             : 
     675           0 :     req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
     676             :                                 sdap_id_ctx->opts,
     677             :                                 sdap_id_op_handle(ctx->sdap_op),
     678             :                                 base->basedn, LDAP_SCOPE_SUBTREE,
     679             :                                 filter, forest_root_attrs,
     680             :                                 NULL, 0,
     681           0 :                                 dp_opt_get_int(sdap_id_ctx->opts->basic,
     682             :                                                 SDAP_SEARCH_TIMEOUT),
     683             :                                 false);
     684             : 
     685           0 :     if (req == NULL) {
     686           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
     687           0 :         return ENOMEM;
     688             :     }
     689             : 
     690           0 :     tevent_req_set_callback(req, ad_subdomains_get_root_domain_done, ctx);
     691           0 :     return EAGAIN;
     692             : }
     693             : 
     694             : static struct sss_domain_info *ads_get_root_domain(struct ad_subdomains_req_ctx *ctx);
     695             : static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx);
     696             : static void ad_subdomains_root_conn_done(struct tevent_req *req);
     697             : 
     698           0 : static void ad_subdomains_get_root_domain_done(struct tevent_req *req)
     699             : {
     700             :     int ret;
     701             :     size_t reply_count;
     702           0 :     struct sysdb_attrs **reply = NULL;
     703             :     struct ad_subdomains_req_ctx *ctx;
     704           0 :     int dp_error = DP_ERR_FATAL;
     705           0 :     bool has_changes = false;
     706             : 
     707           0 :     ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
     708             : 
     709           0 :     ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
     710           0 :     talloc_zfree(req);
     711           0 :     if (ret != EOK) {
     712           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
     713           0 :         goto fail;
     714             :     }
     715             : 
     716           0 :     if (reply_count == 0) {
     717             :         /* If no root domain was found in the default search base, try the
     718             :          * next one, if available
     719             :          */
     720           0 :         ctx->root_base_iter++;
     721           0 :         ret = ad_subdomains_get_root(ctx);
     722           0 :         if (ret == EAGAIN) {
     723           0 :             return;
     724             :         }
     725             : 
     726           0 :         goto fail;
     727           0 :     } else if (reply_count > 1) {
     728           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     729             :               "Multiple results for root domain search, "
     730             :               "domain list might be incomplete!\n");
     731             : 
     732           0 :         ctx->root_op = ctx->sdap_op;
     733           0 :         ctx->root_id_ctx = ctx->sd_ctx->ad_id_ctx;
     734             : 
     735           0 :         ret = ad_subdomains_get_slave(ctx);
     736           0 :         if (ret == EAGAIN) {
     737           0 :             return;
     738             :         }
     739             : 
     740           0 :         goto fail;
     741             :     }
     742             :     /* Exactly one result, good. */
     743             : 
     744             :     /* We won't use the operation to the local LDAP anymore, but
     745             :      * read from the forest root
     746             :      */
     747           0 :     ret = sdap_id_op_done(ctx->sdap_op, ret, &dp_error);
     748           0 :     if (ret != EOK) {
     749           0 :         if (dp_error == DP_ERR_OFFLINE) {
     750           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     751             :                   "No AD server is available, cannot get the "
     752             :                    "subdomain list while offline\n");
     753             :         } else {
     754           0 :             DEBUG(SSSDBG_OP_FAILURE,
     755             :                   "Failed to search the AD server: [%d](%s)\n",
     756             :                   ret, strerror(ret));
     757             :         }
     758           0 :         goto fail;
     759             :     }
     760             : 
     761           0 :     ret = ad_subdomains_refresh(ctx->sd_ctx, 1, true, reply, &has_changes);
     762           0 :     if (ret != EOK) {
     763           0 :         DEBUG(SSSDBG_OP_FAILURE, "ad_subdomains_refresh failed.\n");
     764           0 :         goto fail;
     765             :     }
     766             : 
     767           0 :     if (has_changes) {
     768           0 :         ret = ad_subdom_reinit(ctx->sd_ctx);
     769           0 :         if (ret != EOK) {
     770           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
     771           0 :             goto fail;
     772             :         }
     773             :     }
     774             : 
     775           0 :     ctx->root_domain_attrs = reply[0];
     776           0 :     ctx->root_domain = ads_get_root_domain(ctx);
     777           0 :     if (ctx->root_domain == NULL) {
     778           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not find the root domain\n");
     779           0 :         ret = EFAULT;
     780           0 :         goto fail;
     781             :     }
     782             : 
     783           0 :     ctx->root_id_ctx = ads_get_root_id_ctx(ctx);
     784           0 :     if (ctx->root_id_ctx == NULL) {
     785           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot create id ctx for the root domain\n");
     786           0 :         ret = EFAULT;
     787           0 :         goto fail;
     788             :     }
     789             : 
     790           0 :     ctx->root_op = sdap_id_op_create(ctx,
     791           0 :                                      ctx->root_id_ctx->ldap_ctx->conn_cache);
     792           0 :     if (ctx->root_op == NULL) {
     793           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
     794           0 :         ret = ENOMEM;
     795           0 :         goto fail;
     796             :     }
     797             : 
     798           0 :     req = sdap_id_op_connect_send(ctx->root_op, ctx, &ret);
     799           0 :     if (req == NULL) {
     800           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
     801             :                                   ret, strerror(ret));
     802           0 :         goto fail;
     803             :     }
     804             : 
     805           0 :     tevent_req_set_callback(req, ad_subdomains_root_conn_done, ctx);
     806           0 :     return;
     807             : 
     808             : fail:
     809           0 :     if (ret == EOK) {
     810           0 :         ctx->sd_ctx->last_refreshed = time(NULL);
     811           0 :         dp_error = DP_ERR_OK;
     812             :     }
     813           0 :     be_req_terminate(ctx->be_req, dp_error, ret, NULL);
     814             : }
     815             : 
     816           0 : static struct sss_domain_info *ads_get_root_domain(struct ad_subdomains_req_ctx *ctx)
     817             : {
     818             :     errno_t ret;
     819             :     const char *name;
     820             :     struct sss_domain_info *root;
     821             : 
     822           0 :     ret = sysdb_attrs_get_string(ctx->root_domain_attrs, AD_AT_TRUST_PARTNER, &name);
     823           0 :     if (ret != EOK) {
     824           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
     825           0 :         return NULL;
     826             :     }
     827             : 
     828             :     /* With a subsequent run, the root should already be known */
     829           0 :     root = find_domain_by_name(ctx->sd_ctx->be_ctx->domain,
     830             :                                name, false);
     831             : 
     832           0 :     return root;
     833             : }
     834             : 
     835           0 : static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx)
     836             : {
     837             :     errno_t ret;
     838             :     struct sdap_domain *sdom;
     839             :     struct ad_id_ctx *root_id_ctx;
     840             : 
     841           0 :     sdom = sdap_domain_get(ctx->sd_ctx->ad_id_ctx->sdap_id_ctx->opts,
     842             :                            ctx->root_domain);
     843           0 :     if (sdom == NULL) {
     844           0 :         DEBUG(SSSDBG_OP_FAILURE,
     845             :               "Cannot get the sdom for %s!\n", ctx->root_domain->name);
     846           0 :         return NULL;
     847             :     }
     848             : 
     849           0 :     if (sdom->pvt == NULL) {
     850           0 :         ret = ad_subdom_ad_ctx_new(ctx->sd_ctx->be_ctx,
     851           0 :                                    ctx->sd_ctx->ad_id_ctx,
     852             :                                    ctx->root_domain,
     853             :                                    &root_id_ctx);
     854           0 :         if (ret != EOK) {
     855           0 :             DEBUG(SSSDBG_OP_FAILURE, "ad_subdom_ad_ctx_new failed.\n");
     856           0 :             return NULL;
     857             :         }
     858             : 
     859           0 :         sdom->pvt = root_id_ctx;
     860             :     } else {
     861           0 :         root_id_ctx = sdom->pvt;
     862             :     }
     863             : 
     864           0 :     root_id_ctx->ldap_ctx->ignore_mark_offline = true;
     865           0 :     return root_id_ctx;
     866             : }
     867             : 
     868           0 : static void ad_subdomains_root_conn_done(struct tevent_req *req)
     869             : {
     870             :     int ret;
     871           0 :     int dp_error = DP_ERR_FATAL;
     872             :     struct ad_subdomains_req_ctx *ctx;
     873             : 
     874           0 :     ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
     875             : 
     876           0 :     ret = sdap_id_op_connect_recv(req, &dp_error);
     877           0 :     talloc_zfree(req);
     878           0 :     if (ret) {
     879           0 :         be_mark_dom_offline(ctx->root_domain, be_req_get_be_ctx(ctx->be_req));
     880             : 
     881           0 :         DEBUG(SSSDBG_OP_FAILURE,
     882             :               "Failed to connect to AD server: [%d](%s)\n",
     883             :               ret, strerror(ret));
     884           0 :         goto fail;
     885             :     }
     886             : 
     887           0 :     ret = ad_subdomains_get_slave(ctx);
     888           0 :     if (ret == EAGAIN) {
     889           0 :         return;
     890           0 :     } else if (ret != EOK) {
     891           0 :         goto fail;
     892             :     }
     893             : 
     894             : fail:
     895           0 :     be_req_terminate(ctx->be_req, dp_error, ret, NULL);
     896             : }
     897             : 
     898             : static void ad_subdomains_get_slave_domain_done(struct tevent_req *req);
     899             : 
     900           0 : static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx)
     901             : {
     902             :     struct tevent_req *req;
     903             :     struct sdap_search_base *base;
     904           0 :     const char *slave_dom_attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
     905             :                                       AD_AT_SID, AD_AT_TRUST_TYPE,
     906             :                                       AD_AT_TRUST_ATTRS, NULL };
     907             : 
     908           0 :     base = ctx->root_id_ctx->sdap_id_ctx->opts->sdom->search_bases[ctx->base_iter];
     909           0 :     if (base == NULL) {
     910           0 :         return EOK;
     911             :     }
     912             : 
     913           0 :     req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
     914           0 :                            ctx->root_id_ctx->sdap_id_ctx->opts,
     915             :                            sdap_id_op_handle(ctx->root_op),
     916             :                            base->basedn, LDAP_SCOPE_SUBTREE,
     917             :                            SLAVE_DOMAIN_FILTER, slave_dom_attrs,
     918             :                            NULL, 0,
     919           0 :                            dp_opt_get_int(ctx->root_id_ctx->sdap_id_ctx->opts->basic,
     920             :                                           SDAP_SEARCH_TIMEOUT),
     921             :                            false);
     922             : 
     923           0 :     if (req == NULL) {
     924           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
     925           0 :         return ENOMEM;
     926             :     }
     927             : 
     928           0 :     tevent_req_set_callback(req, ad_subdomains_get_slave_domain_done, ctx);
     929           0 :     return EAGAIN;
     930             : }
     931             : 
     932           0 : static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
     933             :                                      struct sss_domain_info *domain,
     934             :                                      size_t nsd, struct sysdb_attrs **sd,
     935             :                                      struct sysdb_attrs *root,
     936             :                                      size_t *_nsd_out,
     937             :                                      struct sysdb_attrs ***_sd_out)
     938             : {
     939             :     size_t i, sdi;
     940             :     struct sysdb_attrs **sd_out;
     941             :     const char *sd_name;
     942             :     errno_t ret;
     943             : 
     944           0 :     if (root == NULL) {
     945             :         /* We are connected directly to the root domain. The 'sd'
     946             :          * list is complete and we can just use it
     947             :          */
     948           0 :         *_nsd_out = nsd;
     949           0 :         *_sd_out = sd;
     950           0 :         return EOK;
     951             :     }
     952             : 
     953             :     /* If we searched for root separately, we must:
     954             :      *  a) treat the root domain as a subdomain
     955             :      *  b) filter the subdomain we are connected to from the subdomain
     956             :      *     list, from our point of view, it's the master domain
     957             :      */
     958           0 :     sd_out = talloc_zero_array(mem_ctx, struct sysdb_attrs *, nsd+1);
     959           0 :     if (sd_out == NULL) {
     960           0 :         return ENOMEM;
     961             :     }
     962             : 
     963           0 :     sdi = 0;
     964           0 :     for (i = 0; i < nsd; i++) {
     965           0 :         ret = sysdb_attrs_get_string(sd[i], AD_AT_TRUST_PARTNER, &sd_name);
     966           0 :         if (ret != EOK) {
     967           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
     968           0 :             goto fail;
     969             :         }
     970             : 
     971           0 :         if (strcasecmp(sd_name, domain->name) == 0) {
     972           0 :             DEBUG(SSSDBG_TRACE_INTERNAL,
     973             :                   "Not including primary domain %s in the subdomain list\n",
     974             :                   domain->name);
     975           0 :             continue;
     976             :         }
     977             : 
     978           0 :         sd_out[sdi] = talloc_steal(sd_out, sd[i]);
     979           0 :         sdi++;
     980             :     }
     981             : 
     982             :     /* Now include the root */
     983           0 :     sd_out[sdi] = talloc_steal(sd_out, root);
     984             : 
     985           0 :     *_nsd_out = sdi+1;
     986           0 :     *_sd_out = sd_out;
     987           0 :     return EOK;
     988             : 
     989             : fail:
     990           0 :     talloc_free(sd_out);
     991           0 :     return ret;
     992             : }
     993             : 
     994           0 : static void ad_subdomains_get_slave_domain_done(struct tevent_req *req)
     995             : {
     996             :     int ret;
     997             :     size_t reply_count;
     998           0 :     struct sysdb_attrs **reply = NULL;
     999             :     struct ad_subdomains_req_ctx *ctx;
    1000           0 :     int dp_error = DP_ERR_FATAL;
    1001           0 :     bool refresh_has_changes = false;
    1002             :     size_t nsubdoms;
    1003             :     struct sysdb_attrs **subdoms;
    1004             : 
    1005           0 :     ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
    1006             : 
    1007           0 :     ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
    1008           0 :     talloc_zfree(req);
    1009           0 :     if (ret != EOK) {
    1010           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
    1011           0 :         goto done;
    1012             :     }
    1013             : 
    1014           0 :     if (reply_count) {
    1015           0 :         ctx->reply = talloc_realloc(ctx, ctx->reply, struct sysdb_attrs *,
    1016             :                                     ctx->reply_count + reply_count);
    1017           0 :         if (ctx->reply == NULL) {
    1018           0 :             ret = ENOMEM;
    1019           0 :             goto done;
    1020             :         }
    1021           0 :         memcpy(ctx->reply+ctx->reply_count, reply,
    1022             :                reply_count * sizeof(struct sysdb_attrs *));
    1023           0 :         ctx->reply_count += reply_count;
    1024             :     }
    1025             : 
    1026           0 :     ctx->base_iter++;
    1027           0 :     ret = ad_subdomains_get_slave(ctx);
    1028           0 :     if (ret == EAGAIN) {
    1029             :         /* Search in progress */
    1030           0 :         return;
    1031             :     }
    1032             : 
    1033           0 :     ret = sdap_id_op_done(ctx->root_op, ret, &dp_error);
    1034           0 :     if (ret != EOK) {
    1035           0 :         if (dp_error == DP_ERR_OFFLINE) {
    1036           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    1037             :                   "No AD server is available, cannot get the "
    1038             :                    "subdomain list while offline\n");
    1039             :         } else {
    1040           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1041             :                   "Failed to search the AD server: [%d](%s)\n",
    1042             :                   ret, strerror(ret));
    1043             :         }
    1044           0 :         tevent_req_error(req, ret);
    1045           0 :         return;
    1046             :     }
    1047             : 
    1048             :     /* Based on whether we are connected to the forest root or not, we might
    1049             :      * need to exclude the subdomain we are connected to from the list of
    1050             :      * subdomains
    1051             :      */
    1052           0 :     ret = ad_subdomains_process(ctx, ctx->sd_ctx->be_ctx->domain,
    1053             :                                 ctx->reply_count, ctx->reply,
    1054             :                                 ctx->root_domain_attrs, &nsubdoms, &subdoms);
    1055           0 :     if (ret != EOK) {
    1056           0 :         DEBUG(SSSDBG_OP_FAILURE, ("Cannot process subdomain list\n"));
    1057           0 :         tevent_req_error(req, ret);
    1058           0 :         return;
    1059             :     }
    1060             : 
    1061             :     /* Got all the subdomains, let's process them */
    1062           0 :     ret = ad_subdomains_refresh(ctx->sd_ctx, nsubdoms, false, subdoms,
    1063             :                                 &refresh_has_changes);
    1064           0 :     if (ret != EOK) {
    1065           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh subdomains.\n");
    1066           0 :         goto done;
    1067             :     }
    1068             : 
    1069           0 :     DEBUG(SSSDBG_TRACE_LIBS, "There are %schanges\n",
    1070             :                     refresh_has_changes ? "" : "no ");
    1071             : 
    1072           0 :     if (refresh_has_changes) {
    1073           0 :         ret = ad_subdom_reinit(ctx->sd_ctx);
    1074           0 :         if (ret != EOK) {
    1075           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
    1076           0 :             goto done;
    1077             :         }
    1078             :     }
    1079             : 
    1080           0 :     ret = EOK;
    1081             : done:
    1082           0 :     if (ret == EOK) {
    1083           0 :         ctx->sd_ctx->last_refreshed = time(NULL);
    1084           0 :         dp_error = DP_ERR_OK;
    1085             :     }
    1086           0 :     be_req_terminate(ctx->be_req, dp_error, ret, NULL);
    1087             : }
    1088             : 
    1089             : static void ad_subdom_online_cb(void *pvt);
    1090             : 
    1091           0 : static void ad_subdom_timer_refresh(struct tevent_context *ev,
    1092             :                                      struct tevent_timer *te,
    1093             :                                      struct timeval current_time,
    1094             :                                      void *pvt)
    1095             : {
    1096           0 :     ad_subdom_online_cb(pvt);
    1097           0 : }
    1098             : 
    1099           0 : static void ad_subdom_be_req_callback(struct be_req *be_req,
    1100             :                                        int dp_err, int dp_ret,
    1101             :                                        const char *errstr)
    1102             : {
    1103           0 :     talloc_free(be_req);
    1104           0 : }
    1105             : 
    1106           0 : static void ad_subdom_online_cb(void *pvt)
    1107             : {
    1108             :     struct ad_subdomains_ctx *ctx;
    1109             :     struct be_req *be_req;
    1110             :     struct timeval tv;
    1111             :     uint32_t refresh_interval;
    1112             : 
    1113           0 :     ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
    1114           0 :     if (!ctx) {
    1115           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Bad private pointer\n");
    1116           0 :         return;
    1117             :     }
    1118             : 
    1119           0 :     refresh_interval = ctx->be_ctx->domain->subdomain_refresh_interval;
    1120             : 
    1121           0 :     be_req = be_req_create(ctx, NULL, ctx->be_ctx,
    1122             :                            ad_subdom_be_req_callback, NULL);
    1123           0 :     if (be_req == NULL) {
    1124           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "be_req_create() failed.\n");
    1125           0 :         return;
    1126             :     }
    1127             : 
    1128           0 :     ad_subdomains_retrieve(ctx, be_req);
    1129             : 
    1130           0 :     tv = tevent_timeval_current_ofs(refresh_interval, 0);
    1131           0 :     ctx->timer_event = tevent_add_timer(ctx->be_ctx->ev, ctx, tv,
    1132             :                                         ad_subdom_timer_refresh, ctx);
    1133           0 :     if (!ctx->timer_event) {
    1134           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom timer event\n");
    1135             :     }
    1136             : }
    1137             : 
    1138           0 : static void ad_subdom_offline_cb(void *pvt)
    1139             : {
    1140             :     struct ad_subdomains_ctx *ctx;
    1141             : 
    1142           0 :     ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
    1143             : 
    1144           0 :     if (ctx) {
    1145           0 :         talloc_zfree(ctx->timer_event);
    1146             :     }
    1147           0 : }
    1148             : 
    1149           0 : void ad_subdomains_handler(struct be_req *be_req)
    1150             : {
    1151           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
    1152             :     struct ad_subdomains_ctx *ctx;
    1153             :     time_t now;
    1154             : 
    1155           0 :     ctx = talloc_get_type(be_ctx->bet_info[BET_SUBDOMAINS].pvt_bet_data,
    1156             :                           struct ad_subdomains_ctx);
    1157           0 :     if (!ctx) {
    1158           0 :         be_req_terminate(be_req, DP_ERR_FATAL, EINVAL, NULL);
    1159           0 :         return;
    1160             :     }
    1161             : 
    1162           0 :     now = time(NULL);
    1163             : 
    1164           0 :     if (ctx->last_refreshed > now - AD_SUBDOMAIN_REFRESH_LIMIT) {
    1165           0 :         be_req_terminate(be_req, DP_ERR_OK, EOK, NULL);
    1166           0 :         return;
    1167             :     }
    1168             : 
    1169           0 :     ad_subdomains_retrieve(ctx, be_req);
    1170             : }
    1171             : 
    1172             : struct bet_ops ad_subdomains_ops = {
    1173             :     .handler = ad_subdomains_handler,
    1174             :     .finalize = NULL
    1175             : };
    1176             : 
    1177           0 : int ad_subdom_init(struct be_ctx *be_ctx,
    1178             :                    struct ad_id_ctx *id_ctx,
    1179             :                    const char *ad_domain,
    1180             :                    struct bet_ops **ops,
    1181             :                    void **pvt_data)
    1182             : {
    1183             :     struct ad_subdomains_ctx *ctx;
    1184             :     int ret;
    1185             :     enum idmap_error_code err;
    1186             : 
    1187           0 :     ctx = talloc_zero(id_ctx, struct ad_subdomains_ctx);
    1188           0 :     if (ctx == NULL) {
    1189           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
    1190           0 :         return ENOMEM;
    1191             :     }
    1192             : 
    1193           0 :     ctx->be_ctx = be_ctx;
    1194           0 :     ctx->sdom = id_ctx->sdap_id_ctx->opts->sdom;
    1195           0 :     ctx->ldap_ctx = id_ctx->ldap_ctx;
    1196           0 :     ctx->sdap_id_ctx = id_ctx->sdap_id_ctx;
    1197           0 :     ctx->domain_name = talloc_strdup(ctx, ad_domain);
    1198           0 :     if (ctx->domain_name == NULL) {
    1199           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
    1200           0 :         return ENOMEM;
    1201             :     }
    1202           0 :     ctx->ad_id_ctx = id_ctx;
    1203           0 :     *ops = &ad_subdomains_ops;
    1204           0 :     *pvt_data = ctx;
    1205             : 
    1206           0 :     ret = be_add_online_cb(ctx, be_ctx, ad_subdom_online_cb, ctx, NULL);
    1207           0 :     if (ret != EOK) {
    1208           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom online callback\n");
    1209             :     }
    1210             : 
    1211           0 :     ret = be_add_offline_cb(ctx, be_ctx, ad_subdom_offline_cb, ctx, NULL);
    1212           0 :     if (ret != EOK) {
    1213           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom offline callback\n");
    1214             :     }
    1215             : 
    1216           0 :     err = sss_idmap_init(sss_idmap_talloc, ctx, sss_idmap_talloc_free,
    1217             :                          &ctx->idmap_ctx);
    1218           0 :     if (err != IDMAP_SUCCESS) {
    1219           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n");
    1220           0 :         return EFAULT;
    1221             :     }
    1222             : 
    1223           0 :     ret = ad_subdom_reinit(ctx);
    1224           0 :     if (ret != EOK) {
    1225           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Could not reinitialize subdomains. "
    1226             :               "Users from trusted domains might not be resolved correctly\n");
    1227             :         /* Ignore this error and try to discover the subdomains later */
    1228             :     }
    1229             : 
    1230           0 :     return EOK;
    1231             : }

Generated by: LCOV version 1.10