LCOV - code coverage report
Current view: top level - source3/libsmb - namequery_dc.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 51 100 51.0 %
Date: 2024-04-21 15:09:00 Functions: 3 4 75.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         180 : static bool is_our_primary_domain(const char *domain)
      39             : {
      40         180 :         int role = lp_server_role();
      41             : 
      42         180 :         if ((role == ROLE_DOMAIN_MEMBER) && strequal(lp_workgroup(), domain)) {
      43         176 :                 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         180 : static bool ads_dc_name(const char *domain,
      56             :                         const char *realm,
      57             :                         struct sockaddr_storage *dc_ss,
      58             :                         fstring srv_name)
      59             : {
      60         180 :         TALLOC_CTX *tmp_ctx = talloc_stackframe();
      61         180 :         bool ok = false;
      62           0 :         ADS_STRUCT *ads;
      63           0 :         char *sitename;
      64           0 :         int i;
      65           0 :         char addr[INET6_ADDRSTRLEN];
      66             : 
      67         180 :         if (!realm && strequal(domain, lp_workgroup())) {
      68           0 :                 realm = lp_realm();
      69             :         }
      70             : 
      71         180 :         sitename = sitename_fetch(tmp_ctx, realm);
      72             : 
      73             :         /* Try this 3 times then give up. */
      74         182 :         for( i =0 ; i < 3; i++) {
      75         182 :                 ads = ads_init(tmp_ctx, realm, domain, NULL, ADS_SASL_PLAIN);
      76         182 :                 if (!ads) {
      77           0 :                         ok = false;
      78           0 :                         goto out;
      79             :                 }
      80             : 
      81         182 :                 DEBUG(4,("ads_dc_name: domain=%s\n", domain));
      82             : 
      83             : #ifdef HAVE_ADS
      84             :                 /* we don't need to bind, just connect */
      85         182 :                 ads->auth.flags |= ADS_AUTH_NO_BIND;
      86         182 :                 ads_connect(ads);
      87             : #endif
      88             : 
      89         182 :                 if (!ads->config.realm) {
      90           0 :                         ok = false;
      91           0 :                         goto out;
      92             :                 }
      93             : 
      94             :                 /* Now we've found a server, see if our sitename
      95             :                    has changed. If so, we need to re-do the DNS query
      96             :                    to ensure we only find servers in our site. */
      97             : 
      98         182 :                 if (stored_sitename_changed(realm, sitename)) {
      99           2 :                         sitename = sitename_fetch(tmp_ctx, realm);
     100           2 :                         TALLOC_FREE(ads);
     101             :                         /* Ensure we don't cache the DC we just connected to. */
     102           2 :                         namecache_delete(realm, 0x1C);
     103           2 :                         namecache_delete(domain, 0x1C);
     104           2 :                         continue;
     105             :                 }
     106             : 
     107             : #ifdef HAVE_ADS
     108         180 :                 if (is_our_primary_domain(domain) && (ads->config.flags & NBT_SERVER_KDC)) {
     109         176 :                         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         176 :                                 create_local_private_krb5_conf_for_domain(realm,
     115             :                                                                         domain,
     116             :                                                                         sitename,
     117         176 :                                                                         &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         180 :                 break;
     127             :         }
     128             : 
     129         180 :         if (i == 3) {
     130           0 :                 DEBUG(1,("ads_dc_name: sitename (now \"%s\") keeps changing ???\n",
     131             :                         sitename ? sitename : ""));
     132           0 :                 ok = false;
     133           0 :                 goto out;
     134             :         }
     135             : 
     136         180 :         fstrcpy(srv_name, ads->config.ldap_server_name);
     137         180 :         if (!strupper_m(srv_name)) {
     138           0 :                 ok = false;
     139           0 :                 goto out;
     140             :         }
     141             : #ifdef HAVE_ADS
     142         180 :         *dc_ss = ads->ldap.ss;
     143             : #else
     144           0 :         zero_sockaddr(dc_ss);
     145             : #endif
     146         180 :         print_sockaddr(addr, sizeof(addr), dc_ss);
     147         180 :         DEBUG(4,("ads_dc_name: using server='%s' IP=%s\n",
     148             :                  srv_name, addr));
     149             : 
     150         180 :         ok = true;
     151         180 : out:
     152         180 :         TALLOC_FREE(tmp_ctx);
     153             : 
     154         180 :         return ok;
     155             : }
     156             : 
     157             : /****************************************************************************
     158             :  Utility function to return the name of a DC. The name is guaranteed to be
     159             :  valid since we have already done a name_status_find on it
     160             :  ***************************************************************************/
     161             : 
     162           0 : static bool rpc_dc_name(const char *domain,
     163             :                         fstring srv_name,
     164             :                         struct sockaddr_storage *ss_out)
     165             : {
     166           0 :         struct samba_sockaddr *sa_list = NULL;
     167           0 :         size_t count = 0;
     168           0 :         struct sockaddr_storage dc_ss;
     169           0 :         size_t i;
     170           0 :         NTSTATUS result;
     171           0 :         char addr[INET6_ADDRSTRLEN];
     172             : 
     173             :         /* get a list of all domain controllers */
     174             : 
     175           0 :         result = get_sorted_dc_list(talloc_tos(),
     176             :                                 domain,
     177             :                                 NULL,
     178             :                                 &sa_list,
     179             :                                 &count,
     180             :                                 false);
     181           0 :         if (!NT_STATUS_IS_OK(result)) {
     182           0 :                 DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
     183           0 :                 return False;
     184             :         }
     185             : 
     186             :         /* Remove the entry we've already failed with (should be the PDC). */
     187             : 
     188           0 :         for (i = 0; i < count; i++) {
     189           0 :                 if (is_zero_addr(&sa_list[i].u.ss))
     190           0 :                         continue;
     191             : 
     192           0 :                 if (name_status_find(domain, 0x1c, 0x20, &sa_list[i].u.ss, srv_name)) {
     193           0 :                         result = check_negative_conn_cache( domain, srv_name );
     194           0 :                         if ( NT_STATUS_IS_OK(result) ) {
     195           0 :                                 dc_ss = sa_list[i].u.ss;
     196           0 :                                 goto done;
     197             :                         }
     198             :                 }
     199             :         }
     200             : 
     201           0 :         TALLOC_FREE(sa_list);
     202             : 
     203             :         /* No-one to talk to )-: */
     204           0 :         return False;           /* Boo-hoo */
     205             : 
     206           0 :  done:
     207             :         /* We have the netbios name and IP address of a domain controller.
     208             :            Ideally we should sent a SAMLOGON request to determine whether
     209             :            the DC is alive and kicking.  If we can catch a dead DC before
     210             :            performing a cli_connect() we can avoid a 30-second timeout. */
     211             : 
     212           0 :         print_sockaddr(addr, sizeof(addr), &dc_ss);
     213           0 :         DEBUG(3, ("rpc_dc_name: Returning DC %s (%s) for domain %s\n", srv_name,
     214             :                   addr, domain));
     215             : 
     216           0 :         *ss_out = dc_ss;
     217           0 :         TALLOC_FREE(sa_list);
     218             : 
     219           0 :         return True;
     220             : }
     221             : 
     222             : /**********************************************************************
     223             :  wrapper around ads and rpc methods of finds DC's
     224             : **********************************************************************/
     225             : 
     226         180 : bool get_dc_name(const char *domain,
     227             :                 const char *realm,
     228             :                 fstring srv_name,
     229             :                 struct sockaddr_storage *ss_out)
     230             : {
     231           0 :         struct sockaddr_storage dc_ss;
     232           0 :         bool ret;
     233         180 :         bool our_domain = False;
     234             : 
     235         180 :         zero_sockaddr(&dc_ss);
     236             : 
     237         180 :         ret = False;
     238             : 
     239         180 :         if ( strequal(lp_workgroup(), domain) || strequal(lp_realm(), realm) )
     240         180 :                 our_domain = True;
     241             : 
     242             :         /* always try to obey what the admin specified in smb.conf
     243             :            (for the local domain) */
     244             : 
     245         180 :         if ( (our_domain && lp_security()==SEC_ADS) || realm ) {
     246         180 :                 ret = ads_dc_name(domain, realm, &dc_ss, srv_name);
     247             :         }
     248             : 
     249         180 :         if (!domain) {
     250             :                 /* if we have only the realm we can't do anything else */
     251           0 :                 return False;
     252             :         }
     253             : 
     254         180 :         if (!ret) {
     255             :                 /* fall back on rpc methods if the ADS methods fail */
     256           0 :                 ret = rpc_dc_name(domain, srv_name, &dc_ss);
     257             :         }
     258             : 
     259         180 :         *ss_out = dc_ss;
     260             : 
     261         180 :         return ret;
     262             : }

Generated by: LCOV version 1.14