"Fossies" - the Fresh Open Source Software Archive

Member "sssd-2.4.2/src/db/sysdb_subdomains.c" (19 Feb 2021, 53446 Bytes) of package /linux/misc/sssd-2.4.2.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 "sysdb_subdomains.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.1_vs_2.4.2.

    1 /*
    2    SSSD
    3 
    4    System Database - Sub-domain related calls
    5 
    6    Copyright (C) 2012 Jan Zeleny <jzeleny@redhat.com>
    7    Copyright (C) 2012 Sumit Bose <sbose@redhat.com>
    8 
    9    This program is free software; you can redistribute it and/or modify
   10    it under the terms of the GNU General Public License as published by
   11    the Free Software Foundation; either version 3 of the License, or
   12    (at your option) any later version.
   13 
   14    This program is distributed in the hope that it will be useful,
   15    but WITHOUT ANY WARRANTY; without even the implied warranty of
   16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17    GNU General Public License for more details.
   18 
   19    You should have received a copy of the GNU General Public License
   20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   21 */
   22 
   23 #include "util/util.h"
   24 #include "db/sysdb_private.h"
   25 #include "db/sysdb_domain_resolution_order.h"
   26 
   27 static errno_t
   28 check_subdom_config_file(struct confdb_ctx *confdb,
   29                          struct sss_domain_info *subdomain);
   30 
   31 struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx,
   32                                       struct sss_domain_info *parent,
   33                                       const char *name,
   34                                       const char *realm,
   35                                       const char *flat_name,
   36                                       const char *id,
   37                                       enum sss_domain_mpg_mode mpg_mode,
   38                                       bool enumerate,
   39                                       const char *forest,
   40                                       const char **upn_suffixes,
   41                                       uint32_t trust_direction,
   42                                       struct confdb_ctx *confdb,
   43                                       bool enabled)
   44 {
   45     struct sss_domain_info *dom;
   46     bool inherit_option;
   47     errno_t ret;
   48 
   49     DEBUG(SSSDBG_TRACE_FUNC,
   50           "Creating [%s] as subdomain of [%s]!\n", name, parent->name);
   51 
   52     dom = talloc_zero(mem_ctx, struct sss_domain_info);
   53     if (dom == NULL) {
   54         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
   55         return NULL;
   56     }
   57 
   58     dom->parent = parent;
   59 
   60     /* Sub-domains always have the same view as the parent */
   61     dom->has_views = parent->has_views;
   62     if (parent->view_name != NULL) {
   63         dom->view_name = talloc_strdup(dom, parent->view_name);
   64         if (dom->view_name == NULL) {
   65             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy parent's view name.\n");
   66             goto fail;
   67         }
   68     }
   69 
   70     dom->name = talloc_strdup(dom, name);
   71     if (dom->name == NULL) {
   72         DEBUG(SSSDBG_OP_FAILURE, "Failed to copy domain name.\n");
   73         goto fail;
   74     }
   75 
   76     dom->provider = talloc_strdup(dom, parent->provider);
   77     if (dom->provider == NULL) {
   78         DEBUG(SSSDBG_OP_FAILURE, "Failed to copy provider name.\n");
   79         goto fail;
   80     }
   81 
   82     dom->conn_name = talloc_strdup(dom, parent->conn_name);
   83     if (dom->conn_name == NULL) {
   84         DEBUG(SSSDBG_OP_FAILURE, "Failed to copy connection name.\n");
   85         goto fail;
   86     }
   87 
   88     if (realm != NULL) {
   89         dom->realm = talloc_strdup(dom, realm);
   90         if (dom->realm == NULL) {
   91             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy realm name.\n");
   92             goto fail;
   93         }
   94     }
   95 
   96     if (flat_name != NULL) {
   97         dom->flat_name = talloc_strdup(dom, flat_name);
   98         if (dom->flat_name == NULL) {
   99             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy flat name.\n");
  100             goto fail;
  101         }
  102     }
  103 
  104     if (id != NULL) {
  105         dom->domain_id = talloc_strdup(dom, id);
  106         if (dom->domain_id == NULL) {
  107             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy id.\n");
  108             goto fail;
  109         }
  110     }
  111 
  112     if (forest != NULL) {
  113         dom->forest = talloc_strdup(dom, forest);
  114         if (dom->forest == NULL) {
  115             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy forest.\n");
  116             goto fail;
  117         }
  118     }
  119 
  120     if (upn_suffixes != NULL) {
  121         dom->upn_suffixes = dup_string_list(dom, upn_suffixes);
  122         if (dom->upn_suffixes == NULL) {
  123             DEBUG(SSSDBG_OP_FAILURE, "Failed to copy UPN upn_suffixes.\n");
  124             goto fail;
  125         }
  126     }
  127 
  128     dom->hostname = talloc_strdup(dom, parent->hostname);
  129     if (dom->hostname == NULL && parent->hostname != NULL) {
  130         DEBUG(SSSDBG_OP_FAILURE, "Failed to copy hostname.\n");
  131         goto fail;
  132     }
  133 
  134     dom->krb5_keytab = talloc_strdup(dom, parent->krb5_keytab);
  135     if (dom->krb5_keytab == NULL && parent->krb5_keytab != NULL) {
  136         DEBUG(SSSDBG_OP_FAILURE, "Failed to copy krb5_keytab.\n");
  137         goto fail;
  138     }
  139 
  140     dom->enumerate = enumerate;
  141     dom->fqnames = true;
  142     dom->mpg_mode = mpg_mode;
  143     dom->state = enabled ? DOM_ACTIVE : DOM_DISABLED;
  144 
  145     /* use fully qualified names as output in order to avoid causing
  146      * conflicts with users who have the same name and either the
  147      * shortname user resolution is enabled or the trusted domain has
  148      * been explicitly set to use non-fully qualified names as input.
  149      */
  150     dom->output_fqnames = true;
  151 
  152     /* If the parent domain filters out group members, the subdomain should
  153      * as well if configured */
  154     inherit_option = string_in_list(CONFDB_DOMAIN_IGNORE_GROUP_MEMBERS,
  155                                     parent->sd_inherit, false);
  156     if (inherit_option) {
  157         dom->ignore_group_members = parent->ignore_group_members;
  158     }
  159 
  160     /* Inherit case_sensitive. All subdomains are always case insensitive,
  161      * but we want to inherit case preserving which is set with
  162      * case_sensitive=Preserving. */
  163     inherit_option = string_in_list(CONFDB_DOMAIN_CASE_SENSITIVE,
  164                                     parent->sd_inherit, false);
  165     dom->case_sensitive = false;
  166     dom->case_preserve = inherit_option ? parent->case_preserve : false;
  167 
  168     dom->trust_direction = trust_direction;
  169     /* If the parent domain explicitly limits ID ranges, the subdomain
  170      * should honour the limits as well.
  171      */
  172     dom->id_min = parent->id_min ? parent->id_min : 0;
  173     dom->id_max = parent->id_max ? parent->id_max : 0xffffffff;
  174     dom->pwd_expiration_warning = parent->pwd_expiration_warning;
  175     dom->cache_credentials = parent->cache_credentials;
  176     dom->cache_credentials_min_ff_length =
  177                                         parent->cache_credentials_min_ff_length;
  178     dom->cached_auth_timeout = parent->cached_auth_timeout;
  179     dom->user_timeout = parent->user_timeout;
  180     dom->group_timeout = parent->group_timeout;
  181     dom->netgroup_timeout = parent->netgroup_timeout;
  182     dom->service_timeout = parent->service_timeout;
  183     dom->resolver_timeout = parent->resolver_timeout;
  184     dom->names = parent->names;
  185     dom->override_homedir = parent->override_homedir;
  186     dom->fallback_homedir = parent->fallback_homedir;
  187     dom->subdomain_homedir = parent->subdomain_homedir;
  188     dom->override_shell = parent->override_shell;
  189     dom->default_shell = parent->default_shell;
  190     dom->homedir_substr = parent->homedir_substr;
  191     dom->override_gid = parent->override_gid;
  192 
  193     dom->gssapi_services = parent->gssapi_services;
  194     dom->gssapi_indicators_map = parent->gssapi_indicators_map;
  195 
  196     if (parent->sysdb == NULL) {
  197         DEBUG(SSSDBG_OP_FAILURE, "Missing sysdb context in parent domain.\n");
  198         goto fail;
  199     }
  200     dom->sysdb = parent->sysdb;
  201 
  202     if (confdb != NULL) {
  203         /* If confdb was provided, also check for sssd.conf */
  204         ret = check_subdom_config_file(confdb, dom);
  205         if (ret != EOK) {
  206             DEBUG(SSSDBG_CRIT_FAILURE,
  207                   "Failed to read subdomain configuration [%d]: %s",
  208                    ret, sss_strerror(ret));
  209             goto fail;
  210         }
  211     }
  212 
  213     return dom;
  214 
  215 fail:
  216     talloc_free(dom);
  217     return NULL;
  218 }
  219 
  220 static errno_t
  221 check_subdom_config_file(struct confdb_ctx *confdb,
  222                          struct sss_domain_info *subdomain)
  223 {
  224     char *sd_conf_path;
  225     char *case_sensitive_opt;
  226     TALLOC_CTX *tmp_ctx;
  227     errno_t ret;
  228 
  229     tmp_ctx = talloc_new(NULL);
  230     if (tmp_ctx == NULL) {
  231         return ENOMEM;
  232     }
  233 
  234     sd_conf_path = subdomain_create_conf_path(tmp_ctx, subdomain);
  235     if (sd_conf_path == NULL) {
  236         ret = ENOMEM;
  237         goto done;
  238     }
  239 
  240     /* use_fully_qualified_names */
  241     ret = confdb_get_bool(confdb, sd_conf_path, CONFDB_DOMAIN_FQ,
  242                           true, &subdomain->fqnames);
  243     if (ret != EOK) {
  244         DEBUG(SSSDBG_OP_FAILURE,
  245               "Failed to get %s option for the subdomain: %s\n",
  246               CONFDB_DOMAIN_FQ, subdomain->name);
  247         goto done;
  248     }
  249 
  250     DEBUG(SSSDBG_CONF_SETTINGS, "%s/%s has value %s\n",
  251           sd_conf_path, CONFDB_DOMAIN_FQ,
  252           subdomain->fqnames ? "TRUE" : "FALSE");
  253 
  254     /* allow to set pam_gssapi_services */
  255     ret = confdb_get_string_as_list(confdb, subdomain, sd_conf_path,
  256                                     CONFDB_PAM_GSSAPI_SERVICES,
  257                                     &subdomain->gssapi_services);
  258     if (ret != EOK && ret != ENOENT) {
  259         DEBUG(SSSDBG_OP_FAILURE,
  260               "Failed to get %s option for the subdomain: %s\n",
  261               CONFDB_PAM_GSSAPI_SERVICES, subdomain->name);
  262         goto done;
  263     }
  264 
  265     /* allow to set pam_gssapi_check_upn */
  266     ret = confdb_get_string(confdb, subdomain, sd_conf_path,
  267                             CONFDB_PAM_GSSAPI_CHECK_UPN,
  268                             subdomain->parent->gssapi_check_upn,
  269                             &subdomain->gssapi_check_upn);
  270     if (ret != EOK) {
  271         DEBUG(SSSDBG_OP_FAILURE,
  272               "Failed to get %s option for the subdomain: %s\n",
  273               CONFDB_PAM_GSSAPI_CHECK_UPN, subdomain->name);
  274         goto done;
  275     }
  276 
  277     /* allow to set pam_gssapi_indicators_map */
  278     ret = confdb_get_string_as_list(confdb, subdomain, sd_conf_path,
  279                                     CONFDB_PAM_GSSAPI_INDICATORS_MAP,
  280                                     &subdomain->gssapi_indicators_map);
  281     if (ret != EOK && ret != ENOENT) {
  282         DEBUG(SSSDBG_OP_FAILURE,
  283               "Failed to get %s option for the subdomain: %s\n",
  284               CONFDB_PAM_GSSAPI_INDICATORS_MAP, subdomain->name);
  285         goto done;
  286     }
  287 
  288     /* case_sensitive=Preserving */
  289     ret = confdb_get_string(confdb, tmp_ctx, sd_conf_path,
  290                             CONFDB_DOMAIN_CASE_SENSITIVE, NULL,
  291                             &case_sensitive_opt);
  292     if (ret != EOK) {
  293         DEBUG(SSSDBG_OP_FAILURE,
  294               "Failed to get %s option for the subdomain: %s\n",
  295               CONFDB_DOMAIN_CASE_SENSITIVE, subdomain->name);
  296         goto done;
  297     }
  298 
  299     if (case_sensitive_opt != NULL) {
  300         DEBUG(SSSDBG_CONF_SETTINGS, "%s/%s has value %s\n", sd_conf_path,
  301               CONFDB_DOMAIN_CASE_SENSITIVE, case_sensitive_opt);
  302         if (strcasecmp(case_sensitive_opt, "true") == 0) {
  303             DEBUG(SSSDBG_CRIT_FAILURE,
  304                   "Warning: subdomain can not be set as case-sensitive.\n");
  305             subdomain->case_sensitive = false;
  306             subdomain->case_preserve = false;
  307         } else if (strcasecmp(case_sensitive_opt, "false") == 0) {
  308             subdomain->case_sensitive = false;
  309             subdomain->case_preserve = false;
  310         } else if (strcasecmp(case_sensitive_opt, "preserving") == 0) {
  311             subdomain->case_sensitive = false;
  312             subdomain->case_preserve = true;
  313         } else {
  314             DEBUG(SSSDBG_FATAL_FAILURE,
  315                 "Invalid value for %s\n", CONFDB_DOMAIN_CASE_SENSITIVE);
  316             goto done;
  317         }
  318     }
  319 
  320     ret = EOK;
  321 done:
  322     talloc_free(tmp_ctx);
  323     return ret;
  324 }
  325 
  326 static bool is_forest_root(struct sss_domain_info *d)
  327 {
  328     if (d->forest == NULL) {
  329         /* IPA subdomain provider saves/saved trusted forest root domains
  330          * without the forest attribute. Those are automatically forest
  331          * roots
  332          */
  333         return true;
  334     }
  335 
  336     if (d->realm && (strcasecmp(d->forest, d->realm) == 0)) {
  337         return true;
  338     }
  339 
  340     return false;
  341 }
  342 
  343 static bool is_same_forest(struct sss_domain_info *root,
  344                            struct sss_domain_info *member)
  345 {
  346     if (member->forest != NULL
  347             && root->realm != NULL
  348             && strcasecmp(member->forest, root->realm) == 0) {
  349         return true;
  350     }
  351 
  352     return false;
  353 }
  354 
  355 static void link_forest_roots(struct sss_domain_info *domain)
  356 {
  357     struct sss_domain_info *d;
  358     struct sss_domain_info *dd;
  359     uint32_t gnd_flags = SSS_GND_ALL_DOMAINS;
  360 
  361     for (d = domain; d; d = get_next_domain(d, gnd_flags)) {
  362         d->forest_root = NULL;
  363     }
  364 
  365     for (d = domain; d; d = get_next_domain(d, gnd_flags)) {
  366         if (d->forest_root != NULL) {
  367             continue;
  368         }
  369 
  370         if (is_forest_root(d) == true) {
  371             d->forest_root = d;
  372             DEBUG(SSSDBG_TRACE_INTERNAL, "[%s] is a forest root\n", d->name);
  373 
  374             for (dd = domain; dd; dd = get_next_domain(dd, gnd_flags)) {
  375                 if (dd->forest_root != NULL) {
  376                     continue;
  377                 }
  378 
  379                 if (is_same_forest(d, dd) == true) {
  380                     dd->forest_root = d;
  381                     DEBUG(SSSDBG_TRACE_INTERNAL,
  382                           "[%s] is a forest root of [%s]\n",
  383                           d->forest_root->name,
  384                           dd->name);
  385                 }
  386             }
  387         }
  388     }
  389 }
  390 
  391 errno_t sysdb_update_subdomains(struct sss_domain_info *domain,
  392                                 struct confdb_ctx *confdb)
  393 {
  394     int i;
  395     errno_t ret;
  396     TALLOC_CTX *tmp_ctx;
  397     struct ldb_result *res;
  398     const char *attrs[] = {"cn",
  399                            SYSDB_SUBDOMAIN_REALM,
  400                            SYSDB_SUBDOMAIN_FLAT,
  401                            SYSDB_SUBDOMAIN_ID,
  402                            SYSDB_SUBDOMAIN_MPG,
  403                            SYSDB_SUBDOMAIN_ENUM,
  404                            SYSDB_SUBDOMAIN_FOREST,
  405                            SYSDB_SUBDOMAIN_TRUST_DIRECTION,
  406                            SYSDB_UPN_SUFFIXES,
  407                            SYSDB_ENABLED,
  408                            NULL};
  409     struct sss_domain_info *dom;
  410     struct ldb_dn *basedn;
  411     const char *name;
  412     const char *realm;
  413     const char *flat;
  414     const char *id;
  415     const char *forest;
  416     const char *str_mpg_mode;
  417     bool enabled;
  418     enum sss_domain_mpg_mode mpg_mode;
  419     bool enumerate;
  420     uint32_t trust_direction;
  421     struct ldb_message_element *tmp_el;
  422     const char **upn_suffixes;
  423 
  424     tmp_ctx = talloc_new(NULL);
  425     if (tmp_ctx == NULL) {
  426         ret = ENOMEM;
  427         goto done;
  428     }
  429 
  430     basedn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, SYSDB_BASE);
  431     if (basedn == NULL) {
  432         ret = EIO;
  433         goto done;
  434     }
  435     ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
  436                      basedn, LDB_SCOPE_SUBTREE,
  437                      attrs, "objectclass=%s", SYSDB_SUBDOMAIN_CLASS);
  438     if (ret != LDB_SUCCESS) {
  439         ret = EIO;
  440         goto done;
  441     }
  442 
  443     /* disable all domains,
  444      * let the search result refresh any that are still valid */
  445     for (dom = domain->subdomains; dom; dom = get_next_domain(dom, false)) {
  446         sss_domain_set_state(dom, DOM_DISABLED);
  447     }
  448 
  449     if (res->count == 0) {
  450         ret = EOK;
  451         goto done;
  452     }
  453 
  454     for (i = 0; i < res->count; i++) {
  455 
  456         name = ldb_msg_find_attr_as_string(res->msgs[i], "cn", NULL);
  457         if (name == NULL) {
  458             DEBUG(SSSDBG_MINOR_FAILURE,
  459                   "The object [%s] doesn't have a name\n",
  460                    ldb_dn_get_linearized(res->msgs[i]->dn));
  461             ret = EINVAL;
  462             goto done;
  463         }
  464 
  465         realm = ldb_msg_find_attr_as_string(res->msgs[i],
  466                                             SYSDB_SUBDOMAIN_REALM, NULL);
  467 
  468         flat = ldb_msg_find_attr_as_string(res->msgs[i],
  469                                            SYSDB_SUBDOMAIN_FLAT, NULL);
  470 
  471         id = ldb_msg_find_attr_as_string(res->msgs[i],
  472                                          SYSDB_SUBDOMAIN_ID, NULL);
  473 
  474         str_mpg_mode = ldb_msg_find_attr_as_string(res->msgs[i],
  475                                                    SYSDB_SUBDOMAIN_MPG, NULL);
  476         if (str_mpg_mode == NULL || *str_mpg_mode == '\0') {
  477             str_mpg_mode = "false";
  478         }
  479         mpg_mode = str_to_domain_mpg_mode(str_mpg_mode);
  480 
  481         enumerate = ldb_msg_find_attr_as_bool(res->msgs[i],
  482                                               SYSDB_SUBDOMAIN_ENUM, false);
  483 
  484         forest = ldb_msg_find_attr_as_string(res->msgs[i],
  485                                              SYSDB_SUBDOMAIN_FOREST, NULL);
  486 
  487         upn_suffixes = NULL;
  488         tmp_el = ldb_msg_find_element(res->msgs[i], SYSDB_UPN_SUFFIXES);
  489         if (tmp_el != NULL) {
  490             upn_suffixes = sss_ldb_el_to_string_list(tmp_ctx, tmp_el);
  491             if (upn_suffixes == NULL) {
  492                 DEBUG(SSSDBG_OP_FAILURE, "sss_ldb_el_to_string_list failed.\n");
  493                 ret = ENOMEM;
  494                 goto done;
  495             }
  496         }
  497 
  498         trust_direction = ldb_msg_find_attr_as_int(res->msgs[i],
  499                                              SYSDB_SUBDOMAIN_TRUST_DIRECTION,
  500                                              0);
  501 
  502         enabled = ldb_msg_find_attr_as_bool(res->msgs[i], SYSDB_ENABLED, true);
  503 
  504         for (dom = domain->subdomains; dom;
  505                 dom = get_next_domain(dom, SSS_GND_INCLUDE_DISABLED)) {
  506             if (strcasecmp(dom->name, name) == 0) {
  507                 if (enabled) {
  508                     sss_domain_set_state(dom, DOM_ACTIVE);
  509                 }
  510 
  511                 /* in theory these may change, but it should never happen */
  512                 if ((dom->realm == NULL && realm != NULL)
  513                         || (dom->realm != NULL && realm != NULL
  514                             && strcasecmp(dom->realm, realm) != 0)) {
  515                     DEBUG(SSSDBG_TRACE_INTERNAL,
  516                           "Realm name changed from [%s] to [%s]!\n",
  517                            dom->realm, realm);
  518                     talloc_zfree(dom->realm);
  519                     dom->realm = talloc_strdup(dom, realm);
  520                     if (dom->realm == NULL) {
  521                         ret = ENOMEM;
  522                         goto done;
  523                     }
  524                 }
  525                 if ((dom->flat_name == NULL && flat != NULL)
  526                         || (dom->flat_name != NULL && flat != NULL
  527                             && strcasecmp(dom->flat_name, flat) != 0)) {
  528                     DEBUG(SSSDBG_TRACE_INTERNAL,
  529                           "Flat name changed from [%s] to [%s]!\n",
  530                            dom->flat_name, flat);
  531                     talloc_zfree(dom->flat_name);
  532                     dom->flat_name = talloc_strdup(dom, flat);
  533                     if (dom->flat_name == NULL) {
  534                         ret = ENOMEM;
  535                         goto done;
  536                     }
  537                 }
  538                 if ((dom->domain_id == NULL && id != NULL)
  539                         || (dom->domain_id != NULL && id != NULL
  540                             && strcasecmp(dom->domain_id, id) != 0)) {
  541                     DEBUG(SSSDBG_TRACE_INTERNAL,
  542                           "Domain changed from [%s] to [%s]!\n",
  543                            dom->domain_id, id);
  544                     talloc_zfree(dom->domain_id);
  545                     dom->domain_id = talloc_strdup(dom, id);
  546                     if (dom->domain_id == NULL) {
  547                         ret = ENOMEM;
  548                         goto done;
  549                     }
  550                 }
  551 
  552                 if (dom->mpg_mode != mpg_mode) {
  553                     DEBUG(SSSDBG_TRACE_INTERNAL,
  554                           "MPG state change from [%s] to [%s]!\n",
  555                            dom->mpg_mode == MPG_ENABLED ? "true" : "false",
  556                            mpg_mode == MPG_ENABLED ? "true" : "false");
  557                     dom->mpg_mode = mpg_mode;
  558                 }
  559 
  560                 if (dom->enumerate != enumerate) {
  561                     DEBUG(SSSDBG_TRACE_INTERNAL,
  562                           "enumerate state change from [%s] to [%s]!\n",
  563                            dom->enumerate ? "true" : "false",
  564                            enumerate ? "true" : "false");
  565                     dom->enumerate = enumerate;
  566                 }
  567 
  568                 if ((dom->forest == NULL && forest != NULL)
  569                         || (dom->forest != NULL && forest != NULL
  570                             && strcasecmp(dom->forest, forest) != 0)) {
  571                     DEBUG(SSSDBG_TRACE_INTERNAL,
  572                           "Forest changed from [%s] to [%s]!\n",
  573                            dom->forest, forest);
  574                     talloc_zfree(dom->forest);
  575                     dom->forest = talloc_strdup(dom, forest);
  576                     if (dom->forest == NULL) {
  577                         ret = ENOMEM;
  578                         goto done;
  579                     }
  580                 }
  581 
  582                 talloc_zfree(dom->upn_suffixes);
  583                 dom->upn_suffixes = talloc_steal(dom, upn_suffixes);
  584 
  585                 if (!dom->has_views && dom->view_name == NULL) {
  586                     /* maybe views are not initialized, copy from parent */
  587                     dom->has_views = dom->parent->has_views;
  588                     if (dom->parent->view_name != NULL) {
  589                         dom->view_name = talloc_strdup(dom,
  590                                                        dom->parent->view_name);
  591                         if (dom->view_name == NULL) {
  592                             DEBUG(SSSDBG_OP_FAILURE,
  593                                   "Failed to copy parent's view name.\n");
  594                             ret = ENOMEM;
  595                             goto done;
  596                         }
  597                     }
  598                 } else {
  599                     if (dom->has_views != dom->parent->has_views
  600                             || strcmp(dom->view_name,
  601                                       dom->parent->view_name) != 0) {
  602                         DEBUG(SSSDBG_CRIT_FAILURE,
  603                             "Sub-domain [%s][%s] and parent [%s][%s] " \
  604                             "views are different.\n",
  605                             dom->has_views ? "has view" : "has no view",
  606                             dom->view_name,
  607                             dom->parent->has_views ? "has view" : "has no view",
  608                             dom->parent->view_name);
  609                         ret = EINVAL;
  610                         goto done;
  611                     }
  612                 }
  613 
  614                 if (dom->trust_direction != trust_direction) {
  615                     DEBUG(SSSDBG_TRACE_INTERNAL,
  616                           "Trust direction change from [%d] to [%d]!\n",
  617                            dom->trust_direction, trust_direction);
  618                     dom->trust_direction = trust_direction;
  619                 }
  620 
  621                 break;
  622             }
  623         }
  624         /* If not found in loop it is a new subdomain */
  625         if (dom == NULL) {
  626             dom = new_subdomain(domain, domain, name, realm,
  627                                 flat, id, mpg_mode, enumerate, forest,
  628                                 upn_suffixes, trust_direction, confdb,
  629                                 enabled);
  630             if (dom == NULL) {
  631                 ret = ENOMEM;
  632                 goto done;
  633             }
  634             DLIST_ADD_END(domain->subdomains, dom, struct sss_domain_info *);
  635         }
  636     }
  637 
  638     link_forest_roots(domain);
  639 
  640     ret = EOK;
  641 
  642 done:
  643     talloc_free(tmp_ctx);
  644     return ret;
  645 }
  646 
  647 errno_t sysdb_master_domain_update(struct sss_domain_info *domain)
  648 {
  649     errno_t ret;
  650     TALLOC_CTX *tmp_ctx;
  651     const char *tmp_str;
  652     struct ldb_message_element *tmp_el;
  653     struct ldb_dn *basedn;
  654     struct ldb_result *res;
  655     enum sss_domain_state state;
  656     bool enabled;
  657     const char *attrs[] = {"cn",
  658                            SYSDB_SUBDOMAIN_REALM,
  659                            SYSDB_SUBDOMAIN_FLAT,
  660                            SYSDB_SUBDOMAIN_ID,
  661                            SYSDB_SUBDOMAIN_FOREST,
  662                            SYSDB_UPN_SUFFIXES,
  663                            SYSDB_ENABLED,
  664                            NULL};
  665     char *view_name = NULL;
  666 
  667     tmp_ctx = talloc_new(NULL);
  668     if (tmp_ctx == NULL) {
  669         return ENOMEM;
  670     }
  671 
  672     basedn = sysdb_domain_dn(tmp_ctx, domain);
  673     if (basedn == NULL) {
  674         ret = EIO;
  675         goto done;
  676     }
  677     ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
  678                      basedn, LDB_SCOPE_BASE, attrs, NULL);
  679     if (ret != LDB_SUCCESS) {
  680         ret = EIO;
  681         goto done;
  682     }
  683 
  684     if (res->count == 0) {
  685         ret = ENOENT;
  686         goto done;
  687     }
  688 
  689     if (res->count > 1) {
  690         DEBUG(SSSDBG_OP_FAILURE, "Base search returned [%d] results, "
  691                                  "expected 1.\n", res->count);
  692         ret = EINVAL;
  693         goto done;
  694     }
  695 
  696     tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SUBDOMAIN_REALM,
  697                                           NULL);
  698     if (tmp_str != NULL &&
  699         (domain->realm == NULL || strcasecmp(tmp_str, domain->realm) != 0)) {
  700         talloc_free(domain->realm);
  701         domain->realm = talloc_strdup(domain, tmp_str);
  702         if (domain->realm == NULL) {
  703             ret = ENOMEM;
  704             goto done;
  705         }
  706     }
  707 
  708     tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SUBDOMAIN_FLAT,
  709                                           NULL);
  710     if (tmp_str != NULL &&
  711         (domain->flat_name == NULL ||
  712          strcasecmp(tmp_str, domain->flat_name) != 0)) {
  713         talloc_free(domain->flat_name);
  714         domain->flat_name = talloc_strdup(domain, tmp_str);
  715         if (domain->flat_name == NULL) {
  716             ret = ENOMEM;
  717             goto done;
  718         }
  719     }
  720 
  721     tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SUBDOMAIN_ID,
  722                                           NULL);
  723     if (tmp_str != NULL &&
  724         (domain->domain_id == NULL ||
  725          strcasecmp(tmp_str, domain->domain_id) != 0)) {
  726         talloc_free(domain->domain_id);
  727         domain->domain_id = talloc_strdup(domain, tmp_str);
  728         if (domain->domain_id == NULL) {
  729             ret = ENOMEM;
  730             goto done;
  731         }
  732     }
  733 
  734     tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SUBDOMAIN_FOREST,
  735                                           NULL);
  736     if (tmp_str != NULL &&
  737         (domain->forest == NULL ||
  738          strcasecmp(tmp_str, domain->forest) != 0)) {
  739         talloc_free(domain->forest);
  740         domain->forest = talloc_strdup(domain, tmp_str);
  741         if (domain->forest == NULL) {
  742             ret = ENOMEM;
  743             goto done;
  744         }
  745     }
  746 
  747     tmp_el = ldb_msg_find_element(res->msgs[0], SYSDB_UPN_SUFFIXES);
  748     if (tmp_el != NULL) {
  749         talloc_free(domain->upn_suffixes);
  750         domain->upn_suffixes = sss_ldb_el_to_string_list(domain, tmp_el);
  751         if (domain->upn_suffixes == NULL) {
  752             DEBUG(SSSDBG_OP_FAILURE, "sss_ldb_el_to_string_list failed.\n");
  753             ret = ENOMEM;
  754             goto done;
  755         }
  756     } else {
  757         talloc_zfree(domain->upn_suffixes);
  758     }
  759 
  760     state = sss_domain_get_state(domain);
  761     enabled = ldb_msg_find_attr_as_bool(res->msgs[0], SYSDB_ENABLED, true);
  762     if (!enabled) {
  763         sss_domain_set_state(domain, DOM_DISABLED);
  764     } else if (state == DOM_DISABLED) {
  765         /* We do not want to enable INACTIVE or INCONSISTENT domain. This
  766          * is managed by data provider. */
  767         sss_domain_set_state(domain, DOM_ACTIVE);
  768     }
  769 
  770     ret = sysdb_get_view_name(tmp_ctx, domain->sysdb, &view_name);
  771     if (ret != EOK && ret != ENOENT) {
  772         DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name failed.\n");
  773         goto done;
  774     }
  775 
  776     /* If no view is defined the default view will be used. In this case
  777      * domain->has_views is FALSE and
  778      * domain->view_name is set to SYSDB_DEFAULT_VIEW_NAME
  779      *
  780      * If there is a view defined
  781      * domain->has_views is TRUE and
  782      * domain->view_name is set to the given view name
  783      *
  784      * Currently changing the view is not supported hence we have to check for
  785      * changes and error out accordingly.
  786      */
  787     if (ret == ENOENT || is_default_view(view_name)) {
  788         /* handle default view */
  789         if (domain->has_views) {
  790             DEBUG(SSSDBG_CRIT_FAILURE,
  791                   "View name change is currently not supported. " \
  792                   "New view is the default view while current view is [%s]. " \
  793                   "View name is not changed!\n", domain->view_name);
  794         } else {
  795             if (domain->view_name == NULL) {
  796                 domain->view_name = talloc_strdup(domain,
  797                                                   SYSDB_DEFAULT_VIEW_NAME);
  798                 if (domain->view_name == NULL) {
  799                     DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
  800                     ret = ENOMEM;
  801                     goto done;
  802                 }
  803             } else {
  804                 if (strcmp(domain->view_name, SYSDB_DEFAULT_VIEW_NAME) != 0) {
  805                     DEBUG(SSSDBG_CRIT_FAILURE,
  806                           "Domain [%s] has no view but view name [%s] " \
  807                           "is not the default view name [%s].\n",
  808                           domain->name, domain->view_name,
  809                           SYSDB_DEFAULT_VIEW_NAME);
  810                     ret = EINVAL;
  811                     goto done;
  812                 }
  813             }
  814         }
  815     } else {
  816         /* handle view other than default */
  817         if (domain->has_views) {
  818             if (strcmp(domain->view_name, view_name) != 0) {
  819                 DEBUG(SSSDBG_CRIT_FAILURE,
  820                       "View name change is currently not supported. " \
  821                       "New view is [%s] while current view is [%s]. " \
  822                       "View name is not changed!\n",
  823                       view_name, domain->view_name);
  824             }
  825         } else {
  826             if (domain->view_name == NULL) {
  827                 domain->has_views = true;
  828                 domain->view_name = talloc_steal(domain, view_name);
  829                 if (domain->view_name == NULL) {
  830                     DEBUG(SSSDBG_OP_FAILURE, "talloc_steal failed.\n");
  831                     ret = ENOMEM;
  832                     goto done;
  833                 }
  834             } else {
  835                 if (strcmp(domain->view_name, SYSDB_DEFAULT_VIEW_NAME) == 0) {
  836                     DEBUG(SSSDBG_CRIT_FAILURE,
  837                         "View name change is currently not supported. " \
  838                         "New view is [%s] while current is the default view. " \
  839                         "View name is not changed!\n", view_name);
  840                 } else {
  841                     DEBUG(SSSDBG_CRIT_FAILURE,
  842                           "Domain currently has no views, " \
  843                           "but current view name is set to [%s] " \
  844                           "and new view name is [%s].\n",
  845                           domain->view_name, view_name);
  846                     ret = EINVAL;
  847                     goto done;
  848                 }
  849             }
  850         }
  851     }
  852 
  853     ret = EOK;
  854 
  855 done:
  856     talloc_free(tmp_ctx);
  857     return ret;
  858 }
  859 
  860 errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain,
  861                                      const char *realm,
  862                                      const char *flat,
  863                                      const char *id,
  864                                      const char *forest,
  865                                      struct ldb_message_element *upn_suffixes)
  866 {
  867     TALLOC_CTX *tmp_ctx;
  868     struct ldb_message *msg;
  869     int ret;
  870     bool do_update = false;
  871 
  872     tmp_ctx = talloc_new(NULL);
  873     if (tmp_ctx == NULL) {
  874         return ENOMEM;
  875     }
  876 
  877     msg = ldb_msg_new(tmp_ctx);
  878     if (msg == NULL) {
  879         ret = ENOMEM;
  880         goto done;
  881     }
  882 
  883     msg->dn = sysdb_domain_dn(tmp_ctx, domain);
  884     if (msg->dn == NULL) {
  885         ret = EIO;
  886         goto done;
  887     }
  888 
  889     if (flat != NULL && (domain->flat_name == NULL ||
  890                          strcmp(domain->flat_name, flat) != 0)) {
  891         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_FLAT,
  892                                 LDB_FLAG_MOD_REPLACE, NULL);
  893         if (ret != LDB_SUCCESS) {
  894             ret = sysdb_error_to_errno(ret);
  895             goto done;
  896         }
  897 
  898         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_FLAT, flat);
  899         if (ret != LDB_SUCCESS) {
  900             ret = sysdb_error_to_errno(ret);
  901             goto done;
  902         }
  903 
  904         do_update = true;
  905     }
  906 
  907     if (id != NULL && (domain->domain_id == NULL ||
  908                        strcmp(domain->domain_id, id) != 0)) {
  909         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_ID,
  910                                 LDB_FLAG_MOD_REPLACE, NULL);
  911         if (ret != LDB_SUCCESS) {
  912             ret = sysdb_error_to_errno(ret);
  913             goto done;
  914         }
  915 
  916         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_ID, id);
  917         if (ret != LDB_SUCCESS) {
  918             ret = sysdb_error_to_errno(ret);
  919             goto done;
  920         }
  921 
  922         do_update = true;
  923     }
  924 
  925    if (forest != NULL && (domain->forest == NULL ||
  926                        strcmp(domain->forest, forest) != 0)) {
  927         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_FOREST,
  928                                 LDB_FLAG_MOD_REPLACE, NULL);
  929         if (ret != LDB_SUCCESS) {
  930             ret = sysdb_error_to_errno(ret);
  931             goto done;
  932         }
  933 
  934         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_FOREST, forest);
  935         if (ret != LDB_SUCCESS) {
  936             ret = sysdb_error_to_errno(ret);
  937             goto done;
  938         }
  939 
  940         do_update = true;
  941     }
  942 
  943    if (realm != NULL && (domain->realm == NULL ||
  944                        strcmp(domain->realm, realm) != 0)) {
  945         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_REALM,
  946                                 LDB_FLAG_MOD_REPLACE, NULL);
  947         if (ret != LDB_SUCCESS) {
  948             ret = sysdb_error_to_errno(ret);
  949             goto done;
  950         }
  951         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_REALM, realm);
  952         if (ret != LDB_SUCCESS) {
  953             ret = sysdb_error_to_errno(ret);
  954             goto done;
  955         }
  956 
  957         do_update = true;
  958     }
  959 
  960     if (upn_suffixes != NULL) {
  961         talloc_free(discard_const(upn_suffixes->name));
  962         upn_suffixes->name = talloc_strdup(upn_suffixes, SYSDB_UPN_SUFFIXES);
  963         if (upn_suffixes->name == NULL) {
  964             DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
  965             ret = ENOMEM;
  966             goto done;
  967         }
  968 
  969         ret = ldb_msg_add(msg, upn_suffixes, LDB_FLAG_MOD_REPLACE);
  970         if (ret != LDB_SUCCESS) {
  971             ret = sysdb_error_to_errno(ret);
  972             goto done;
  973         }
  974 
  975         do_update = true;
  976     } else {
  977         /* Remove alternative_domain_suffixes from the cache */
  978         if (domain->upn_suffixes != NULL) {
  979             ret = ldb_msg_add_empty(msg, SYSDB_UPN_SUFFIXES,
  980                                     LDB_FLAG_MOD_DELETE, NULL);
  981             if (ret != LDB_SUCCESS) {
  982                 ret = sysdb_error_to_errno(ret);
  983                 goto done;
  984             }
  985 
  986             do_update = true;
  987         }
  988     }
  989 
  990     if (do_update == false) {
  991         ret = EOK;
  992         goto done;
  993     }
  994 
  995     ret = ldb_modify(domain->sysdb->ldb, msg);
  996     if (ret != LDB_SUCCESS) {
  997         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to add subdomain attributes to "
  998                                      "[%s]: [%d][%s]!\n", domain->name, ret,
  999                                      ldb_errstring(domain->sysdb->ldb));
 1000         ret = sysdb_error_to_errno(ret);
 1001         goto done;
 1002     }
 1003 
 1004     ret = sysdb_master_domain_update(domain);
 1005     if (ret != EOK) {
 1006         goto done;
 1007     }
 1008 
 1009     ret = EOK;
 1010 
 1011 done:
 1012     talloc_free(tmp_ctx);
 1013 
 1014     return ret;
 1015 }
 1016 
 1017 errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
 1018                               const char *name, const char *realm,
 1019                               const char *flat_name, const char *domain_id,
 1020                               enum sss_domain_mpg_mode mpg_mode,
 1021                               bool enumerate, const char *forest,
 1022                               uint32_t trust_direction,
 1023                               struct ldb_message_element *upn_suffixes)
 1024 {
 1025     TALLOC_CTX *tmp_ctx;
 1026     struct ldb_message *msg;
 1027     struct ldb_dn *dn;
 1028     struct ldb_result *res;
 1029     const char *attrs[] = {"cn",
 1030                            SYSDB_SUBDOMAIN_REALM,
 1031                            SYSDB_SUBDOMAIN_FLAT,
 1032                            SYSDB_SUBDOMAIN_ID,
 1033                            SYSDB_SUBDOMAIN_MPG,
 1034                            SYSDB_SUBDOMAIN_ENUM,
 1035                            SYSDB_SUBDOMAIN_FOREST,
 1036                            SYSDB_SUBDOMAIN_TRUST_DIRECTION,
 1037                            SYSDB_UPN_SUFFIXES,
 1038                            NULL};
 1039     const char *tmp_str;
 1040     struct ldb_message_element *tmp_el;
 1041     bool tmp_bool;
 1042     bool store = false;
 1043     int realm_flags = 0;
 1044     int flat_flags = 0;
 1045     int id_flags = 0;
 1046     int mpg_flags = 0;
 1047     int enum_flags = 0;
 1048     int forest_flags = 0;
 1049     int td_flags = 0;
 1050     int upn_flags = 0;
 1051     uint32_t tmp_td;
 1052     int ret;
 1053 
 1054     tmp_ctx = talloc_new(NULL);
 1055     if (tmp_ctx == NULL) {
 1056         return ENOMEM;
 1057     }
 1058 
 1059     dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, name);
 1060     if (dn == NULL) {
 1061         ret = EIO;
 1062         goto done;
 1063     }
 1064     ret = ldb_search(sysdb->ldb, tmp_ctx, &res,
 1065                      dn, LDB_SCOPE_BASE, attrs, NULL);
 1066     if (ret != LDB_SUCCESS) {
 1067         ret = EIO;
 1068         goto done;
 1069     }
 1070 
 1071     if (res->count == 0) {
 1072         ret = sysdb_domain_create(sysdb, name);
 1073         if (ret) {
 1074             goto done;
 1075         }
 1076         store = true;
 1077         if (realm) realm_flags = LDB_FLAG_MOD_ADD;
 1078         if (flat_name) flat_flags = LDB_FLAG_MOD_ADD;
 1079         if (domain_id) id_flags = LDB_FLAG_MOD_ADD;
 1080         mpg_flags = LDB_FLAG_MOD_ADD;
 1081         enum_flags = LDB_FLAG_MOD_ADD;
 1082         if (forest) forest_flags = LDB_FLAG_MOD_ADD;
 1083         if (trust_direction) td_flags = LDB_FLAG_MOD_ADD;
 1084         if (upn_suffixes) upn_flags = LDB_FLAG_MOD_ADD;
 1085     } else if (res->count != 1) {
 1086         ret = EINVAL;
 1087         goto done;
 1088     } else { /* 1 found */
 1089         if (realm) {
 1090             tmp_str = ldb_msg_find_attr_as_string(res->msgs[0],
 1091                                                   SYSDB_SUBDOMAIN_REALM, NULL);
 1092             if (!tmp_str || strcasecmp(tmp_str, realm) != 0) {
 1093                 realm_flags = LDB_FLAG_MOD_REPLACE;
 1094             }
 1095         }
 1096         if (flat_name) {
 1097             tmp_str = ldb_msg_find_attr_as_string(res->msgs[0],
 1098                                                   SYSDB_SUBDOMAIN_FLAT, NULL);
 1099             if (!tmp_str || strcasecmp(tmp_str, flat_name) != 0) {
 1100                 flat_flags = LDB_FLAG_MOD_REPLACE;
 1101             }
 1102         }
 1103         if (domain_id) {
 1104             tmp_str = ldb_msg_find_attr_as_string(res->msgs[0],
 1105                                                   SYSDB_SUBDOMAIN_ID, NULL);
 1106             if (!tmp_str || strcasecmp(tmp_str, domain_id) != 0) {
 1107                 id_flags = LDB_FLAG_MOD_REPLACE;
 1108             }
 1109         }
 1110 
 1111         tmp_str = ldb_msg_find_attr_as_string(res->msgs[0],
 1112                                               SYSDB_SUBDOMAIN_MPG,
 1113                                               "false");
 1114         /* If mpg_mode changed we need to replace the old  value in sysdb */
 1115         switch (mpg_mode) {
 1116         case MPG_ENABLED:
 1117             if (strcasecmp(tmp_str, "true") != 0) {
 1118                 mpg_flags = LDB_FLAG_MOD_REPLACE;
 1119             }
 1120             break;
 1121         case MPG_DISABLED:
 1122             if (strcasecmp(tmp_str, "false") != 0) {
 1123                 mpg_flags = LDB_FLAG_MOD_REPLACE;
 1124             }
 1125             break;
 1126         case MPG_HYBRID:
 1127             if (strcasecmp(tmp_str, "hybrid") != 0) {
 1128                 mpg_flags = LDB_FLAG_MOD_REPLACE;
 1129             }
 1130             break;
 1131         }
 1132 
 1133         tmp_bool = ldb_msg_find_attr_as_bool(res->msgs[0], SYSDB_SUBDOMAIN_ENUM,
 1134                                              !enumerate);
 1135         if (tmp_bool != enumerate) {
 1136             enum_flags = LDB_FLAG_MOD_REPLACE;
 1137         }
 1138 
 1139         if (forest) {
 1140             tmp_str = ldb_msg_find_attr_as_string(res->msgs[0],
 1141                                                   SYSDB_SUBDOMAIN_FOREST, NULL);
 1142             if (!tmp_str || strcasecmp(tmp_str, forest) != 0) {
 1143                 forest_flags = LDB_FLAG_MOD_REPLACE;
 1144             }
 1145         }
 1146 
 1147         tmp_td = ldb_msg_find_attr_as_uint(res->msgs[0],
 1148                                            SYSDB_SUBDOMAIN_TRUST_DIRECTION,
 1149                                            0);
 1150         if (tmp_td != trust_direction) {
 1151             td_flags = LDB_FLAG_MOD_REPLACE;
 1152         }
 1153 
 1154         if (upn_suffixes) {
 1155             tmp_el = ldb_msg_find_element(res->msgs[0], SYSDB_UPN_SUFFIXES);
 1156             /* Luckily ldb_msg_element_compare() only compares the values and
 1157              * not the name. */
 1158             if (tmp_el == NULL
 1159                     || ldb_msg_element_compare(upn_suffixes, tmp_el) != 0) {
 1160                 upn_flags = LDB_FLAG_MOD_REPLACE;
 1161             }
 1162         }
 1163     }
 1164 
 1165     if (!store && realm_flags == 0 && flat_flags == 0 && id_flags == 0
 1166             && mpg_flags == 0 && enum_flags == 0 && forest_flags == 0
 1167             && td_flags == 0 && upn_flags == 0) {
 1168         ret = EOK;
 1169         goto done;
 1170     }
 1171 
 1172     msg = ldb_msg_new(tmp_ctx);
 1173     if (msg == NULL) {
 1174         ret = ENOMEM;
 1175         goto done;
 1176     }
 1177     msg->dn = dn;
 1178 
 1179     if (store) {
 1180         ret = ldb_msg_add_empty(msg, SYSDB_OBJECTCLASS, LDB_FLAG_MOD_ADD, NULL);
 1181         if (ret != LDB_SUCCESS) {
 1182             ret = sysdb_error_to_errno(ret);
 1183             goto done;
 1184         }
 1185 
 1186         ret = ldb_msg_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_SUBDOMAIN_CLASS);
 1187         if (ret != LDB_SUCCESS) {
 1188             ret = sysdb_error_to_errno(ret);
 1189             goto done;
 1190         }
 1191     }
 1192 
 1193     if (realm_flags) {
 1194         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_REALM, realm_flags, NULL);
 1195         if (ret != LDB_SUCCESS) {
 1196             ret = sysdb_error_to_errno(ret);
 1197             goto done;
 1198         }
 1199 
 1200         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_REALM, realm);
 1201         if (ret != LDB_SUCCESS) {
 1202             ret = sysdb_error_to_errno(ret);
 1203             goto done;
 1204         }
 1205     }
 1206 
 1207     if (flat_flags) {
 1208         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_FLAT, flat_flags, NULL);
 1209         if (ret != LDB_SUCCESS) {
 1210             ret = sysdb_error_to_errno(ret);
 1211             goto done;
 1212         }
 1213 
 1214         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_FLAT, flat_name);
 1215         if (ret != LDB_SUCCESS) {
 1216             ret = sysdb_error_to_errno(ret);
 1217             goto done;
 1218         }
 1219     }
 1220 
 1221     if (id_flags) {
 1222         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_ID, id_flags, NULL);
 1223         if (ret != LDB_SUCCESS) {
 1224             ret = sysdb_error_to_errno(ret);
 1225             goto done;
 1226         }
 1227 
 1228         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_ID, domain_id);
 1229         if (ret != LDB_SUCCESS) {
 1230             ret = sysdb_error_to_errno(ret);
 1231             goto done;
 1232         }
 1233     }
 1234 
 1235     if (mpg_flags) {
 1236         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_MPG, mpg_flags, NULL);
 1237         if (ret != LDB_SUCCESS) {
 1238             ret = sysdb_error_to_errno(ret);
 1239             goto done;
 1240         }
 1241 
 1242         tmp_str = str_domain_mpg_mode(mpg_mode);
 1243         if (tmp_str == NULL) {
 1244             DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't convert mpg_mode to string\n");
 1245             ret = EINVAL;
 1246             goto done;
 1247         }
 1248 
 1249         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_MPG, tmp_str);
 1250         if (ret != LDB_SUCCESS) {
 1251             ret = sysdb_error_to_errno(ret);
 1252             goto done;
 1253         }
 1254     }
 1255 
 1256     if (enum_flags) {
 1257         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_ENUM, enum_flags, NULL);
 1258         if (ret != LDB_SUCCESS) {
 1259             ret = sysdb_error_to_errno(ret);
 1260             goto done;
 1261         }
 1262 
 1263         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_ENUM,
 1264                                  enumerate ? "TRUE" : "FALSE");
 1265         if (ret != LDB_SUCCESS) {
 1266             ret = sysdb_error_to_errno(ret);
 1267             goto done;
 1268         }
 1269     }
 1270 
 1271     if (forest_flags) {
 1272         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_FOREST, forest_flags,
 1273                                 NULL);
 1274         if (ret != LDB_SUCCESS) {
 1275             ret = sysdb_error_to_errno(ret);
 1276             goto done;
 1277         }
 1278 
 1279         ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_FOREST, forest);
 1280         if (ret != LDB_SUCCESS) {
 1281             ret = sysdb_error_to_errno(ret);
 1282             goto done;
 1283         }
 1284     }
 1285 
 1286     if (td_flags) {
 1287         ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_TRUST_DIRECTION,
 1288                                 td_flags, NULL);
 1289         if (ret != LDB_SUCCESS) {
 1290             ret = sysdb_error_to_errno(ret);
 1291             goto done;
 1292         }
 1293 
 1294         ret = ldb_msg_add_fmt(msg, SYSDB_SUBDOMAIN_TRUST_DIRECTION,
 1295                               "%u", trust_direction);
 1296         if (ret != LDB_SUCCESS) {
 1297             ret = sysdb_error_to_errno(ret);
 1298             goto done;
 1299         }
 1300     }
 1301 
 1302     if (upn_flags) {
 1303         tmp_el = talloc_zero(tmp_ctx, struct ldb_message_element);
 1304         if (tmp_el == NULL) {
 1305             DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
 1306             ret = ENOMEM;
 1307             goto done;
 1308         }
 1309 
 1310         tmp_el->name = SYSDB_UPN_SUFFIXES;
 1311         tmp_el->num_values = upn_suffixes->num_values;
 1312         tmp_el->values = upn_suffixes->values;
 1313         ret = ldb_msg_add(msg, tmp_el, upn_flags);
 1314         if (ret != LDB_SUCCESS) {
 1315             ret = sysdb_error_to_errno(ret);
 1316             goto done;
 1317         }
 1318     }
 1319 
 1320     ret = ldb_msg_add_empty(msg, SYSDB_ENABLED, LDB_FLAG_MOD_REPLACE, NULL);
 1321     if (ret != LDB_SUCCESS) {
 1322         ret = sysdb_error_to_errno(ret);
 1323         goto done;
 1324     }
 1325 
 1326     ret = ldb_msg_add_string(msg, SYSDB_ENABLED, "TRUE");
 1327     if (ret != LDB_SUCCESS) {
 1328         ret = sysdb_error_to_errno(ret);
 1329         goto done;
 1330     }
 1331 
 1332     ret = ldb_modify(sysdb->ldb, msg);
 1333     if (ret != LDB_SUCCESS) {
 1334         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to add subdomain attributes to "
 1335                                      "[%s]: [%d][%s]!\n", name, ret,
 1336                                      ldb_errstring(sysdb->ldb));
 1337         ret = sysdb_error_to_errno(ret);
 1338         goto done;
 1339     }
 1340 
 1341     ret = EOK;
 1342 
 1343 done:
 1344     talloc_free(tmp_ctx);
 1345 
 1346     return ret;
 1347 }
 1348 
 1349 static errno_t sysdb_subdomain_delete_with_filter(struct sysdb_ctx *sysdb,
 1350                                                   const char *name,
 1351                                                   const char *filter)
 1352 {
 1353     TALLOC_CTX *tmp_ctx = NULL;
 1354     struct ldb_dn *dn;
 1355     int ret;
 1356 
 1357     tmp_ctx = talloc_new(NULL);
 1358     if (tmp_ctx == NULL) {
 1359         ret = ENOMEM;
 1360         goto done;
 1361     }
 1362 
 1363     DEBUG(SSSDBG_TRACE_FUNC, "Removing sub-domain [%s] from db.\n", name);
 1364     dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, name);
 1365     if (dn == NULL) {
 1366         ret = ENOMEM;
 1367         goto done;
 1368     }
 1369 
 1370     ret = sysdb_delete_recursive_with_filter(sysdb, dn, true, filter);
 1371     if (ret != EOK) {
 1372         DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_recursive failed.\n");
 1373         goto done;
 1374     }
 1375 
 1376 done:
 1377     talloc_free(tmp_ctx);
 1378     return ret;
 1379 }
 1380 
 1381 errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name)
 1382 {
 1383     return sysdb_subdomain_delete_with_filter(sysdb, name,
 1384                                               "(distinguishedName=*)");
 1385 }
 1386 
 1387 errno_t sysdb_subdomain_content_delete(struct sysdb_ctx *sysdb,
 1388                                        const char *name)
 1389 {
 1390     const char *filter = "(|("SYSDB_UC")("SYSDB_GC"))";
 1391 
 1392     return sysdb_subdomain_delete_with_filter(sysdb, name, filter);
 1393 }
 1394 
 1395 errno_t
 1396 sysdb_domain_get_domain_resolution_order(TALLOC_CTX *mem_ctx,
 1397                                          struct sysdb_ctx *sysdb,
 1398                                          const char *domain_name,
 1399                                          const char **_domain_resolution_order)
 1400 {
 1401     TALLOC_CTX *tmp_ctx;
 1402     struct ldb_dn *dn;
 1403     errno_t ret;
 1404 
 1405     tmp_ctx = talloc_new(NULL);
 1406     if (tmp_ctx == NULL) {
 1407         return ENOMEM;
 1408     }
 1409 
 1410     dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, domain_name);
 1411     if (dn == NULL) {
 1412         ret = ENOMEM;
 1413         goto done;
 1414     }
 1415 
 1416     ret = sysdb_get_domain_resolution_order(mem_ctx, sysdb, dn,
 1417                                             _domain_resolution_order);
 1418 
 1419 done:
 1420     talloc_free(tmp_ctx);
 1421     return ret;
 1422 }
 1423 
 1424 errno_t
 1425 sysdb_domain_update_domain_resolution_order(struct sysdb_ctx *sysdb,
 1426                                             const char *domain_name,
 1427                                             const char *domain_resolution_order)
 1428 {
 1429 
 1430     TALLOC_CTX *tmp_ctx;
 1431     struct ldb_dn *dn;
 1432     errno_t ret;
 1433 
 1434     tmp_ctx = talloc_new(NULL);
 1435     if (tmp_ctx == NULL) {
 1436         return ENOMEM;
 1437     }
 1438 
 1439     dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, domain_name);
 1440     if (dn == NULL) {
 1441         ret = ENOMEM;
 1442         goto done;
 1443     }
 1444 
 1445     ret = sysdb_update_domain_resolution_order(sysdb, dn,
 1446                                                domain_resolution_order);
 1447     if (ret != EOK) {
 1448         DEBUG(SSSDBG_OP_FAILURE,
 1449               "sysdb_update_domain_resolution_order() failed [%d]: [%s].\n",
 1450               ret, sss_strerror(ret));
 1451         goto done;
 1452     }
 1453 
 1454     ret = EOK;
 1455 
 1456 done:
 1457     talloc_free(tmp_ctx);
 1458     return ret;
 1459 }
 1460 
 1461 errno_t
 1462 sysdb_get_site(TALLOC_CTX *mem_ctx,
 1463                struct sss_domain_info *dom,
 1464                const char **_site)
 1465 {
 1466     TALLOC_CTX *tmp_ctx;
 1467     struct ldb_result *res;
 1468     struct ldb_dn *dn;
 1469     const char *attrs[] = { SYSDB_SITE, NULL };
 1470     errno_t ret;
 1471 
 1472     tmp_ctx = talloc_new(NULL);
 1473     if (tmp_ctx == NULL) {
 1474         return ENOMEM;
 1475     }
 1476 
 1477     dn = sysdb_domain_dn(tmp_ctx, dom);
 1478     if (dn == NULL) {
 1479         ret = ENOMEM;
 1480         goto done;
 1481     }
 1482 
 1483     ret = ldb_search(dom->sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
 1484                      attrs, NULL);
 1485     if (ret != LDB_SUCCESS) {
 1486         ret = sysdb_error_to_errno(ret);
 1487         goto done;
 1488     }
 1489 
 1490     if (res->count == 0) {
 1491         *_site = NULL;
 1492         ret = EOK;
 1493         goto done;
 1494     } else if (res->count != 1) {
 1495         DEBUG(SSSDBG_CRIT_FAILURE,
 1496               "Got more than one reply for base search!\n");
 1497         ret = EIO;
 1498         goto done;
 1499     }
 1500 
 1501     *_site = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SITE, NULL);
 1502     talloc_steal(mem_ctx, *_site);
 1503 
 1504     ret = EOK;
 1505 
 1506 done:
 1507     talloc_free(tmp_ctx);
 1508     return ret;
 1509 }
 1510 
 1511 errno_t
 1512 sysdb_set_site(struct sss_domain_info *dom,
 1513                const char *site)
 1514 {
 1515     TALLOC_CTX *tmp_ctx;
 1516     struct ldb_message *msg;
 1517     struct ldb_dn *dn;
 1518     errno_t ret;
 1519 
 1520     tmp_ctx = talloc_new(NULL);
 1521     if (tmp_ctx == NULL) {
 1522         return ENOMEM;
 1523     }
 1524 
 1525     dn = sysdb_domain_dn(tmp_ctx, dom);
 1526     if (dn == NULL) {
 1527         ret = ENOMEM;
 1528         goto done;
 1529     }
 1530 
 1531     msg = ldb_msg_new(tmp_ctx);
 1532     if (msg == NULL) {
 1533         ret = ENOMEM;
 1534         goto done;
 1535     }
 1536 
 1537     msg->dn = dn;
 1538 
 1539     ret = ldb_msg_add_empty(msg, SYSDB_SITE, LDB_FLAG_MOD_REPLACE, NULL);
 1540     if (ret != LDB_SUCCESS) {
 1541         ret = sysdb_error_to_errno(ret);
 1542         goto done;
 1543     }
 1544 
 1545     if (site != NULL) {
 1546         ret = ldb_msg_add_string(msg, SYSDB_SITE, site);
 1547         if (ret != LDB_SUCCESS) {
 1548             ret = sysdb_error_to_errno(ret);
 1549             goto done;
 1550         }
 1551     }
 1552 
 1553     ret = ldb_modify(dom->sysdb->ldb, msg);
 1554     if (ret != LDB_SUCCESS) {
 1555         DEBUG(SSSDBG_OP_FAILURE,
 1556               "ldb_modify()_failed: [%s][%d][%s]\n",
 1557               ldb_strerror(ret), ret, ldb_errstring(dom->sysdb->ldb));
 1558         ret = sysdb_error_to_errno(ret);
 1559         goto done;
 1560     }
 1561 
 1562     ret = EOK;
 1563 
 1564 done:
 1565     talloc_free(tmp_ctx);
 1566     return ret;
 1567 }
 1568 
 1569 errno_t
 1570 sysdb_domain_set_enabled(struct sysdb_ctx *sysdb,
 1571                          const char *name,
 1572                          bool enabled)
 1573 {
 1574     struct ldb_dn *dn;
 1575     errno_t ret;
 1576 
 1577     dn = ldb_dn_new_fmt(NULL, sysdb->ldb, SYSDB_DOM_BASE, name);
 1578     if (dn == NULL) {
 1579         return ENOMEM;
 1580     }
 1581 
 1582     ret = sysdb_set_bool(sysdb, dn, NULL, SYSDB_ENABLED, enabled);
 1583     talloc_free(dn);
 1584 
 1585     return ret;
 1586 }
 1587 
 1588 errno_t
 1589 sysdb_list_subdomains(TALLOC_CTX *mem_ctx,
 1590                       struct sysdb_ctx *sysdb,
 1591                       const char ***_names)
 1592 {
 1593     TALLOC_CTX *tmp_ctx;
 1594     struct ldb_dn *base_dn;
 1595     const char *attrs[] = {"cn", NULL};
 1596     struct ldb_message **msgs;
 1597     const char *name;
 1598     size_t count;
 1599     const char **names;
 1600     errno_t ret;
 1601     size_t i;
 1602 
 1603     tmp_ctx = talloc_new(NULL);
 1604     if (tmp_ctx == NULL) {
 1605         return ENOMEM;
 1606     }
 1607 
 1608     base_dn = sysdb_base_dn(sysdb, tmp_ctx);
 1609     if (base_dn == NULL) {
 1610         ret = ENOMEM;
 1611         goto done;
 1612     }
 1613 
 1614 
 1615     ret = sysdb_search_entry(tmp_ctx, sysdb, base_dn, LDB_SCOPE_ONELEVEL,
 1616                              "("SYSDB_OBJECTCLASS"="SYSDB_SUBDOMAIN_CLASS")",
 1617                              attrs, &count, &msgs);
 1618     if (ret != EOK && ret != ENOENT) {
 1619         goto done;
 1620     }
 1621 
 1622     names = talloc_zero_array(tmp_ctx, const char *, count + 1);
 1623     if (names == NULL) {
 1624         ret = ENOMEM;
 1625         goto done;
 1626     }
 1627 
 1628     for (i = 0; i < count; i++) {
 1629         name = ldb_msg_find_attr_as_string(msgs[i], "cn", NULL);
 1630         if (name == NULL) {
 1631             ret = EINVAL;
 1632             goto done;
 1633         }
 1634 
 1635         names[i] = talloc_steal(names, name);
 1636     }
 1637 
 1638     *_names = talloc_steal(mem_ctx, names);
 1639 
 1640     ret = EOK;
 1641 
 1642 done:
 1643     talloc_free(tmp_ctx);
 1644 
 1645     return ret;
 1646 }