1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-22 05:57:43 +03:00

merge from APP_HEAD. Push negative connection cache

into rpc_find_dc().  Should probably be extended some more
in 3.0 but this is what we have for the moment.
(This used to be commit 0e23abf95cf7ba2d0a314a34bddb4d46de2a3cd1)
This commit is contained in:
Gerald Carter 2003-06-06 14:11:14 +00:00
parent 711f8d0a13
commit 0d55e9c536
2 changed files with 152 additions and 324 deletions

View File

@ -25,15 +25,149 @@
#include "includes.h"
/*
find the DC for a domain using methods appropriate for a RPC domain
*/
#define FAILED_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
struct failed_connection_cache {
fstring domain_name;
fstring controller;
time_t lookup_time;
NTSTATUS nt_status;
struct failed_connection_cache *prev, *next;
};
static struct failed_connection_cache *failed_connection_cache;
/**********************************************************************
Check for a previously failed connection
**********************************************************************/
static NTSTATUS check_negative_conn_cache( const char *domain, const char *server )
{
struct failed_connection_cache *fcc;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
/* can't check if we don't have strings */
if ( !domain || !server )
return NT_STATUS_OK;
for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
/*
* we have a match IFF the domain and server name matches
* (a) the domain matches,
* (b) the IP address matches (if we have one)
* (c) the server name (if specified) matches
*/
if ( !strequal(domain, fcc->domain_name) || !strequal(server, fcc->controller) )
continue; /* no match; check the next entry */
/* we have a match so see if it is still current */
if ((time(NULL) - fcc->lookup_time) > FAILED_CONNECTION_CACHE_TIMEOUT)
{
/* Cache entry has expired, delete it */
DEBUG(10, ("check_negative_conn_cache: cache entry expired for %s, %s\n",
domain, server ));
DLIST_REMOVE(failed_connection_cache, fcc);
SAFE_FREE(fcc);
return NT_STATUS_OK;
}
/* The timeout hasn't expired yet so return false */
DEBUG(10, ("check_negative_conn_cache: returning negative entry for %s, %s\n",
domain, server ));
result = fcc->nt_status;
return result;
}
/* end of function means no cache entry */
return NT_STATUS_OK;
}
/**********************************************************************
Add an entry to the failed conneciton cache
**********************************************************************/
void add_failed_connection_entry(const char *domain, const char *server, NTSTATUS result)
{
struct failed_connection_cache *fcc;
SMB_ASSERT(!NT_STATUS_IS_OK(result));
/* Check we already aren't in the cache. We always have to have
a domain, but maybe not a specific DC name. */
for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
if ( strequal(fcc->domain_name, domain) && strequal(fcc->controller, server) )
{
DEBUG(10, ("add_failed_connection_entry: domain %s (%s) already tried and failed\n",
domain, server ));
return;
}
}
/* Create negative lookup cache entry for this domain and controller */
if ( !(fcc = (struct failed_connection_cache *)malloc(sizeof(struct failed_connection_cache))) )
{
DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
return;
}
ZERO_STRUCTP(fcc);
fstrcpy( fcc->domain_name, domain );
fstrcpy( fcc->controller, server );
fcc->lookup_time = time(NULL);
fcc->nt_status = result;
DEBUG(10,("add_failed_connection_entry: added domain %s (%s) to failed conn cache\n",
domain, server ));
DLIST_ADD(failed_connection_cache, fcc);
}
/****************************************************************************
****************************************************************************/
void flush_negative_conn_cache( void )
{
struct failed_connection_cache *fcc;
fcc = failed_connection_cache;
while (fcc) {
struct failed_connection_cache *fcc_next;
fcc_next = fcc->next;
DLIST_REMOVE(failed_connection_cache, fcc);
free(fcc);
fcc = fcc_next;
}
}
/****************************************************************************
Utility function to return the name of a DC using RPC. The name is
guaranteed to be valid since we have already done a name_status_find on it
and we have checked our negative connection cache
***************************************************************************/
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;
NTSTATUS result;
zero_ip(&exclude_ip);
@ -41,11 +175,15 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
/* Lookup domain controller name */
if ( use_pdc_only && get_pdc_ip(domain, &dc_ip) ) {
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;
/* makre we we haven't tried this on previously and failed */
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;
@ -77,8 +215,11 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
continue;
if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
dc_ip = ip_list[i];
goto done;
result = check_negative_conn_cache( domain, srv_name );
if ( NT_STATUS_IS_OK(result) ) {
dc_ip = ip_list[i];
goto done;
}
}
}

View File

