merge of get_dc_name()-like code from APP_HEAD; better support password server =...
authorGerald Carter <jerry@samba.org>
Thu, 12 Dec 2002 23:35:55 +0000 (23:35 +0000)
committerGerald Carter <jerry@samba.org>
Thu, 12 Dec 2002 23:35:55 +0000 (23:35 +0000)
(This used to be commit 6b18ca9511ddcf1718f222af3f61491d1e5f3b60)

source3/Makefile.in
source3/auth/auth_domain.c
source3/include/smb.h
source3/libsmb/namequery_dc.c [new file with mode: 0644]
source3/nsswitch/winbindd_cm.c
source3/passdb/secrets.c

index 7fa27a24cd57cd94437e14dd810536ff8d3bee70..5044609d138a0fd3b2f71184cdd8905f0b725944 100644 (file)
@@ -196,7 +196,7 @@ LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \
               rpc_client/cli_wkssvc.o rpc_client/cli_dfs.o \
               rpc_client/cli_reg.o rpc_client/cli_pipe.o \
               rpc_client/cli_spoolss.o rpc_client/cli_spoolss_notify.o  \
-               rpc_client/cli_ds.o
+              rpc_client/cli_ds.o libsmb/namequery_dc.o
 
 LIBMSRPC_SERVER_OBJ = libsmb/trust_passwd.o
 
@@ -228,7 +228,7 @@ RPC_PARSE_OBJ = rpc_parse/parse_lsa.o rpc_parse/parse_net.o \
                $(REGOBJS_OBJ)
 
 
-RPC_CLIENT_OBJ = rpc_client/cli_pipe.o
+RPC_CLIENT_OBJ = rpc_client/cli_pipe.o 
 
 LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o
 
@@ -469,7 +469,7 @@ LOCKTEST2_OBJ = torture/locktest2.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
 
 SMBCACLS_OBJ = utils/smbcacls.o $(LOCKING_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) \
                  $(UBIQX_OBJ) $(LIB_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_GET_SET_OBJ) \
-                $(LIBMSRPC_OBJ) 
+                $(LIBMSRPC_OBJ) $(SECRETS_OBJ)
 
 TALLOCTORT_OBJ = lib/talloctort.o  $(LIB_OBJ) $(PARAM_OBJ) $(UBIQX_OBJ)
 
