"Fossies" - the Fresh Open Source Software Archive

Member "sssd-2.2.3/src/providers/ad/ad_domain_info.c" (30 Nov 2019, 14404 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_domain_info.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2     SSSD
    3 
    4     AD Domain Info 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 <errno.h>
   26 #include <tevent.h>
   27 #include <ctype.h>
   28 #include <ndr.h>
   29 #include <ndr/ndr_nbt.h>
   30 
   31 #include "providers/ldap/sdap.h"
   32 #include "providers/ldap/sdap_async.h"
   33 #include "providers/ldap/sdap_idmap.h"
   34 #include "providers/ad/ad_domain_info.h"
   35 #include "providers/ad/ad_common.h"
   36 #include "util/util.h"
   37 
   38 errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx,
   39                                  struct sysdb_attrs *reply,
   40                                  bool check_next_nearest_site_as_well,
   41                                  char **_flat_name,
   42                                  char **_site,
   43                                  char **_forest)
   44 {
   45     errno_t ret;
   46     struct ldb_message_element *el;
   47     DATA_BLOB blob;
   48     struct ndr_pull *ndr_pull = NULL;
   49     enum ndr_err_code ndr_err;
   50     struct netlogon_samlogon_response response;
   51     TALLOC_CTX *tmp_ctx;
   52 
   53     ret = sysdb_attrs_get_el(reply, AD_AT_NETLOGON, &el);
   54     if (ret != EOK) {
   55         DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
   56         return ret;
   57     }
   58 
   59     if (el->num_values == 0) {
   60         DEBUG(SSSDBG_OP_FAILURE, "netlogon has no value\n");
   61         return ENOENT;
   62     } else if (el->num_values > 1) {
   63         DEBUG(SSSDBG_OP_FAILURE, "More than one netlogon value?\n");
   64         return EIO;
   65     }
   66 
   67     tmp_ctx = talloc_new(NULL);
   68     if (tmp_ctx == NULL) {
   69         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
   70         return ENOMEM;
   71     }
   72 
   73     blob.data = el->values[0].data;
   74     blob.length = el->values[0].length;
   75 
   76     /* The ndr_pull_* calls do not use ndr_pull as a talloc context to
   77      * allocate memory but the second argument of ndr_pull_init_blob(). To
   78      * make sure no memory is leaked here a temporary talloc context is
   79      * needed. */
   80     ndr_pull = ndr_pull_init_blob(&blob, tmp_ctx);
   81     if (ndr_pull == NULL) {
   82         DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob() failed.\n");
   83         ret = ENOMEM;
   84         goto done;
   85     }
   86 
   87     ndr_err = ndr_pull_netlogon_samlogon_response(ndr_pull, NDR_SCALARS,
   88                                                   &response);
   89     if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
   90         DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_netlogon_samlogon_response() "
   91                                   "failed [%d]\n", ndr_err);
   92         ret = EBADMSG;
   93         goto done;
   94     }
   95 
   96     if (!(response.ntver & NETLOGON_NT_VERSION_5EX)) {
   97         DEBUG(SSSDBG_OP_FAILURE, "Wrong version returned [%x]\n",
   98                                   response.ntver);
   99         ret = EBADMSG;
  100         goto done;
  101     }
  102 
  103     /* get flat domain name */
  104     if (_flat_name != NULL) {
  105         if (response.data.nt5_ex.domain_name != NULL &&
  106             *response.data.nt5_ex.domain_name != '\0') {
  107             *_flat_name = talloc_strdup(mem_ctx,
  108                                         response.data.nt5_ex.domain_name);
  109             if (*_flat_name == NULL) {
  110                 DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
  111                 ret = ENOMEM;
  112                 goto done;
  113             }
  114         } else {
  115             DEBUG(SSSDBG_MINOR_FAILURE,
  116                   "No netlogon flat domain name data available.\n");
  117             *_flat_name = NULL;
  118         }
  119     }
  120 
  121 
  122     /* get forest */
  123     if (_forest != NULL) {
  124         if (response.data.nt5_ex.forest != NULL &&
  125             *response.data.nt5_ex.forest != '\0') {
  126             *_forest = talloc_strdup(mem_ctx, response.data.nt5_ex.forest);
  127             if (*_forest == NULL) {
  128                 DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
  129                 ret = ENOMEM;
  130                 goto done;
  131             }
  132         } else {
  133             DEBUG(SSSDBG_MINOR_FAILURE, "No netlogon forest data available.\n");
  134             *_forest = NULL;
  135         }
  136     }
  137 
  138     /* get site name */
  139     if (_site != NULL) {
  140         if (response.data.nt5_ex.client_site != NULL
  141             && response.data.nt5_ex.client_site[0] != '\0') {
  142             *_site = talloc_strdup(mem_ctx, response.data.nt5_ex.client_site);
  143             if (*_site == NULL) {
  144                 DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
  145                 ret = ENOMEM;
  146                 goto done;
  147             }
  148         } else {
  149             DEBUG(SSSDBG_MINOR_FAILURE,
  150                   "No netlogon site name data available.\n");
  151             *_site = NULL;
  152 
  153             if (check_next_nearest_site_as_well) {
  154                 if (response.data.nt5_ex.next_closest_site != NULL
  155                         && response.data.nt5_ex.next_closest_site[0] != '\0') {
  156                     *_site = talloc_strdup(mem_ctx,
  157                                         response.data.nt5_ex.next_closest_site);
  158                     if (*_site == NULL) {
  159                         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
  160                         ret = ENOMEM;
  161                         goto done;
  162                     }
  163                 } else {
  164                     DEBUG(SSSDBG_MINOR_FAILURE,
  165                           "No netlogon next closest site name data "
  166                           "available.\n");
  167                 }
  168             }
  169         }
  170     }
  171 
  172     ret = EOK;
  173 done:
  174     talloc_free(tmp_ctx);
  175     return ret;
  176 }
  177 
  178 struct ad_master_domain_state {
  179     struct tevent_context *ev;
  180     struct sdap_id_conn_ctx *conn;
  181     struct sdap_id_op *id_op;
  182     struct sdap_id_ctx *id_ctx;
  183     struct sdap_options *opts;
  184 
  185     const char *dom_name;
  186     int base_iter;
  187 
  188     char *flat;
  189     char *site;
  190     char *forest;
  191     char *sid;
  192 };
  193 
  194 static errno_t ad_master_domain_next(struct tevent_req *req);
  195 static void ad_master_domain_next_done(struct tevent_req *subreq);
  196 static void ad_master_domain_netlogon_done(struct tevent_req *req);
  197 
  198 struct tevent_req *
  199 ad_master_domain_send(TALLOC_CTX *mem_ctx,
  200                       struct tevent_context *ev,
  201                       struct sdap_id_conn_ctx *conn,
  202                       struct sdap_id_op *op,
  203                       const char *dom_name)
  204 {
  205     errno_t ret;
  206     struct tevent_req *req;
  207     struct ad_master_domain_state *state;
  208 
  209     req = tevent_req_create(mem_ctx, &state, struct ad_master_domain_state);
  210     if (!req) return NULL;
  211 
  212     state->ev = ev;
  213     state->id_op = op;
  214     state->conn = conn;
  215     state->id_ctx = conn->id_ctx;
  216     state->opts = conn->id_ctx->opts;
  217     state->dom_name = dom_name;
  218 
  219     ret = ad_master_domain_next(req);
  220     if (ret != EOK && ret != EAGAIN) {
  221         goto immediate;
  222     }
  223 
  224     return req;
  225 
  226 immediate:
  227     if (ret != EOK) {
  228         tevent_req_error(req, ret);
  229     } else {
  230         tevent_req_done(req);
  231     }
  232     tevent_req_post(req, ev);
  233     return req;
  234 }
  235 
  236 static errno_t
  237 ad_master_domain_next(struct tevent_req *req)
  238 {
  239     struct tevent_req *subreq;
  240     struct sdap_search_base *base;
  241     const char *master_sid_attrs[] = {AD_AT_OBJECT_SID, NULL};
  242 
  243     struct ad_master_domain_state *state =
  244         tevent_req_data(req, struct ad_master_domain_state);
  245 
  246     base = state->opts->sdom->search_bases[state->base_iter];
  247     if (base == NULL) {
  248         return EOK;
  249     }
  250 
  251     subreq = sdap_get_generic_send(state, state->ev,
  252                                    state->id_ctx->opts,
  253                                    sdap_id_op_handle(state->id_op),
  254                                    base->basedn, LDAP_SCOPE_BASE,
  255                                    MASTER_DOMAIN_SID_FILTER, master_sid_attrs,
  256                                    NULL, 0,
  257                                    dp_opt_get_int(state->opts->basic,
  258                                                   SDAP_SEARCH_TIMEOUT),
  259                                    false);
  260     if (subreq == NULL) {
  261         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
  262         return ENOMEM;
  263     }
  264     tevent_req_set_callback(subreq, ad_master_domain_next_done, req);
  265 
  266     return EAGAIN;
  267 }
  268 
  269 static void
  270 ad_master_domain_next_done(struct tevent_req *subreq)
  271 {
  272     errno_t ret;
  273     size_t reply_count;
  274     struct sysdb_attrs **reply = NULL;
  275     struct ldb_message_element *el;
  276     char *sid_str;
  277     enum idmap_error_code err;
  278     static const char *attrs[] = {AD_AT_NETLOGON, NULL};
  279     char *filter;
  280     char *ntver;
  281 
  282     struct tevent_req *req = tevent_req_callback_data(subreq,
  283                                                       struct tevent_req);
  284     struct ad_master_domain_state *state =
  285         tevent_req_data(req, struct ad_master_domain_state);
  286 
  287     ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
  288     talloc_zfree(subreq);
  289     if (ret != EOK) {
  290         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
  291         goto done;
  292     }
  293 
  294     if (reply_count == 0) {
  295         state->base_iter++;
  296         ret = ad_master_domain_next(req);
  297         if (ret == EAGAIN) {
  298             /* Async request will get us back here again */
  299             return;
  300         } else if (ret != EOK) {
  301             goto done;
  302         }
  303 
  304         /* EOK */
  305         tevent_req_done(req);
  306         return;
  307     } else if (reply_count == 1) {
  308         ret = sysdb_attrs_get_el(reply[0], AD_AT_OBJECT_SID, &el);
  309         if (ret != EOK || el->num_values != 1) {
  310             DEBUG(SSSDBG_OP_FAILURE, "sdap_attrs_get_el failed.\n");
  311             goto done;
  312         }
  313 
  314         err = sss_idmap_bin_sid_to_sid(state->opts->idmap_ctx->map,
  315                                        el->values[0].data,
  316                                        el->values[0].length,
  317                                        &sid_str);
  318         if (err != IDMAP_SUCCESS) {
  319             DEBUG(SSSDBG_MINOR_FAILURE,
  320                   "Could not convert SID: [%s].\n", idmap_error_string(err));
  321             ret = EFAULT;
  322             goto done;
  323         }
  324 
  325         state->sid = talloc_steal(state, sid_str);
  326     } else {
  327         DEBUG(SSSDBG_OP_FAILURE,
  328               "More than one result for domain SID found.\n");
  329         ret = EINVAL;
  330         goto done;
  331     }
  332 
  333     DEBUG(SSSDBG_TRACE_FUNC, "Found SID [%s].\n", state->sid);
  334 
  335     ntver = sss_ldap_encode_ndr_uint32(state, NETLOGON_NT_VERSION_5EX |
  336                                        NETLOGON_NT_VERSION_WITH_CLOSEST_SITE);
  337     if (ntver == NULL) {
  338         DEBUG(SSSDBG_OP_FAILURE, "sss_ldap_encode_ndr_uint32 failed.\n");
  339         ret = ENOMEM;
  340         goto done;
  341     }
  342 
  343     filter = talloc_asprintf(state, "(&(%s=%s)(%s=%s))",
  344                              AD_AT_DNS_DOMAIN, state->dom_name,
  345                              AD_AT_NT_VERSION, ntver);
  346     if (filter == NULL) {
  347         DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
  348         ret = ENOMEM;
  349         goto done;
  350     }
  351 
  352     subreq = sdap_get_generic_send(state, state->ev,
  353                                    state->id_ctx->opts,
  354                                    sdap_id_op_handle(state->id_op),
  355                                    "", LDAP_SCOPE_BASE, filter, attrs, NULL, 0,
  356                                    dp_opt_get_int(state->opts->basic,
  357                                                   SDAP_SEARCH_TIMEOUT),
  358                                    false);
  359     if (subreq == NULL) {
  360         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
  361         ret = ENOMEM;
  362         goto done;
  363     }
  364 
  365     tevent_req_set_callback(subreq, ad_master_domain_netlogon_done, req);
  366     return;
  367 
  368 done:
  369     tevent_req_error(req, ret);
  370 }
  371 
  372 static void
  373 ad_master_domain_netlogon_done(struct tevent_req *subreq)
  374 {
  375     int ret;
  376     size_t reply_count;
  377     struct sysdb_attrs **reply = NULL;
  378 
  379     struct tevent_req *req = tevent_req_callback_data(subreq,
  380                                                       struct tevent_req);
  381     struct ad_master_domain_state *state =
  382         tevent_req_data(req, struct ad_master_domain_state);
  383 
  384     ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
  385     talloc_zfree(subreq);
  386     if (ret != EOK) {
  387         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
  388         tevent_req_error(req, ret);
  389         return;
  390     }
  391 
  392     /* Failure to get the flat name is not fatal. Just quit. */
  393     if (reply_count == 0) {
  394         DEBUG(SSSDBG_MINOR_FAILURE, "No netlogon data available. Flat name " \
  395                                      "might not be usable\n");
  396         goto done;
  397     } else if (reply_count > 1) {
  398         DEBUG(SSSDBG_MINOR_FAILURE,
  399                 "More than one netlogon info returned.\n");
  400         goto done;
  401     }
  402 
  403     /* Exactly one flat name. Carry on */
  404 
  405     ret = netlogon_get_domain_info(state, reply[0], false, &state->flat,
  406                                    &state->site, &state->forest);
  407     if (ret != EOK) {
  408         DEBUG(SSSDBG_MINOR_FAILURE,
  409               "Could not get the flat name or forest: %d:[%s]\n",
  410               ret, sss_strerror(ret));
  411         /* Not fatal. Just quit. */
  412         goto done;
  413     }
  414 
  415     DEBUG(SSSDBG_TRACE_FUNC, "Found flat name [%s].\n", state->flat);
  416     DEBUG(SSSDBG_TRACE_FUNC, "Found site [%s].\n", state->site);
  417     DEBUG(SSSDBG_TRACE_FUNC, "Found forest [%s].\n", state->forest);
  418 
  419 done:
  420     tevent_req_done(req);
  421     return;
  422 }
  423 
  424 errno_t
  425 ad_master_domain_recv(struct tevent_req *req,
  426                       TALLOC_CTX *mem_ctx,
  427                       char **_flat,
  428                       char **_id,
  429                       char **_site,
  430                       char **_forest)
  431 {
  432     struct ad_master_domain_state *state = tevent_req_data(req,
  433                                               struct ad_master_domain_state);
  434 
  435     TEVENT_REQ_RETURN_ON_ERROR(req);
  436 
  437     if (_flat) {
  438         *_flat = talloc_steal(mem_ctx, state->flat);
  439     }
  440 
  441     if (_site) {
  442         *_site = talloc_steal(mem_ctx, state->site);
  443     }
  444 
  445     if (_forest) {
  446         *_forest = talloc_steal(mem_ctx, state->forest);
  447     }
  448 
  449     if (_id) {
  450         *_id = talloc_steal(mem_ctx, state->sid);
  451     }
  452 
  453     return EOK;
  454 }