LCOV - code coverage report
Current view: top level - source4/libcli - finddcs_cldap.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 114 219 52.1 %
Date: 2024-04-21 15:09:00 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    a composite API for finding a DC and its name via CLDAP
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2010
       7             :    Copyright (C) Andrew Bartlett 2010
       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 "include/includes.h"
      24             : #include <tevent.h>
      25             : #include "libcli/resolve/resolve.h"
      26             : #include "libcli/cldap/cldap.h"
      27             : #include "libcli/finddc.h"
      28             : #include "libcli/security/security.h"
      29             : #include "lib/util/tevent_ntstatus.h"
      30             : #include "lib/tsocket/tsocket.h"
      31             : #include "libcli/composite/composite.h"
      32             : #include "lib/util/util_net.h"
      33             : 
      34             : struct finddcs_cldap_state {
      35             :         struct tevent_context *ev;
      36             :         struct tevent_req *req;
      37             :         const char *domain_name;
      38             :         struct dom_sid *domain_sid;
      39             :         const char *srv_name;
      40             :         const char **srv_addresses;
      41             :         uint32_t minimum_dc_flags;
      42             :         uint32_t srv_address_index;
      43             :         struct cldap_socket *cldap;
      44             :         struct cldap_netlogon *netlogon;
      45             :         NTSTATUS status;
      46             : };
      47             : 
      48             : static void finddcs_cldap_srv_resolved(struct composite_context *ctx);
      49             : static void finddcs_cldap_netlogon_replied(struct tevent_req *req);
      50             : static bool finddcs_cldap_srv_lookup(struct finddcs_cldap_state *state,
      51             :                                      struct finddcs *io,
      52             :                                      struct resolve_context *resolve_ctx,
      53             :                                      struct tevent_context *event_ctx);
      54             : static bool finddcs_cldap_nbt_lookup(struct finddcs_cldap_state *state,
      55             :                                      struct finddcs *io,
      56             :                                      struct resolve_context *resolve_ctx,
      57             :                                      struct tevent_context *event_ctx);
      58             : static void finddcs_cldap_nbt_resolved(struct composite_context *ctx);
      59             : static bool finddcs_cldap_name_lookup(struct finddcs_cldap_state *state,
      60             :                                       struct finddcs *io,
      61             :                                       struct resolve_context *resolve_ctx,
      62             :                                       struct tevent_context *event_ctx);
      63             : static void finddcs_cldap_name_resolved(struct composite_context *ctx);
      64             : static void finddcs_cldap_next_server(struct finddcs_cldap_state *state);
      65             : static bool finddcs_cldap_ipaddress(struct finddcs_cldap_state *state, struct finddcs *io);
      66             : 
      67             : 
      68             : /*
      69             :  * find a list of DCs via DNS/CLDAP
      70             :  */
      71         701 : struct tevent_req *finddcs_cldap_send(TALLOC_CTX *mem_ctx,
      72             :                                       struct finddcs *io,
      73             :                                       struct resolve_context *resolve_ctx,
      74             :                                       struct tevent_context *event_ctx)
      75             : {
      76           0 :         struct finddcs_cldap_state *state;
      77           0 :         struct tevent_req *req;
      78             : 
      79         701 :         req = tevent_req_create(mem_ctx, &state, struct finddcs_cldap_state);
      80         701 :         if (req == NULL) {
      81           0 :                 return NULL;
      82             :         }
      83             : 
      84         701 :         state->req = req;
      85         701 :         state->ev = event_ctx;
      86         701 :         state->minimum_dc_flags = io->in.minimum_dc_flags;
      87             : 
      88         701 :         if (io->in.domain_name) {
      89         392 :                 state->domain_name = talloc_strdup(state, io->in.domain_name);
      90         392 :                 if (tevent_req_nomem(state->domain_name, req)) {
      91           0 :                         return tevent_req_post(req, event_ctx);
      92             :                 }
      93             :         } else {
      94         309 :                 state->domain_name = NULL;
      95             :         }
      96             : 
      97         701 :         if (io->in.domain_sid) {
      98           0 :                 state->domain_sid = dom_sid_dup(state, io->in.domain_sid);
      99           0 :                 if (tevent_req_nomem(state->domain_sid, req)) {
     100           0 :                         return tevent_req_post(req, event_ctx);
     101             :                 }
     102             :         } else {
     103         701 :                 state->domain_sid = NULL;
     104             :         }
     105             : 
     106         701 :         if (io->in.server_address) {
     107         472 :                 if (is_ipaddress(io->in.server_address)) {
     108          24 :                         DEBUG(4,("finddcs: searching for a DC by IP %s\n",
     109             :                                  io->in.server_address));
     110          24 :                         if (!finddcs_cldap_ipaddress(state, io)) {
     111           0 :                                 return tevent_req_post(req, event_ctx);
     112             :                         }
     113             :                 } else {
     114         448 :                         if (!finddcs_cldap_name_lookup(state, io, resolve_ctx,
     115             :                                                        event_ctx)) {
     116           0 :                                 return tevent_req_post(req, event_ctx);
     117             :                         }
     118             :                 }
     119         229 :         } else if (io->in.domain_name) {
     120         229 :                 if (strchr(state->domain_name, '.')) {
     121             :                         /* looks like a DNS name */
     122         229 :                         DEBUG(4,("finddcs: searching for a DC by DNS domain %s\n", state->domain_name));
     123         229 :                         if (!finddcs_cldap_srv_lookup(state, io, resolve_ctx,
     124             :                                                       event_ctx)) {
     125           0 :                                 return tevent_req_post(req, event_ctx);
     126             :                         }
     127             :                 } else {
     128           0 :                         DEBUG(4,("finddcs: searching for a DC by NBT lookup %s\n", state->domain_name));
     129           0 :                         if (!finddcs_cldap_nbt_lookup(state, io, resolve_ctx,
     130             :                                                       event_ctx)) {
     131           0 :                                 return tevent_req_post(req, event_ctx);
     132             :                         }
     133             :                 }
     134             :         } else {
     135             :                 /* either we have the domain name or the IP address */
     136           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
     137           0 :                 DEBUG(2,("finddcs: Please specify at least the domain name or the IP address! \n"));
     138           0 :                 return tevent_req_post(req, event_ctx);
     139             :         }
     140             : 
     141         701 :         return req;
     142             : }
     143             : 
     144             : 
     145             : /*
     146             :   we've been told the IP of the server, bypass name
     147             :   resolution and go straight to CLDAP
     148             : */
     149          24 : static bool finddcs_cldap_ipaddress(struct finddcs_cldap_state *state, struct finddcs *io)
     150             : {
     151           0 :         NTSTATUS status;
     152             : 
     153          24 :         state->srv_addresses = talloc_array(state, const char *, 2);
     154          24 :         if (tevent_req_nomem(state->srv_addresses, state->req)) {
     155           0 :                 return false;
     156             :         }
     157          24 :         state->srv_addresses[0] = talloc_strdup(state->srv_addresses, io->in.server_address);
     158          24 :         if (tevent_req_nomem(state->srv_addresses[0], state->req)) {
     159           0 :                 return false;
     160             :         }
     161          24 :         state->srv_addresses[1] = NULL;
     162          24 :         state->srv_address_index = 0;
     163             : 
     164          24 :         finddcs_cldap_next_server(state);
     165          24 :         return tevent_req_is_nterror(state->req, &status);
     166             : }
     167             : 
     168             : /*
     169             :   start a SRV DNS lookup
     170             :  */
     171         229 : static bool finddcs_cldap_srv_lookup(struct finddcs_cldap_state *state,
     172             :                                      struct finddcs *io,
     173             :                                      struct resolve_context *resolve_ctx,
     174             :                                      struct tevent_context *event_ctx)
     175             : {
     176           0 :         struct composite_context *creq;
     177           0 :         struct nbt_name name;
     178             : 
     179         229 :         if (io->in.site_name) {
     180           0 :                 state->srv_name = talloc_asprintf(state, "_ldap._tcp.%s._sites.%s",
     181             :                                            io->in.site_name, io->in.domain_name);
     182             :         } else {
     183         229 :                 state->srv_name = talloc_asprintf(state, "_ldap._tcp.%s", io->in.domain_name);
     184             :         }
     185             : 
     186         229 :         DEBUG(4,("finddcs: looking for SRV records for %s\n", state->srv_name));
     187             : 
     188         229 :         make_nbt_name(&name, state->srv_name, 0);
     189             : 
     190         229 :         creq = resolve_name_ex_send(resolve_ctx, state,
     191             :                                     RESOLVE_NAME_FLAG_FORCE_DNS | RESOLVE_NAME_FLAG_DNS_SRV,
     192             :                                     0, &name, event_ctx);
     193         229 :         if (tevent_req_nomem(creq, state->req)) {
     194           0 :                 return false;
     195             :         }
     196         229 :         creq->async.fn = finddcs_cldap_srv_resolved;
     197         229 :         creq->async.private_data = state;
     198             : 
     199         229 :         return true;
     200             : }
     201             : 
     202             : /*
     203             :   start a NBT name lookup for domain<1C>
     204             :  */
     205           0 : static bool finddcs_cldap_nbt_lookup(struct finddcs_cldap_state *state,
     206             :                                      struct finddcs *io,
     207             :                                      struct resolve_context *resolve_ctx,
     208             :                                      struct tevent_context *event_ctx)
     209             : {
     210           0 :         struct composite_context *creq;
     211           0 :         struct nbt_name name;
     212             : 
     213           0 :         make_nbt_name(&name, state->domain_name, NBT_NAME_LOGON);
     214           0 :         creq = resolve_name_send(resolve_ctx, state, &name, event_ctx);
     215           0 :         if (tevent_req_nomem(creq, state->req)) {
     216           0 :                 return false;
     217             :         }
     218           0 :         creq->async.fn = finddcs_cldap_nbt_resolved;
     219           0 :         creq->async.private_data = state;
     220           0 :         return true;
     221             : }
     222             : 
     223         448 : static bool finddcs_cldap_name_lookup(struct finddcs_cldap_state *state,
     224             :                                       struct finddcs *io,
     225             :                                       struct resolve_context *resolve_ctx,
     226             :                                       struct tevent_context *event_ctx)
     227             : {
     228           0 :         struct composite_context *creq;
     229           0 :         struct nbt_name name;
     230             : 
     231         448 :         make_nbt_name(&name, io->in.server_address, NBT_NAME_SERVER);
     232         448 :         creq = resolve_name_send(resolve_ctx, state, &name, event_ctx);
     233         448 :         if (tevent_req_nomem(creq, state->req)) {
     234           0 :                 return false;
     235             :         }
     236         448 :         creq->async.fn = finddcs_cldap_name_resolved;
     237         448 :         creq->async.private_data = state;
     238         448 :         return true;
     239             : }
     240             : 
     241             : /*
     242             :   fire off a CLDAP query to the next server
     243             :  */
     244         701 : static void finddcs_cldap_next_server(struct finddcs_cldap_state *state)
     245             : {
     246           0 :         struct tevent_req *subreq;
     247           0 :         struct tsocket_address *dest;
     248           0 :         int ret;
     249             : 
     250         701 :         TALLOC_FREE(state->cldap);
     251             : 
     252         701 :         if (state->srv_addresses[state->srv_address_index] == NULL) {
     253           0 :                 if (NT_STATUS_IS_OK(state->status)) {
     254           0 :                         tevent_req_nterror(state->req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
     255             :                 } else {
     256           0 :                         tevent_req_nterror(state->req, state->status);
     257             :                 }
     258           0 :                 DEBUG(2,("finddcs: No matching CLDAP server found\n"));
     259           0 :                 return;
     260             :         }
     261             : 
     262             :         /* we should get the port from the SRV response */
     263         701 :         ret = tsocket_address_inet_from_strings(state, "ip",
     264             :                                                 state->srv_addresses[state->srv_address_index],
     265             :                                                 389,
     266             :                                                 &dest);
     267         701 :         if (ret == 0) {
     268         701 :                 state->status = NT_STATUS_OK;
     269             :         } else {
     270           0 :                 state->status = map_nt_error_from_unix_common(errno);
     271             :         }
     272         701 :         if (!NT_STATUS_IS_OK(state->status)) {
     273           0 :                 state->srv_address_index++;
     274           0 :                 finddcs_cldap_next_server(state);
     275           0 :                 return;
     276             :         }
     277             : 
     278         701 :         state->status = cldap_socket_init(state, NULL, dest, &state->cldap);
     279         701 :         if (!NT_STATUS_IS_OK(state->status)) {
     280           0 :                 state->srv_address_index++;
     281           0 :                 finddcs_cldap_next_server(state);
     282           0 :                 return;
     283             :         }
     284             : 
     285         701 :         TALLOC_FREE(state->netlogon);
     286         701 :         state->netlogon = talloc_zero(state, struct cldap_netlogon);
     287         701 :         if (state->netlogon == NULL) {
     288           0 :                 state->status = NT_STATUS_NO_MEMORY;
     289           0 :                 state->srv_address_index++;
     290           0 :                 finddcs_cldap_next_server(state);
     291           0 :                 return;
     292             :         }
     293             : 
     294         701 :         if ((state->domain_name != NULL) && (strchr(state->domain_name, '.'))) {
     295         392 :                 state->netlogon->in.realm = state->domain_name;
     296             :         }
     297         701 :         if (state->domain_sid) {
     298           0 :                 state->netlogon->in.domain_sid = dom_sid_string(state, state->domain_sid);
     299           0 :                 if (state->netlogon->in.domain_sid == NULL) {
     300           0 :                         state->status = NT_STATUS_NO_MEMORY;
     301           0 :                         state->srv_address_index++;
     302           0 :                         finddcs_cldap_next_server(state);
     303           0 :                         return;
     304             :                 }
     305             :         }
     306         701 :         state->netlogon->in.acct_control = -1;
     307         701 :         state->netlogon->in.version =
     308             :                 NETLOGON_NT_VERSION_5 |
     309             :                 NETLOGON_NT_VERSION_5EX |
     310             :                 NETLOGON_NT_VERSION_IP;
     311         701 :         state->netlogon->in.map_response = true;
     312             : 
     313         701 :         DEBUG(4,("finddcs: performing CLDAP query on %s\n",
     314             :                  state->srv_addresses[state->srv_address_index]));
     315             : 
     316         701 :         subreq = cldap_netlogon_send(state, state->ev,
     317         701 :                                      state->cldap, state->netlogon);
     318         701 :         if (subreq == NULL) {
     319           0 :                 state->status = NT_STATUS_NO_MEMORY;
     320           0 :                 state->srv_address_index++;
     321           0 :                 finddcs_cldap_next_server(state);
     322           0 :                 return;
     323             :         }
     324             : 
     325         701 :         tevent_req_set_callback(subreq, finddcs_cldap_netlogon_replied, state);
     326             : }
     327             : 
     328             : 
     329             : /*
     330             :   we have a response from a CLDAP server for a netlogon request
     331             :  */
     332         701 : static void finddcs_cldap_netlogon_replied(struct tevent_req *subreq)
     333             : {
     334           0 :         struct finddcs_cldap_state *state;
     335           0 :         NTSTATUS status;
     336             : 
     337         701 :         state = tevent_req_callback_data(subreq, struct finddcs_cldap_state);
     338             : 
     339         701 :         status = cldap_netlogon_recv(subreq, state->netlogon, state->netlogon);
     340         701 :         TALLOC_FREE(subreq);
     341         701 :         TALLOC_FREE(state->cldap);
     342         701 :         if (!NT_STATUS_IS_OK(status)) {
     343           0 :                 state->status = status;
     344           0 :                 state->srv_address_index++;
     345           0 :                 finddcs_cldap_next_server(state);
     346           0 :                 return;
     347             :         }
     348         701 :         if (state->minimum_dc_flags !=
     349         701 :             (state->minimum_dc_flags & state->netlogon->out.netlogon.data.nt5_ex.server_type)) {
     350             :                 /* the server didn't match the minimum requirements */
     351           0 :                 DEBUG(4,("finddcs: Skipping DC %s with server_type=0x%08x - required 0x%08x\n",
     352             :                          state->srv_addresses[state->srv_address_index],
     353             :                          state->netlogon->out.netlogon.data.nt5_ex.server_type,
     354             :                          state->minimum_dc_flags));
     355           0 :                 state->srv_address_index++;
     356           0 :                 finddcs_cldap_next_server(state);
     357           0 :                 return;
     358             :         }
     359             : 
     360         701 :         DEBUG(4,("finddcs: Found matching DC %s with server_type=0x%08x\n",
     361             :                  state->srv_addresses[state->srv_address_index],
     362             :                  state->netlogon->out.netlogon.data.nt5_ex.server_type));
     363             : 
     364         701 :         tevent_req_done(state->req);
     365             : }
     366             : 
     367         448 : static void finddcs_cldap_name_resolved(struct composite_context *ctx)
     368             : {
     369           0 :         struct finddcs_cldap_state *state =
     370         448 :                 talloc_get_type(ctx->async.private_data, struct finddcs_cldap_state);
     371           0 :         NTSTATUS status;
     372           0 :         unsigned i;
     373             : 
     374         448 :         status = resolve_name_multiple_recv(ctx, state, &state->srv_addresses);
     375         448 :         if (tevent_req_nterror(state->req, status)) {
     376           0 :                 DEBUG(2,("finddcs: No matching server found\n"));
     377           0 :                 return;
     378             :         }
     379             : 
     380        1344 :         for (i=0; state->srv_addresses[i]; i++) {
     381         896 :                 DEBUG(4,("finddcs: response %u at '%s'\n",
     382             :                          i, state->srv_addresses[i]));
     383             :         }
     384             : 
     385         448 :         state->srv_address_index = 0;
     386             : 
     387         448 :         state->status = NT_STATUS_OK;
     388         448 :         finddcs_cldap_next_server(state);
     389             : }
     390             : 
     391             : /*
     392             :    handle NBT name lookup reply
     393             :  */
     394           0 : static void finddcs_cldap_nbt_resolved(struct composite_context *ctx)
     395             : {
     396           0 :         struct finddcs_cldap_state *state =
     397           0 :                 talloc_get_type(ctx->async.private_data, struct finddcs_cldap_state);
     398           0 :         NTSTATUS status;
     399           0 :         unsigned i;
     400             : 
     401           0 :         status = resolve_name_multiple_recv(ctx, state, &state->srv_addresses);
     402           0 :         if (tevent_req_nterror(state->req, status)) {
     403           0 :                 DEBUG(2,("finddcs: No matching NBT <1c> server found\n"));
     404           0 :                 return;
     405             :         }
     406             : 
     407           0 :         for (i=0; state->srv_addresses[i]; i++) {
     408           0 :                 DEBUG(4,("finddcs: NBT <1c> response %u at '%s'\n",
     409             :                          i, state->srv_addresses[i]));
     410             :         }
     411             : 
     412           0 :         state->srv_address_index = 0;
     413             : 
     414           0 :         finddcs_cldap_next_server(state);
     415             : }
     416             : 
     417             : 
     418             : /*
     419             :  * Having got a DNS SRV answer, fire off the first CLDAP request
     420             :  */
     421         229 : static void finddcs_cldap_srv_resolved(struct composite_context *ctx)
     422             : {
     423           0 :         struct finddcs_cldap_state *state =
     424         229 :                 talloc_get_type(ctx->async.private_data, struct finddcs_cldap_state);
     425           0 :         NTSTATUS status;
     426           0 :         unsigned i;
     427             : 
     428         229 :         status = resolve_name_multiple_recv(ctx, state, &state->srv_addresses);
     429         229 :         if (tevent_req_nterror(state->req, status)) {
     430           0 :                 DEBUG(2,("finddcs: Failed to find SRV record for %s\n", state->srv_name));
     431           0 :                 return;
     432             :         }
     433             : 
     434         687 :         for (i=0; state->srv_addresses[i]; i++) {
     435         458 :                 DEBUG(4,("finddcs: DNS SRV response %u at '%s'\n", i, state->srv_addresses[i]));
     436             :         }
     437             : 
     438         229 :         state->srv_address_index = 0;
     439             : 
     440         229 :         state->status = NT_STATUS_OK;
     441         229 :         finddcs_cldap_next_server(state);
     442             : }
     443             : 
     444             : 
     445         701 : NTSTATUS finddcs_cldap_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct finddcs *io)
     446             : {
     447         701 :         struct finddcs_cldap_state *state = tevent_req_data(req, struct finddcs_cldap_state);
     448           0 :         bool ok;
     449           0 :         NTSTATUS status;
     450             : 
     451         701 :         ok = tevent_req_poll(req, state->ev);
     452         701 :         if (!ok) {
     453           0 :                 talloc_free(req);
     454           0 :                 return NT_STATUS_INTERNAL_ERROR;
     455             :         }
     456         701 :         if (tevent_req_is_nterror(req, &status)) {
     457           0 :                 tevent_req_received(req);
     458           0 :                 return status;
     459             :         }
     460             : 
     461         701 :         talloc_steal(mem_ctx, state->netlogon);
     462         701 :         io->out.netlogon = state->netlogon->out.netlogon;
     463         701 :         io->out.address = talloc_steal(
     464             :                 mem_ctx, state->srv_addresses[state->srv_address_index]);
     465             : 
     466         701 :         tevent_req_received(req);
     467         701 :         return NT_STATUS_OK;
     468             : }
     469             : 
     470         491 : NTSTATUS finddcs_cldap(TALLOC_CTX *mem_ctx,
     471             :                        struct finddcs *io,
     472             :                        struct resolve_context *resolve_ctx,
     473             :                        struct tevent_context *event_ctx)
     474             : {
     475           0 :         NTSTATUS status;
     476         491 :         struct tevent_req *req = finddcs_cldap_send(mem_ctx,
     477             :                                                     io,
     478             :                                                     resolve_ctx,
     479             :                                                     event_ctx);
     480         491 :         status = finddcs_cldap_recv(req, mem_ctx, io);
     481         491 :         talloc_free(req);
     482         491 :         return status;
     483             : }

Generated by: LCOV version 1.14