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
/**************************************************************************
2006-08-30 09:52:31 +04:00
Find the name and IP address for a server in the realm / domain
2003-07-01 00:45:14 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-30 09:52:31 +04:00
static BOOL ads_dc_name ( const char * domain ,
const char * realm ,
struct in_addr * dc_ip ,
fstring srv_name )
2003-07-01 00:45:14 +04:00
{
ADS_STRUCT * ads ;
2006-08-30 09:52:31 +04:00
char * sitename = sitename_fetch ( ) ;
int i ;
2003-07-01 00:45:14 +04:00
2006-08-31 05:20:21 +04:00
if ( ! realm & & strequal ( domain , lp_workgroup ( ) ) ) {
2003-07-01 00:45:14 +04:00
realm = lp_realm ( ) ;
2006-08-31 05:20:21 +04:00
}
2003-07-01 00:45:14 +04:00
2006-08-30 09:52:31 +04:00
/* Try this 3 times then give up. */
for ( i = 0 ; i < 3 ; i + + ) {
ads = ads_init ( realm , domain , NULL ) ;
if ( ! ads ) {
SAFE_FREE ( sitename ) ;
return False ;
}
2003-07-01 00:45:14 +04:00
2006-08-30 09:52:31 +04:00
DEBUG ( 4 , ( " ads_dc_name: domain=%s \n " , domain ) ) ;
2003-07-01 00:45:14 +04:00
# ifdef HAVE_ADS
2006-08-30 09:52:31 +04:00
/* we don't need to bind, just connect */
ads - > auth . flags | = ADS_AUTH_NO_BIND ;
ads_connect ( ads ) ;
2003-07-01 00:45:14 +04:00
# endif
2006-08-30 09:52:31 +04:00
if ( ! ads - > config . realm ) {
SAFE_FREE ( sitename ) ;
ads_destroy ( & ads ) ;
return False ;
}
/* Now we've found a server, see if our sitename
2006-08-31 05:20:21 +04:00
has changed . If so , we need to re - do the DNS query
2006-08-30 09:52:31 +04:00
to ensure we only find servers in our site . */
2006-08-31 08:14:08 +04:00
if ( stored_sitename_changed ( sitename ) ) {
2006-08-31 05:20:21 +04:00
SAFE_FREE ( sitename ) ;
sitename = sitename_fetch ( ) ;
ads_destroy ( & ads ) ;
2006-10-11 22:54:40 +04:00
/* Ensure we don't cache the DC we just connected to. */
namecache_delete ( realm , 0x1C ) ;
namecache_delete ( domain , 0x1C ) ;
2006-08-31 05:20:21 +04:00
continue ;
2006-08-30 09:52:31 +04:00
}
2006-08-31 05:20:21 +04:00
# ifdef HAVE_KRB5
2006-11-10 15:42:50 +03:00
if ( ( ads - > config . flags & ADS_KDC ) & & ads_closest_dc ( ads ) ) {
2006-08-31 05:20:21 +04:00
/* We're going to use this KDC for this realm/domain.
If we are using sites , then force the krb5 libs
to use this KDC . */
2006-08-30 09:52:31 +04:00
2006-08-31 05:20:21 +04:00
create_local_private_krb5_conf_for_domain ( realm ,
domain ,
ads - > ldap_ip ) ;
}
# endif
break ;
}
2006-08-30 09:52:31 +04:00
if ( i = = 3 ) {
2006-08-30 20:02:08 +04:00
DEBUG ( 1 , ( " ads_dc_name: sitename (now \" %s \" ) keeps changing ??? \n " ,
sitename ? sitename : " " ) ) ;
2006-08-30 09:52:31 +04:00
SAFE_FREE ( sitename ) ;
2003-07-01 00:45:14 +04:00
return False ;
2004-05-07 03:16:52 +04:00
}
2003-07-01 00:45:14 +04:00
2006-08-30 09:52:31 +04:00
SAFE_FREE ( sitename ) ;
2003-07-01 00:45:14 +04:00
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 ;
2003-06-06 18:11:14 +04:00
NTSTATUS result ;
2002-12-13 02:35:55 +03:00
zero_ip ( & exclude_ip ) ;
/* get a list of all domain controllers */
2006-08-28 13:19:30 +04:00
if ( ! NT_STATUS_IS_OK ( 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). */
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-01-05 07:10:28 +03:00
BOOL get_dc_name ( const char * domain , const char * realm , fstring srv_name , struct in_addr * ip_out )
2003-07-01 00:45:14 +04:00
{
struct in_addr dc_ip ;
BOOL ret ;
2003-08-09 03:53:13 +04:00
BOOL our_domain = False ;
2003-07-01 00:45:14 +04:00
zero_ip ( & dc_ip ) ;
ret = False ;
2003-08-09 03:53:13 +04:00
2004-01-05 07:10:28 +03:00
if ( strequal ( lp_workgroup ( ) , domain ) | | strequal ( lp_realm ( ) , realm ) )
2003-08-09 03:53:13 +04:00
our_domain = True ;
2004-01-05 07:10:28 +03:00
/* always try to obey what the admin specified in smb.conf
( for the local domain ) */
2003-08-09 03:53:13 +04:00
2004-01-05 07:10:28 +03:00
if ( ( our_domain & & lp_security ( ) = = SEC_ADS ) | | realm ) {
ret = ads_dc_name ( domain , realm , & dc_ip , srv_name ) ;
2003-08-09 03:53:13 +04:00
}
2003-07-01 00:45:14 +04:00
if ( ! ret ) {
/* fall back on rpc methods if the ADS methods fail */
ret = rpc_dc_name ( domain , srv_name , & dc_ip ) ;
}
2003-08-09 03:53:13 +04:00
2003-07-01 00:45:14 +04:00
* ip_out = dc_ip ;
return ret ;
}