index f3fd2284d26c8cabbd94f9fe2444cc0b3e2b650e..79cf5b156d56fecbf8a357c63c1afde243ff86b1 100644 (file)
@@ -262,103 +262,23 @@ static NTSTATUS attempt_connect_to_dc(struct cli_state **cli,
  We have been asked to dynamically determine the IP addresses of
  the PDC and BDC's for DOMAIN, and query them in turn.
 ************************************************************************/
-static NTSTATUS find_connect_pdc(struct cli_state **cli, 
+static NTSTATUS find_connect_dc(struct cli_state **cli, 
                                 const char *domain,
                                 const char *setup_creds_as,
                                 uint16 sec_chan,
                                 unsigned char *trust_passwd, 
                                 time_t last_change_time)
 {
-       struct in_addr *ip_list = NULL;
-       int count = 0;
-       int i;
-       NTSTATUS nt_status = NT_STATUS_NO_LOGON_SERVERS;
-       time_t time_now = time(NULL);
-       BOOL use_pdc_only = False;
-       BOOL list_ordered;
-
-       /*
-        * If the time the machine password has changed
-        * was less than an hour ago then we need to contact
-        * the PDC only, as we cannot be sure domain replication
-        * has yet taken place. Bug found by Gerald (way to go
-        * Gerald !). JRA.
-        */
-
-       if (time_now - last_change_time < 3600)
-               use_pdc_only = True;
-
-       if (use_pdc_only) {
-               struct in_addr pdc_ip;
-
-               if (!get_pdc_ip(domain, &pdc_ip))
-                       return NT_STATUS_NO_LOGON_SERVERS;
-
-               if ((ip_list = (struct in_addr *)
-                    malloc(sizeof(struct in_addr))) == NULL) 
-                       return NT_STATUS_NO_MEMORY;
-
-               ip_list[0] = pdc_ip;
-               count = 1;
-
-       } else {
-               if (!get_dc_list(domain, &ip_list, &count, &list_ordered))
-                       return NT_STATUS_NO_LOGON_SERVERS;
-       }
+       struct in_addr dc_ip;
+       fstring srv_name;
 
-       /*
-        * Firstly try and contact a PDC/BDC who has the same
-        * network address as any of our interfaces.
-        */
-       for(i = 0; i < count; i++) {
-               if( !list_ordered && !is_local_net(ip_list[i]) )
-                       continue;
-
-               if(NT_STATUS_IS_OK(nt_status = 
-                                  attempt_connect_to_dc(cli, domain, 
-                                                        &ip_list[i], setup_creds_as, 
-                                                        sec_chan, trust_passwd))) 
-                       break;
-               
-               zero_ip(&ip_list[i]); /* Tried and failed. */
-       }
-
-       /*
-        * Secondly try and contact a random PDC/BDC.
-        */
-       if(!NT_STATUS_IS_OK(nt_status)) {
-               i = (sys_random() % count);
-
-               if (!is_zero_ip(ip_list[i])) {
-                       if (!NT_STATUS_IS_OK(nt_status = 
-                                            attempt_connect_to_dc(cli, domain, 
-                                                                  &ip_list[i], setup_creds_as, 
-                                                                  sec_chan, trust_passwd)))
-                               zero_ip(&ip_list[i]); /* Tried and failed. */
-               }
-       }
-
-       /*
-        * Finally go through the IP list in turn, ignoring any addresses
-        * we have already tried.
-        */
-       if(!NT_STATUS_IS_OK(nt_status)) {
-               /*
-                * Try and connect to any of the other IP addresses in the PDC/BDC list.
-                * Note that from a WINS server the #1 IP address is the PDC.
-                */
-               for(i = 0; i < count; i++) {
-                       if (is_zero_ip(ip_list[i]))
-                               continue;
-
-                       if (NT_STATUS_IS_OK(nt_status = attempt_connect_to_dc(cli, domain, 
-                                                 &ip_list[i], setup_creds_as, sec_chan, trust_passwd)))
-                               break;
-               }
+       if ( !rpc_find_dc(lp_workgroup(), srv_name, &dc_ip) ) {
+               DEBUG(0,("find_connect_dc: Failed to find an DCs for %s\n", lp_workgroup()));
+               return NT_STATUS_NO_LOGON_SERVERS;
        }
-
-       SAFE_FREE(ip_list);
-       return nt_status;
+       
+       return attempt_connect_to_dc( cli, domain, &dc_ip, setup_creds_as, 
+                       sec_chan, trust_passwd );
 }
 
 /***********************************************************************
@@ -393,7 +313,7 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx,
        while (!NT_STATUS_IS_OK(nt_status) &&
               next_token(&server,remote_machine,LIST_SEP,sizeof(remote_machine))) {
                if(lp_security() != SEC_ADS && strequal(remote_machine, "*")) {
-                       nt_status = find_connect_pdc(&cli, domain, setup_creds_as, sec_chan, trust_passwd, last_change_time);
+                       nt_status = find_connect_dc(&cli, domain, setup_creds_as, sec_chan, trust_passwd, last_change_time);
                } else {
                        int i;
                        BOOL retry = True;
index de0f10b3c5047ded36ff5dba6b65e1ad7f277b00..b389020e238d0fd5419a131b4f5a4d1cfe880391 100644 (file)
@@ -221,6 +221,14 @@ typedef struct nttime_info
  
 #define MAX_HOURS_LEN 32
 
+/* 
+ * window during which we must talk to the PDC to avoid
+ * sam sync delays; expressed in seconds (15 minutes is the 
+ * default period for SAM replication under Windows NT 4.0
+ */
+#define SAM_SYNC_WINDOW                900
+
+
 #ifndef MAXSUBAUTHS
 #define MAXSUBAUTHS 15 /* max sub authorities in a SID */
 #endif
diff --git a/source3/libsmb/namequery_dc.c b/source3/libsmb/namequery_dc.c
new file mode 100644 (file)
index 0000000..ffc6413
--- /dev/null
@@ -0,0 +1,104 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Winbind daemon connection manager
+
+   Copyright (C) Tim Potter 2001
+   Copyright (C) Andrew Bartlett 2002
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include "includes.h"
+
+
+/*
+  find the DC for a domain using methods appropriate for a RPC domain
+*/
+BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
+{
+       struct in_addr *ip_list = NULL, dc_ip, exclude_ip;
+       int count, i;
+       BOOL list_ordered;
+       BOOL use_pdc_only;
+       
+       zero_ip(&exclude_ip);
+
+       use_pdc_only = must_use_pdc(domain);
+       
+       /* Lookup domain controller name */
+          
+       if ( use_pdc_only && get_pdc_ip(domain, &dc_ip) ) {
+               DEBUG(10,("rpc_find_dc: Atempting to lookup PDC to avoid sam sync delays\n"));
+               
+               if (name_status_find(domain, 0x1c, 0x20, dc_ip, srv_name)) {
+                       goto done;
+               }
+               /* Didn't get name, remember not to talk to this DC. */
+               exclude_ip = dc_ip;
+       }
+
+       /* get a list of all domain controllers */
+       
+       if (!get_dc_list( domain, &ip_list, &count, &list_ordered) ) {
+               DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
+               return False;
+       }
+
+       /* Remove the entry we've already failed with (should be the PDC). */
+
+       if ( use_pdc_only ) {
+               for (i = 0; i < count; i++) {   
+                       if (ip_equal( exclude_ip, ip_list[i]))
+                               zero_ip(&ip_list[i]);
+               }
+       }
+
+       /* Pick a nice close server, but only if the list was not ordered */
+       if (!list_ordered && (count > 1) ) {
+               qsort(ip_list, count, sizeof(struct in_addr), QSORT_CAST ip_compare);
+       }
+
+       for (i = 0; i < count; i++) {
+               if (is_zero_ip(ip_list[i]))
+                       continue;
+
+               if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
+                       dc_ip = ip_list[i];
+                       goto done;
+               }
+       }
+
+
+       SAFE_FREE(ip_list);
+
+       return False;
+done:
+       /* We have the netbios name and IP address of a domain controller.
+          Ideally we should sent a SAMLOGON request to determine whether
+          the DC is alive and kicking.  If we can catch a dead DC before
+          performing a cli_connect() we can avoid a 30-second timeout. */
+
+       DEBUG(3, ("rpc_find_dc: Returning DC %s (%s) for domain %s\n", srv_name,
+                 inet_ntoa(dc_ip), domain));
+
+       *ip_out = dc_ip;
+
+       SAFE_FREE(ip_list);
+
+       return True;
+}
+
index 403bc38052e51733894e7986a3e798f3e3e086b4..075da1e2b2e9a47b41c902ef30f53de4c813ce50 100644 (file)
@@ -135,54 +135,6 @@ static BOOL cm_ads_find_dc(const char *domain, struct in_addr *dc_ip, fstring sr
        return True;
 }
 
-/*
-  find the DC for a domain using methods appropriate for a RPC domain
-*/
-static BOOL cm_rpc_find_dc(const char *domain, struct in_addr *dc_ip, fstring srv_name)
-{
-       struct in_addr *ip_list = NULL;
-       int count, i;
-       BOOL list_ordered;
-
-       if (!get_dc_list(domain, &ip_list, &count, &list_ordered)) {
-               struct in_addr pdc_ip;
-               
-               if (!get_pdc_ip(domain, &pdc_ip)) {
-                       DEBUG(3, ("Could not look up any DCs for domain %s\n", 
-                                 domain));
-                       return False;
-               }
-
-               ip_list = (struct in_addr *)malloc(sizeof(struct in_addr));
-
-               if (!ip_list)
-                       return False;
-
-               ip_list[0] = pdc_ip;
-               count = 1;
-       }
-
-       /* Pick a nice close server, but only if the list was not ordered */
-       if (!list_ordered && (count > 1) ) {
-               qsort(ip_list, count, sizeof(struct in_addr), QSORT_CAST ip_compare);
-       }
-
-       for (i = 0; i < count; i++) {
-               if (is_zero_ip(ip_list[i]))
-                       continue;
-
-               if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
-                       *dc_ip = ip_list[i];
-                       SAFE_FREE(ip_list);
-                       return True;
-               }
-       }
-
-
-       SAFE_FREE(ip_list);
-
-       return False;
-}
 
 
 static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)
