From: Gerald Carter Date: Thu, 12 Dec 2002 23:35:55 +0000 (+0000) Subject: merge of get_dc_name()-like code from APP_HEAD; better support password server =... X-Git-Tag: samba-4.0.0alpha6~801^2~14906^2 X-Git-Url: http://git.samba.org/samba.git/?a=commitdiff_plain;h=f6c4f25e4319b47ac6c8dbf67a4b1c513148384c;hp=-c;p=ira%2Fwip.git merge of get_dc_name()-like code from APP_HEAD; better support password server = DC1 * (This used to be commit 6b18ca9511ddcf1718f222af3f61491d1e5f3b60) --- f6c4f25e4319b47ac6c8dbf67a4b1c513148384c diff --git a/source3/Makefile.in b/source3/Makefile.in index 7fa27a24cd5..5044609d138 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -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) diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c index f3fd2284d26..79cf5b156d5 100644 --- a/source3/auth/auth_domain.c +++ b/source3/auth/auth_domain.c @@ -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; diff --git a/source3/include/smb.h b/source3/include/smb.h index de0f10b3c50..b389020e238 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -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 index 00000000000..ffc64139e9b --- /dev/null +++ b/source3/libsmb/namequery_dc.c @@ -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; +} + diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index 403bc38052e..075da1e2b2e 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -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) { diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index 29afaddea30..b93ea74d8bd 100644 --- a/source3/passdb/secrets.c +++ b/source3/passdb/secrets.c @@ -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; + +} +