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
2011-01-12 20:12:29 +03:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2002-12-13 02:35:55 +03:00
( at your option ) any later version .
2011-01-12 20:12:29 +03:00
2002-12-13 02:35:55 +03:00
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 .
2011-01-12 20:12:29 +03:00
2002-12-13 02:35:55 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-12-13 02:35:55 +03:00
*/
# include "includes.h"
2010-02-23 19:11:37 +03:00
# include "libads/sitename_cache.h"
2010-07-02 02:32:52 +04:00
# include "ads.h"
2010-08-03 01:21:09 +04:00
# include "../librpc/gen_ndr/nbt.h"
2012-07-23 06:47:01 +04:00
# include "lib/param/loadparm.h"
2002-12-13 02:35:55 +03:00
2006-12-21 03:43:21 +03:00
/**********************************************************************
Is this our primary domain ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_KRB5
2007-10-19 04:40:25 +04:00
static bool is_our_primary_domain ( const char * domain )
2006-12-21 03:43:21 +03: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-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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-01-12 20:12:29 +03:00
2007-10-19 04:40:25 +04:00
static bool ads_dc_name ( const char * domain ,
2006-08-30 09:52:31 +04:00
const char * realm ,
2007-10-25 01:16:54 +04:00
struct sockaddr_storage * dc_ss ,
2006-08-30 09:52:31 +04:00
fstring srv_name )
2003-07-01 00:45:14 +04:00
{
ADS_STRUCT * ads ;
2007-01-18 12:58:57 +03:00
char * sitename ;
2006-08-30 09:52:31 +04:00
int i ;
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
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
2013-09-05 00:58:18 +04:00
sitename = sitename_fetch ( talloc_tos ( ) , realm ) ;
2007-01-18 12:58:57 +03: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 ) {
2013-09-05 00:58:18 +04:00
TALLOC_FREE ( sitename ) ;
2006-08-30 09:52:31 +04:00
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 ) {
2013-09-05 00:58:18 +04:00
TALLOC_FREE ( sitename ) ;
2006-08-30 09:52:31 +04:00
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 . */
2007-01-18 12:58:57 +03:00
if ( stored_sitename_changed ( realm , sitename ) ) {
2013-09-05 00:58:18 +04:00
TALLOC_FREE ( sitename ) ;
sitename = sitename_fetch ( talloc_tos ( ) , realm ) ;
2006-08-31 05:20:21 +04:00
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
}
2011-02-11 13:16:08 +03:00
# ifdef HAVE_ADS
2008-04-21 21:59:27 +04:00
if ( is_our_primary_domain ( domain ) & & ( ads - > config . flags & NBT_SERVER_KDC ) ) {
2007-09-08 18:56:11 +04: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 ,
2010-05-15 01:23:34 +04:00
& ads - > ldap . ss ,
ads - > config . ldap_server_name ) ;
2007-09-08 18:56:11 +04:00
} else {
create_local_private_krb5_conf_for_domain ( realm ,
domain ,
NULL ,
2010-05-15 01:23:34 +04:00
& ads - > ldap . ss ,
ads - > config . ldap_server_name ) ;
2007-09-08 18:56:11 +04:00
}
2006-08-31 05:20:21 +04:00
}
# 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 : " " ) ) ;
2013-09-05 00:58:18 +04:00
TALLOC_FREE ( sitename ) ;
2012-08-09 02:21:33 +04:00
ads_destroy ( & ads ) ;
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
2013-09-05 00:58:18 +04:00
TALLOC_FREE ( sitename ) ;
2006-08-30 09:52:31 +04:00
2003-07-01 00:45:14 +04:00
fstrcpy ( srv_name , ads - > config . ldap_server_name ) ;
2012-08-09 02:35:28 +04:00
if ( ! strupper_m ( srv_name ) ) {
ads_destroy ( & ads ) ;
return false ;
}
2007-07-16 18:35:33 +04:00
# ifdef HAVE_ADS
2007-10-25 01:16:54 +04:00
* dc_ss = ads - > ldap . ss ;
2007-07-16 18:35:33 +04:00
# else
2008-12-03 10:29:57 +03:00
zero_sockaddr ( dc_ss ) ;
2007-07-16 18:35:33 +04:00
# endif
2003-07-01 00:45:14 +04:00
ads_destroy ( & ads ) ;
2007-10-25 01:16:54 +04:00
print_sockaddr ( addr , sizeof ( addr ) , dc_ss ) ;
2003-07-01 00:45:14 +04:00
DEBUG ( 4 , ( " ads_dc_name: using server='%s' IP=%s \n " ,
2007-10-25 01:16:54 +04:00
srv_name , addr ) ) ;
2003-07-01 00:45:14 +04:00
return True ;
}
2003-06-06 18:11:14 +04:00
/****************************************************************************
2007-10-25 01:16:54 +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
2007-10-25 01:16:54 +04:00
static bool rpc_dc_name ( const char * domain ,
fstring srv_name ,
struct sockaddr_storage * ss_out )
2002-12-13 02:35:55 +03:00
{
2003-06-25 21:41:05 +04:00
struct ip_service * ip_list = NULL ;
2007-10-25 01:16:54 +04:00
struct sockaddr_storage dc_ss ;
2002-12-13 02:35:55 +03:00
int count , i ;
2003-06-06 18:11:14 +04:00
NTSTATUS result ;
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
2002-12-13 02:35:55 +03:00
/* get a list of all domain controllers */
2007-10-25 01:16:54 +04:00
2007-01-17 21:25:35 +03:00
if ( ! NT_STATUS_IS_OK ( get_sorted_dc_list ( domain , NULL , & ip_list , & count ,
2006-08-28 13:19:30 +04:00
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 + + ) {
2011-02-27 11:57:18 +03:00
if ( is_zero_addr ( & ip_list [ i ] . ss ) )
2002-12-13 02:35:55 +03:00
continue ;
2007-10-25 01:16:54 +04:00
if ( name_status_find ( domain , 0x1c , 0x20 , & ip_list [ i ] . ss , srv_name ) ) {
2003-06-06 18:11:14 +04:00
result = check_negative_conn_cache ( domain , srv_name ) ;
if ( NT_STATUS_IS_OK ( result ) ) {
2007-10-25 01:16:54 +04:00
dc_ss = ip_list [ i ] . ss ;
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
}
SAFE_FREE ( ip_list ) ;
2003-06-14 01:03:15 +04:00
/* No-one to talk to )-: */
return False ; /* Boo-hoo */
2007-10-25 01:16:54 +04:00
2003-06-14 01:03:15 +04:00
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 . */
2007-10-25 01:16:54 +04:00
print_sockaddr ( addr , sizeof ( addr ) , & dc_ss ) ;
2003-06-23 23:05:23 +04:00
DEBUG ( 3 , ( " rpc_dc_name: Returning DC %s (%s) for domain %s \n " , srv_name ,
2007-10-25 01:16:54 +04:00
addr , domain ) ) ;
2002-12-13 02:35:55 +03:00
2007-10-25 01:16:54 +04:00
* ss_out = dc_ss ;
2002-12-13 02:35:55 +03:00
SAFE_FREE ( ip_list ) ;
return True ;
}
2003-07-01 00:45:14 +04:00
/**********************************************************************
wrapper around ads and rpc methods of finds DC ' s
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-25 01:16:54 +04:00
bool get_dc_name ( const char * domain ,
const char * realm ,
fstring srv_name ,
struct sockaddr_storage * ss_out )
2003-07-01 00:45:14 +04:00
{
2007-10-25 01:16:54 +04:00
struct sockaddr_storage dc_ss ;
2007-10-19 04:40:25 +04:00
bool ret ;
bool our_domain = False ;
2003-07-01 00:45:14 +04:00
2008-12-03 10:29:57 +03:00
zero_sockaddr ( & dc_ss ) ;
2003-07-01 00:45:14 +04:00
ret = False ;
2007-10-25 01:16:54 +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 ;
2007-10-25 01:16:54 +04:00
/* always try to obey what the admin specified in smb.conf
2004-01-05 07:10:28 +03:00
( for the local domain ) */
2007-10-25 01:16:54 +04:00
2004-01-05 07:10:28 +03:00
if ( ( our_domain & & lp_security ( ) = = SEC_ADS ) | | realm ) {
2007-10-25 01:16:54 +04:00
ret = ads_dc_name ( domain , realm , & dc_ss , srv_name ) ;
2003-08-09 03:53:13 +04:00
}
2007-04-22 00:43:54 +04:00
if ( ! domain ) {
/* if we have only the realm we can't do anything else */
return False ;
}
2007-10-25 01:16:54 +04:00
2003-07-01 00:45:14 +04:00
if ( ! ret ) {
/* fall back on rpc methods if the ADS methods fail */
2007-10-25 01:16:54 +04:00
ret = rpc_dc_name ( domain , srv_name , & dc_ss ) ;
2003-07-01 00:45:14 +04:00
}
2007-10-25 01:16:54 +04:00
* ss_out = dc_ss ;
2003-07-01 00:45:14 +04:00
return ret ;
}