From 69a6bf3eddc73d54f16c79df0b19e0baf5fdd975 Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Thu, 15 Nov 2001 03:33:12 +0000 Subject: Cache positive and negative name domain controller lookups. Cache negative connection attempt lookups. Fixed loginc bug in connection_ok() (This used to be commit e07bcfcccd6d4a29f188d978b2c34a7b18ff21fa) --- source3/nsswitch/winbindd_cm.c | 159 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 148 insertions(+), 11 deletions(-) (limited to 'source3/nsswitch') diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c index a94476a0bc..205ab4fb31 100644 --- a/source3/nsswitch/winbindd_cm.c +++ b/source3/nsswitch/winbindd_cm.c @@ -124,14 +124,75 @@ struct winbindd_cm_conn { struct winbindd_cm_conn *cm_conns = NULL; -/* Get a domain controller name */ +/* Get a domain controller name. Cache positive and negative lookups so we + don't go to the network too often when something is badly broken. */ -BOOL cm_get_dc_name(char *domain, fstring srv_name) +#define GET_DC_NAME_CACHE_TIMEOUT 30 /* Seconds between dc lookups */ + +struct get_dc_name_cache { + fstring domain_name; + fstring srv_name; + time_t lookup_time; + struct get_dc_name_cache *prev, *next; +}; + +static BOOL cm_get_dc_name(char *domain, fstring srv_name) { + static struct get_dc_name_cache *get_dc_name_cache; + struct get_dc_name_cache *dcc; struct in_addr *ip_list, dc_ip; extern pstring global_myname; int count, i; + /* Check the cache for previous lookups */ + + for (dcc = get_dc_name_cache; dcc; dcc = dcc->next) { + + if (!strequal(domain, dcc->domain_name)) + continue; /* Not our domain */ + + if ((time(NULL) - dcc->lookup_time) > GET_DC_NAME_CACHE_TIMEOUT) { + + /* Cache entry has expired, delete it */ + + DEBUG(10, ("get_dc_name_cache entry expired for %s\n", + domain)); + + DLIST_REMOVE(get_dc_name_cache, dcc); + free(dcc); + + break; + } + + /* Return a positive or negative lookup for this domain */ + + if (dcc->srv_name[0]) { + DEBUG(10, ("returning positive get_dc_name_cache " + "entry for %s\n", domain)); + fstrcpy(srv_name, dcc->srv_name); + return True; + } else { + DEBUG(10, ("returning negative get_dc_name_cache " + "entry for %s\n", domain)); + return False; + } + } + + /* Add cache entry for this lookup. */ + + DEBUG(10, ("Creating get_dc_name_cache entry for %s\n", domain)); + + if (!(dcc = (struct get_dc_name_cache *) + malloc(sizeof(struct get_dc_name_cache)))) + return False; + + ZERO_STRUCTP(dcc); + + fstrcpy(dcc->domain_name, domain); + dcc->lookup_time = time(NULL); + + DLIST_ADD(get_dc_name_cache, dcc); + /* Lookup domain controller name */ if (!get_dc_list(False, domain, &ip_list, &count)) @@ -154,14 +215,31 @@ BOOL cm_get_dc_name(char *domain, fstring srv_name) if (!lookup_pdc_name(global_myname, domain, &dc_ip, srv_name)) return False; + /* We have a name so make the cache entry positive now */ + + fstrcpy(dcc->srv_name, srv_name); + return True; } -/* Open a new smb pipe connection to a DC on a given domain */ +/* Open a new smb pipe connection to a DC on a given domain. Cache + negative creation attempts so we don't try and connect to broken + machines too often. */ + +#define OPEN_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */ + +struct open_connection_cache { + fstring domain_name; + fstring controller; + time_t lookup_time; + struct open_connection_cache *prev, *next; +}; static BOOL cm_open_connection(char *domain, char *pipe_name, struct winbindd_cm_conn *new_conn) { + static struct open_connection_cache *open_connection_cache; + struct open_connection_cache *occ; struct nmb_name calling, called; extern pstring global_myname; fstring dest_host; @@ -172,11 +250,43 @@ static BOOL cm_open_connection(char *domain, char *pipe_name, fstrcpy(new_conn->domain, domain); fstrcpy(new_conn->pipe_name, pipe_name); - /* Look for a domain controller for this domain */ + /* Look for a domain controller for this domain. Negative results + are cached so don't bother applying the caching for this + function just yet. */ if (!cm_get_dc_name(domain, new_conn->controller)) goto done; + /* Return false if we have tried to look up this domain and netbios + name before and failed. */ + + for (occ = open_connection_cache; occ; occ = occ->next) { + + if (!(strequal(domain, occ->domain_name) && + strequal(new_conn->controller, occ->controller))) + continue; /* Not our domain */ + + if ((time(NULL) - occ->lookup_time) > OPEN_CONNECTION_CACHE_TIMEOUT) { + /* Cache entry has expired, delete it */ + + DEBUG(10, ("cm_open_connection cache entry expired " + "for %s, %s\n", domain, + new_conn->controller)); + + DLIST_REMOVE(open_connection_cache, occ); + free(occ); + + break; + } + + /* The timeout hasn't expired yet so return false */ + + DEBUG(10, ("returning negative open_connection_cache entry " + "for %s, %s\n", domain, new_conn->controller)); + + goto done; + } + /* Initialise SMB connection */ if (!(new_conn->cli = cli_initialise(NULL))) @@ -205,6 +315,23 @@ static BOOL cm_open_connection(char *domain, char *pipe_name, result = True; done: + /* Create negative lookup cache entry for this domain and + controller */ + + if (!result) { + if (!(occ = (struct open_connection_cache *) + malloc(sizeof(struct open_connection_cache)))) + return False; + + ZERO_STRUCTP(occ); + + fstrcpy(occ->domain_name, domain); + fstrcpy(occ->controller, new_conn->controller); + occ->lookup_time = time(NULL); + + DLIST_ADD(open_connection_cache, occ); + } + if (!result && new_conn->cli) cli_shutdown(new_conn->cli); @@ -218,7 +345,7 @@ static BOOL connection_ok(struct winbindd_cm_conn *conn) if (!conn->cli->initialised) return False; - if (!conn->cli->fd == -1) + if (conn->cli->fd == -1) return False; return True; @@ -239,8 +366,10 @@ CLI_POLICY_HND *cm_get_lsa_handle(char *domain) if (strequal(conn->domain, domain) && strequal(conn->pipe_name, PIPE_LSARPC)) { - if (!connection_ok(conn)) + if (!connection_ok(conn)) { + DLIST_REMOVE(cm_conns, conn); return NULL; + } goto ok; } @@ -293,8 +422,10 @@ CLI_POLICY_HND *cm_get_sam_handle(char *domain) strequal(conn->pipe_name, PIPE_SAMR) && conn->pipe_data.samr.pipe_type == SAM_PIPE_BASIC) { - if (!connection_ok(conn)) + if (!connection_ok(conn)) { + DLIST_REMOVE(cm_conns, conn); return NULL; + } goto ok; } @@ -347,8 +478,10 @@ CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain, DOM_SID *domain_sid) strequal(conn->pipe_name, PIPE_SAMR) && conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM) { - if (!connection_ok(conn)) + if (!connection_ok(conn)) { + DLIST_REMOVE(cm_conns, conn); return NULL; + } goto ok; } @@ -415,8 +548,10 @@ CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid, conn->pipe_data.samr.pipe_type == SAM_PIPE_USER && conn->pipe_data.samr.rid == user_rid) { - if (!connection_ok(conn)) + if (!connection_ok(conn)) { + DLIST_REMOVE(cm_conns, conn); return NULL; + } goto ok; } @@ -489,8 +624,10 @@ CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid, conn->pipe_data.samr.pipe_type == SAM_PIPE_GROUP && conn->pipe_data.samr.rid == group_rid) { - if (!connection_ok(conn)) + if (!connection_ok(conn)) { + DLIST_REMOVE(cm_conns, conn); return NULL; + } goto ok; } @@ -581,7 +718,7 @@ static void dump_conn_list(void) { struct winbindd_cm_conn *con; - DEBUG(0, ("\tDomain Controller Pipe\n")); + DEBUG(0, ("\tDomain Controller Pipe Handle type\n")); for(con = cm_conns; con; con = con->next) { char *msg; -- cgit