2002-12-13 02:35:55 +03:00
/*
Unix SMB / CIFS implementation .
Winbind daemon connection manager
Copyright ( C ) Tim Potter 2001
Copyright ( C ) Andrew Bartlett 2002
2003-07-01 00:45:14 +04:00
Copyright ( C ) Gerald Carter 2003
2002-12-13 02:35:55 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
2003-07-01 00:45:14 +04:00
/**************************************************************************
Find the name and IP address for a server in he realm / domain
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL ads_dc_name ( const char * domain , struct in_addr * dc_ip , fstring srv_name )
{
ADS_STRUCT * ads ;
const char * realm = domain ;
if ( strcasecmp ( realm , lp_workgroup ( ) ) = = 0 )
realm = lp_realm ( ) ;
ads = ads_init ( realm , domain , NULL ) ;
if ( ! ads )
return False ;
/* we don't need to bind, just connect */
ads - > auth . flags | = ADS_AUTH_NO_BIND ;
DEBUG ( 4 , ( " ads_dc_name: domain=%s \n " , domain ) ) ;
# ifdef HAVE_ADS
/* a full ads_connect() is actually overkill, as we don't srictly need
to do the SASL auth in order to get the info we need , but libads
doesn ' t offer a better way right now */
ads_connect ( ads ) ;
# endif
if ( ! ads - > config . realm )
return False ;
fstrcpy ( srv_name , ads - > config . ldap_server_name ) ;
2003-07-03 23:11:31 +04:00
strupper_m ( srv_name ) ;
2003-07-01 00:45:14 +04:00
* dc_ip = ads - > ldap_ip ;
ads_destroy ( & ads ) ;
DEBUG ( 4 , ( " ads_dc_name: using server='%s' IP=%s \n " ,
srv_name , inet_ntoa ( * dc_ip ) ) ) ;
return True ;
}
2003-06-06 18:11:14 +04:00
/****************************************************************************
2003-06-14 01:03:15 +04:00
Utility function to return the name of a DC . The name is guaranteed to be
valid since we have already done a name_status_find on it
2003-06-06 18:11:14 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-06-14 01:03:15 +04:00
2003-07-01 00:45:14 +04:00
static BOOL rpc_dc_name ( const char * domain , fstring srv_name , struct in_addr * ip_out )
2002-12-13 02:35:55 +03:00
{
2003-06-25 21:41:05 +04:00
struct ip_service * ip_list = NULL ;
struct in_addr dc_ip , exclude_ip ;
2002-12-13 02:35:55 +03:00
int count , i ;
BOOL use_pdc_only ;
2003-06-06 18:11:14 +04:00
NTSTATUS result ;
2002-12-13 02:35:55 +03:00
zero_ip ( & exclude_ip ) ;
use_pdc_only = must_use_pdc ( domain ) ;
/* Lookup domain controller name */
2003-06-06 18:11:14 +04:00
if ( use_pdc_only & & get_pdc_ip ( domain , & dc_ip ) )
{
2003-06-23 23:05:23 +04:00
DEBUG ( 10 , ( " rpc_dc_name: Atempting to lookup PDC to avoid sam sync delays \n " ) ) ;
2002-12-13 02:35:55 +03:00
2003-06-14 01:03:15 +04:00
/* check the connection cache and perform the node status
lookup only if the IP is not found to be bad */
2003-06-25 21:41:05 +04:00
if ( name_status_find ( domain , 0x1b , 0x20 , dc_ip , srv_name ) ) {
2003-06-06 18:11:14 +04:00
result = check_negative_conn_cache ( domain , srv_name ) ;
if ( NT_STATUS_IS_OK ( result ) )
goto done ;
2002-12-13 02:35:55 +03:00
}
/* Didn't get name, remember not to talk to this DC. */
exclude_ip = dc_ip ;
}
/* get a list of all domain controllers */
2003-06-25 21:41:05 +04:00
if ( ! get_sorted_dc_list ( domain , & ip_list , & count , False ) ) {
2002-12-13 02:35:55 +03:00
DEBUG ( 3 , ( " Could not look up dc's for domain %s \n " , domain ) ) ;
return False ;
}
/* Remove the entry we've already failed with (should be the PDC). */
if ( use_pdc_only ) {
for ( i = 0 ; i < count ; i + + ) {
2003-06-25 21:41:05 +04:00
if ( ip_equal ( exclude_ip , ip_list [ i ] . ip ) )
zero_ip ( & ip_list [ i ] . ip ) ;
2002-12-13 02:35:55 +03:00
}
}
for ( i = 0 ; i < count ; i + + ) {
2003-06-25 21:41:05 +04:00
if ( is_zero_ip ( ip_list [ i ] . ip ) )
2002-12-13 02:35:55 +03:00
continue ;
2003-06-25 21:41:05 +04:00
if ( name_status_find ( domain , 0x1c , 0x20 , ip_list [ i ] . ip , srv_name ) ) {
2003-06-06 18:11:14 +04:00
result = check_negative_conn_cache ( domain , srv_name ) ;
if ( NT_STATUS_IS_OK ( result ) ) {
2003-06-25 21:41:05 +04:00
dc_ip = ip_list [ i ] . ip ;
2003-06-06 18:11:14 +04:00
goto done ;
}
2003-06-23 23:05:23 +04:00
}
2002-12-13 02:35:55 +03:00
}
2003-06-23 23:05:23 +04:00
2002-12-13 02:35:55 +03:00
SAFE_FREE ( ip_list ) ;
2003-06-14 01:03:15 +04:00
/* No-one to talk to )-: */
return False ; /* Boo-hoo */
done :
2002-12-13 02:35:55 +03:00
/* We have the netbios name and IP address of a domain controller.
Ideally we should sent a SAMLOGON request to determine whether
the DC is alive and kicking . If we can catch a dead DC before
performing a cli_connect ( ) we can avoid a 30 - second timeout . */
2003-06-23 23:05:23 +04:00
DEBUG ( 3 , ( " rpc_dc_name: Returning DC %s (%s) for domain %s \n " , srv_name ,
2002-12-13 02:35:55 +03:00
inet_ntoa ( dc_ip ) , domain ) ) ;
* ip_out = dc_ip ;
SAFE_FREE ( ip_list ) ;
return True ;
}
2003-07-01 00:45:14 +04:00
/**********************************************************************
wrapper around ads and rpc methods of finds DC ' s
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL get_dc_name ( const char * domain , fstring srv_name , struct in_addr * ip_out )
{
struct in_addr dc_ip ;
BOOL ret ;
zero_ip ( & dc_ip ) ;
ret = False ;
if ( lp_security ( ) = = SEC_ADS )
ret = ads_dc_name ( domain , & dc_ip , srv_name ) ;
if ( ! ret ) {
/* fall back on rpc methods if the ADS methods fail */
ret = rpc_dc_name ( domain , srv_name , & dc_ip ) ;
}
* ip_out = dc_ip ;
return ret ;
}