@ -246,65 +246,11 @@ static void cm_get_ipc_userpass(char **username, char **domain, char **password)
}
}
/* 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 FAILED_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
struct failed_connection_cache {
fstring domain_name;
fstring controller;
time_t lookup_time;
NTSTATUS nt_status;
struct failed_connection_cache *prev, *next;
};
static struct failed_connection_cache *failed_connection_cache;
/* Add an entry to the failed conneciton cache */
static void add_failed_connection_entry(struct winbindd_cm_conn *new_conn,
NTSTATUS result)
{
struct failed_connection_cache *fcc;
SMB_ASSERT(!NT_STATUS_IS_OK(result));
/* Check we already aren't in the cache */
for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
if (strequal(fcc->domain_name, new_conn->domain)) {
DEBUG(10, ("domain %s already tried and failed\n",
fcc->domain_name));
return;
}
}
/* Create negative lookup cache entry for this domain and controller */
if (!(fcc = (struct failed_connection_cache *)
malloc(sizeof(struct failed_connection_cache)))) {
DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
return;
}
ZERO_STRUCTP(fcc);
fstrcpy(fcc->domain_name, new_conn->domain);
fstrcpy(fcc->controller, new_conn->controller);
fcc->lookup_time = time(NULL);
fcc->nt_status = result;
DLIST_ADD(failed_connection_cache, fcc);
}
/* Open a connction to the remote server, cache failures for 30 seconds */
static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
struct winbindd_cm_conn *new_conn)
{
struct failed_connection_cache *fcc;
NTSTATUS result;
char *ipc_username, *ipc_domain, *ipc_password;
struct in_addr dc_ip;
@ -316,47 +262,15 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
fstrcpy(new_conn->domain, domain);
fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index));
/* Look for a domain controller for this domain. Negative results
are cached so don't bother applying the caching for this
function just yet. */
/* connection failure cache has been moved inside of get_dc_name
so we can deal with half dead DC's --jerry */
if (!cm_get_dc_name(domain, new_conn->controller, &dc_ip)) {
result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
add_failed_connection_entry(new_conn, result);
add_failed_connection_entry(domain, "", result);
return result;
}
/* Return false if we have tried to look up this domain and netbios
name before and failed. */
for (fcc = failed_connection_cache; fcc; fcc = fcc->next) {
if (!(strequal(domain, fcc->domain_name) &&
strequal(new_conn->controller, fcc->controller)))
continue; /* Not our domain */
if ((time(NULL) - fcc->lookup_time) >
FAILED_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(failed_connection_cache, fcc);
free(fcc);
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));
result = fcc->nt_status;
SMB_ASSERT(!NT_STATUS_IS_OK(result));
return result;
}
/* Initialise SMB connection */
cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
@ -402,7 +316,7 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
* specific UUID right now, i'm not going to bother. --jerry
*/
if ( !is_win2k_pipe(pipe_index) )
add_failed_connection_entry(new_conn, result);
add_failed_connection_entry(domain, new_conn->controller, result);
cli_shutdown(new_conn->cli);
return result;
}
@ -644,233 +558,6 @@ CLI_POLICY_HND *cm_get_sam_handle(char *domain)
return &hnd;
}
#if 0 /* This code now *well* out of date */
/* Return a SAM domain policy handle on a domain */
CLI_POLICY_HND *cm_get_sam_dom_handle(char *domain, DOM_SID *domain_sid)
{
struct winbindd_cm_conn *conn, *basic_conn = NULL;
static CLI_POLICY_HND hnd;
NTSTATUS result;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
/* Look for existing connections */
for (conn = cm_conns; conn; conn = conn->next) {
if (strequal(conn->domain, domain) &&
strequal(conn->pipe_name, PIPE_SAMR) &&
conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM) {
if (!connection_ok(conn)) {
/* Shutdown cli? Free conn? Allow retry of DC? */
DLIST_REMOVE(cm_conns, conn);
return NULL;
}
goto ok;
}
}
/* Create a basic handle to open a domain handle from */
if (!cm_get_sam_handle(domain))
return False;
for (conn = cm_conns; conn; conn = conn->next) {
if (strequal(conn->domain, domain) &&
strequal(conn->pipe_name, PIPE_SAMR) &&
conn->pipe_data.samr.pipe_type == SAM_PIPE_BASIC)
basic_conn = conn;
}
if (!(conn = (struct winbindd_cm_conn *)
malloc(sizeof(struct winbindd_cm_conn))))
return NULL;
ZERO_STRUCTP(conn);
fstrcpy(conn->domain, basic_conn->domain);
fstrcpy(conn->controller, basic_conn->controller);
fstrcpy(conn->pipe_name, basic_conn->pipe_name);
conn->pipe_data.samr.pipe_type = SAM_PIPE_DOM;
conn->cli = basic_conn->cli;
result = cli_samr_open_domain(conn->cli, conn->cli->mem_ctx,
&basic_conn->pol, des_access,
domain_sid, &conn->pol);
if (!NT_STATUS_IS_OK(result))
return NULL;
/* Add to list */
DLIST_ADD(cm_conns, conn);
ok:
hnd.pol = conn->pol;
hnd.cli = conn->cli;
return &hnd;
}
/* Return a SAM policy handle on a domain user */
CLI_POLICY_HND *cm_get_sam_user_handle(char *domain, DOM_SID *domain_sid,
uint32 user_rid)
{
struct winbindd_cm_conn *conn, *basic_conn = NULL;
static CLI_POLICY_HND hnd;
NTSTATUS result;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
/* Look for existing connections */
for (conn = cm_conns; conn; conn = conn->next) {
if (strequal(conn->domain, domain) &&
strequal(conn->pipe_name, PIPE_SAMR) &&
conn->pipe_data.samr.pipe_type == SAM_PIPE_USER &&
conn->pipe_data.samr.rid == user_rid) {
if (!connection_ok(conn)) {
/* Shutdown cli? Free conn? Allow retry of DC? */
DLIST_REMOVE(cm_conns, conn);
return NULL;
}
goto ok;
}
}
/* Create a domain handle to open a user handle from */
if (!cm_get_sam_dom_handle(domain, domain_sid))
return NULL;
for (conn = cm_conns; conn; conn = conn->next) {
if (strequal(conn->domain, domain) &&
strequal(conn->pipe_name, PIPE_SAMR) &&
conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
basic_conn = conn;
}
if (!basic_conn) {
DEBUG(0, ("No domain sam handle was created!\n"));
return NULL;
}
if (!(conn = (struct winbindd_cm_conn *)
malloc(sizeof(struct winbindd_cm_conn))))
return NULL;
ZERO_STRUCTP(conn);
fstrcpy(conn->domain, basic_conn->domain);
fstrcpy(conn->controller, basic_conn->controller);
fstrcpy(conn->pipe_name, basic_conn->pipe_name);
conn->pipe_data.samr.pipe_type = SAM_PIPE_USER;
conn->cli = basic_conn->cli;
conn->pipe_data.samr.rid = user_rid;
result = cli_samr_open_user(conn->cli, conn->cli->mem_ctx,
&basic_conn->pol, des_access, user_rid,
&conn->pol);
if (!NT_STATUS_IS_OK(result))
return NULL;
/* Add to list */
DLIST_ADD(cm_conns, conn);
ok:
hnd.pol = conn->pol;
hnd.cli = conn->cli;
return &hnd;
}
/* Return a SAM policy handle on a domain group */
CLI_POLICY_HND *cm_get_sam_group_handle(char *domain, DOM_SID *domain_sid,
uint32 group_rid)
{
struct winbindd_cm_conn *conn, *basic_conn = NULL;
static CLI_POLICY_HND hnd;
NTSTATUS result;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
/* Look for existing connections */
for (conn = cm_conns; conn; conn = conn->next) {
if (strequal(conn->domain, domain) &&
strequal(conn->pipe_name, PIPE_SAMR) &&
conn->pipe_data.samr.pipe_type == SAM_PIPE_GROUP &&
conn->pipe_data.samr.rid == group_rid) {
if (!connection_ok(conn)) {
/* Shutdown cli? Free conn? Allow retry of DC? */
DLIST_REMOVE(cm_conns, conn);
return NULL;
}
goto ok;
}
}
/* Create a domain handle to open a user handle from */
if (!cm_get_sam_dom_handle(domain, domain_sid))
return NULL;
for (conn = cm_conns; conn; conn = conn->next) {
if (strequal(conn->domain, domain) &&
strequal(conn->pipe_name, PIPE_SAMR) &&
conn->pipe_data.samr.pipe_type == SAM_PIPE_DOM)
basic_conn = conn;
}
if (!basic_conn) {
DEBUG(0, ("No domain sam handle was created!\n"));
return NULL;
}
if (!(conn = (struct winbindd_cm_conn *)
malloc(sizeof(struct winbindd_cm_conn))))
return NULL;
ZERO_STRUCTP(conn);
fstrcpy(conn->domain, basic_conn->domain);
fstrcpy(conn->controller, basic_conn->controller);
fstrcpy(conn->pipe_name, basic_conn->pipe_name);
conn->pipe_data.samr.pipe_type = SAM_PIPE_GROUP;
conn->cli = basic_conn->cli;
conn->pipe_data.samr.rid = group_rid;
result = cli_samr_open_group(conn->cli, conn->cli->mem_ctx,
&basic_conn->pol, des_access, group_rid,
&conn->pol);
if (!NT_STATUS_IS_OK(result))
return NULL;
/* Add to list */
DLIST_ADD(cm_conns, conn);
ok:
hnd.pol = conn->pol;
hnd.cli = conn->cli;
return &hnd;
}
#endif
/* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
netlogon pipe as no handle is returned. */