From 855e02f1649992f05b685be96dfff4a9140170e9 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 3 Feb 2006 21:19:24 +0000 Subject: r13310: first round of server affinity patches for winbindd & net ads join (This used to be commit 6c3480f9aecc061660ad5c06347b8f1d3e11a330) --- source3/include/smb.h | 8 - source3/lib/gencache.c | 20 ++- source3/libads/ldap.c | 4 + source3/libsmb/cliconnect.c | 12 +- source3/libsmb/namequery.c | 323 +++++++++++++++++++++++++++-------------- source3/libsmb/namequery_dc.c | 28 ---- source3/nsswitch/winbindd_cm.c | 70 +++++---- 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= 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= 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; idomain, (*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. *******************************************************************************/ -- cgit