LCOV - code coverage report
Current view: top level - source3/libads - cldap.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 128 205 62.4 %
Date: 2023-11-21 12:31:41 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /* 
       2             :    Samba Unix/Linux SMB client library 
       3             :    net ads cldap functions 
       4             :    Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
       5             :    Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com)
       6             :    Copyright (C) 2008 Guenther Deschner (gd@samba.org)
       7             :    Copyright (C) 2009 Stefan Metzmacher (metze@samba.org)
       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 "includes.h"
      24             : #include "../libcli/cldap/cldap.h"
      25             : #include "../librpc/gen_ndr/ndr_netlogon.h"
      26             : #include "../lib/tsocket/tsocket.h"
      27             : #include "../lib/util/tevent_ntstatus.h"
      28             : #include "libads/cldap.h"
      29             : 
      30             : struct cldap_multi_netlogon_state {
      31             :         struct tevent_context *ev;
      32             :         const struct tsocket_address * const *servers;
      33             :         int num_servers;
      34             :         const char *domain;
      35             :         const char *hostname;
      36             :         unsigned ntversion;
      37             :         int min_servers;
      38             : 
      39             :         struct cldap_socket **cldap;
      40             :         struct tevent_req **subreqs;
      41             :         int num_sent;
      42             :         int num_received;
      43             :         int num_good_received;
      44             :         struct cldap_netlogon *ios;
      45             :         struct netlogon_samlogon_response **responses;
      46             : };
      47             : 
      48             : static void cldap_multi_netlogon_done(struct tevent_req *subreq);
      49             : static void cldap_multi_netlogon_next(struct tevent_req *subreq);
      50             : 
      51             : /****************************************************************
      52             : ****************************************************************/
      53             : 
      54             : #define RETURN_ON_FALSE(x) if (!(x)) return false;
      55             : 
      56         678 : bool check_cldap_reply_required_flags(uint32_t ret_flags,
      57             :                                       uint32_t req_flags)
      58             : {
      59         678 :         if (req_flags == 0) {
      60         581 :                 return true;
      61             :         }
      62             : 
      63          97 :         if (req_flags & DS_PDC_REQUIRED)
      64           0 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_PDC);
      65             : 
      66          97 :         if (req_flags & DS_GC_SERVER_REQUIRED)
      67           0 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_GC);
      68             : 
      69          97 :         if (req_flags & DS_ONLY_LDAP_NEEDED)
      70           0 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_LDAP);
      71             : 
      72          97 :         if ((req_flags & DS_DIRECTORY_SERVICE_REQUIRED) ||
      73           9 :             (req_flags & DS_DIRECTORY_SERVICE_PREFERRED))
      74          88 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS);
      75             : 
      76          97 :         if (req_flags & DS_KDC_REQUIRED)
      77           0 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_KDC);
      78             : 
      79          97 :         if (req_flags & DS_TIMESERV_REQUIRED)
      80           0 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_TIMESERV);
      81             : 
      82          97 :         if (req_flags & DS_WEB_SERVICE_REQUIRED)
      83           0 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_ADS_WEB_SERVICE);
      84             : 
      85          97 :         if (req_flags & DS_WRITABLE_REQUIRED)
      86          88 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_WRITABLE);
      87             : 
      88          97 :         if (req_flags & DS_DIRECTORY_SERVICE_6_REQUIRED)
      89           0 :                 RETURN_ON_FALSE(ret_flags & (NBT_SERVER_SELECT_SECRET_DOMAIN_6
      90           0 :                                              |NBT_SERVER_FULL_SECRET_DOMAIN_6));
      91             : 
      92          97 :         if (req_flags & DS_DIRECTORY_SERVICE_8_REQUIRED)
      93           0 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_8);
      94             : 
      95          97 :         if (req_flags & DS_DIRECTORY_SERVICE_9_REQUIRED)
      96           0 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_9);
      97             : 
      98          97 :         if (req_flags & DS_DIRECTORY_SERVICE_10_REQUIRED)
      99           0 :                 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_10);
     100             : 
     101          97 :         return true;
     102             : }
     103             : 
     104             : /*
     105             :  * Do a parallel cldap ping to the servers. The first "min_servers"
     106             :  * are fired directly, the remaining ones in 100msec intervals. If
     107             :  * "min_servers" responses came in successfully, we immediately reply,
     108             :  * not waiting for the remaining ones.
     109             :  */
     110             : 
     111         866 : struct tevent_req *cldap_multi_netlogon_send(
     112             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     113             :         const struct tsocket_address * const *servers, int num_servers,
     114             :         const char *domain, const char *hostname, unsigned ntversion,
     115             :         int min_servers)
     116             : {
     117           0 :         struct tevent_req *req, *subreq;
     118           0 :         struct cldap_multi_netlogon_state *state;
     119           0 :         int i;
     120             : 
     121         866 :         req = tevent_req_create(mem_ctx, &state,
     122             :                                 struct cldap_multi_netlogon_state);
     123         866 :         if (req == NULL) {
     124           0 :                 return NULL;
     125             :         }
     126         866 :         state->ev = ev;
     127         866 :         state->servers = servers;
     128         866 :         state->num_servers = num_servers;
     129         866 :         state->domain = domain;
     130         866 :         state->hostname = hostname;
     131         866 :         state->ntversion = ntversion;
     132         866 :         state->min_servers = min_servers;
     133             : 
     134         866 :         if (min_servers > num_servers) {
     135           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     136           0 :                 return tevent_req_post(req, ev);
     137             :         }
     138             : 
     139         866 :         state->subreqs = talloc_zero_array(state,
     140             :                                            struct tevent_req *,
     141             :                                            num_servers);
     142         866 :         if (tevent_req_nomem(state->subreqs, req)) {
     143           0 :                 return tevent_req_post(req, ev);
     144             :         }
     145             : 
     146         866 :         state->cldap = talloc_zero_array(state,
     147             :                                          struct cldap_socket *,
     148             :                                          num_servers);
     149         866 :         if (tevent_req_nomem(state->cldap, req)) {
     150           0 :                 return tevent_req_post(req, ev);
     151             :         }
     152             : 
     153         866 :         state->responses = talloc_zero_array(state,
     154             :                                 struct netlogon_samlogon_response *,
     155             :                                 num_servers);
     156         866 :         if (tevent_req_nomem(state->responses, req)) {
     157           0 :                 return tevent_req_post(req, ev);
     158             :         }
     159             : 
     160         866 :         state->ios = talloc_zero_array(state->responses,
     161             :                                        struct cldap_netlogon,
     162             :                                        num_servers);
     163         866 :         if (tevent_req_nomem(state->ios, req)) {
     164           0 :                 return tevent_req_post(req, ev);
     165             :         }
     166             : 
     167        1926 :         for (i=0; i<num_servers; i++) {
     168           0 :                 NTSTATUS status;
     169             : 
     170        1060 :                 status = cldap_socket_init(state->cldap,
     171             :                                            NULL, /* local_addr */
     172        1060 :                                            state->servers[i],
     173        1060 :                                            &state->cldap[i]);
     174        1060 :                 if (!NT_STATUS_IS_OK(status)) {
     175             :                         /*
     176             :                          * Don't error out all sends just
     177             :                          * because one cldap_socket_init() failed.
     178             :                          * Log it here, and the cldap_netlogon_send()
     179             :                          * will catch it (with in.dest_address == NULL)
     180             :                          * and correctly error out in
     181             :                          * cldap_multi_netlogon_done(). This still allows
     182             :                          * the other requests to be concurrently sent.
     183             :                          */
     184           0 :                         DBG_NOTICE("cldap_socket_init failed for %s "
     185             :                                 " error %s\n",
     186             :                                 tsocket_address_string(state->servers[i],
     187             :                                         req),
     188             :                                 nt_errstr(status));
     189             :                 }
     190             : 
     191        1060 :                 state->ios[i].in.dest_address        = NULL;
     192        1060 :                 state->ios[i].in.dest_port   = 0;
     193        1060 :                 state->ios[i].in.realm               = domain;
     194        1060 :                 state->ios[i].in.host                = NULL;
     195        1060 :                 state->ios[i].in.user                = NULL;
     196        1060 :                 state->ios[i].in.domain_guid = NULL;
     197        1060 :                 state->ios[i].in.domain_sid  = NULL;
     198        1060 :                 state->ios[i].in.acct_control        = 0;
     199        1060 :                 state->ios[i].in.version     = ntversion;
     200        1060 :                 state->ios[i].in.map_response        = false;
     201             :         }
     202             : 
     203        1732 :         for (i=0; i<min_servers; i++) {
     204        1732 :                 state->subreqs[i] = cldap_netlogon_send(state->subreqs,
     205         866 :                                                         state->ev,
     206         866 :                                                         state->cldap[i],
     207         866 :                                                         &state->ios[i]);
     208         866 :                 if (tevent_req_nomem(state->subreqs[i], req)) {
     209           0 :                         return tevent_req_post(req, ev);
     210             :                 }
     211         866 :                 tevent_req_set_callback(
     212             :                         state->subreqs[i], cldap_multi_netlogon_done, req);
     213             :         }
     214         866 :         state->num_sent = min_servers;
     215             : 
     216         866 :         if (state->num_sent < state->num_servers) {
     217             :                 /*
     218             :                  * After 100 milliseconds fire the next one
     219             :                  */
     220         194 :                 subreq = tevent_wakeup_send(state, state->ev,
     221             :                                             timeval_current_ofs(0, 100000));
     222         194 :                 if (tevent_req_nomem(subreq, req)) {
     223           0 :                         return tevent_req_post(req, ev);
     224             :                 }
     225         194 :                 tevent_req_set_callback(subreq, cldap_multi_netlogon_next,
     226             :                                         req);
     227             :         }
     228             : 
     229         866 :         return req;
     230             : }
     231             : 
     232         866 : static void cldap_multi_netlogon_done(struct tevent_req *subreq)
     233             : {
     234         866 :         struct tevent_req *req = tevent_req_callback_data(
     235             :                 subreq, struct tevent_req);
     236         866 :         struct cldap_multi_netlogon_state *state = tevent_req_data(
     237             :                 req, struct cldap_multi_netlogon_state);
     238           0 :         NTSTATUS status;
     239           0 :         struct netlogon_samlogon_response *response;
     240           0 :         int i;
     241             : 
     242         866 :         for (i=0; i<state->num_sent; i++) {
     243         866 :                 if (state->subreqs[i] == subreq) {
     244         866 :                         break;
     245             :                 }
     246             :         }
     247         866 :         if (i == state->num_sent) {
     248             :                 /*
     249             :                  * Got a response we did not fire...
     250             :                  */
     251           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     252           0 :                 return;
     253             :         }
     254         866 :         state->subreqs[i] = NULL;
     255             : 
     256         866 :         response = talloc_zero(state, struct netlogon_samlogon_response);
     257         866 :         if (tevent_req_nomem(response, req)) {
     258           0 :                 return;
     259             :         }
     260             : 
     261         866 :         status = cldap_netlogon_recv(subreq, response,
     262         866 :                                      &state->ios[i]);
     263         866 :         TALLOC_FREE(subreq);
     264         866 :         state->num_received += 1;
     265             : 
     266         866 :         if (NT_STATUS_IS_OK(status)) {
     267         856 :                 *response = state->ios[i].out.netlogon;
     268         856 :                 state->responses[i] = talloc_move(state->responses,
     269             :                                                   &response);
     270         856 :                 state->num_good_received += 1;
     271             :         }
     272             : 
     273         866 :         if ((state->num_received == state->num_servers) ||
     274         194 :             (state->num_good_received >= state->min_servers)) {
     275         866 :                 tevent_req_done(req);
     276         866 :                 return;
     277             :         }
     278             : }
     279             : 
     280           0 : static void cldap_multi_netlogon_next(struct tevent_req *subreq)
     281             : {
     282           0 :         struct tevent_req *req = tevent_req_callback_data(
     283             :                 subreq, struct tevent_req);
     284           0 :         struct cldap_multi_netlogon_state *state = tevent_req_data(
     285             :                 req, struct cldap_multi_netlogon_state);
     286           0 :         bool ret;
     287             : 
     288           0 :         ret = tevent_wakeup_recv(subreq);
     289           0 :         TALLOC_FREE(subreq);
     290           0 :         if (!ret) {
     291           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     292           0 :                 return;
     293             :         }
     294             : 
     295           0 :         subreq = cldap_netlogon_send(state->subreqs,
     296             :                                      state->ev,
     297           0 :                                      state->cldap[state->num_sent],
     298           0 :                                      &state->ios[state->num_sent]);
     299           0 :         if (tevent_req_nomem(subreq, req)) {
     300           0 :                 return;
     301             :         }
     302           0 :         tevent_req_set_callback(subreq, cldap_multi_netlogon_done, req);
     303           0 :         state->subreqs[state->num_sent] = subreq;
     304           0 :         state->num_sent += 1;
     305             : 
     306           0 :         if (state->num_sent < state->num_servers) {
     307             :                 /*
     308             :                  * After 100 milliseconds fire the next one
     309             :                  */
     310           0 :                 subreq = tevent_wakeup_send(state, state->ev,
     311             :                                             timeval_current_ofs(0, 100000));
     312           0 :                 if (tevent_req_nomem(subreq, req)) {
     313           0 :                         return;
     314             :                 }
     315           0 :                 tevent_req_set_callback(subreq, cldap_multi_netlogon_next,
     316             :                                         req);
     317             :         }
     318             : }
     319             : 
     320         866 : NTSTATUS cldap_multi_netlogon_recv(
     321             :         struct tevent_req *req, TALLOC_CTX *mem_ctx,
     322             :         struct netlogon_samlogon_response ***responses)
     323             : {
     324         866 :         struct cldap_multi_netlogon_state *state = tevent_req_data(
     325             :                 req, struct cldap_multi_netlogon_state);
     326           0 :         NTSTATUS status;
     327             : 
     328         866 :         if (tevent_req_is_nterror(req, &status) &&
     329           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
     330           0 :                 return status;
     331             :         }
     332             :         /*
     333             :          * If we timeout, give back what we have so far
     334             :          */
     335         866 :         *responses = talloc_move(mem_ctx, &state->responses);
     336         866 :         return NT_STATUS_OK;
     337             : }
     338             : 
     339         866 : NTSTATUS cldap_multi_netlogon(
     340             :         TALLOC_CTX *mem_ctx,
     341             :         const struct tsocket_address * const *servers,
     342             :         int num_servers,
     343             :         const char *domain, const char *hostname, unsigned ntversion,
     344             :         int min_servers, struct timeval timeout,
     345             :         struct netlogon_samlogon_response ***responses)
     346             : {
     347           0 :         struct tevent_context *ev;
     348           0 :         struct tevent_req *req;
     349         866 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     350             : 
     351         866 :         ev = samba_tevent_context_init(talloc_tos());
     352         866 :         if (ev == NULL) {
     353           0 :                 goto fail;
     354             :         }
     355         866 :         req = cldap_multi_netlogon_send(
     356             :                 ev, ev, servers, num_servers, domain, hostname, ntversion,
     357             :                 min_servers);
     358         866 :         if (req == NULL) {
     359           0 :                 goto fail;
     360             :         }
     361         866 :         if (!tevent_req_set_endtime(req, ev, timeout)) {
     362           0 :                 goto fail;
     363             :         }
     364         866 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     365           0 :                 goto fail;
     366             :         }
     367         866 :         status = cldap_multi_netlogon_recv(req, mem_ctx, responses);
     368         866 : fail:
     369         866 :         TALLOC_FREE(ev);
     370         866 :         return status;
     371             : }
     372             : 
     373             : /*******************************************************************
     374             :   do a cldap netlogon query.  Always 389/udp
     375             : *******************************************************************/
     376             : 
     377         420 : bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
     378             :                         struct sockaddr_storage *ss,
     379             :                         const char *realm,
     380             :                         uint32_t nt_version,
     381             :                         struct netlogon_samlogon_response **_reply)
     382             : {
     383           0 :         NTSTATUS status;
     384           0 :         char addrstr[INET6_ADDRSTRLEN];
     385           0 :         const char *dest_str;
     386           0 :         struct tsocket_address *dest_addr;
     387           0 :         const struct tsocket_address * const *dest_addrs;
     388         420 :         struct netlogon_samlogon_response **responses = NULL;
     389           0 :         int ret;
     390             : 
     391         420 :         dest_str = print_sockaddr(addrstr, sizeof(addrstr), ss);
     392             : 
     393         420 :         ret = tsocket_address_inet_from_strings(mem_ctx, "ip",
     394             :                                                 dest_str, LDAP_PORT,
     395             :                                                 &dest_addr);
     396         420 :         if (ret != 0) {
     397           0 :                 status = map_nt_error_from_unix(errno);
     398           0 :                 DEBUG(2,("Failed to create cldap tsocket_address for %s - %s\n",
     399             :                          dest_str, nt_errstr(status)));
     400           0 :                 return false;
     401             :         }
     402             : 
     403         420 :         dest_addrs = (const struct tsocket_address * const *)&dest_addr;
     404             : 
     405         840 :         status = cldap_multi_netlogon(talloc_tos(),
     406             :                                 dest_addrs, 1,
     407             :                                 realm, NULL,
     408             :                                 nt_version, 1,
     409         840 :                                 timeval_current_ofs(MAX(3,lp_ldap_timeout()/2), 0),
     410             :                                 &responses);
     411         420 :         if (!NT_STATUS_IS_OK(status)) {
     412           0 :                 DEBUG(2, ("ads_cldap_netlogon: cldap_multi_netlogon "
     413             :                           "failed: %s\n", nt_errstr(status)));
     414           0 :                 return false;
     415             :         }
     416         420 :         if (responses == NULL || responses[0] == NULL) {
     417          10 :                 DEBUG(2, ("ads_cldap_netlogon: did not get a reply\n"));
     418          10 :                 TALLOC_FREE(responses);
     419          10 :                 return false;
     420             :         }
     421         410 :         *_reply = talloc_move(mem_ctx, &responses[0]);
     422             : 
     423         410 :         return true;
     424             : }
     425             : 
     426             : /*******************************************************************
     427             :   do a cldap netlogon query.  Always 389/udp
     428             : *******************************************************************/
     429             : 
     430         352 : bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
     431             :                           struct sockaddr_storage *ss,
     432             :                           const char *realm,
     433             :                           struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply5)
     434             : {
     435         352 :         uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
     436         352 :         struct netlogon_samlogon_response *reply = NULL;
     437           0 :         bool ret;
     438             : 
     439         352 :         ret = ads_cldap_netlogon(mem_ctx, ss, realm, nt_version, &reply);
     440         352 :         if (!ret) {
     441           0 :                 return false;
     442             :         }
     443             : 
     444         352 :         if (reply->ntver != NETLOGON_NT_VERSION_5EX) {
     445           0 :                 DEBUG(0,("ads_cldap_netlogon_5: nt_version mismatch: 0x%08x\n",
     446             :                         reply->ntver));
     447           0 :                 return false;
     448             :         }
     449             : 
     450         352 :         *reply5 = reply->data.nt5_ex;
     451             : 
     452         352 :         return true;
     453             : }

Generated by: LCOV version 1.14