@@ -247,7 +199,7 @@ static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr
        }
        if (!ret) {
                /* fall back on rpc methods if the ADS methods fail */
-               ret = cm_rpc_find_dc(domain, &dc_ip, srv_name);
+               ret = rpc_find_dc(domain, srv_name, &dc_ip);
        }
 
        if (!ret) {
index 29afaddea30b03b7578c634df61b98b5b27bdce7..b93ea74d8bd76ef41b1945eeebf471319d4bb0b0 100644 (file)
@@ -610,3 +610,33 @@ void secrets_named_mutex_release(const char *name)
        tdb_unlock_bystring(tdb, name);
        DEBUG(10,("secrets_named_mutex: released mutex for %s\n", name ));
 }
+
+/*********************************************************
+ Check to see if we must talk to the PDC to avoid sam 
+ sync delays
+ ********************************************************/
+BOOL must_use_pdc( const char *domain )
+{
+       time_t  now = time(NULL);
+       time_t  last_change_time;
+       unsigned char   passwd[16];   
+       
+       if ( !secrets_fetch_trust_account_password(domain, passwd, &last_change_time) )
+               return False;
+               
+       /*
+        * If the time the machine password has changed
+        * was less than about 15 minutes then we need to contact
+        * the PDC only, as we cannot be sure domain replication
+        * has yet taken place. Bug found by Gerald (way to go
+        * Gerald !). JRA.
+        */
+        
+       if ( now - last_change_time < SAM_SYNC_WINDOW )
+               return True;
+               
+       return False;
+
+}
+