LCOV - code coverage report
Current view: top level - source3/libsmb - namequery_dc.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 60 90 66.7 %
Date: 2021-09-23 10:06:22 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Winbind daemon connection manager
       5             : 
       6             :    Copyright (C) Tim Potter 2001
       7             :    Copyright (C) Andrew Bartlett 2002
       8             :    Copyright (C) Gerald Carter 2003
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : 
      25             : #include "includes.h"
      26             : #include "libsmb/namequery.h"
      27             : #include "libads/sitename_cache.h"
      28             : #include "ads.h"
      29             : #include "../librpc/gen_ndr/nbt.h"
      30             : #include "lib/param/loadparm.h"
      31             : #include "lib/util/string_wrappers.h"
      32             : 
      33             : /**********************************************************************
      34             :  Is this our primary domain ?
      35             : **********************************************************************/
      36             : 
      37             : #ifdef HAVE_ADS
      38         196 : static bool is_our_primary_domain(const char *domain)
      39             : {
      40         196 :         int role = lp_server_role();
      41             : 
      42         196 :         if ((role == ROLE_DOMAIN_MEMBER) && strequal(lp_workgroup(), domain)) {
      43         192 :                 return True;
      44           4 :         } else if (strequal(get_global_sam_name(), domain)) {
      45           0 :                 return True;
      46             :         }
      47           4 :         return False;
      48             : }
      49             : #endif
      50             : 
      51             : /**************************************************************************
      52             :  Find the name and IP address for a server in the realm/domain
      53             :  *************************************************************************/
      54             : 
      55         199 : static bool ads_dc_name(const char *domain,
      56             :                         const char *realm,
      57             :                         struct sockaddr_storage *dc_ss,
      58             :                         fstring srv_name)
      59             : {
      60             :         ADS_STRUCT *ads;
      61             :         char *sitename;
      62             :         int i;
      63             :         char addr[INET6_ADDRSTRLEN];
      64             : 
      65         199 :         if (!realm && strequal(domain, lp_workgroup())) {
      66           0 :                 realm = lp_realm();
      67             :         }
      68             : 
      69         199 :         sitename = sitename_fetch(talloc_tos(), realm);
      70             : 
      71             :         /* Try this 3 times then give up. */
      72         308 :         for( i =0 ; i < 3; i++) {
      73         202 :                 ads = ads_init(realm, domain, NULL, ADS_SASL_PLAIN);
      74         202 :                 if (!ads) {
      75           0 :                         TALLOC_FREE(sitename);
      76           0 :                         return False;
      77             :                 }
      78             : 
      79         202 :                 DEBUG(4,("ads_dc_name: domain=%s\n", domain));
      80             : 
      81             : #ifdef HAVE_ADS
      82             :                 /* we don't need to bind, just connect */
      83         202 :                 ads->auth.flags |= ADS_AUTH_NO_BIND;
      84         202 :                 ads_connect(ads);
      85             : #endif
      86             : 
      87         202 :                 if (!ads->config.realm) {
      88           3 :                         TALLOC_FREE(sitename);
      89           3 :                         ads_destroy(&ads);
      90           3 :                         return False;
      91             :                 }
      92             : 
      93             :                 /* Now we've found a server, see if our sitename
      94             :                    has changed. If so, we need to re-do the DNS query
      95             :                    to ensure we only find servers in our site. */
      96             : 
      97         199 :                 if (stored_sitename_changed(realm, sitename)) {
      98           3 :                         TALLOC_FREE(sitename);
      99           3 :                         sitename = sitename_fetch(talloc_tos(), realm);
     100           3 :                         ads_destroy(&ads);
     101             :                         /* Ensure we don't cache the DC we just connected to. */
     102           3 :                         namecache_delete(realm, 0x1C);
     103           3 :                         namecache_delete(domain, 0x1C);
     104           3 :                         continue;
     105             :                 }
     106             : 
     107             : #ifdef HAVE_ADS
     108         196 :                 if (is_our_primary_domain(domain) && (ads->config.flags & NBT_SERVER_KDC)) {
     109         192 :                         if (ads_closest_dc(ads)) {
     110             :                                 /* We're going to use this KDC for this realm/domain.
     111             :                                    If we are using sites, then force the krb5 libs
     112             :                                    to use this KDC. */
     113             : 
     114         192 :                                 create_local_private_krb5_conf_for_domain(realm,
     115             :                                                                         domain,
     116             :                                                                         sitename,
     117         192 :                                                                         &ads->ldap.ss);
     118             :                         } else {
     119           0 :                                 create_local_private_krb5_conf_for_domain(realm,
     120             :                                                                         domain,
     121             :                                                                         NULL,
     122           0 :                                                                         &ads->ldap.ss);
     123             :                         }
     124             :                 }
     125             : #endif
     126         196 :                 break;
     127             :         }
     128             : 
     129         196 :         if (i == 3) {
     130           0 :                 DEBUG(1,("ads_dc_name: sitename (now \"%s\") keeps changing ???\n",
     131             :                         sitename ? sitename : ""));
     132           0 :                 TALLOC_FREE(sitename);
     133           0 :                 ads_destroy(&ads);
     134           0 :                 return False;
     135             :         }
     136             : 
     137         196 :         TALLOC_FREE(sitename);
     138             : 
     139         196 :         fstrcpy(srv_name, ads->config.ldap_server_name);
     140         196 :         if (!strupper_m(srv_name)) {
     141           0 :                 ads_destroy(&ads);
     142           0 :                 return false;
     143             :         }
     144             : #ifdef HAVE_ADS
     145         196 :         *dc_ss = ads->ldap.ss;
     146             : #else
     147           0 :         zero_sockaddr(dc_ss);
     148             : #endif
     149         196 :         ads_destroy(&ads);
     150             : 
     151         196 :         print_sockaddr(addr, sizeof(addr), dc_ss);
     152         196 :         DEBUG(4,("ads_dc_name: using server='%s' IP=%s\n",
     153             :                  srv_name, addr));
     154             : 
     155         196 :         return True;
     156             : }
     157             : 
     158             : /****************************************************************************
     159             :  Utility function to return the name of a DC. The name is guaranteed to be
     160             :  valid since we have already done a name_status_find on it
     161             :  ***************************************************************************/
     162             : 
     163           3 : static bool rpc_dc_name(const char *domain,
     164             :                         fstring srv_name,
     165             :                         struct sockaddr_storage *ss_out)
     166             : {
     167           3 :         struct samba_sockaddr *sa_list = NULL;
     168           3 :         size_t count = 0;
     169             :         struct sockaddr_storage dc_ss;
     170             :         size_t i;
     171             :         NTSTATUS result;
     172             :         char addr[INET6_ADDRSTRLEN];
     173             : 
     174             :         /* get a list of all domain controllers */
     175             : 
     176           3 :         result = get_sorted_dc_list(talloc_tos(),
     177             :                                 domain,
     178             :                                 NULL,
     179             :                                 &sa_list,
     180             :                                 &count,
     181             :                                 false);
     182           3 :         if (!NT_STATUS_IS_OK(result)) {
     183           3 :                 DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
     184           3 :                 return False;
     185             :         }
     186             : 
     187             :         /* Remove the entry we've already failed with (should be the PDC). */
     188             : 
     189           0 :         for (i = 0; i < count; i++) {
     190           0 :                 if (is_zero_addr(&sa_list[i].u.ss))
     191           0 :                         continue;
     192             : 
     193           0 :                 if (name_status_find(domain, 0x1c, 0x20, &sa_list[i].u.ss, srv_name)) {
     194           0 :                         result = check_negative_conn_cache( domain, srv_name );
     195           0 :                         if ( NT_STATUS_IS_OK(result) ) {
     196           0 :                                 dc_ss = sa_list[i].u.ss;
     197           0 :                                 goto done;
     198             :                         }
     199             :                 }
     200             :         }
     201             : 
     202           0 :         TALLOC_FREE(sa_list);
     203             : 
     204             :         /* No-one to talk to )-: */
     205           0 :         return False;           /* Boo-hoo */
     206             : 
     207           0 :  done:
     208             :         /* We have the netbios name and IP address of a domain controller.
     209             :            Ideally we should sent a SAMLOGON request to determine whether
     210             :            the DC is alive and kicking.  If we can catch a dead DC before
     211             :            performing a cli_connect() we can avoid a 30-second timeout. */
     212             : 
     213           0 :         print_sockaddr(addr, sizeof(addr), &dc_ss);
     214           0 :         DEBUG(3, ("rpc_dc_name: Returning DC %s (%s) for domain %s\n", srv_name,
     215             :                   addr, domain));
     216             : 
     217           0 :         *ss_out = dc_ss;
     218           0 :         TALLOC_FREE(sa_list);
     219             : 
     220           0 :         return True;
     221             : }
     222             : 
     223             : /**********************************************************************
     224             :  wrapper around ads and rpc methods of finds DC's
     225             : **********************************************************************/
     226             : 
     227         199 : bool get_dc_name(const char *domain,
     228             :                 const char *realm,
     229             :                 fstring srv_name,
     230             :                 struct sockaddr_storage *ss_out)
     231             : {
     232             :         struct sockaddr_storage dc_ss;
     233             :         bool ret;
     234         199 :         bool our_domain = False;
     235             : 
     236         199 :         zero_sockaddr(&dc_ss);
     237             : 
     238         199 :         ret = False;
     239             : 
     240         199 :         if ( strequal(lp_workgroup(), domain) || strequal(lp_realm(), realm) )
     241         197 :                 our_domain = True;
     242             : 
     243             :         /* always try to obey what the admin specified in smb.conf
     244             :            (for the local domain) */
     245             : 
     246         199 :         if ( (our_domain && lp_security()==SEC_ADS) || realm ) {
     247         199 :                 ret = ads_dc_name(domain, realm, &dc_ss, srv_name);
     248             :         }
     249             : 
     250         199 :         if (!domain) {
     251             :                 /* if we have only the realm we can't do anything else */
     252           0 :                 return False;
     253             :         }
     254             : 
     255         199 :         if (!ret) {
     256             :                 /* fall back on rpc methods if the ADS methods fail */
     257           3 :                 ret = rpc_dc_name(domain, srv_name, &dc_ss);
     258             :         }
     259             : 
     260         199 :         *ss_out = dc_ss;
     261             : 
     262         199 :         return ret;
     263             : }

Generated by: LCOV version 1.13