diff options
author | Gerald Carter <jerry@samba.org> | 2006-02-03 21:19:24 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:06:23 -0500 |
commit | 855e02f1649992f05b685be96dfff4a9140170e9 (patch) | |
tree | f3224a28b08d3d569f929039e0bd7313ab81dbd9 /source3 | |
parent | 989c9311c5c155a8bea2b7921edf5eeb36c54ead (diff) | |
download | samba-855e02f1649992f05b685be96dfff4a9140170e9.tar.gz samba-855e02f1649992f05b685be96dfff4a9140170e9.tar.bz2 samba-855e02f1649992f05b685be96dfff4a9140170e9.zip |
r13310: first round of server affinity patches for winbindd & net ads join
(This used to be commit 6c3480f9aecc061660ad5c06347b8f1d3e11a330)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/smb.h | 8 | ||||
-rw-r--r-- | source3/lib/gencache.c | 20 | ||||
-rw-r--r-- | source3/libads/ldap.c | 4 | ||||
-rw-r--r-- | source3/libsmb/cliconnect.c | 12 | ||||
-rw-r--r-- | source3/libsmb/namequery.c | 323 | ||||
-rw-r--r-- | source3/libsmb/namequery_dc.c | 28 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cm.c | 70 | ||||
-rw-r--r-- | source3/passdb/secrets.c | 29 |
8 files changed, 275 insertions, 219 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h index b8211aac45..3a6f68b9ec 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -238,14 +238,6 @@ 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/lib/gencache.c b/source3/lib/gencache.c index fd44616270..89badcd4f9 100644 --- a/source3/lib/gencache.c +++ b/source3/lib/gencache.c @@ -268,7 +268,7 @@ BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout) SAFE_FREE(entry_buf); DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, " - "timeout = %s\n", t > time(NULL) ? "valid" : + "timeout = %s", t > time(NULL) ? "valid" : "expired", keystr, v, ctime(&t))); if (valstr) @@ -281,20 +281,18 @@ BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout) return t > time(NULL); - } else { - SAFE_FREE(databuf.dptr); + } - if (valstr) - *valstr = NULL; + SAFE_FREE(databuf.dptr); - if (timeout) - timeout = NULL; + if (valstr) + *valstr = NULL; + if (timeout) + timeout = NULL; - DEBUG(10, ("Cache entry with key = %s couldn't be found\n", - keystr)); + DEBUG(10, ("Cache entry with key = %s couldn't be found\n", keystr)); - return False; - } + return False; } diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index dc93bd556c..e503da62a4 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -136,6 +136,10 @@ BOOL ads_try_connect(ADS_STRUCT *ads, const char *server, unsigned port) ads->ldap_port = port; ads->ldap_ip = *interpret_addr2(srv); free(srv); + + /* cache the successful connection */ + + saf_store( ads->server.workgroup, server ); return True; } diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index ac7d1b1650..7c15c8d19f 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -865,14 +865,16 @@ BOOL cli_session_setup(struct cli_state *cli, DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status))); return False; } - return True; + } else { + /* otherwise do a NT1 style session setup */ + if ( !cli_session_setup_nt1(cli, user, pass, passlen, ntpass, ntpasslen, workgroup) ) { + DEBUG(3,("cli_session_setup: NT1 session setup failed!\n")); + return False; + } } - /* otherwise do a NT1 style session setup */ + return True; - return cli_session_setup_nt1(cli, user, - pass, passlen, ntpass, ntpasslen, - workgroup); } /**************************************************************************** diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index 28b89db908..0986e7f29a 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -24,6 +24,94 @@ /* nmbd.c sets this to True. */ BOOL global_in_nmbd = False; + +/**************************** + * SERVER AFFINITY ROUTINES * + ****************************/ + + /* Server affinity is the concept of preferring the last domain + controller with whom you had a successful conversation */ + +/**************************************************************************** +****************************************************************************/ +#define SAFKEY_FMT "SAF/DOMAIN/%s" +#define SAF_TTL 900 + +static char *saf_key(const char *domain) +{ + char *keystr; + + asprintf( &keystr, SAFKEY_FMT, strupper_static(domain) ); + + return keystr; +} + +/**************************************************************************** +****************************************************************************/ + +BOOL saf_store( const char *domain, const char *servername ) +{ + char *key; + time_t expire; + BOOL ret = False; + + if ( !domain || !servername ) { + DEBUG(2,("saf_store: Refusing to store empty domain or servername!\n")); + return False; + } + + if ( !gencache_init() ) + return False; + + key = saf_key( domain ); + expire = time( NULL ) + SAF_TTL; + + + DEBUG(10,("saf_store: domain = [%s], server = [%s], expire = [%d]\n", + domain, servername, expire )); + + ret = gencache_set( key, servername, expire ); + + SAFE_FREE( key ); + + return ret; +} + +/**************************************************************************** +****************************************************************************/ + +char *saf_fetch( const char *domain ) +{ + char *server = NULL; + time_t timeout; + BOOL ret = False; + char *key = NULL; + + if ( !domain ) { + DEBUG(2,("saf_fetch: Empty domain name!\n")); + return NULL; + } + + if ( !gencache_init() ) + return False; + + key = saf_key( domain ); + + ret = gencache_get( key, &server, &timeout ); + + SAFE_FREE( key ); + + if ( !ret ) { + DEBUG(5,("saf_fetch: failed to find server for \"%s\" domain\n", domain )); + } else { + DEBUG(5,("saf_fetch: Returning \"%s\" for \"%s\" domain\n", + server, domain )); + } + + return server; +} + + /**************************************************************************** Generate a random trn_id. ****************************************************************************/ @@ -1261,6 +1349,18 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list, int *count, BOOL ads_only, int *ordered) { fstring resolve_order; + char *saf_servername; + pstring pserver; + const char *p; + char *port_str; + int port; + fstring name; + int num_addresses = 0; + int local_count, i, j; + struct ip_service *return_iplist = NULL; + struct ip_service *auto_ip_list = NULL; + BOOL done_auto_lookup = False; + int auto_count = 0; /* if we are restricted to solely using DNS for looking up a domain controller, make sure that host lookups @@ -1277,148 +1377,145 @@ static BOOL get_dc_list(const char *domain, struct ip_service **ip_list, fstrcpy( resolve_order, "NULL" ); } - *ordered = False; - - /* If it's our domain then use the 'password server' parameter. */ - + + /* fetch the server we have affinity for. Add the + 'password server' list to a search for our domain controllers */ + + saf_servername = saf_fetch( domain ); + if ( strequal(domain, lp_workgroup()) || strequal(domain, lp_realm()) ) { - const char *p; - char *pserver = lp_passwordserver(); /* UNIX charset. */ - char *port_str; - int port; - fstring name; - int num_addresses = 0; - int local_count, i, j; - struct ip_service *return_iplist = NULL; - struct ip_service *auto_ip_list = NULL; - BOOL done_auto_lookup = False; - int auto_count = 0; - + pstr_sprintf( pserver, "%s, %s", + saf_servername ? saf_servername : "", + lp_passwordserver() ); + } else { + pstr_sprintf( pserver, "%s, *", + saf_servername ? saf_servername : "" ); + } - if (!*pserver) - return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order); + SAFE_FREE( saf_servername ); - p = pserver; - - /* - * if '*' appears in the "password server" list then add - * an auto lookup to the list of manually configured - * DC's. If any DC is listed by name, then the list should be - * considered to be ordered - */ - - while (next_token(&p,name,LIST_SEP,sizeof(name))) { - if (strequal(name, "*")) { - if ( internal_resolve_name(domain, 0x1C, &auto_ip_list, &auto_count, resolve_order) ) - num_addresses += auto_count; - done_auto_lookup = True; - DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count)); - } else { - num_addresses++; - } + /* if we are starting from scratch, just lookup DOMAIN<0x1c> */ + + if ( !*pserver ) { + DEBUG(10,("get_dc_list: no preferred domain controllers.\n")); + return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order); + } + + DEBUG(3,("get_dc_list: preferred server list: \"%s\"\n", pserver )); + + /* + * if '*' appears in the "password server" list then add + * an auto lookup to the list of manually configured + * DC's. If any DC is listed by name, then the list should be + * considered to be ordered + */ + + p = pserver; + while (next_token(&p,name,LIST_SEP,sizeof(name))) { + if (strequal(name, "*")) { + if ( internal_resolve_name(domain, 0x1C, &auto_ip_list, &auto_count, resolve_order) ) + num_addresses += auto_count; + done_auto_lookup = True; + DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count)); + } else { + num_addresses++; } + } - /* if we have no addresses and haven't done the auto lookup, then - just return the list of DC's */ + /* if we have no addresses and haven't done the auto lookup, then + just return the list of DC's. Or maybe we just failed. */ - if ( (num_addresses == 0) && !done_auto_lookup ) { + if ( (num_addresses == 0) ) { + if ( !done_auto_lookup ) { return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order); - } - - /* maybe we just failed? */ - - if ( num_addresses == 0 ) { - DEBUG(4,("get_dc_list: no servers found\n")); - return False; - } - - if ( (return_iplist = SMB_MALLOC_ARRAY(struct ip_service, num_addresses)) == NULL ) { - DEBUG(3,("get_dc_list: malloc fail !\n")); + } else { + DEBUG(4,("get_dc_list: no servers found\n")); return False; } + } + + if ( (return_iplist = SMB_MALLOC_ARRAY(struct ip_service, num_addresses)) == NULL ) { + DEBUG(3,("get_dc_list: malloc fail !\n")); + return False; + } - p = pserver; - local_count = 0; + p = pserver; + local_count = 0; - /* fill in the return list now with real IP's */ + /* fill in the return list now with real IP's */ - while ( (local_count<num_addresses) && next_token(&p,name,LIST_SEP,sizeof(name)) ) { - struct in_addr name_ip; + while ( (local_count<num_addresses) && next_token(&p,name,LIST_SEP,sizeof(name)) ) { + struct in_addr name_ip; - /* copy any addersses from the auto lookup */ + /* copy any addersses from the auto lookup */ - if ( strequal(name, "*") ) { - for ( j=0; j<auto_count; j++ ) { - /* Check for and don't copy any known bad DC IP's. */ - if(!NT_STATUS_IS_OK(check_negative_conn_cache(domain, - inet_ntoa(auto_ip_list[j].ip)))) { - DEBUG(5,("get_dc_list: negative entry %s removed from DC list\n", - inet_ntoa(auto_ip_list[j].ip) )); - continue; - } - return_iplist[local_count].ip = auto_ip_list[j].ip; - return_iplist[local_count].port = auto_ip_list[j].port; - local_count++; + if ( strequal(name, "*") ) { + for ( j=0; j<auto_count; j++ ) { + /* Check for and don't copy any known bad DC IP's. */ + if(!NT_STATUS_IS_OK(check_negative_conn_cache(domain, + inet_ntoa(auto_ip_list[j].ip)))) { + DEBUG(5,("get_dc_list: negative entry %s removed from DC list\n", + inet_ntoa(auto_ip_list[j].ip) )); + continue; } - continue; + return_iplist[local_count].ip = auto_ip_list[j].ip; + return_iplist[local_count].port = auto_ip_list[j].port; + local_count++; } + continue; + } - /* added support for address:port syntax for ads (not that I think - anyone will ever run the LDAP server in an AD domain on something - other than port 389 */ + /* added support for address:port syntax for ads (not that I think + anyone will ever run the LDAP server in an AD domain on something + other than port 389 */ - port = (lp_security() == SEC_ADS) ? LDAP_PORT : PORT_NONE; - if ( (port_str=strchr(name, ':')) != NULL ) { - *port_str = '\0'; - port_str++; - port = atoi( port_str ); - } - - /* explicit lookup; resolve_name() will handle names & IP addresses */ - if ( resolve_name( name, &name_ip, 0x20 ) ) { + port = (lp_security() == SEC_ADS) ? LDAP_PORT : PORT_NONE; + if ( (port_str=strchr(name, ':')) != NULL ) { + *port_str = '\0'; + port_str++; + port = atoi( port_str ); + } - /* Check for and don't copy any known bad DC IP's. */ - if( !NT_STATUS_IS_OK(check_negative_conn_cache(domain, inet_ntoa(name_ip))) ) { - DEBUG(5,("get_dc_list: negative entry %s removed from DC list\n",name )); - continue; - } + /* explicit lookup; resolve_name() will handle names & IP addresses */ + if ( resolve_name( name, &name_ip, 0x20 ) ) { - return_iplist[local_count].ip = name_ip; - return_iplist[local_count].port = port; - local_count++; - *ordered = True; + /* Check for and don't copy any known bad DC IP's. */ + if( !NT_STATUS_IS_OK(check_negative_conn_cache(domain, inet_ntoa(name_ip))) ) { + DEBUG(5,("get_dc_list: negative entry %s removed from DC list\n",name )); + continue; } + + return_iplist[local_count].ip = name_ip; + return_iplist[local_count].port = port; + local_count++; + *ordered = True; } + } - SAFE_FREE(auto_ip_list); + SAFE_FREE(auto_ip_list); - /* need to remove duplicates in the list if we have any - explicit password servers */ - - if ( local_count ) { - local_count = remove_duplicate_addrs2( return_iplist, local_count ); - } + /* need to remove duplicates in the list if we have any + explicit password servers */ + + if ( local_count ) { + local_count = remove_duplicate_addrs2( return_iplist, local_count ); + } - if ( DEBUGLEVEL >= 4 ) { - DEBUG(4,("get_dc_list: returning %d ip addresses in an %sordered list\n", local_count, - *ordered ? "":"un")); - DEBUG(4,("get_dc_list: ")); - for ( i=0; i<local_count; i++ ) - DEBUGADD(4,("%s:%d ", inet_ntoa(return_iplist[i].ip), return_iplist[i].port )); - DEBUGADD(4,("\n")); - } + if ( DEBUGLEVEL >= 4 ) { + DEBUG(4,("get_dc_list: returning %d ip addresses in an %sordered list\n", local_count, + *ordered ? "":"un")); + DEBUG(4,("get_dc_list: ")); + for ( i=0; i<local_count; i++ ) + DEBUGADD(4,("%s:%d ", inet_ntoa(return_iplist[i].ip), return_iplist[i].port )); + DEBUGADD(4,("\n")); + } - *ip_list = return_iplist; - *count = local_count; + *ip_list = return_iplist; + *count = local_count; - return (*count != 0); - } - - DEBUG(10,("get_dc_list: defaulting to internal auto lookup for domain %s\n", domain)); - - return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_order); + return (*count != 0); } /********************************************************************* diff --git a/source3/libsmb/namequery_dc.c b/source3/libsmb/namequery_dc.c index 0c9f19313c..b9a593bf2a 100644 --- a/source3/libsmb/namequery_dc.c +++ b/source3/libsmb/namequery_dc.c @@ -75,31 +75,10 @@ static BOOL rpc_dc_name(const char *domain, fstring srv_name, struct in_addr *ip struct ip_service *ip_list = NULL; struct in_addr dc_ip, exclude_ip; int count, i; - BOOL use_pdc_only; NTSTATUS result; 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_dc_name: Atempting to lookup PDC to avoid sam sync delays\n")); - - /* check the connection cache and perform the node status - lookup only if the IP is not found to be bad */ - - if (name_status_find(domain, 0x1b, 0x20, dc_ip, srv_name) ) { - result = check_negative_conn_cache( domain, srv_name ); - if ( NT_STATUS_IS_OK(result) ) - 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_sorted_dc_list(domain, &ip_list, &count, False) ) { @@ -109,13 +88,6 @@ static BOOL rpc_dc_name(const char *domain, fstring srv_name, struct in_addr *ip /* 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].ip)) - zero_ip(&ip_list[i].ip); - } - } - for (i = 0; i < count; i++) { if (is_zero_ip(ip_list[i].ip)) continue; diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index 2ac984176c..177ac54d3e 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -358,6 +358,10 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, session_setup_done: + /* cache the server name for later connections */ + + saf_store( (*cli)->domain, (*cli)->desthost ); + if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) { result = cli_nt_error(*cli); @@ -658,14 +662,6 @@ static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain, return True; } - if ( is_our_domain - && must_use_pdc(domain->name) - && get_pdc_ip(domain->name, &ip)) - { - if (add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip), ip, dcs, num_dcs)) - return True; - } - /* try standard netbios queries first */ get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False); @@ -752,12 +748,35 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain, { TALLOC_CTX *mem_ctx; NTSTATUS result; - + char *saf_servername = saf_fetch( domain->name ); int retries; if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) return NT_STATUS_NO_MEMORY; + /* we have to check the server affinity cache here since + later we selecte a DC based on response time and not preference */ + + if ( saf_servername ) + { + /* convert an ip address to a name */ + if ( is_ipaddress( saf_servername ) ) + { + fstring saf_name; + struct in_addr ip; + + ip = *interpret_addr2( saf_servername ); + dcip_to_name( domain->name, domain->alt_name, &domain->sid, ip, saf_name ); + fstrcpy( domain->dcname, saf_name ); + } + else + { + fstrcpy( domain->dcname, saf_servername ); + } + + SAFE_FREE( saf_servername ); + } + for (retries = 0; retries < 3; retries++) { int fd = -1; @@ -765,27 +784,28 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain, result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; - if ((strlen(domain->dcname) > 0) && - NT_STATUS_IS_OK(check_negative_conn_cache( - domain->name, domain->dcname)) && - (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, - 0x20))) { - int dummy; - struct sockaddr_in addrs[2]; - addrs[0] = domain->dcaddr; - addrs[0].sin_port = htons(445); - addrs[1] = domain->dcaddr; - addrs[1].sin_port = htons(139); - if (!open_any_socket_out(addrs, 2, 10000, - &dummy, &fd)) { + if ((strlen(domain->dcname) > 0) + && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname)) + && (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, 0x20))) + { + struct sockaddr_in *addrs = NULL; + int num_addrs = 0; + int dummy = 0; + + + add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 445, &addrs, &num_addrs); + add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 139, &addrs, &num_addrs); + + if (!open_any_socket_out(addrs, num_addrs, 10000, &dummy, &fd)) { fd = -1; } } - if ((fd == -1) && - !find_new_dc(mem_ctx, domain, domain->dcname, - &domain->dcaddr, &fd)) + if ((fd == -1) + && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd)) + { break; + } new_conn->cli = NULL; diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index 14896a3340..88dabbd644 100644 --- a/source3/passdb/secrets.c +++ b/source3/passdb/secrets.c @@ -821,35 +821,6 @@ void secrets_named_mutex_release(const char *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, NULL) ) - 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; - -} - /******************************************************************************* Store a complete AFS keyfile into secrets.tdb. *******************************************************************************/ |