"Fossies" - the Fresh Open Source Software Archive

Member "sssd-2.2.3/src/providers/ad/ad_subdomains.c" (30 Nov 2019, 69196 Bytes) of package /linux/misc/sssd-2.2.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ad_subdomains.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.2.2_vs_2.2.3.

    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 "providers/ldap/sdap_ops.h"
   33 #include "util/util_sss_idmap.h"
   34 #include <ctype.h>
   35 #include <ndr.h>
   36 #include <ndr/ndr_nbt.h>
   37 
   38 /* Attributes of AD trusted domains */
   39 #define AD_AT_FLATNAME      "flatName"
   40 #define AD_AT_SID           "securityIdentifier"
   41 #define AD_AT_TRUST_TYPE    "trustType"
   42 #define AD_AT_TRUST_PARTNER "trustPartner"
   43 #define AD_AT_TRUST_ATTRS   "trustAttributes"
   44 
   45 /* trustType=2 denotes uplevel (NT5 and later) trusted domains. See
   46  * http://msdn.microsoft.com/en-us/library/windows/desktop/ms680342%28v=vs.85%29.aspx
   47  * for example.
   48  *
   49  * The absence of msDS-TrustForestTrustInfo attribute denotes a domain from
   50  * the same forest. See http://msdn.microsoft.com/en-us/library/cc223786.aspx
   51  * for more information.
   52  */
   53 #define SLAVE_DOMAIN_FILTER_BASE "(objectclass=trustedDomain)(trustType=2)(!(msDS-TrustForestTrustInfo=*))"
   54 #define SLAVE_DOMAIN_FILTER      "(&"SLAVE_DOMAIN_FILTER_BASE")"
   55 #define FOREST_ROOT_FILTER_FMT   "(&"SLAVE_DOMAIN_FILTER_BASE"(cn=%s))"
   56 
   57 /* Attributes of schema objects. See e.g.
   58  * https://docs.microsoft.com/en-us/windows/desktop/AD/characteristics-of-attributes
   59  * for more details
   60  */
   61 #define AD_SCHEMA_AT_OC         "attributeSchema"
   62 #define AD_AT_SCHEMA_NAME       "cn"
   63 #define AD_AT_SCHEMA_IS_REPL    "isMemberOfPartialAttributeSet"
   64 
   65 /* do not refresh more often than every 5 seconds for now */
   66 #define AD_SUBDOMAIN_REFRESH_LIMIT 5
   67 
   68 static void
   69 ad_disable_gc(struct ad_options *ad_options)
   70 {
   71     errno_t ret;
   72 
   73     if (dp_opt_get_bool(ad_options->basic, AD_ENABLE_GC) == false) {
   74         return;
   75     }
   76 
   77     DEBUG(SSSDBG_IMPORTANT_INFO, "POSIX attributes were requested "
   78           "but are not present on the server side. Global Catalog "
   79           "lookups will be disabled\n");
   80 
   81     ret = dp_opt_set_bool(ad_options->basic,
   82                           AD_ENABLE_GC, false);
   83     if (ret != EOK) {
   84         DEBUG(SSSDBG_MINOR_FAILURE,
   85                 "Could not turn off GC support\n");
   86         /* Not fatal */
   87     }
   88 }
   89 
   90 static struct sss_domain_info *
   91 ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs)
   92 {
   93     struct sss_domain_info *dom;
   94     const char *name;
   95     errno_t ret;
   96 
   97     if (attrs == NULL) {
   98         /* Clients joined to the forest root directly don't even discover
   99          * the root domain, so the attrs are expected to be NULL in this
  100          * case
  101          */
  102         return be_ctx->domain;
  103     }
  104 
  105     ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name);
  106     if (ret != EOK) {
  107         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
  108         return NULL;
  109     }
  110 
  111     /* With a subsequent run, the root should already be known */
  112     for (dom = be_ctx->domain; dom != NULL;
  113          dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) {
  114 
  115         if (strcasecmp(dom->name, name) == 0) {
  116             /* The forest root is special, although it might be disabled for
  117              * general lookups we still want to try to get the domains in the
  118              * forest from a DC of the forest root */
  119             if (sss_domain_get_state(dom) == DOM_DISABLED
  120                     && !sss_domain_is_forest_root(dom)) {
  121                 return NULL;
  122             }
  123             return dom;
  124         }
  125     }
  126 
  127     return NULL;
  128 }
  129 
  130 static struct sdap_domain *
  131 ads_get_root_sdap_domain(struct be_ctx *be_ctx,
  132                          struct sdap_options *opts,
  133                          struct sysdb_attrs *attrs)
  134 {
  135     struct sdap_domain *root_sdom;
  136     struct sss_domain_info *root_dom;
  137 
  138     root_dom = ads_get_root_domain(be_ctx, attrs);
  139     if (root_dom == NULL) {
  140         DEBUG(SSSDBG_OP_FAILURE,
  141               "ads_get_root_domain did not find the domain\n");
  142         return NULL;
  143     }
  144 
  145     root_sdom = sdap_domain_get(opts, root_dom);
  146     if (root_sdom == NULL) {
  147         DEBUG(SSSDBG_OP_FAILURE,
  148               "Failed to find sdap_domain for the root domain\n");
  149         return NULL;
  150     }
  151 
  152     return root_sdom;
  153 }
  154 
  155 static errno_t ad_get_enabled_domains(TALLOC_CTX *mem_ctx,
  156                                       struct ad_id_ctx *ad_id_ctx,
  157                                       const char *ad_domain,
  158                                       const char ***_ad_enabled_domains)
  159 {
  160     int ret;
  161     const char *str;
  162     const char *option_name;
  163     const char **domains = NULL;
  164     int count;
  165     bool is_ad_in_domains;
  166     TALLOC_CTX *tmp_ctx = NULL;
  167 
  168     tmp_ctx = talloc_new(NULL);
  169     if (tmp_ctx == NULL) {
  170         return ENOMEM;
  171     }
  172 
  173     str = dp_opt_get_cstring(ad_id_ctx->ad_options->basic, AD_ENABLED_DOMAINS);
  174     if (str == NULL) {
  175         *_ad_enabled_domains = NULL;
  176         ret = EOK;
  177         goto done;
  178     }
  179 
  180     count = 0;
  181     ret = split_on_separator(tmp_ctx, str, ',', true, true,
  182                              discard_const_p(char **, &domains), &count);
  183     if (ret != EOK) {
  184         option_name = ad_id_ctx->ad_options->basic[AD_ENABLED_DOMAINS].opt_name;
  185         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse option [%s], [%i] [%s]!\n",
  186                                    option_name, ret, sss_strerror(ret));
  187         ret = EINVAL;
  188         goto done;
  189     }
  190 
  191     is_ad_in_domains = false;
  192     for (int i = 0; i < count; i++) {
  193         is_ad_in_domains += strcasecmp(ad_domain, domains[i]) == 0 ? true : false;
  194     }
  195 
  196     if (is_ad_in_domains == false) {
  197         domains = talloc_realloc(tmp_ctx, domains, const char*, count + 2);
  198         if (domains == NULL) {
  199             ret = ENOMEM;
  200             goto done;
  201         }
  202 
  203         domains[count] = talloc_strdup(domains, ad_domain);
  204         if (domains[count] == NULL) {
  205             ret = ENOMEM;
  206             goto done;
  207         }
  208 
  209         domains[count + 1] = NULL;
  210     } else {
  211         domains = talloc_realloc(tmp_ctx, domains, const char*, count + 1);
  212         if (domains == NULL) {
  213             ret = ENOMEM;
  214             goto done;
  215         }
  216 
  217         domains[count] = NULL;
  218     }
  219 
  220     *_ad_enabled_domains = talloc_steal(mem_ctx, domains);
  221     ret = EOK;
  222 
  223 done:
  224     talloc_free(tmp_ctx);
  225     return ret;
  226 }
  227 
  228 static bool is_domain_enabled(const char *domain,
  229                               const char **enabled_doms)
  230 {
  231     if (enabled_doms == NULL) {
  232         return true;
  233     }
  234 
  235     return string_in_list(domain, discard_const_p(char *, enabled_doms), false);
  236 }
  237 
  238 static errno_t
  239 update_parent_sdap_list(struct sdap_domain *parent_list,
  240                         struct sdap_domain *child_sdap)
  241 {
  242     struct sdap_domain *sditer;
  243 
  244     DLIST_FOR_EACH(sditer, parent_list) {
  245         if (sditer->dom == child_sdap->dom) {
  246             break;
  247         }
  248     }
  249 
  250     if (sditer == NULL) {
  251         /* Nothing to do */
  252         return EOK;
  253     }
  254 
  255     /* Update the search bases */
  256     sdap_domain_copy_search_bases(sditer, child_sdap);
  257 
  258     return EOK;
  259 }
  260 
  261 static errno_t
  262 ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
  263                      struct ad_id_ctx *id_ctx,
  264                      struct sss_domain_info *subdom,
  265                      struct ad_id_ctx **_subdom_id_ctx)
  266 {
  267     struct ad_options *ad_options;
  268     struct ad_id_ctx *ad_id_ctx;
  269     const char *gc_service_name;
  270     const char *service_name;
  271     struct ad_srv_plugin_ctx *srv_ctx;
  272     char *ad_domain;
  273     char *ad_site_override;
  274     struct sdap_domain *sdom;
  275     errno_t ret;
  276     const char *realm;
  277     const char *servers;
  278     const char *backup_servers;
  279     const char *hostname;
  280     const char *keytab;
  281     char *subdom_conf_path;
  282     bool use_kdcinfo = false;
  283     size_t n_lookahead_primary = SSS_KRB5_LOOKAHEAD_PRIMARY_DEFAULT;
  284     size_t n_lookahead_backup = SSS_KRB5_LOOKAHEAD_BACKUP_DEFAULT;
  285 
  286     realm = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_KRB5_REALM);
  287     hostname = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_HOSTNAME);
  288     keytab = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_KEYTAB);
  289     ad_domain = subdom->name;
  290     if (realm == NULL || hostname == NULL || ad_domain == NULL) {
  291         DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm or hostname.\n");
  292         return EINVAL;
  293     }
  294 
  295     subdom_conf_path = subdomain_create_conf_path(id_ctx, subdom);
  296     if (subdom_conf_path == NULL) {
  297         DEBUG(SSSDBG_CRIT_FAILURE, "subdom_conf_path failed\n");
  298         return ENOMEM;
  299     }
  300 
  301     ad_options = ad_create_2way_trust_options(id_ctx,
  302                                               be_ctx->cdb,
  303                                               subdom_conf_path,
  304                                               be_ctx->provider,
  305                                               realm,
  306                                               subdom,
  307                                               hostname, keytab);
  308     if (ad_options == NULL) {
  309         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
  310         talloc_free(ad_options);
  311         talloc_free(subdom_conf_path);
  312         return ENOMEM;
  313     }
  314 
  315     ret = ad_inherit_opts_if_needed(id_ctx->sdap_id_ctx->opts->basic,
  316                                     ad_options->id->basic,
  317                                     be_ctx->cdb, subdom_conf_path,
  318                                     SDAP_SASL_MECH);
  319     talloc_free(subdom_conf_path);
  320     if (ret != EOK) {
  321         DEBUG(SSSDBG_CRIT_FAILURE,
  322               "Failed to inherit option [%s] to sub-domain [%s]. "
  323               "This error is ignored but might cause issues or unexpected "
  324               "behavior later on.\n",
  325               id_ctx->ad_options->id->basic[SDAP_SASL_MECH].opt_name,
  326               subdom->name);
  327 
  328         return ret;
  329     }
  330 
  331     ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
  332 
  333     gc_service_name = talloc_asprintf(ad_options, "sd_gc_%s", subdom->name);
  334     if (gc_service_name == NULL) {
  335         talloc_free(ad_options);
  336         return ENOMEM;
  337     }
  338 
  339     service_name = talloc_asprintf(ad_options, "sd_%s", subdom->name);
  340     if (service_name == NULL) {
  341         talloc_free(ad_options);
  342         return ENOMEM;
  343     }
  344 
  345     servers = dp_opt_get_string(ad_options->basic, AD_SERVER);
  346     backup_servers = dp_opt_get_string(ad_options->basic, AD_BACKUP_SERVER);
  347 
  348     if (id_ctx->ad_options->auth_ctx != NULL
  349             && id_ctx->ad_options->auth_ctx->opts != NULL) {
  350         use_kdcinfo = dp_opt_get_bool(id_ctx->ad_options->auth_ctx->opts,
  351                                       KRB5_USE_KDCINFO);
  352         sss_krb5_parse_lookahead(
  353             dp_opt_get_string(id_ctx->ad_options->auth_ctx->opts,
  354                               KRB5_KDCINFO_LOOKAHEAD),
  355             &n_lookahead_primary,
  356             &n_lookahead_backup);
  357     }
  358 
  359     DEBUG(SSSDBG_TRACE_ALL,
  360           "Init failover for [%s][%s] with use_kdcinfo [%s].\n",
  361           subdom->name, subdom->realm, use_kdcinfo ? "true" : "false");
  362 
  363     ret = ad_failover_init(ad_options, be_ctx, servers, backup_servers,
  364                            subdom->realm, service_name, gc_service_name,
  365                            subdom->name, use_kdcinfo,
  366                            n_lookahead_primary,
  367                            n_lookahead_backup,
  368                            &ad_options->service);
  369     if (ret != EOK) {
  370         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
  371         talloc_free(ad_options);
  372         return ret;
  373     }
  374 
  375     ad_id_ctx = ad_id_ctx_init(ad_options, be_ctx);
  376     if (ad_id_ctx == NULL) {
  377         talloc_free(ad_options);
  378         return ENOMEM;
  379     }
  380     ad_id_ctx->sdap_id_ctx->opts = ad_options->id;
  381     ad_options->id_ctx = ad_id_ctx;
  382 
  383     /* use AD plugin */
  384     srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res,
  385                                      default_host_dbs,
  386                                      ad_id_ctx->ad_options->id,
  387                                      hostname,
  388                                      ad_domain,
  389                                      ad_site_override);
  390     if (srv_ctx == NULL) {
  391         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
  392         return ENOMEM;
  393     }
  394     be_fo_set_srv_lookup_plugin(be_ctx, ad_srv_plugin_send,
  395                                 ad_srv_plugin_recv, srv_ctx, "AD");
  396 
  397     ret = sdap_domain_subdom_add(ad_id_ctx->sdap_id_ctx,
  398                                  ad_id_ctx->sdap_id_ctx->opts->sdom,
  399                                  subdom->parent);
  400     if (ret != EOK) {
  401         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize sdap domain\n");
  402         talloc_free(ad_options);
  403         return ret;
  404     }
  405 
  406     sdom = sdap_domain_get(ad_id_ctx->sdap_id_ctx->opts, subdom);
  407     if (sdom == NULL) {
  408         return EFAULT;
  409     }
  410 
  411     sdap_inherit_options(subdom->parent->sd_inherit,
  412                          id_ctx->sdap_id_ctx->opts,
  413                          ad_id_ctx->sdap_id_ctx->opts);
  414 
  415     /* Set up the ID mapping object */
  416     ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
  417         id_ctx->sdap_id_ctx->opts->idmap_ctx;
  418 
  419     ret = ad_set_search_bases(ad_options->id, sdom);
  420     if (ret != EOK) {
  421         DEBUG(SSSDBG_MINOR_FAILURE, "Failed to set LDAP search bases for "
  422               "domain '%s'. Will try to use automatically detected search "
  423               "bases.", subdom->name);
  424     }
  425 
  426     ret = update_parent_sdap_list(id_ctx->sdap_id_ctx->opts->sdom,
  427                                   sdom);
  428     if (ret != EOK) {
  429         return ret;
  430     }
  431 
  432     *_subdom_id_ctx = ad_id_ctx;
  433     return EOK;
  434 }
  435 
  436 struct ad_subdomains_ctx {
  437     struct be_ctx *be_ctx;
  438     struct ad_id_ctx *ad_id_ctx;
  439     struct sdap_id_ctx *sdap_id_ctx;
  440 
  441     struct sdap_domain *sdom;
  442     char *domain_name;
  443     const char **ad_enabled_domains;
  444 
  445     time_t last_refreshed;
  446 };
  447 
  448 static errno_t ad_subdom_enumerates(struct sss_domain_info *parent,
  449                                     struct sysdb_attrs *attrs,
  450                                     bool *_enumerates)
  451 {
  452     errno_t ret;
  453     const char *name;
  454 
  455     ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name);
  456     if (ret != EOK) {
  457         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
  458         return ret;
  459     }
  460 
  461     *_enumerates = subdomain_enumerates(parent, name);
  462     return EOK;
  463 }
  464 
  465 static enum sss_domain_mpg_mode
  466 get_default_subdom_mpg_mode(struct sdap_idmap_ctx *idmap_ctx,
  467                             struct sss_domain_info *parent,
  468                             const char *subdom_name,
  469                             char *subdom_sid_str)
  470 {
  471     bool use_id_mapping;
  472     bool inherit_option;
  473     enum sss_domain_mpg_mode default_mpg_mode;
  474 
  475     inherit_option = string_in_list(CONFDB_DOMAIN_AUTO_UPG,
  476                                     parent->sd_inherit, false);
  477     if (inherit_option) {
  478         return get_domain_mpg_mode(parent);
  479     }
  480 
  481     use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx,
  482                                                                subdom_name,
  483                                                                subdom_sid_str);
  484     if (use_id_mapping == true) {
  485         default_mpg_mode = MPG_ENABLED;
  486     } else {
  487         /* Domains that use the POSIX attributes set by the admin must
  488          * inherit the MPG setting from the parent domain so that the
  489          * auto_private_groups options works for trusted domains as well
  490          */
  491         default_mpg_mode = get_domain_mpg_mode(parent);
  492     }
  493 
  494     return default_mpg_mode;
  495 }
  496 
  497 static enum sss_domain_mpg_mode
  498 ad_subdom_mpg_mode(TALLOC_CTX *mem_ctx,
  499                    struct confdb_ctx *cdb,
  500                    struct sss_domain_info *parent,
  501                    enum sss_domain_mpg_mode default_mpg_mode,
  502                    const char *subdom_name)
  503 {
  504     char *subdom_conf_path;
  505     char *mpg_str_opt;
  506     errno_t ret;
  507     enum sss_domain_mpg_mode ret_mode;
  508 
  509     subdom_conf_path = subdomain_create_conf_path_from_str(mem_ctx,
  510                                                            parent->name,
  511                                                            subdom_name);
  512     if (subdom_conf_path == NULL) {
  513         DEBUG(SSSDBG_OP_FAILURE,
  514               "subdom_conf_path failed, will use %s mode as fallback\n",
  515               str_domain_mpg_mode(default_mpg_mode));
  516         return default_mpg_mode;
  517     }
  518 
  519     ret = confdb_get_string(cdb, mem_ctx, subdom_conf_path,
  520                             CONFDB_DOMAIN_AUTO_UPG,
  521                             NULL,
  522                             &mpg_str_opt);
  523     talloc_free(subdom_conf_path);
  524     if (ret != EOK) {
  525         DEBUG(SSSDBG_OP_FAILURE,
  526               "condb_get_string failed, will use %s mode as fallback\n",
  527               str_domain_mpg_mode(default_mpg_mode));
  528         return default_mpg_mode;
  529     }
  530 
  531     if (mpg_str_opt == NULL) {
  532         DEBUG(SSSDBG_CONF_SETTINGS,
  533               "Subdomain MPG mode not set, using %s\n",
  534               str_domain_mpg_mode(default_mpg_mode));
  535         return default_mpg_mode;
  536     }
  537 
  538     ret_mode = str_to_domain_mpg_mode(mpg_str_opt);
  539     talloc_free(mpg_str_opt);
  540     return ret_mode;
  541 }
  542 
  543 static errno_t
  544 ad_subdom_store(struct confdb_ctx *cdb,
  545                 struct sdap_idmap_ctx *idmap_ctx,
  546                 struct sss_domain_info *domain,
  547                 struct sysdb_attrs *subdom_attrs,
  548                 bool enumerate)
  549 {
  550     TALLOC_CTX *tmp_ctx;
  551     const char *name;
  552     char *realm;
  553     const char *flat;
  554     errno_t ret;
  555     enum idmap_error_code err;
  556     struct ldb_message_element *el;
  557     char *sid_str = NULL;
  558     uint32_t trust_type;
  559     enum sss_domain_mpg_mode mpg_mode;
  560     enum sss_domain_mpg_mode default_mpg_mode;
  561 
  562     tmp_ctx = talloc_new(NULL);
  563     if (tmp_ctx == NULL) {
  564         ret = ENOMEM;
  565         goto done;
  566     }
  567 
  568     ret = sysdb_attrs_get_uint32_t(subdom_attrs, AD_AT_TRUST_TYPE,
  569                                    &trust_type);
  570     if (ret != EOK) {
  571         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_uint32_t failed.\n");
  572         goto done;
  573     }
  574 
  575     ret = sysdb_attrs_get_string(subdom_attrs, AD_AT_TRUST_PARTNER, &name);
  576     if (ret != EOK) {
  577         DEBUG(SSSDBG_OP_FAILURE, "failed to get subdomain name\n");
  578         goto done;
  579     }
  580 
  581     realm = get_uppercase_realm(tmp_ctx, name);
  582     if (!realm) {
  583         ret = ENOMEM;
  584         goto done;
  585     }
  586 
  587     ret = sysdb_attrs_get_string(subdom_attrs, AD_AT_FLATNAME, &flat);
  588     if (ret) {
  589         DEBUG(SSSDBG_OP_FAILURE, "failed to get flat name of subdomain %s\n",
  590                                   name);
  591         goto done;
  592     }
  593 
  594     ret = sysdb_attrs_get_el(subdom_attrs, AD_AT_SID, &el);
  595     if (ret != EOK || el->num_values != 1) {
  596         DEBUG(SSSDBG_OP_FAILURE, "sdap_attrs_get_el failed.\n");
  597         goto done;
  598     }
  599 
  600     err = sss_idmap_bin_sid_to_sid(idmap_ctx->map, el->values[0].data,
  601                                    el->values[0].length, &sid_str);
  602     if (err != IDMAP_SUCCESS) {
  603         DEBUG(SSSDBG_MINOR_FAILURE,
  604               "Could not convert SID: [%s].\n", idmap_error_string(err));
  605         ret = EFAULT;
  606         goto done;
  607     }
  608 
  609     default_mpg_mode = get_default_subdom_mpg_mode(idmap_ctx, domain,
  610                                                    name, sid_str);
  611 
  612     mpg_mode = ad_subdom_mpg_mode(tmp_ctx, cdb, domain,
  613                                   default_mpg_mode, name);
  614     DEBUG(SSSDBG_CONF_SETTINGS, "MPG mode of %s is %s\n",
  615                                 name, str_domain_mpg_mode(mpg_mode));
  616 
  617     ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
  618                                 mpg_mode, enumerate, domain->forest, 0, NULL);
  619     if (ret != EOK) {
  620         DEBUG(SSSDBG_OP_FAILURE, "sysdb_subdomain_store failed.\n");
  621         goto done;
  622     }
  623 
  624     ret = EOK;
  625 done:
  626     sss_idmap_free_sid(idmap_ctx->map, sid_str);
  627     talloc_free(tmp_ctx);
  628 
  629     return ret;
  630 }
  631 
  632 static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
  633                                      struct sdap_idmap_ctx *idmap_ctx,
  634                                      struct sdap_options *opts,
  635                                      struct sysdb_attrs **subdomains,
  636                                      size_t num_subdomains,
  637                                      bool root_domain,
  638                                      time_t *_last_refreshed,
  639                                      bool *_changes)
  640 {
  641     struct sdap_domain *sdom;
  642     struct sss_domain_info *domain;
  643     struct sss_domain_info *dom;
  644     bool handled[num_subdomains];
  645     const char *value;
  646     const char *root_name = NULL;
  647     size_t c, h;
  648     int ret;
  649     bool enumerate;
  650 
  651     domain = be_ctx->domain;
  652     memset(handled, 0, sizeof(bool) * num_subdomains);
  653     h = 0;
  654 
  655     if (root_domain) {
  656         ret = sysdb_attrs_get_string(subdomains[0], AD_AT_TRUST_PARTNER,
  657                                      &root_name);
  658         if (ret != EOK) {
  659             DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
  660             goto done;
  661         }
  662     }
  663 
  664     /* check existing subdomains */
  665     for (dom = get_next_domain(domain, SSS_GND_DESCEND);
  666          dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */
  667          dom = get_next_domain(dom, 0)) {
  668 
  669         /* If we are handling root domain, skip all the other domains. We don't
  670          * want to accidentally remove non-root domains
  671          */
  672         if (root_name && strcmp(root_name, dom->name) != 0) {
  673             continue;
  674         }
  675 
  676         for (c = 0; c < num_subdomains; c++) {
  677             if (handled[c]) {
  678                 continue;
  679             }
  680             ret = sysdb_attrs_get_string(subdomains[c], AD_AT_TRUST_PARTNER,
  681                                          &value);
  682             if (ret != EOK) {
  683                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
  684                 goto done;
  685             }
  686             if (strcmp(value, dom->name) == 0) {
  687                 break;
  688             }
  689         }
  690 
  691         if (c >= num_subdomains) {
  692             /* ok this subdomain does not exist anymore, let's clean up */
  693             sss_domain_set_state(dom, DOM_DISABLED);
  694 
  695             /* Just disable the forest root but do not remove sdap data */
  696             if (sss_domain_is_forest_root(dom)) {
  697                 DEBUG(SSSDBG_TRACE_ALL,
  698                       "Skipping removal of forest root sdap data.\n");
  699 
  700                 ret = sysdb_domain_set_enabled(dom->sysdb, dom->name, false);
  701                 if (ret != EOK && ret != ENOENT) {
  702                     DEBUG(SSSDBG_OP_FAILURE, "Unable to disable domain %s "
  703                           "[%d]: %s\n", dom->name, ret, sss_strerror(ret));
  704                     goto done;
  705                 }
  706                 continue;
  707             }
  708 
  709             ret = sysdb_subdomain_delete(dom->sysdb, dom->name);
  710             if (ret != EOK) {
  711                 goto done;
  712             }
  713 
  714             sdom = sdap_domain_get(opts, dom);
  715             if (sdom == NULL) {
  716                 DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Domain does not exist?\n");
  717                 continue;
  718             }
  719 
  720             /* Remove the subdomain from the list of LDAP domains */
  721             sdap_domain_remove(opts, dom);
  722 
  723             /* terminate all requests for this subdomain so we can free it */
  724             dp_terminate_domain_requests(be_ctx->provider, dom->name);
  725             talloc_zfree(sdom);
  726         } else {
  727             /* ok let's try to update it */
  728             ret = ad_subdom_enumerates(domain, subdomains[c], &enumerate);
  729             if (ret != EOK) {
  730                 goto done;
  731             }
  732 
  733             ret = ad_subdom_store(be_ctx->cdb, idmap_ctx, domain,
  734                                   subdomains[c], enumerate);
  735             if (ret) {
  736                 /* Nothing we can do about the error. Let's at least try
  737                  * to reuse the existing domains
  738                  */
  739                 DEBUG(SSSDBG_MINOR_FAILURE, "Failed to parse subdom data, "
  740                       "will try to use cached subdomain\n");
  741             }
  742             handled[c] = true;
  743             h++;
  744         }
  745     }
  746 
  747     if (num_subdomains == h) {
  748         /* all domains were already accounted for and have been updated */
  749         ret = EOK;
  750         *_changes = false;
  751         goto done;
  752     }
  753 
  754     /* if we get here it means we have changes to the subdomains list */
  755     *_changes = true;
  756 
  757     for (c = 0; c < num_subdomains; c++) {
  758         if (handled[c]) {
  759             continue;
  760         }
  761         /* Nothing we can do about the error. Let's at least try
  762          * to reuse the existing domains.
  763          */
  764         ret = ad_subdom_enumerates(domain, subdomains[c], &enumerate);
  765         if (ret != EOK) {
  766             goto done;
  767         }
  768 
  769         ret = ad_subdom_store(be_ctx->cdb, idmap_ctx, domain,
  770                               subdomains[c], enumerate);
  771         if (ret) {
  772             DEBUG(SSSDBG_MINOR_FAILURE, "Failed to parse subdom data, "
  773                   "will try to use cached subdomain\n");
  774         }
  775     }
  776 
  777     ret = EOK;
  778 
  779 done:
  780     if (ret != EOK) {
  781         *_last_refreshed = 0;
  782     } else {
  783         *_last_refreshed = time(NULL);
  784     }
  785 
  786     return ret;
  787 }
  788 
  789 static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
  790                                      struct sss_domain_info *domain,
  791                                      const char **enabled_domains_list,
  792                                      size_t nsd, struct sysdb_attrs **sd,
  793                                      struct sysdb_attrs *root,
  794                                      size_t *_nsd_out,
  795                                      struct sysdb_attrs ***_sd_out)
  796 {
  797     size_t i, sdi;
  798     struct sysdb_attrs **sd_out;
  799     const char *sd_name;
  800     const char *root_name;
  801     errno_t ret;
  802 
  803     if (root == NULL && enabled_domains_list == NULL) {
  804         /* We are connected directly to the root domain. The 'sd'
  805          * list is complete and we can just use it
  806          */
  807         *_nsd_out = nsd;
  808         *_sd_out = sd;
  809         return EOK;
  810     }
  811 
  812     /* If we searched for root separately, we must:
  813      *  a) treat the root domain as a subdomain
  814      *  b) filter the subdomain we are connected to from the subdomain
  815      *     list, from our point of view, it's the master domain
  816      */
  817     sd_out = talloc_zero_array(mem_ctx, struct sysdb_attrs *, nsd+1);
  818     if (sd_out == NULL) {
  819         return ENOMEM;
  820     }
  821 
  822     sdi = 0;
  823     for (i = 0; i < nsd; i++) {
  824         ret = sysdb_attrs_get_string(sd[i], AD_AT_TRUST_PARTNER, &sd_name);
  825         if (ret != EOK) {
  826             DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
  827             goto fail;
  828         }
  829 
  830         if (is_domain_enabled(sd_name, enabled_domains_list) == false) {
  831             DEBUG(SSSDBG_TRACE_FUNC, "Disabling subdomain %s\n", sd_name);
  832 
  833             /* The subdomain is now disabled in configuraiton file, we
  834              * need to delete its cached content so it is not returned
  835              * by responders. The subdomain shares sysdb with its parent
  836              * domain so it is OK to use domain->sysdb. */
  837             ret = sysdb_subdomain_delete(domain->sysdb, sd_name);
  838             if (ret != EOK) {
  839                 goto fail;
  840             }
  841             continue;
  842         } else {
  843             DEBUG(SSSDBG_TRACE_FUNC, "Enabling subdomain %s\n", sd_name);
  844         }
  845 
  846         if (strcasecmp(sd_name, domain->name) == 0) {
  847             DEBUG(SSSDBG_TRACE_INTERNAL,
  848                   "Not including primary domain %s in the subdomain list\n",
  849                   domain->name);
  850             continue;
  851         }
  852 
  853         sd_out[sdi] = talloc_steal(sd_out, sd[i]);
  854         sdi++;
  855     }
  856 
  857     /* Now include the root */
  858     if (root != NULL) {
  859         ret = sysdb_attrs_get_string(root, AD_AT_TRUST_PARTNER, &root_name);
  860         if (ret != EOK) {
  861             DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
  862             goto fail;
  863         }
  864 
  865         if (is_domain_enabled(root_name, enabled_domains_list) == true) {
  866             sd_out[sdi] = talloc_steal(sd_out, root);
  867             sdi++;
  868         } else {
  869             DEBUG(SSSDBG_TRACE_FUNC, "Disabling forest root domain %s\n",
  870                                      root_name);
  871             ret = sysdb_domain_set_enabled(domain->sysdb, root_name, false);
  872             if (ret != EOK && ret != ENOENT) {
  873                 DEBUG(SSSDBG_OP_FAILURE, "Unable to disable domain %s "
  874                       "[%d]: %s\n", root_name, ret, sss_strerror(ret));
  875                 goto fail;
  876             }
  877         }
  878     }
  879 
  880     *_nsd_out = sdi;
  881     *_sd_out = sd_out;
  882     return EOK;
  883 
  884 fail:
  885     talloc_free(sd_out);
  886     return ret;
  887 }
  888 
  889 static errno_t
  890 ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
  891                       struct sss_domain_info *parent)
  892 {
  893     int ret;
  894     struct sdap_domain *sditer;
  895     struct ad_id_ctx *subdom_id_ctx;
  896 
  897     ret = sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent);
  898     if (ret != EOK) {
  899         DEBUG(SSSDBG_OP_FAILURE, "sdap_domain_subdom_add failed.\n");
  900         return ret;
  901     }
  902 
  903     ret = ad_set_search_bases(ctx->ad_id_ctx->ad_options->id, ctx->sdom);
  904     if (ret != EOK) {
  905         DEBUG(SSSDBG_MINOR_FAILURE, "failed to set ldap search bases for "
  906               "domain '%s'. will try to use automatically detected search "
  907               "bases.", ctx->sdom->dom->name);
  908     }
  909 
  910     DLIST_FOR_EACH(sditer, ctx->sdom) {
  911         if (IS_SUBDOMAIN(sditer->dom) && sditer->pvt == NULL) {
  912             ret = ad_subdom_ad_ctx_new(ctx->be_ctx, ctx->ad_id_ctx,
  913                                        sditer->dom, &subdom_id_ctx);
  914             if (ret != EOK) {
  915                 DEBUG(SSSDBG_OP_FAILURE, "ad_subdom_ad_ctx_new failed.\n");
  916             } else {
  917                 sditer->pvt = subdom_id_ctx;
  918             }
  919         }
  920     }
  921 
  922     return EOK;
  923 }
  924 
  925 static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx)
  926 {
  927     const char *path;
  928     errno_t ret;
  929     bool canonicalize = false;
  930     struct sss_domain_info *dom;
  931 
  932     path = dp_opt_get_string(subdoms_ctx->ad_id_ctx->ad_options->basic,
  933                              AD_KRB5_CONFD_PATH);
  934 
  935     if (subdoms_ctx->ad_id_ctx->ad_options->auth_ctx != NULL
  936             && subdoms_ctx->ad_id_ctx->ad_options->auth_ctx->opts != NULL) {
  937         canonicalize = dp_opt_get_bool(
  938                              subdoms_ctx->ad_id_ctx->ad_options->auth_ctx->opts,
  939                              KRB5_CANONICALIZE);
  940     } else {
  941         DEBUG(SSSDBG_CONF_SETTINGS, "Auth provider data is not available, "
  942                                     "most probably because the auth provider "
  943                                     "is not 'ad'. Kerberos configuration "
  944                                     "snippet to set the 'canonicalize' option "
  945                                     "will not be created.\n");
  946     }
  947 
  948     ret = sss_write_krb5_conf_snippet(path, canonicalize, true);
  949     if (ret != EOK) {
  950         DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n");
  951         /* Just continue */
  952     }
  953 
  954     ret = sysdb_update_subdomains(subdoms_ctx->be_ctx->domain,
  955                                   subdoms_ctx->be_ctx->cdb);
  956     if (ret != EOK) {
  957         DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
  958         return ret;
  959     }
  960 
  961     ret = sss_write_domain_mappings(subdoms_ctx->be_ctx->domain);
  962     if (ret != EOK) {
  963         DEBUG(SSSDBG_MINOR_FAILURE, "sss_krb5_write_mappings failed.\n");
  964         /* Just continue */
  965     }
  966 
  967     ret = ads_store_sdap_subdom(subdoms_ctx, subdoms_ctx->be_ctx->domain);
  968     if (ret != EOK) {
  969         DEBUG(SSSDBG_OP_FAILURE, "ads_store_sdap_subdom failed.\n");
  970         return ret;
  971     }
  972 
  973     /* Make sure disabled domains are not re-enabled accidentally */
  974     if (subdoms_ctx->ad_enabled_domains != NULL) {
  975         for (dom = subdoms_ctx->be_ctx->domain->subdomains; dom;
  976                                             dom = get_next_domain(dom, false)) {
  977             if (!is_domain_enabled(dom->name,
  978                                    subdoms_ctx->ad_enabled_domains)) {
  979                 sss_domain_set_state(dom, DOM_DISABLED);
  980             }
  981         }
  982     }
  983 
  984     return EOK;
  985 }
  986 
  987 struct ad_get_slave_domain_state {
  988     struct tevent_context *ev;
  989     struct ad_subdomains_ctx *sd_ctx;
  990     struct be_ctx *be_ctx;
  991     struct sdap_options *opts;
  992     struct sdap_idmap_ctx *idmap_ctx;
  993     struct sysdb_attrs *root_attrs;
  994     struct sdap_domain *root_sdom;
  995     struct sdap_id_op *sdap_op;
  996 };
  997 
  998 static errno_t ad_get_slave_domain_retry(struct tevent_req *req);
  999 static void ad_get_slave_domain_connect_done(struct tevent_req *subreq);
 1000 static void ad_get_slave_domain_done(struct tevent_req *subreq);
 1001 
 1002 static struct tevent_req *
 1003 ad_get_slave_domain_send(TALLOC_CTX *mem_ctx,
 1004                          struct tevent_context *ev,
 1005                          struct ad_subdomains_ctx *sd_ctx,
 1006                          struct sysdb_attrs *root_attrs,
 1007                          struct ad_id_ctx *root_id_ctx)
 1008 {
 1009     struct ad_get_slave_domain_state *state;
 1010     struct tevent_req *req;
 1011     errno_t ret;
 1012 
 1013     req = tevent_req_create(mem_ctx, &state,
 1014                             struct ad_get_slave_domain_state);
 1015     if (req == NULL) {
 1016         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
 1017         return NULL;
 1018     }
 1019 
 1020     state->ev = ev;
 1021     state->sd_ctx = sd_ctx;
 1022     state->be_ctx = sd_ctx->be_ctx;
 1023     state->opts = root_id_ctx->sdap_id_ctx->opts;
 1024     state->idmap_ctx = root_id_ctx->sdap_id_ctx->opts->idmap_ctx;
 1025     state->root_attrs = root_attrs;
 1026     state->root_sdom = ads_get_root_sdap_domain(state->be_ctx,
 1027                                                 state->opts,
 1028                                                 state->root_attrs);
 1029     if (state->root_sdom == NULL) {
 1030         ret = ERR_DOMAIN_NOT_FOUND;
 1031         goto immediately;
 1032     }
 1033 
 1034     state->sdap_op = sdap_id_op_create(state, root_id_ctx->ldap_ctx->conn_cache);
 1035     if (state->sdap_op == NULL) {
 1036         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
 1037         ret = ENOMEM;
 1038         goto immediately;
 1039     }
 1040 
 1041     ret = ad_get_slave_domain_retry(req);
 1042     if (ret == EAGAIN) {
 1043         /* asynchronous processing */
 1044         return req;
 1045     }
 1046 
 1047 immediately:
 1048     if (ret == EOK) {
 1049         tevent_req_done(req);
 1050     } else {
 1051         tevent_req_error(req, ret);
 1052     }
 1053     tevent_req_post(req, ev);
 1054 
 1055     return req;
 1056 }
 1057 
 1058 static errno_t ad_get_slave_domain_retry(struct tevent_req *req)
 1059 {
 1060     struct ad_get_slave_domain_state *state;
 1061     struct tevent_req *subreq;
 1062     int ret;
 1063 
 1064     state = tevent_req_data(req, struct ad_get_slave_domain_state);
 1065 
 1066     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
 1067     if (subreq == NULL) {
 1068         DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed "
 1069               "[%d]: %s\n", ret, sss_strerror(ret));
 1070         return ret;
 1071     }
 1072 
 1073     tevent_req_set_callback(subreq, ad_get_slave_domain_connect_done, req);
 1074 
 1075     return EAGAIN;
 1076 }
 1077 
 1078 static void ad_get_slave_domain_connect_done(struct tevent_req *subreq)
 1079 {
 1080     struct ad_get_slave_domain_state *state;
 1081     struct tevent_req *req = NULL;
 1082     int dp_error;
 1083     errno_t ret;
 1084     const char *attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
 1085                             AD_AT_SID, AD_AT_TRUST_TYPE,
 1086                             AD_AT_TRUST_ATTRS, NULL };
 1087 
 1088     req = tevent_req_callback_data(subreq, struct tevent_req);
 1089     state = tevent_req_data(req, struct ad_get_slave_domain_state);
 1090 
 1091     ret = sdap_id_op_connect_recv(subreq, &dp_error);
 1092     talloc_zfree(subreq);
 1093 
 1094     if (ret != EOK) {
 1095         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to connect to LDAP "
 1096               "[%d]: %s\n", ret, sss_strerror(ret));
 1097         if (dp_error == DP_ERR_OFFLINE) {
 1098             DEBUG(SSSDBG_MINOR_FAILURE, "No AD server is available, "
 1099                   "cannot get the subdomain list while offline\n");
 1100             ret = ERR_OFFLINE;
 1101         }
 1102         tevent_req_error(req, ret);
 1103         return;
 1104     }
 1105 
 1106     subreq = sdap_search_bases_send(state, state->ev, state->opts,
 1107                                     sdap_id_op_handle(state->sdap_op),
 1108                                     state->root_sdom->search_bases,
 1109                                     NULL, false, 0,
 1110                                     SLAVE_DOMAIN_FILTER, attrs, NULL);
 1111     if (subreq == NULL) {
 1112         tevent_req_error(req, ret);
 1113         return;
 1114     }
 1115 
 1116     tevent_req_set_callback(subreq, ad_get_slave_domain_done, req);
 1117     return;
 1118 }
 1119 
 1120 static void ad_get_slave_domain_done(struct tevent_req *subreq)
 1121 {
 1122     struct ad_get_slave_domain_state *state;
 1123     struct tevent_req *req;
 1124     struct sysdb_attrs **reply;
 1125     size_t reply_count;
 1126     struct sysdb_attrs **subdoms;
 1127     size_t nsubdoms;
 1128     bool has_changes;
 1129     int dp_error;
 1130     errno_t ret;
 1131 
 1132     req = tevent_req_callback_data(subreq, struct tevent_req);
 1133     state = tevent_req_data(req, struct ad_get_slave_domain_state);
 1134 
 1135     ret = sdap_search_bases_recv(subreq, state, &reply_count, &reply);
 1136     talloc_zfree(subreq);
 1137     if (ret != EOK) {
 1138         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup slave domain data "
 1139               "[%d]: %s\n", ret, sss_strerror(ret));
 1140         /* We continue to finish sdap_id_op. */
 1141     }
 1142 
 1143     ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
 1144     if (dp_error == DP_ERR_OK && ret != EOK) {
 1145         /* retry */
 1146         ret = ad_get_slave_domain_retry(req);
 1147         if (ret != EOK) {
 1148             goto done;
 1149         }
 1150         return;
 1151     } else if (dp_error == DP_ERR_OFFLINE) {
 1152         ret = ERR_OFFLINE;
 1153         goto done;
 1154     } else if (ret != EOK) {
 1155         goto done;
 1156     }
 1157 
 1158     /* Based on whether we are connected to the forest root or not, we might
 1159      * need to exclude the subdomain we are connected to from the list of
 1160      * subdomains.
 1161      */
 1162     ret = ad_subdomains_process(state, state->be_ctx->domain,
 1163                                 state->sd_ctx->ad_enabled_domains,
 1164                                 reply_count, reply, state->root_attrs,
 1165                                 &nsubdoms, &subdoms);
 1166     if (ret != EOK) {
 1167         DEBUG(SSSDBG_OP_FAILURE, "Cannot process subdomain list\n");
 1168         tevent_req_error(req, ret);
 1169         return;
 1170     }
 1171 
 1172     /* Got all the subdomains, let's process them. */
 1173     ret = ad_subdomains_refresh(state->be_ctx, state->idmap_ctx, state->opts,
 1174                                 subdoms, nsubdoms, false,
 1175                                 &state->sd_ctx->last_refreshed,
 1176                                 &has_changes);
 1177     if (ret != EOK) {
 1178         DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh subdomains.\n");
 1179         goto done;
 1180     }
 1181 
 1182     DEBUG(SSSDBG_TRACE_LIBS, "There are %schanges\n",
 1183           has_changes ? "" : "no ");
 1184 
 1185     if (has_changes) {
 1186         ret = ad_subdom_reinit(state->sd_ctx);
 1187         if (ret != EOK) {
 1188             DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
 1189             goto done;
 1190         }
 1191     }
 1192 
 1193     state->sd_ctx->last_refreshed = time(NULL);
 1194     ret = EOK;
 1195 
 1196 done:
 1197     if (ret != EOK) {
 1198         tevent_req_error(req, ret);
 1199         return;
 1200     }
 1201 
 1202     tevent_req_done(req);
 1203 }
 1204 
 1205 static errno_t ad_get_slave_domain_recv(struct tevent_req *req)
 1206 {
 1207     TEVENT_REQ_RETURN_ON_ERROR(req);
 1208 
 1209     return EOK;
 1210 }
 1211 
 1212 static struct ad_id_ctx *
 1213 ads_get_root_id_ctx(struct be_ctx *be_ctx,
 1214                     struct ad_id_ctx *ad_id_ctx,
 1215                     struct sss_domain_info *root_domain,
 1216                     struct sdap_options *opts)
 1217 {
 1218     errno_t ret;
 1219     struct sdap_domain *sdom;
 1220     struct ad_id_ctx *root_id_ctx;
 1221 
 1222     sdom = sdap_domain_get(opts, root_domain);
 1223     if (sdom == NULL) {
 1224         DEBUG(SSSDBG_OP_FAILURE,
 1225               "Cannot get the sdom for %s!\n", root_domain->name);
 1226         return NULL;
 1227     }
 1228 
 1229     if (sdom->pvt == NULL) {
 1230         ret = ad_subdom_ad_ctx_new(be_ctx, ad_id_ctx, root_domain,
 1231                                    &root_id_ctx);
 1232         if (ret != EOK) {
 1233             DEBUG(SSSDBG_OP_FAILURE, "ad_subdom_ad_ctx_new failed.\n");
 1234             return NULL;
 1235         }
 1236 
 1237         sdom->pvt = root_id_ctx;
 1238     } else {
 1239         root_id_ctx = sdom->pvt;
 1240     }
 1241 
 1242     root_id_ctx->ldap_ctx->ignore_mark_offline = true;
 1243     return root_id_ctx;
 1244 }
 1245 
 1246 struct ad_get_root_domain_state {
 1247     struct ad_subdomains_ctx *sd_ctx;
 1248     struct be_ctx *be_ctx;
 1249     struct sdap_idmap_ctx *idmap_ctx;
 1250     struct sdap_options *opts;
 1251 
 1252     struct ad_id_ctx *root_id_ctx;
 1253     struct sysdb_attrs *root_domain_attrs;
 1254 };
 1255 
 1256 static void ad_get_root_domain_done(struct tevent_req *subreq);
 1257 
 1258 static struct tevent_req *
 1259 ad_get_root_domain_send(TALLOC_CTX *mem_ctx,
 1260                         struct tevent_context *ev,
 1261                         const char *domain,
 1262                         const char *forest,
 1263                         struct sdap_handle *sh,
 1264                         struct ad_subdomains_ctx *sd_ctx)
 1265 {
 1266     struct ad_get_root_domain_state *state;
 1267     struct tevent_req *subreq;
 1268     struct tevent_req *req;
 1269     struct sdap_options *opts;
 1270     errno_t ret;
 1271     const char *filter;
 1272     const char *attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
 1273                             AD_AT_SID, AD_AT_TRUST_TYPE,
 1274                             AD_AT_TRUST_ATTRS, NULL };
 1275 
 1276     req = tevent_req_create(mem_ctx, &state, struct ad_get_root_domain_state);
 1277     if (req == NULL) {
 1278         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
 1279         return NULL;
 1280     }
 1281 
 1282     if (forest != NULL && strcasecmp(domain, forest) == 0) {
 1283         state->root_id_ctx = sd_ctx->ad_id_ctx;
 1284         state->root_domain_attrs = NULL;
 1285         ret = EOK;
 1286         goto immediately;
 1287     }
 1288 
 1289     DEBUG(SSSDBG_TRACE_FUNC, "Looking up the forest root domain.\n");
 1290 
 1291     state->sd_ctx = sd_ctx;
 1292     state->opts = opts = sd_ctx->sdap_id_ctx->opts;
 1293     state->be_ctx = sd_ctx->be_ctx;
 1294     state->idmap_ctx = opts->idmap_ctx;
 1295 
 1296     filter = talloc_asprintf(state, FOREST_ROOT_FILTER_FMT, forest);
 1297     if (filter == NULL) {
 1298         ret = ENOMEM;
 1299         goto immediately;
 1300     }
 1301 
 1302     subreq = sdap_search_bases_return_first_send(state, ev, opts, sh,
 1303                                                  opts->sdom->search_bases,
 1304                                                  NULL, false, 0, filter, attrs,
 1305                                                  NULL);
 1306     if (subreq == NULL) {
 1307         ret = ENOMEM;
 1308         goto immediately;
 1309     }
 1310 
 1311     tevent_req_set_callback(subreq, ad_get_root_domain_done, req);
 1312 
 1313     return req;
 1314 
 1315 immediately:
 1316     if (ret == EOK) {
 1317         tevent_req_done(req);
 1318     } else {
 1319         tevent_req_error(req, ret);
 1320     }
 1321     tevent_req_post(req, ev);
 1322 
 1323     return req;
 1324 }
 1325 
 1326 static void ad_get_root_domain_done(struct tevent_req *subreq)
 1327 {
 1328     struct tevent_req *req;
 1329     struct ad_get_root_domain_state *state;
 1330     struct sysdb_attrs **reply;
 1331     struct sss_domain_info *root_domain;
 1332     size_t reply_count;
 1333     bool has_changes;
 1334     errno_t ret;
 1335 
 1336     req = tevent_req_callback_data(subreq, struct tevent_req);
 1337     state = tevent_req_data(req, struct ad_get_root_domain_state);
 1338 
 1339     ret = sdap_search_bases_return_first_recv(subreq, state, &reply_count,
 1340                                               &reply);
 1341     talloc_zfree(subreq);
 1342     if (ret != EOK) {
 1343         DEBUG(SSSDBG_OP_FAILURE, "Unable to lookup forest root information "
 1344               "[%d]: %s\n", ret, sss_strerror(ret));
 1345         goto done;
 1346     }
 1347 
 1348     if (reply_count == 0) {
 1349         DEBUG(SSSDBG_OP_FAILURE, "No information provided for root domain\n");
 1350         ret = ENOENT;
 1351         goto done;
 1352     } else if (reply_count > 1) {
 1353         DEBUG(SSSDBG_CRIT_FAILURE, "Multiple results for root domain search, "
 1354               "domain list might be incomplete!\n");
 1355         ret = ERR_MALFORMED_ENTRY;
 1356         goto done;
 1357     }
 1358 
 1359     ret = ad_subdomains_refresh(state->be_ctx, state->idmap_ctx, state->opts,
 1360                                 reply, reply_count, true,
 1361                                 &state->sd_ctx->last_refreshed,
 1362                                 &has_changes);
 1363     if (ret != EOK) {
 1364         DEBUG(SSSDBG_OP_FAILURE, "ad_subdomains_refresh failed [%d]: %s\n",
 1365               ret, sss_strerror(ret));
 1366         goto done;
 1367     }
 1368 
 1369     if (has_changes) {
 1370         ret = ad_subdom_reinit(state->sd_ctx);
 1371         if (ret != EOK) {
 1372             DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
 1373             goto done;
 1374         }
 1375     }
 1376 
 1377     state->root_domain_attrs = reply[0];
 1378     root_domain = ads_get_root_domain(state->be_ctx, reply[0]);
 1379     if (root_domain == NULL) {
 1380         DEBUG(SSSDBG_OP_FAILURE, "Could not find the root domain\n");
 1381         ret = EFAULT;
 1382         goto done;
 1383     }
 1384 
 1385     state->root_id_ctx = ads_get_root_id_ctx(state->be_ctx,
 1386                                              state->sd_ctx->ad_id_ctx,
 1387                                              root_domain, state->opts);
 1388     if (state->root_id_ctx == NULL) {
 1389         DEBUG(SSSDBG_OP_FAILURE, "Cannot create id ctx for the root domain\n");
 1390         ret = EFAULT;
 1391         goto done;
 1392     }
 1393 
 1394     ret = EOK;
 1395 
 1396 done:
 1397     if (ret != EOK) {
 1398         tevent_req_error(req, ret);
 1399         return;
 1400     }
 1401 
 1402     tevent_req_done(req);
 1403 }
 1404 
 1405 static errno_t ad_get_root_domain_recv(TALLOC_CTX *mem_ctx,
 1406                                        struct tevent_req *req,
 1407                                        struct sysdb_attrs **_attrs,
 1408                                        struct ad_id_ctx **_id_ctx)
 1409 {
 1410     struct ad_get_root_domain_state *state = NULL;
 1411     state = tevent_req_data(req, struct ad_get_root_domain_state);
 1412 
 1413     TEVENT_REQ_RETURN_ON_ERROR(req);
 1414 
 1415     *_attrs = talloc_steal(mem_ctx, state->root_domain_attrs);
 1416     *_id_ctx = state->root_id_ctx;
 1417 
 1418     return EOK;
 1419 }
 1420 
 1421 static void ad_check_gc_usability_search_done(struct tevent_req *subreq);
 1422 
 1423 struct ad_check_gc_usability_state {
 1424     struct sdap_options *sdap_opts;
 1425 
 1426     const char *attrs[3];
 1427 
 1428     bool is_gc_usable;
 1429 };
 1430 
 1431 static struct tevent_req *
 1432 ad_check_gc_usability_send(TALLOC_CTX *mem_ctx,
 1433                            struct tevent_context *ev,
 1434                            struct ad_options *ad_options,
 1435                            struct sdap_options *sdap_opts,
 1436                            struct sdap_id_op *op,
 1437                            const char *domain_name,
 1438                            const char *domain_sid)
 1439 {
 1440     struct ad_check_gc_usability_state *state = NULL;
 1441     struct tevent_req *req = NULL;
 1442     struct tevent_req *subreq = NULL;
 1443     const char *filter = NULL;
 1444     errno_t ret;
 1445     bool uses_id_mapping;
 1446 
 1447     req = tevent_req_create(mem_ctx, &state,
 1448                             struct ad_check_gc_usability_state);
 1449     if (req == NULL) {
 1450         return NULL;
 1451     }
 1452     state->sdap_opts = sdap_opts;
 1453     state->is_gc_usable = false;
 1454 
 1455     if (dp_opt_get_bool(ad_options->basic, AD_ENABLE_GC) == false) {
 1456         DEBUG(SSSDBG_TRACE_FUNC, "GC explicitly disabled\n");
 1457         state->is_gc_usable = false;
 1458         ret = EOK;
 1459         goto immediately;
 1460     }
 1461 
 1462     uses_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
 1463                                                         sdap_opts->idmap_ctx,
 1464                                                         domain_name,
 1465                                                         domain_sid);
 1466     if (uses_id_mapping == true) {
 1467         DEBUG(SSSDBG_TRACE_FUNC, "GC always usable while ID mapping\n");
 1468         state->is_gc_usable = true;
 1469         ret = EOK;
 1470         goto immediately;
 1471     }
 1472 
 1473     /* The schema partition is replicated across all DCs in the forest, so
 1474      * it's safe to use the baseDN even if e.g. joined to a child domain
 1475      * even though the base DN "looks" like a part of the forest root
 1476      * tree. On the other hand, it doesn't make sense to guess the value
 1477      * if we can't detect it from the rootDSE.
 1478      */
 1479     if (state->sdap_opts->schema_basedn == NULL) {
 1480         DEBUG(SSSDBG_TRACE_FUNC,
 1481               "No idea where to look for the schema, disabling GC\n");
 1482         state->is_gc_usable = false;
 1483         ret = EOK;
 1484         goto immediately;
 1485     }
 1486 
 1487     state->attrs[0] = AD_AT_SCHEMA_NAME;
 1488     state->attrs[1] = AD_AT_SCHEMA_IS_REPL;
 1489     state->attrs[2] = NULL;
 1490 
 1491     DEBUG(SSSDBG_TRACE_FUNC, "Checking for POSIX attributes in GC\n");
 1492 
 1493     filter = talloc_asprintf(
 1494                         state,
 1495                         "(&(objectclass=%s)(|(%s=%s)(%s=%s)))",
 1496                         AD_SCHEMA_AT_OC,
 1497                         AD_AT_SCHEMA_NAME,
 1498                         state->sdap_opts->user_map[SDAP_AT_USER_UID].name,
 1499                         AD_AT_SCHEMA_NAME,
 1500                         state->sdap_opts->group_map[SDAP_AT_GROUP_GID].name);
 1501     if (filter == NULL) {
 1502         ret = ENOMEM;
 1503         goto immediately;
 1504     }
 1505 
 1506     subreq = sdap_get_generic_send(state,
 1507                                    ev,
 1508                                    state->sdap_opts,
 1509                                    sdap_id_op_handle(op),
 1510                                    state->sdap_opts->schema_basedn,
 1511                                    LDAP_SCOPE_SUBTREE,
 1512                                    filter,
 1513                                    state->attrs,
 1514                                    NULL, 0,
 1515                                    dp_opt_get_int(state->sdap_opts->basic,
 1516                                                   SDAP_SEARCH_TIMEOUT),
 1517                                    false);
 1518     if (subreq == NULL) {
 1519         ret = ENOMEM;
 1520         goto immediately;
 1521     }
 1522     tevent_req_set_callback(subreq, ad_check_gc_usability_search_done, req);
 1523 
 1524     return req;
 1525 
 1526 immediately:
 1527     if (ret == EOK) {
 1528         tevent_req_done(req);
 1529     } else {
 1530         tevent_req_error(req, ret);
 1531     }
 1532     tevent_req_post(req, ev);
 1533 
 1534     return req;
 1535 }
 1536 
 1537 static void ad_check_gc_usability_search_done(struct tevent_req *subreq)
 1538 {
 1539     struct tevent_req *req = tevent_req_callback_data(subreq,
 1540                                                       struct tevent_req);
 1541     struct ad_check_gc_usability_state *state = tevent_req_data(req,
 1542                                           struct ad_check_gc_usability_state);
 1543     errno_t ret;
 1544     size_t reply_count;
 1545     struct sysdb_attrs **reply = NULL;
 1546     bool uid = false;
 1547     bool gid = false;
 1548 
 1549     ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
 1550     talloc_zfree(subreq);
 1551     if (ret != EOK) {
 1552         DEBUG(SSSDBG_OP_FAILURE,
 1553               "sdap_get_generic_recv failed [%d]: %s\n",
 1554               ret, strerror(ret));
 1555         /* We continue to finish sdap_id_op. */
 1556     }
 1557 
 1558     if (reply_count == 0) {
 1559         DEBUG(SSSDBG_TRACE_LIBS,
 1560               "Nothing found, so no POSIX attrs can exist\n");
 1561         state->is_gc_usable = false;
 1562         tevent_req_done(req);
 1563         return;
 1564     }
 1565 
 1566     for (size_t i = 0; i < reply_count; i++) {
 1567         const char *name = NULL;
 1568         const char *is_in_partial_set = NULL;
 1569         bool *val = NULL;
 1570 
 1571         ret = sysdb_attrs_get_string(reply[i], AD_AT_SCHEMA_NAME, &name);
 1572         if (ret != EOK) {
 1573             DEBUG(SSSDBG_MINOR_FAILURE, "Cannot get "AD_AT_SCHEMA_NAME);
 1574             continue;
 1575         }
 1576 
 1577         if (strcasecmp(name, state->sdap_opts->user_map[SDAP_AT_USER_UID].name) == 0) {
 1578             val = &uid;
 1579         } else if (strcasecmp(name, state->sdap_opts->user_map[SDAP_AT_USER_GID].name) == 0) {
 1580             val = &gid;
 1581         } else {
 1582             DEBUG(SSSDBG_MINOR_FAILURE, "Unexpected attribute\n");
 1583             continue;
 1584         }
 1585 
 1586         ret = sysdb_attrs_get_string(reply[i],
 1587                                      AD_AT_SCHEMA_IS_REPL,
 1588                                      &is_in_partial_set);
 1589         if (ret != EOK) {
 1590             DEBUG(SSSDBG_MINOR_FAILURE, "Cannot get "AD_AT_SCHEMA_IS_REPL);
 1591             continue;
 1592         }
 1593 
 1594         if (strcasecmp(is_in_partial_set, "true") == 0) {
 1595             *val = true;
 1596         }
 1597     }
 1598 
 1599     if (uid == true && gid == true) {
 1600         state->is_gc_usable = true;
 1601     }
 1602 
 1603     if (state->is_gc_usable == true) {
 1604         DEBUG(SSSDBG_FUNC_DATA, "Server has POSIX attributes. Global Catalog will "
 1605                                 "be used for user and group lookups. Note that if "
 1606                                 "only a subset of POSIX attributes is present "
 1607                                 "in GC, the non-replicated attributes are "
 1608                                 "currently not read from the LDAP port\n");
 1609     }
 1610 
 1611     tevent_req_done(req);
 1612 }
 1613 
 1614 static errno_t ad_check_gc_usability_recv(struct tevent_req *req,
 1615                                           bool *_is_gc_usable)
 1616 {
 1617     struct ad_check_gc_usability_state *state = NULL;
 1618 
 1619     state = tevent_req_data(req, struct ad_check_gc_usability_state);
 1620 
 1621     TEVENT_REQ_RETURN_ON_ERROR(req);
 1622 
 1623     *_is_gc_usable = state->is_gc_usable;
 1624     return EOK;
 1625 }
 1626 
 1627 struct ad_subdomains_refresh_state {
 1628     struct tevent_context *ev;
 1629     struct be_ctx *be_ctx;
 1630     struct ad_subdomains_ctx *sd_ctx;
 1631     struct sdap_id_op *sdap_op;
 1632     struct sdap_id_ctx *id_ctx;
 1633     struct ad_options *ad_options;
 1634 
 1635     char *forest;
 1636 };
 1637 
 1638 static errno_t ad_subdomains_refresh_retry(struct tevent_req *req);
 1639 static void ad_subdomains_refresh_connect_done(struct tevent_req *subreq);
 1640 static void ad_subdomains_refresh_master_done(struct tevent_req *subreq);
 1641 static void ad_subdomains_refresh_gc_check_done(struct tevent_req *subreq);
 1642 static void ad_subdomains_refresh_root_done(struct tevent_req *subreq);
 1643 static void ad_subdomains_refresh_done(struct tevent_req *subreq);
 1644 
 1645 static struct tevent_req *
 1646 ad_subdomains_refresh_send(TALLOC_CTX *mem_ctx,
 1647                            struct tevent_context *ev,
 1648                            struct ad_subdomains_ctx *sd_ctx)
 1649 {
 1650     struct ad_subdomains_refresh_state *state;
 1651     struct tevent_req *req;
 1652     errno_t ret;
 1653 
 1654     req = tevent_req_create(mem_ctx, &state,
 1655                             struct ad_subdomains_refresh_state);
 1656     if (req == NULL) {
 1657         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
 1658         return NULL;
 1659     }
 1660 
 1661     state->ev = ev;
 1662     state->be_ctx = sd_ctx->be_ctx;
 1663     state->sd_ctx = sd_ctx;
 1664     state->id_ctx = sd_ctx->sdap_id_ctx;
 1665     state->ad_options = sd_ctx->ad_id_ctx->ad_options;
 1666 
 1667     state->sdap_op = sdap_id_op_create(state,
 1668                                        sd_ctx->sdap_id_ctx->conn->conn_cache);
 1669     if (state->sdap_op == NULL) {
 1670         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
 1671         ret = ENOMEM;
 1672         goto immediately;
 1673     }
 1674 
 1675     ret = ad_subdomains_refresh_retry(req);
 1676     if (ret == EAGAIN) {
 1677         /* asynchronous processing */
 1678         return req;
 1679     }
 1680 
 1681 immediately:
 1682     if (ret == EOK) {
 1683         tevent_req_done(req);
 1684     } else {
 1685         tevent_req_error(req, ret);
 1686     }
 1687     tevent_req_post(req, ev);
 1688 
 1689     return req;
 1690 }
 1691 
 1692 static errno_t ad_subdomains_refresh_retry(struct tevent_req *req)
 1693 {
 1694     struct ad_subdomains_refresh_state *state;
 1695     struct tevent_req *subreq;
 1696     int ret;
 1697 
 1698     state = tevent_req_data(req, struct ad_subdomains_refresh_state);
 1699 
 1700     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
 1701     if (subreq == NULL) {
 1702         DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed "
 1703               "[%d]: %s\n", ret, sss_strerror(ret));
 1704         return ret;
 1705     }
 1706 
 1707     tevent_req_set_callback(subreq, ad_subdomains_refresh_connect_done, req);
 1708 
 1709     return EAGAIN;
 1710 }
 1711 
 1712 static void ad_subdomains_refresh_connect_done(struct tevent_req *subreq)
 1713 {
 1714     struct ad_subdomains_refresh_state *state;
 1715     struct tevent_req *req;
 1716     int dp_error;
 1717     errno_t ret;
 1718 
 1719     req = tevent_req_callback_data(subreq, struct tevent_req);
 1720     state = tevent_req_data(req, struct ad_subdomains_refresh_state);
 1721 
 1722     ret = sdap_id_op_connect_recv(subreq, &dp_error);
 1723     talloc_zfree(subreq);
 1724 
 1725     if (ret != EOK) {
 1726         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to connect to LDAP "
 1727               "[%d]: %s\n", ret, sss_strerror(ret));
 1728         if (dp_error == DP_ERR_OFFLINE) {
 1729             DEBUG(SSSDBG_MINOR_FAILURE, "No AD server is available, "
 1730                   "cannot get the subdomain list while offline\n");
 1731             ret = ERR_OFFLINE;
 1732         }
 1733         tevent_req_error(req, ret);
 1734         return;
 1735     }
 1736 
 1737     /* connect to the DC we are a member of */
 1738     subreq = ad_master_domain_send(state, state->ev, state->id_ctx->conn,
 1739                                    state->sdap_op, state->sd_ctx->domain_name);
 1740     if (subreq == NULL) {
 1741         tevent_req_error(req, ENOMEM);
 1742         return;
 1743     }
 1744 
 1745     tevent_req_set_callback(subreq, ad_subdomains_refresh_master_done, req);
 1746     return;
 1747 }
 1748 
 1749 static void ad_subdomains_refresh_master_done(struct tevent_req *subreq)
 1750 {
 1751     struct ad_subdomains_refresh_state *state;
 1752     struct tevent_req *req;
 1753     const char *realm;
 1754     char *master_sid;
 1755     char *flat_name;
 1756     errno_t ret;
 1757 
 1758     req = tevent_req_callback_data(subreq, struct tevent_req);
 1759     state = tevent_req_data(req, struct ad_subdomains_refresh_state);
 1760 
 1761     ret = ad_master_domain_recv(subreq, state, &flat_name, &master_sid,
 1762                                 NULL, &state->forest);
 1763     talloc_zfree(subreq);
 1764     if (ret != EOK) {
 1765         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get master domain information "
 1766               "[%d]: %s\n", ret, sss_strerror(ret));
 1767         tevent_req_error(req, ret);
 1768         return;
 1769     }
 1770 
 1771     realm = dp_opt_get_cstring(state->ad_options->basic, AD_KRB5_REALM);
 1772     if (realm == NULL) {
 1773         DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm.\n");
 1774         tevent_req_error(req, EINVAL);
 1775         return;
 1776     }
 1777 
 1778     ret = sysdb_master_domain_add_info(state->be_ctx->domain, realm,
 1779                                        flat_name, master_sid, state->forest, NULL);
 1780     if (ret != EOK) {
 1781         DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info [%d]: %s\n",
 1782               ret, sss_strerror(ret));
 1783         tevent_req_error(req, ret);
 1784         return;
 1785     }
 1786 
 1787     subreq = ad_check_gc_usability_send(state,
 1788                                         state->ev,
 1789                                         state->ad_options,
 1790                                         state->id_ctx->opts,
 1791                                         state->sdap_op,
 1792                                         state->be_ctx->domain->name,
 1793                                         master_sid);
 1794     if (subreq == NULL) {
 1795         tevent_req_error(req, ENOMEM);
 1796         return;
 1797     }
 1798     tevent_req_set_callback(subreq, ad_subdomains_refresh_gc_check_done, req);
 1799 }
 1800 
 1801 static void ad_subdomains_refresh_gc_check_done(struct tevent_req *subreq)
 1802 {
 1803     struct ad_subdomains_refresh_state *state;
 1804     struct tevent_req *req;
 1805     const char **subdoms;
 1806     const char *ad_domain;
 1807     bool is_gc_usable;
 1808     errno_t ret;
 1809     int i;
 1810 
 1811     req = tevent_req_callback_data(subreq, struct tevent_req);
 1812     state = tevent_req_data(req, struct ad_subdomains_refresh_state);
 1813 
 1814     ret = ad_check_gc_usability_recv(subreq, &is_gc_usable);
 1815     talloc_zfree(subreq);
 1816     if (ret != EOK) {
 1817         DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get GC usability status\n");
 1818         is_gc_usable = false;
 1819     }
 1820 
 1821     if (is_gc_usable == false) {
 1822         ad_disable_gc(state->ad_options);
 1823     }
 1824 
 1825     /*
 1826      * If ad_enabled_domains contains only master domain
 1827      * we shouldn't lookup other domains.
 1828      */
 1829     if (state->sd_ctx->ad_enabled_domains != NULL) {
 1830         if (talloc_array_length(state->sd_ctx->ad_enabled_domains) == 2) {
 1831             if (strcasecmp(state->sd_ctx->ad_enabled_domains[0],
 1832                            state->be_ctx->domain->name) == 0) {
 1833                 DEBUG(SSSDBG_TRACE_FUNC,
 1834                       "No other enabled domain than master.\n");
 1835 
 1836                 ret = sysdb_list_subdomains(state, state->be_ctx->domain->sysdb,
 1837                                             &subdoms);
 1838                 if (ret != EOK) {
 1839                     DEBUG(SSSDBG_OP_FAILURE, "Unable to list subdomains "
 1840                           "[%d]: %s\n", ret, sss_strerror(ret));
 1841                     tevent_req_error(req, ret);
 1842                     return;
 1843                 }
 1844 
 1845                 for (i = 0; subdoms[i] != NULL; i++) {
 1846                     ret = sysdb_subdomain_delete(state->be_ctx->domain->sysdb,
 1847                                                  subdoms[i]);
 1848                     if (ret != EOK) {
 1849                         DEBUG(SSSDBG_OP_FAILURE, "Unable to remove subdomain "
 1850                               "[%d]: %s\n", ret, sss_strerror(ret));
 1851                         tevent_req_error(req, ret);
 1852                         return;
 1853                     }
 1854                 }
 1855 
 1856                 tevent_req_done(req);
 1857                 return;
 1858             }
 1859         }
 1860     }
 1861 
 1862     ad_domain = dp_opt_get_cstring(state->ad_options->basic, AD_DOMAIN);
 1863     if (ad_domain == NULL) {
 1864         DEBUG(SSSDBG_CONF_SETTINGS,
 1865              "Missing AD domain name, falling back to sssd domain name\n");
 1866         ad_domain = state->sd_ctx->be_ctx->domain->name;
 1867     }
 1868 
 1869     subreq = ad_get_root_domain_send(state, state->ev, ad_domain, state->forest,
 1870                                      sdap_id_op_handle(state->sdap_op),
 1871                                      state->sd_ctx);
 1872     if (subreq == NULL) {
 1873         tevent_req_error(req, ENOMEM);
 1874         return;
 1875     }
 1876 
 1877     tevent_req_set_callback(subreq, ad_subdomains_refresh_root_done, req);
 1878     return;
 1879 }
 1880 
 1881 static void ad_subdomains_refresh_root_done(struct tevent_req *subreq)
 1882 {
 1883     struct ad_subdomains_refresh_state *state;
 1884     struct tevent_req *req;
 1885     struct ad_id_ctx *root_id_ctx;
 1886     struct sysdb_attrs *root_attrs;
 1887     int dp_error;
 1888     errno_t ret;
 1889 
 1890     req = tevent_req_callback_data(subreq, struct tevent_req);
 1891     state = tevent_req_data(req, struct ad_subdomains_refresh_state);
 1892 
 1893     /* Note: For clients joined to the root domain, root_attrs is NULL,
 1894      * see ad_get_root_domain_send()
 1895      */
 1896     ret = ad_get_root_domain_recv(state, subreq, &root_attrs, &root_id_ctx);
 1897     talloc_zfree(subreq);
 1898     if (ret != EOK) {
 1899         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get forest root [%d]: %s\n",
 1900               ret, sss_strerror(ret));
 1901         root_attrs = NULL;
 1902         root_id_ctx = NULL;
 1903         /* We continue to finish sdap_id_op. */
 1904     }
 1905 
 1906     /* We finish sdap_id_op here since we connect
 1907      * to forest root for slave domains. */
 1908     ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
 1909     if (dp_error == DP_ERR_OK && ret != EOK) {
 1910         /* retry */
 1911         ret = ad_subdomains_refresh_retry(req);
 1912         if (ret != EOK) {
 1913             tevent_req_error(req, ret);
 1914         }
 1915         return;
 1916     } else if (dp_error == DP_ERR_OFFLINE) {
 1917         tevent_req_error(req, ERR_OFFLINE);
 1918         return;
 1919     } else if (ret != EOK) {
 1920         tevent_req_error(req, ret);
 1921         return;
 1922     }
 1923 
 1924     subreq = ad_get_slave_domain_send(state, state->ev, state->sd_ctx,
 1925                                       root_attrs, root_id_ctx);
 1926     if (subreq == NULL) {
 1927         tevent_req_error(req, ENOMEM);
 1928         return;
 1929     }
 1930 
 1931     tevent_req_set_callback(subreq, ad_subdomains_refresh_done, req);
 1932     return;
 1933 }
 1934 
 1935 static void ad_subdomains_refresh_done(struct tevent_req *subreq)
 1936 {
 1937     struct tevent_req *req;
 1938     errno_t ret;
 1939 
 1940     req = tevent_req_callback_data(subreq, struct tevent_req);
 1941 
 1942     ret = ad_get_slave_domain_recv(subreq);
 1943     talloc_zfree(subreq);
 1944     if (ret != EOK) {
 1945         DEBUG(SSSDBG_OP_FAILURE, "Unable to get subdomains [%d]: %s\n",
 1946               ret, sss_strerror(ret));
 1947     }
 1948 
 1949     if (ret != EOK) {
 1950         DEBUG(SSSDBG_TRACE_FUNC, "Unable to refresh subdomains [%d]: %s\n",
 1951               ret, sss_strerror(ret));
 1952         tevent_req_error(req, ret);
 1953         return;
 1954     }
 1955 
 1956     DEBUG(SSSDBG_TRACE_FUNC, "Subdomains refreshed.\n");
 1957     tevent_req_done(req);
 1958 }
 1959 
 1960 static errno_t ad_subdomains_refresh_recv(struct tevent_req *req)
 1961 {
 1962     TEVENT_REQ_RETURN_ON_ERROR(req);
 1963 
 1964     return EOK;
 1965 }
 1966 
 1967 struct ad_subdomains_handler_state {
 1968     struct dp_reply_std reply;
 1969 };
 1970 
 1971 static void ad_subdomains_handler_done(struct tevent_req *subreq);
 1972 
 1973 static struct tevent_req *
 1974 ad_subdomains_handler_send(TALLOC_CTX *mem_ctx,
 1975                            struct ad_subdomains_ctx *sd_ctx,
 1976                            struct dp_subdomains_data *data,
 1977                            struct dp_req_params *params)
 1978 {
 1979     struct ad_subdomains_handler_state *state;
 1980     struct tevent_req *req;
 1981     struct tevent_req *subreq;
 1982     errno_t ret;
 1983 
 1984     req = tevent_req_create(mem_ctx, &state,
 1985                             struct ad_subdomains_handler_state);
 1986     if (req == NULL) {
 1987         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
 1988         return NULL;
 1989     }
 1990 
 1991 
 1992     if (sd_ctx->last_refreshed > time(NULL) - AD_SUBDOMAIN_REFRESH_LIMIT) {
 1993         DEBUG(SSSDBG_TRACE_FUNC, "Subdomains were recently refreshed, "
 1994               "nothing to do\n");
 1995         ret = EOK;
 1996         goto immediately;
 1997     }
 1998 
 1999     subreq = ad_subdomains_refresh_send(state, params->ev, sd_ctx);
 2000     if (subreq == NULL) {
 2001         ret = ENOMEM;
 2002         goto immediately;
 2003     }
 2004 
 2005     tevent_req_set_callback(subreq, ad_subdomains_handler_done, req);
 2006 
 2007     return req;
 2008 
 2009 immediately:
 2010     dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
 2011 
 2012     /* TODO For backward compatibility we always return EOK to DP now. */
 2013     tevent_req_done(req);
 2014     tevent_req_post(req, params->ev);
 2015 
 2016     return req;
 2017 }
 2018 
 2019 static void ad_subdomains_handler_done(struct tevent_req *subreq)
 2020 {
 2021     struct ad_subdomains_handler_state *state;
 2022     struct tevent_req *req;
 2023     errno_t ret;
 2024 
 2025     req = tevent_req_callback_data(subreq, struct tevent_req);
 2026     state = tevent_req_data(req, struct ad_subdomains_handler_state);
 2027 
 2028     ret = ad_subdomains_refresh_recv(subreq);
 2029     talloc_zfree(subreq);
 2030 
 2031     /* TODO For backward compatibility we always return EOK to DP now. */
 2032     dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
 2033     tevent_req_done(req);
 2034 }
 2035 
 2036 static errno_t ad_subdomains_handler_recv(TALLOC_CTX *mem_ctx,
 2037                                           struct tevent_req *req,
 2038                                           struct dp_reply_std *data)
 2039 {
 2040    struct ad_subdomains_handler_state *state;
 2041 
 2042    state = tevent_req_data(req, struct ad_subdomains_handler_state);
 2043 
 2044    TEVENT_REQ_RETURN_ON_ERROR(req);
 2045 
 2046    *data = state->reply;
 2047 
 2048    return EOK;
 2049 }
 2050 
 2051 static struct tevent_req *
 2052 ad_subdomains_ptask_send(TALLOC_CTX *mem_ctx,
 2053                          struct tevent_context *ev,
 2054                          struct be_ctx *be_ctx,
 2055                          struct be_ptask *be_ptask,
 2056                          void *pvt)
 2057 {
 2058     struct ad_subdomains_ctx *sd_ctx;
 2059     sd_ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
 2060 
 2061     return ad_subdomains_refresh_send(mem_ctx, ev, sd_ctx);
 2062 }
 2063 
 2064 static errno_t
 2065 ad_subdomains_ptask_recv(struct tevent_req *req)
 2066 {
 2067     return ad_subdomains_refresh_recv(req);
 2068 }
 2069 
 2070 errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx,
 2071                            struct be_ctx *be_ctx,
 2072                            struct ad_id_ctx *ad_id_ctx,
 2073                            struct dp_method *dp_methods)
 2074 {
 2075     struct ad_subdomains_ctx *sd_ctx;
 2076     const char *ad_domain;
 2077     const char **ad_enabled_domains = NULL;
 2078     time_t period;
 2079     errno_t ret;
 2080 
 2081     ad_domain = dp_opt_get_string(ad_id_ctx->ad_options->basic, AD_DOMAIN);
 2082 
 2083     sd_ctx = talloc_zero(mem_ctx, struct ad_subdomains_ctx);
 2084     if (sd_ctx == NULL) {
 2085         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
 2086         return ENOMEM;
 2087     }
 2088 
 2089     ret = ad_get_enabled_domains(sd_ctx, ad_id_ctx, ad_domain,
 2090                                  &ad_enabled_domains);
 2091     if (ret != EOK) {
 2092         return EINVAL;
 2093     }
 2094 
 2095     sd_ctx->be_ctx = be_ctx;
 2096     sd_ctx->sdom = ad_id_ctx->sdap_id_ctx->opts->sdom;
 2097     sd_ctx->sdap_id_ctx = ad_id_ctx->sdap_id_ctx;
 2098     sd_ctx->domain_name = talloc_strdup(sd_ctx, ad_domain);
 2099     if (sd_ctx->domain_name == NULL) {
 2100         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
 2101         return ENOMEM;
 2102     }
 2103     sd_ctx->ad_enabled_domains = ad_enabled_domains;
 2104     sd_ctx->ad_id_ctx = ad_id_ctx;
 2105 
 2106     dp_set_method(dp_methods, DPM_DOMAINS_HANDLER,
 2107                   ad_subdomains_handler_send, ad_subdomains_handler_recv, sd_ctx,
 2108                   struct ad_subdomains_ctx, struct dp_subdomains_data, struct dp_reply_std);
 2109 
 2110     period = be_ctx->domain->subdomain_refresh_interval;
 2111     ret = be_ptask_create(sd_ctx, be_ctx, period, 0, 0, 0, period, 0,
 2112                           ad_subdomains_ptask_send, ad_subdomains_ptask_recv,
 2113                           sd_ctx,
 2114                           "Subdomains Refresh",
 2115                           BE_PTASK_OFFLINE_DISABLE |
 2116                           BE_PTASK_SCHEDULE_FROM_LAST,
 2117                           NULL);
 2118     if (ret != EOK) {
 2119         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
 2120               "[%d]: %s\n", ret, sss_strerror(ret));
 2121         /* Ignore, responders will trigger refresh from time to time. */
 2122     }
 2123 
 2124     ret = ad_subdom_reinit(sd_ctx);
 2125     if (ret != EOK) {
 2126         DEBUG(SSSDBG_MINOR_FAILURE, "Could not reinitialize subdomains. "
 2127               "Users from trusted domains might not be resolved correctly\n");
 2128         /* Ignore this error and try to discover the subdomains later */
 2129     }
 2130 
 2131     return EOK;
 2132 }