1
0
mirror of https://github.com/samba-team/samba.git synced 2025-08-26 01:49:31 +03:00

r13310: first round of server affinity patches for winbindd & net ads join

(This used to be commit 6c3480f9ae)
This commit is contained in:
Gerald Carter
2006-02-03 21:19:24 +00:00
committed by Gerald (Jerry) Carter
parent 989c9311c5
commit 855e02f164
8 changed files with 279 additions and 223 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
/****************************************************************************

View File

@ -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 we are starting from scratch, just lookup DOMAIN<0x1c> */
/*
* 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 ( !*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;
}
}
p = pserver;
local_count = 0;
if ( (return_iplist = SMB_MALLOC_ARRAY(struct ip_service, num_addresses)) == NULL ) {
DEBUG(3,("get_dc_list: malloc fail !\n"));
return False;
}
/* fill in the return list now with real IP's */
p = pserver;
local_count = 0;
/* 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++;
}
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 */
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 ) ) {
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(name_ip))) ) {
DEBUG(5,("get_dc_list: negative entry %s removed from DC list\n",name ));
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 = name_ip;
return_iplist[local_count].port = port;
return_iplist[local_count].ip = auto_ip_list[j].ip;
return_iplist[local_count].port = auto_ip_list[j].port;
local_count++;
*ordered = True;
}
}
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 );
}
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"));
continue;
}
*ip_list = return_iplist;
*count = local_count;
/* 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 );
}
return (*count != 0);
/* explicit lookup; resolve_name() will handle names & IP addresses */
if ( resolve_name( name, &name_ip, 0x20 ) ) {
/* 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;
}
}
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);
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 );
}
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;
return (*count != 0);
}
/*********************************************************************

View File

@ -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;

View File

@ -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;

View File

@ -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.
*******************************************************************************/