2002-12-12 23:35:55 +00:00
/*
Unix SMB / CIFS implementation .
Winbind daemon connection manager
Copyright ( C ) Tim Potter 2001
Copyright ( C ) Andrew Bartlett 2002
2003-06-30 20:45:14 +00:00
Copyright ( C ) Gerald Carter 2003
2002-12-12 23:35:55 +00: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
2007-07-09 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
2002-12-12 23:35:55 +00:00
( 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
2007-07-10 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-12-12 23:35:55 +00:00
*/
# include "includes.h"
2006-12-21 00:43:21 +00:00
/**********************************************************************
Is this our primary domain ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_KRB5
2007-10-18 17:40:25 -07:00
static bool is_our_primary_domain ( const char * domain )
2006-12-21 00:43:21 +00:00
{
int role = lp_server_role ( ) ;
if ( ( role = = ROLE_DOMAIN_MEMBER ) & & strequal ( lp_workgroup ( ) , domain ) ) {
return True ;
} else if ( strequal ( get_global_sam_name ( ) , domain ) ) {
return True ;
}
return False ;
}
# endif
2003-06-30 20:45:14 +00:00
/**************************************************************************
2006-08-30 05:52:31 +00:00
Find the name and IP address for a server in the realm / domain
2003-06-30 20:45:14 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-18 17:40:25 -07:00
static bool ads_dc_name ( const char * domain ,
2006-08-30 05:52:31 +00:00
const char * realm ,
2007-10-24 14:16:54 -07:00
struct sockaddr_storage * dc_ss ,
2006-08-30 05:52:31 +00:00
fstring srv_name )
2003-06-30 20:45:14 +00:00
{
ADS_STRUCT * ads ;
2007-01-18 09:58:57 +00:00
char * sitename ;
2006-08-30 05:52:31 +00:00
int i ;
2007-10-24 14:16:54 -07:00
char addr [ INET6_ADDRSTRLEN ] ;
2003-06-30 20:45:14 +00:00
2006-08-31 01:20:21 +00:00
if ( ! realm & & strequal ( domain , lp_workgroup ( ) ) ) {
2003-06-30 20:45:14 +00:00
realm = lp_realm ( ) ;
2006-08-31 01:20:21 +00:00
}
2003-06-30 20:45:14 +00:00
2007-01-18 09:58:57 +00:00
sitename = sitename_fetch ( realm ) ;
2006-08-30 05:52:31 +00: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-06-30 20:45:14 +00:00
2006-08-30 05:52:31 +00:00
DEBUG ( 4 , ( " ads_dc_name: domain=%s \n " , domain ) ) ;
2003-06-30 20:45:14 +00:00
# ifdef HAVE_ADS
2006-08-30 05:52:31 +00:00
/* we don't need to bind, just connect */
ads - > auth . flags | = ADS_AUTH_NO_BIND ;
ads_connect ( ads ) ;
2003-06-30 20:45:14 +00:00
# endif
2006-08-30 05:52:31 +00: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 01:20:21 +00:00
has changed . If so , we need to re - do the DNS query
2006-08-30 05:52:31 +00:00
to ensure we only find servers in our site . */
2007-01-18 09:58:57 +00:00
if ( stored_sitename_changed ( realm , sitename ) ) {
2006-08-31 01:20:21 +00:00
SAFE_FREE ( sitename ) ;
2007-01-18 09:58:57 +00:00
sitename = sitename_fetch ( realm ) ;
2006-08-31 01:20:21 +00:00
ads_destroy ( & ads ) ;
2006-10-11 18:54:40 +00:00
/* Ensure we don't cache the DC we just connected to. */
namecache_delete ( realm , 0x1C ) ;
namecache_delete ( domain , 0x1C ) ;
2006-08-31 01:20:21 +00:00
continue ;
2006-08-30 05:52:31 +00:00
}
2006-08-31 01:20:21 +00:00
# ifdef HAVE_KRB5
2008-04-21 19:59:27 +02:00
if ( is_our_primary_domain ( domain ) & & ( ads - > config . flags & NBT_SERVER_KDC ) ) {
2007-09-08 14:56:11 +00:00
if ( ads_closest_dc ( ads ) ) {
/* 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 . */
create_local_private_krb5_conf_for_domain ( realm ,
domain ,
sitename ,
2007-10-24 14:16:54 -07:00
& ads - > ldap . ss ) ;
2007-09-08 14:56:11 +00:00
} else {
create_local_private_krb5_conf_for_domain ( realm ,
domain ,
NULL ,
2007-10-24 14:16:54 -07:00
& ads - > ldap . ss ) ;
2007-09-08 14:56:11 +00:00
}
2006-08-31 01:20:21 +00:00
}
# endif
break ;
}
2006-08-30 05:52:31 +00:00
if ( i = = 3 ) {
2006-08-30 16:02:08 +00:00
DEBUG ( 1 , ( " ads_dc_name: sitename (now \" %s \" ) keeps changing ??? \n " ,
sitename ? sitename : " " ) ) ;
2006-08-30 05:52:31 +00:00
SAFE_FREE ( sitename ) ;
2003-06-30 20:45:14 +00:00
return False ;
2004-05-06 23:16:52 +00:00
}
2003-06-30 20:45:14 +00:00
2006-08-30 05:52:31 +00:00
SAFE_FREE ( sitename ) ;
2003-06-30 20:45:14 +00:00
fstrcpy ( srv_name , ads - > config . ldap_server_name ) ;
2003-07-03 19:11:31 +00:00
strupper_m ( srv_name ) ;
2007-07-16 14:35:33 +00:00
# ifdef HAVE_ADS
2007-10-24 14:16:54 -07:00
* dc_ss = ads - > ldap . ss ;
2007-07-16 14:35:33 +00:00
# else
2007-10-27 20:29:36 -07:00
zero_addr ( dc_ss ) ;
2007-07-16 14:35:33 +00:00
# endif
2003-06-30 20:45:14 +00:00
ads_destroy ( & ads ) ;
2007-10-24 14:16:54 -07:00
print_sockaddr ( addr , sizeof ( addr ) , dc_ss ) ;
2003-06-30 20:45:14 +00:00
DEBUG ( 4 , ( " ads_dc_name: using server='%s' IP=%s \n " ,
2007-10-24 14:16:54 -07:00
srv_name , addr ) ) ;
2003-06-30 20:45:14 +00:00
return True ;
}
2003-06-06 14:11:14 +00:00
/****************************************************************************
2007-10-24 14:16:54 -07: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 14:11:14 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-06-13 21:03:15 +00:00
2007-10-24 14:16:54 -07:00
static bool rpc_dc_name ( const char * domain ,
fstring srv_name ,
struct sockaddr_storage * ss_out )
2002-12-12 23:35:55 +00:00
{
2003-06-25 17:41:05 +00:00
struct ip_service * ip_list = NULL ;
2007-10-24 14:16:54 -07:00
struct sockaddr_storage dc_ss ;
2002-12-12 23:35:55 +00:00
int count , i ;
2003-06-06 14:11:14 +00:00
NTSTATUS result ;
2007-10-24 14:16:54 -07:00
char addr [ INET6_ADDRSTRLEN ] ;
2002-12-12 23:35:55 +00:00
/* get a list of all domain controllers */
2007-10-24 14:16:54 -07:00
2007-01-17 18:25:35 +00:00
if ( ! NT_STATUS_IS_OK ( get_sorted_dc_list ( domain , NULL , & ip_list , & count ,
2006-08-28 09:19:30 +00:00
False ) ) ) {
2002-12-12 23:35:55 +00: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 + + ) {
2007-10-24 14:16:54 -07:00
if ( is_zero_addr ( & ip_list [ i ] . ss ) )
2002-12-12 23:35:55 +00:00
continue ;
2007-10-24 14:16:54 -07:00
if ( name_status_find ( domain , 0x1c , 0x20 , & ip_list [ i ] . ss , srv_name ) ) {
2003-06-06 14:11:14 +00:00
result = check_negative_conn_cache ( domain , srv_name ) ;
if ( NT_STATUS_IS_OK ( result ) ) {
2007-10-24 14:16:54 -07:00
dc_ss = ip_list [ i ] . ss ;
2003-06-06 14:11:14 +00:00
goto done ;
}
2003-06-23 19:05:23 +00:00
}
2002-12-12 23:35:55 +00:00
}
SAFE_FREE ( ip_list ) ;
2003-06-13 21:03:15 +00:00
/* No-one to talk to )-: */
return False ; /* Boo-hoo */
2007-10-24 14:16:54 -07:00
2003-06-13 21:03:15 +00:00
done :
2002-12-12 23:35:55 +00: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 . */
2007-10-24 14:16:54 -07:00
print_sockaddr ( addr , sizeof ( addr ) , & dc_ss ) ;
2003-06-23 19:05:23 +00:00
DEBUG ( 3 , ( " rpc_dc_name: Returning DC %s (%s) for domain %s \n " , srv_name ,
2007-10-24 14:16:54 -07:00
addr , domain ) ) ;
2002-12-12 23:35:55 +00:00
2007-10-24 14:16:54 -07:00
* ss_out = dc_ss ;
2002-12-12 23:35:55 +00:00
SAFE_FREE ( ip_list ) ;
return True ;
}
2003-06-30 20:45:14 +00:00
/**********************************************************************
wrapper around ads and rpc methods of finds DC ' s
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-24 14:16:54 -07:00
bool get_dc_name ( const char * domain ,
const char * realm ,
fstring srv_name ,
struct sockaddr_storage * ss_out )
2003-06-30 20:45:14 +00:00
{
2007-10-24 14:16:54 -07:00
struct sockaddr_storage dc_ss ;
2007-10-18 17:40:25 -07:00
bool ret ;
bool our_domain = False ;
2003-06-30 20:45:14 +00:00
2007-10-27 20:29:36 -07:00
zero_addr ( & dc_ss ) ;
2003-06-30 20:45:14 +00:00
ret = False ;
2007-10-24 14:16:54 -07:00
2004-01-05 04:10:28 +00:00
if ( strequal ( lp_workgroup ( ) , domain ) | | strequal ( lp_realm ( ) , realm ) )
2003-08-08 23:53:13 +00:00
our_domain = True ;
2007-10-24 14:16:54 -07:00
/* always try to obey what the admin specified in smb.conf
2004-01-05 04:10:28 +00:00
( for the local domain ) */
2007-10-24 14:16:54 -07:00
2004-01-05 04:10:28 +00:00
if ( ( our_domain & & lp_security ( ) = = SEC_ADS ) | | realm ) {
2007-10-24 14:16:54 -07:00
ret = ads_dc_name ( domain , realm , & dc_ss , srv_name ) ;
2003-08-08 23:53:13 +00:00
}
2007-04-21 20:43:54 +00:00
if ( ! domain ) {
/* if we have only the realm we can't do anything else */
return False ;
}
2007-10-24 14:16:54 -07:00
2003-06-30 20:45:14 +00:00
if ( ! ret ) {
/* fall back on rpc methods if the ADS methods fail */
2007-10-24 14:16:54 -07:00
ret = rpc_dc_name ( domain , srv_name , & dc_ss ) ;
2003-06-30 20:45:14 +00:00
}
2007-10-24 14:16:54 -07:00
* ss_out = dc_ss ;
2003-06-30 20:45:14 +00:00
return ret ;
}