2000-05-09 15:43:00 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-05-09 15:43:00 +04:00
Winbind daemon for ntdom nss module
2001-11-23 06:54:07 +03:00
Copyright ( C ) Tim Potter 2000 - 2001
Copyright ( C ) 2001 by Martin Pool < mbp @ samba . org >
2000-05-09 15:43:00 +04: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
2000-05-09 15:43:00 +04: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 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2000-05-09 15:43:00 +04:00
*/
2003-11-12 04:51:10 +03:00
# include "includes.h"
2000-05-09 15:43:00 +04:00
# include "winbindd.h"
2002-07-15 14:35:28 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
2000-05-09 15:43:00 +04:00
2006-12-12 20:38:42 +03:00
extern struct winbindd_methods cache_methods ;
extern struct winbindd_methods passdb_methods ;
2001-11-23 06:54:07 +03:00
/**
* @ file winbindd_util . c
*
* Winbind daemon for NT domain authentication nss module .
* */
2007-10-11 00:34:30 +04:00
2002-01-11 08:33:45 +03:00
/* The list of trusted domains. Note that the list can be deleted and
recreated using the init_domain_list ( ) function so pointers to
individual winbindd_domain structures cannot be made . Keep a copy of
the domain name instead . */
2001-11-23 06:54:07 +03:00
2008-01-23 15:52:42 +03:00
static struct winbindd_domain * _domain_list = NULL ;
2001-11-21 12:59:15 +03:00
2004-01-08 11:19:18 +03:00
/**
When was the last scan of trusted domains done ?
0 = = not ever
*/
static time_t last_trustdom_scan ;
2002-01-11 08:33:45 +03:00
struct winbindd_domain * domain_list ( void )
2001-11-21 12:59:15 +03:00
{
2002-01-11 08:33:45 +03:00
/* Initialise list */
2001-11-21 12:59:15 +03:00
2006-03-16 18:21:41 +03:00
if ( ( ! _domain_list ) & & ( ! init_domain_list ( ) ) ) {
2007-06-16 01:58:49 +04:00
smb_panic ( " Init_domain_list failed " ) ;
2006-03-16 18:21:41 +03:00
}
2001-11-21 12:59:15 +03:00
2002-01-11 08:33:45 +03:00
return _domain_list ;
2001-11-21 12:59:15 +03:00
}
2002-01-11 08:33:45 +03:00
/* Free all entries in the trusted domain list */
2001-11-21 12:59:15 +03:00
2002-01-11 08:33:45 +03:00
void free_domain_list ( void )
2001-11-21 12:59:15 +03:00
{
2002-01-11 08:33:45 +03:00
struct winbindd_domain * domain = _domain_list ;
while ( domain ) {
struct winbindd_domain * next = domain - > next ;
DLIST_REMOVE ( _domain_list , domain ) ;
SAFE_FREE ( domain ) ;
domain = next ;
2001-11-21 12:59:15 +03:00
}
}
2007-10-19 04:40:25 +04:00
static bool is_internal_domain ( const DOM_SID * sid )
2004-04-07 16:43:44 +04:00
{
2004-04-20 06:37:49 +04:00
if ( sid = = NULL )
return False ;
2008-05-29 21:37:52 +04:00
if ( IS_DC )
return sid_check_is_builtin ( sid ) ;
2005-06-09 02:10:34 +04:00
return ( sid_check_is_domain ( sid ) | | sid_check_is_builtin ( sid ) ) ;
2004-04-07 16:43:44 +04:00
}
2007-10-19 04:40:25 +04:00
static bool is_in_internal_domain ( const DOM_SID * sid )
2005-12-08 22:34:22 +03:00
{
if ( sid = = NULL )
return False ;
2008-05-29 21:37:52 +04:00
if ( IS_DC )
return sid_check_is_in_builtin ( sid ) ;
2005-12-08 22:34:22 +03:00
return ( sid_check_is_in_our_domain ( sid ) | | sid_check_is_in_builtin ( sid ) ) ;
}
2002-10-05 01:42:04 +04:00
2001-05-07 08:32:40 +04:00
/* Add a trusted domain to our list of domains */
2002-08-17 21:00:51 +04:00
static struct winbindd_domain * add_trusted_domain ( const char * domain_name , const char * alt_name ,
struct winbindd_methods * methods ,
2005-04-09 15:46:40 +04:00
const DOM_SID * sid )
2000-05-09 15:43:00 +04:00
{
2002-01-10 09:20:03 +03:00
struct winbindd_domain * domain ;
2003-09-05 21:57:45 +04:00
const char * alternative_name = NULL ;
/* ignore alt_name if we are not in an AD domain */
if ( ( lp_security ( ) = = SEC_ADS ) & & alt_name & & * alt_name ) {
alternative_name = alt_name ;
}
2001-10-11 03:08:13 +04:00
2002-01-11 08:33:45 +03:00
/* We can't call domain_list() as this function is called from
init_domain_list ( ) and we ' ll get stuck in a loop . */
for ( domain = _domain_list ; domain ; domain = domain - > next ) {
2003-10-23 03:38:20 +04:00
if ( strequal ( domain_name , domain - > name ) | |
2007-05-06 23:17:30 +04:00
strequal ( domain_name , domain - > alt_name ) )
{
break ;
2001-11-22 11:31:50 +03:00
}
2007-05-06 23:17:30 +04:00
if ( alternative_name & & * alternative_name )
{
2003-10-23 03:38:20 +04:00
if ( strequal ( alternative_name , domain - > name ) | |
2007-05-06 23:17:30 +04:00
strequal ( alternative_name , domain - > alt_name ) )
{
break ;
2002-09-25 19:19:00 +04:00
}
}
2007-05-06 23:17:30 +04:00
if ( sid )
{
2006-01-19 03:03:07 +03:00
if ( is_null_sid ( sid ) ) {
2007-05-06 23:17:30 +04:00
continue ;
}
2004-01-08 11:19:18 +03:00
2007-05-06 23:17:30 +04:00
if ( sid_equal ( sid , & domain - > sid ) ) {
break ;
2004-01-08 11:19:18 +03:00
}
}
2001-11-22 11:31:50 +03:00
}
2001-10-11 03:08:13 +04:00
2007-05-06 23:17:30 +04:00
/* See if we found a match. Check if we need to update the
SID . */
2007-09-08 08:57:17 +04:00
if ( domain & & sid ) {
2007-05-21 23:12:14 +04:00
if ( sid_equal ( & domain - > sid , & global_sid_NULL ) )
sid_copy ( & domain - > sid , sid ) ;
return domain ;
}
2001-11-22 11:31:50 +03:00
/* Create new domain entry */
2002-01-10 09:20:03 +03:00
2004-12-07 21:25:53 +03:00
if ( ( domain = SMB_MALLOC_P ( struct winbindd_domain ) ) = = NULL )
2001-11-22 11:31:50 +03:00
return NULL ;
2000-05-09 15:43:00 +04:00
2001-11-22 11:31:50 +03:00
/* Fill in fields */
2001-10-11 03:08:13 +04:00
2001-11-22 11:31:50 +03:00
ZERO_STRUCTP ( domain ) ;
2002-01-10 09:20:03 +03:00
2002-08-17 21:00:51 +04:00
/* prioritise the short name */
2003-09-05 21:57:45 +04:00
if ( strchr_m ( domain_name , ' . ' ) & & alternative_name & & * alternative_name ) {
fstrcpy ( domain - > name , alternative_name ) ;
2002-08-17 21:00:51 +04:00
fstrcpy ( domain - > alt_name , domain_name ) ;
} else {
2003-07-31 09:43:47 +04:00
fstrcpy ( domain - > name , domain_name ) ;
2003-09-05 21:57:45 +04:00
if ( alternative_name ) {
fstrcpy ( domain - > alt_name , alternative_name ) ;
2002-08-17 21:00:51 +04:00
}
}
2002-10-05 01:42:04 +04:00
domain - > methods = methods ;
2003-06-10 07:50:38 +04:00
domain - > backend = NULL ;
2004-04-07 16:43:44 +04:00
domain - > internal = is_internal_domain ( sid ) ;
2001-12-10 02:59:42 +03:00
domain - > sequence_number = DOM_SEQUENCE_NONE ;
domain - > last_seq_check = 0 ;
2004-04-20 06:37:49 +04:00
domain - > initialized = False ;
2006-05-31 13:25:44 +04:00
domain - > online = is_internal_domain ( sid ) ;
2006-12-07 02:14:15 +03:00
domain - > check_online_timeout = 0 ;
2002-08-17 21:00:51 +04:00
if ( sid ) {
sid_copy ( & domain - > sid , sid ) ;
}
2002-10-05 01:42:04 +04:00
2001-11-22 11:31:50 +03:00
/* Link to domain list */
2007-09-20 22:37:34 +04:00
DLIST_ADD_END ( _domain_list , domain , struct winbindd_domain * ) ;
2001-10-11 03:08:13 +04:00
2007-05-06 23:17:30 +04:00
wcache_tdc_add_domain ( domain ) ;
2004-06-14 07:24:17 +04:00
DEBUG ( 2 , ( " Added domain %s %s %s \n " ,
2002-08-17 21:00:51 +04:00
domain - > name , domain - > alt_name ,
2007-12-15 23:11:36 +03:00
& domain - > sid ? sid_string_dbg ( & domain - > sid ) : " " ) ) ;
2002-08-17 21:00:51 +04:00
2001-11-22 11:31:50 +03:00
return domain ;
2000-05-09 15:43:00 +04:00
}
2003-08-26 01:45:57 +04:00
/********************************************************************
2002-08-17 21:00:51 +04:00
rescan our domains looking for new trusted domains
2003-08-26 01:45:57 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-09 02:10:34 +04:00
struct trustdom_state {
TALLOC_CTX * mem_ctx ;
2007-10-19 04:40:25 +04:00
bool primary ;
bool forest_root ;
2005-06-09 02:10:34 +04:00
struct winbindd_response * response ;
} ;
2007-10-19 04:40:25 +04:00
static void trustdom_recv ( void * private_data , bool success ) ;
2007-05-06 23:17:30 +04:00
static void rescan_forest_root_trusts ( void ) ;
static void rescan_forest_trusts ( void ) ;
2005-06-09 02:10:34 +04:00
2004-02-08 14:26:46 +03:00
static void add_trusted_domains ( struct winbindd_domain * domain )
2002-08-17 21:00:51 +04:00
{
TALLOC_CTX * mem_ctx ;
2005-06-09 02:10:34 +04:00
struct winbindd_request * request ;
struct winbindd_response * response ;
2008-01-29 19:49:38 +03:00
uint32 fr_flags = ( NETR_TRUST_FLAG_TREEROOT | NETR_TRUST_FLAG_IN_FOREST ) ;
2005-06-09 02:10:34 +04:00
struct trustdom_state * state ;
mem_ctx = talloc_init ( " add_trusted_domains " ) ;
if ( mem_ctx = = NULL ) {
DEBUG ( 0 , ( " talloc_init failed \n " ) ) ;
2002-11-06 03:10:04 +03:00
return ;
}
2003-02-14 03:31:30 +03:00
2005-06-09 02:10:34 +04:00
request = TALLOC_ZERO_P ( mem_ctx , struct winbindd_request ) ;
response = TALLOC_P ( mem_ctx , struct winbindd_response ) ;
state = TALLOC_P ( mem_ctx , struct trustdom_state ) ;
2002-08-17 21:00:51 +04:00
2005-06-09 02:10:34 +04:00
if ( ( request = = NULL ) | | ( response = = NULL ) | | ( state = = NULL ) ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
talloc_destroy ( mem_ctx ) ;
2002-08-17 21:00:51 +04:00
return ;
2005-06-09 02:10:34 +04:00
}
2002-08-17 21:00:51 +04:00
2005-06-09 02:10:34 +04:00
state - > mem_ctx = mem_ctx ;
state - > response = response ;
2002-08-17 21:00:51 +04:00
2007-05-06 23:17:30 +04:00
/* Flags used to know how to continue the forest trust search */
state - > primary = domain - > primary ;
state - > forest_root = ( ( domain - > domain_flags & fr_flags ) = = fr_flags ) ;
2005-06-09 02:10:34 +04:00
request - > length = sizeof ( * request ) ;
request - > cmd = WINBINDD_LIST_TRUSTDOM ;
async_domain_request ( mem_ctx , domain , request , response ,
trustdom_recv , state ) ;
}
2007-10-19 04:40:25 +04:00
static void trustdom_recv ( void * private_data , bool success )
2005-06-09 02:10:34 +04:00
{
struct trustdom_state * state =
2005-06-25 00:25:18 +04:00
talloc_get_type_abort ( private_data , struct trustdom_state ) ;
2005-06-09 02:10:34 +04:00
struct winbindd_response * response = state - > response ;
char * p ;
if ( ( ! success ) | | ( response - > result ! = WINBINDD_OK ) ) {
DEBUG ( 1 , ( " Could not receive trustdoms \n " ) ) ;
talloc_destroy ( state - > mem_ctx ) ;
return ;
}
2006-08-18 18:05:25 +04:00
p = ( char * ) response - > extra_data . data ;
2005-06-09 02:10:34 +04:00
while ( ( p ! = NULL ) & & ( * p ! = ' \0 ' ) ) {
char * q , * sidstr , * alt_name ;
DOM_SID sid ;
2007-05-06 23:17:30 +04:00
struct winbindd_domain * domain ;
char * alternate_name = NULL ;
2005-06-09 02:10:34 +04:00
alt_name = strchr ( p , ' \\ ' ) ;
if ( alt_name = = NULL ) {
DEBUG ( 0 , ( " Got invalid trustdom response \n " ) ) ;
break ;
}
* alt_name = ' \0 ' ;
alt_name + = 1 ;
sidstr = strchr ( alt_name , ' \\ ' ) ;
if ( sidstr = = NULL ) {
DEBUG ( 0 , ( " Got invalid trustdom response \n " ) ) ;
break ;
}
* sidstr = ' \0 ' ;
sidstr + = 1 ;
q = strchr ( sidstr , ' \n ' ) ;
if ( q ! = NULL )
* q = ' \0 ' ;
if ( ! string_to_sid ( & sid , sidstr ) ) {
2006-12-20 19:57:10 +03:00
/* Allow NULL sid for sibling domains */
if ( strcmp ( sidstr , " S-0-0 " ) = = 0 ) {
sid_copy ( & sid , & global_sid_NULL ) ;
} else {
DEBUG ( 0 , ( " Got invalid trustdom response \n " ) ) ;
break ;
}
2005-06-09 02:10:34 +04:00
}
2007-09-08 08:57:17 +04:00
/* use the real alt_name if we have one, else pass in NULL */
2005-06-09 02:10:34 +04:00
2007-09-08 08:57:17 +04:00
if ( ! strequal ( alt_name , " (null) " ) )
alternate_name = alt_name ;
2005-06-09 02:10:34 +04:00
2007-05-06 23:17:30 +04:00
/* If we have an existing domain structure, calling
add_trusted_domain ( ) will update the SID if
necessary . This is important because we need the
SID for sibling domains */
if ( find_domain_from_name_noinit ( p ) ! = NULL ) {
domain = add_trusted_domain ( p , alternate_name ,
& cache_methods ,
& sid ) ;
} else {
2005-06-09 02:10:34 +04:00
domain = add_trusted_domain ( p , alternate_name ,
& cache_methods ,
& sid ) ;
2007-07-24 12:59:36 +04:00
if ( domain ) {
2007-10-08 16:25:57 +04:00
setup_domain_child ( domain ,
2007-12-13 14:27:57 +03:00
& domain - > child ) ;
2007-07-24 12:59:36 +04:00
}
2002-08-17 21:00:51 +04:00
}
2005-06-09 02:10:34 +04:00
p = q ;
if ( p ! = NULL )
p + = 1 ;
2002-08-17 21:00:51 +04:00
}
2006-04-12 18:10:39 +04:00
SAFE_FREE ( response - > extra_data . data ) ;
2007-05-06 23:17:30 +04:00
/*
Cases to consider when scanning trusts :
( a ) we are calling from a child domain ( primary & & ! forest_root )
( b ) we are calling from the root of the forest ( primary & & forest_root )
( c ) we are calling from a trusted forest domain ( ! primary
& & ! forest_root )
*/
if ( state - > primary ) {
2008-03-26 02:50:58 +03:00
/* If this is our primary domain and we are not in the
2007-05-06 23:17:30 +04:00
forest root , we have to scan the root trusts first */
if ( ! state - > forest_root )
rescan_forest_root_trusts ( ) ;
else
rescan_forest_trusts ( ) ;
} else if ( state - > forest_root ) {
/* Once we have done root forest trust search, we can
2008-03-26 02:50:58 +03:00
go on to search the trusted forests */
2007-05-06 23:17:30 +04:00
rescan_forest_trusts ( ) ;
}
2005-06-09 02:10:34 +04:00
talloc_destroy ( state - > mem_ctx ) ;
2007-05-06 23:17:30 +04:00
return ;
}
/********************************************************************
Scan the trusts of our forest root
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void rescan_forest_root_trusts ( void )
{
struct winbindd_tdc_domain * dom_list = NULL ;
size_t num_trusts = 0 ;
int i ;
/* The only transitive trusts supported by Windows 2003 AD are
( a ) Parent - Child , ( b ) Tree - Root , and ( c ) Forest . The
first two are handled in forest and listed by
DsEnumerateDomainTrusts ( ) . Forest trusts are not so we
have to do that ourselves . */
if ( ! wcache_tdc_fetch_list ( & dom_list , & num_trusts ) )
return ;
for ( i = 0 ; i < num_trusts ; i + + ) {
struct winbindd_domain * d = NULL ;
/* Find the forest root. Don't necessarily trust
the domain_list ( ) as our primary domain may not
have been initialized . */
2008-01-29 19:49:38 +03:00
if ( ! ( dom_list [ i ] . trust_flags & NETR_TRUST_FLAG_TREEROOT ) ) {
continue ;
2007-05-06 23:17:30 +04:00
}
/* Here's the forest root */
d = find_domain_from_name_noinit ( dom_list [ i ] . domain_name ) ;
if ( ! d ) {
d = add_trusted_domain ( dom_list [ i ] . domain_name ,
dom_list [ i ] . dns_name ,
& cache_methods ,
& dom_list [ i ] . sid ) ;
}
DEBUG ( 10 , ( " rescan_forest_root_trusts: Following trust path "
" for domain tree root %s (%s) \n " ,
d - > name , d - > alt_name ) ) ;
d - > domain_flags = dom_list [ i ] . trust_flags ;
d - > domain_type = dom_list [ i ] . trust_type ;
d - > domain_trust_attribs = dom_list [ i ] . trust_attribs ;
add_trusted_domains ( d ) ;
break ;
}
TALLOC_FREE ( dom_list ) ;
return ;
2002-08-17 21:00:51 +04:00
}
2004-02-10 06:51:19 +03:00
/********************************************************************
2008-03-26 02:50:58 +03:00
scan the transitive forest trusts ( not our own )
2004-02-10 06:51:19 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-06 23:17:30 +04:00
static void rescan_forest_trusts ( void )
{
struct winbindd_domain * d = NULL ;
struct winbindd_tdc_domain * dom_list = NULL ;
size_t num_trusts = 0 ;
int i ;
/* The only transitive trusts supported by Windows 2003 AD are
( a ) Parent - Child , ( b ) Tree - Root , and ( c ) Forest . The
first two are handled in forest and listed by
DsEnumerateDomainTrusts ( ) . Forest trusts are not so we
have to do that ourselves . */
if ( ! wcache_tdc_fetch_list ( & dom_list , & num_trusts ) )
return ;
for ( i = 0 ; i < num_trusts ; i + + ) {
uint32 flags = dom_list [ i ] . trust_flags ;
uint32 type = dom_list [ i ] . trust_type ;
uint32 attribs = dom_list [ i ] . trust_attribs ;
d = find_domain_from_name_noinit ( dom_list [ i ] . domain_name ) ;
/* ignore our primary and internal domains */
if ( d & & ( d - > internal | | d - > primary ) )
continue ;
2008-01-29 19:49:38 +03:00
if ( ( flags & NETR_TRUST_FLAG_INBOUND ) & &
( type = = NETR_TRUST_TYPE_UPLEVEL ) & &
( attribs = = NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE ) )
2007-05-06 23:17:30 +04:00
{
/* add the trusted domain if we don't know
about it */
if ( ! d ) {
d = add_trusted_domain ( dom_list [ i ] . domain_name ,
dom_list [ i ] . dns_name ,
& cache_methods ,
& dom_list [ i ] . sid ) ;
}
DEBUG ( 10 , ( " Following trust path for domain %s (%s) \n " ,
d - > name , d - > alt_name ) ) ;
add_trusted_domains ( d ) ;
}
}
TALLOC_FREE ( dom_list ) ;
return ;
}
/*********************************************************************
The process of updating the trusted domain list is a three step
async process :
( a ) ask our domain
( b ) ask the root domain in our forest
( c ) ask the a DC in any Win2003 trusted forests
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-02-10 06:51:19 +03:00
void rescan_trusted_domains ( void )
{
time_t now = time ( NULL ) ;
/* see if the time has come... */
2005-06-09 02:10:34 +04:00
if ( ( now > = last_trustdom_scan ) & &
( ( now - last_trustdom_scan ) < WINBINDD_RESCAN_FREQ ) )
2004-02-10 06:51:19 +03:00
return ;
2008-01-04 22:35:41 +03:00
/* I use to clear the cache here and start over but that
caused problems in child processes that needed the
trust dom list early on . Removing it means we
could have some trusted domains listed that have been
removed from our primary domain ' s DC until a full
restart . This should be ok since I think this is what
Windows does as well . */
2007-05-06 23:17:30 +04:00
/* this will only add new domains we didn't already know about
in the domain_list ( ) */
2004-02-10 06:51:19 +03:00
2005-06-09 02:10:34 +04:00
add_trusted_domains ( find_our_domain ( ) ) ;
2004-02-10 06:51:19 +03:00
last_trustdom_scan = now ;
return ;
}
2005-06-09 02:10:34 +04:00
struct init_child_state {
TALLOC_CTX * mem_ctx ;
struct winbindd_domain * domain ;
struct winbindd_request * request ;
struct winbindd_response * response ;
2007-10-19 04:40:25 +04:00
void ( * continuation ) ( void * private_data , bool success ) ;
2005-06-25 00:25:18 +04:00
void * private_data ;
2005-06-09 02:10:34 +04:00
} ;
2007-10-19 04:40:25 +04:00
static void init_child_recv ( void * private_data , bool success ) ;
static void init_child_getdc_recv ( void * private_data , bool success ) ;
2005-06-09 02:10:34 +04:00
enum winbindd_result init_child_connection ( struct winbindd_domain * domain ,
2005-06-25 00:25:18 +04:00
void ( * continuation ) ( void * private_data ,
2007-10-19 04:40:25 +04:00
bool success ) ,
2005-06-25 00:25:18 +04:00
void * private_data )
2005-06-09 02:10:34 +04:00
{
TALLOC_CTX * mem_ctx ;
struct winbindd_request * request ;
struct winbindd_response * response ;
struct init_child_state * state ;
2006-02-04 01:19:41 +03:00
struct winbindd_domain * request_domain ;
2005-06-09 02:10:34 +04:00
mem_ctx = talloc_init ( " init_child_connection " ) ;
if ( mem_ctx = = NULL ) {
DEBUG ( 0 , ( " talloc_init failed \n " ) ) ;
return WINBINDD_ERROR ;
}
request = TALLOC_ZERO_P ( mem_ctx , struct winbindd_request ) ;
response = TALLOC_P ( mem_ctx , struct winbindd_response ) ;
state = TALLOC_P ( mem_ctx , struct init_child_state ) ;
if ( ( request = = NULL ) | | ( response = = NULL ) | | ( state = = NULL ) ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
2006-10-04 20:33:42 +04:00
TALLOC_FREE ( mem_ctx ) ;
2005-06-25 00:25:18 +04:00
continuation ( private_data , False ) ;
2005-06-09 02:10:34 +04:00
return WINBINDD_ERROR ;
}
request - > length = sizeof ( * request ) ;
state - > mem_ctx = mem_ctx ;
state - > domain = domain ;
state - > request = request ;
state - > response = response ;
state - > continuation = continuation ;
2005-06-25 00:25:18 +04:00
state - > private_data = private_data ;
2005-06-09 02:10:34 +04:00
2007-05-07 00:16:12 +04:00
if ( IS_DC | | domain - > primary | | domain - > internal ) {
2005-06-09 02:10:34 +04:00
/* The primary domain has to find the DC name itself */
request - > cmd = WINBINDD_INIT_CONNECTION ;
fstrcpy ( request - > domain_name , domain - > name ) ;
2008-01-25 00:47:49 +03:00
request - > data . init_conn . is_primary = domain - > primary ? true : false ;
2005-06-09 02:10:34 +04:00
fstrcpy ( request - > data . init_conn . dcname , " " ) ;
async_request ( mem_ctx , & domain - > child , request , response ,
init_child_recv , state ) ;
return WINBINDD_PENDING ;
}
/* This is *not* the primary domain, let's ask our DC about a DC
* name */
request - > cmd = WINBINDD_GETDCNAME ;
fstrcpy ( request - > domain_name , domain - > name ) ;
2006-02-04 01:19:41 +03:00
request_domain = find_our_domain ( ) ;
async_domain_request ( mem_ctx , request_domain , request , response ,
2005-06-09 02:10:34 +04:00
init_child_getdc_recv , state ) ;
return WINBINDD_PENDING ;
}
2007-10-19 04:40:25 +04:00
static void init_child_getdc_recv ( void * private_data , bool success )
2005-06-09 02:10:34 +04:00
{
struct init_child_state * state =
2005-06-25 00:25:18 +04:00
talloc_get_type_abort ( private_data , struct init_child_state ) ;
2005-06-09 02:10:34 +04:00
const char * dcname = " " ;
DEBUG ( 10 , ( " Received getdcname response \n " ) ) ;
if ( success & & ( state - > response - > result = = WINBINDD_OK ) ) {
dcname = state - > response - > data . dc_name ;
}
state - > request - > cmd = WINBINDD_INIT_CONNECTION ;
fstrcpy ( state - > request - > domain_name , state - > domain - > name ) ;
state - > request - > data . init_conn . is_primary = False ;
fstrcpy ( state - > request - > data . init_conn . dcname , dcname ) ;
async_request ( state - > mem_ctx , & state - > domain - > child ,
state - > request , state - > response ,
init_child_recv , state ) ;
}
2007-10-19 04:40:25 +04:00
static void init_child_recv ( void * private_data , bool success )
2005-06-09 02:10:34 +04:00
{
struct init_child_state * state =
2005-06-25 00:25:18 +04:00
talloc_get_type_abort ( private_data , struct init_child_state ) ;
2005-06-09 02:10:34 +04:00
DEBUG ( 5 , ( " Received child initialization response for domain %s \n " ,
state - > domain - > name ) ) ;
if ( ( ! success ) | | ( state - > response - > result ! = WINBINDD_OK ) ) {
DEBUG ( 3 , ( " Could not init child \n " ) ) ;
2005-06-25 00:25:18 +04:00
state - > continuation ( state - > private_data , False ) ;
2005-06-09 02:10:34 +04:00
talloc_destroy ( state - > mem_ctx ) ;
return ;
}
fstrcpy ( state - > domain - > name ,
state - > response - > data . domain_info . name ) ;
fstrcpy ( state - > domain - > alt_name ,
state - > response - > data . domain_info . alt_name ) ;
string_to_sid ( & state - > domain - > sid ,
state - > response - > data . domain_info . sid ) ;
state - > domain - > native_mode =
state - > response - > data . domain_info . native_mode ;
state - > domain - > active_directory =
state - > response - > data . domain_info . active_directory ;
2006-12-20 07:50:46 +03:00
init_dc_connection ( state - > domain ) ;
2005-06-09 02:10:34 +04:00
if ( state - > continuation ! = NULL )
2005-06-25 00:25:18 +04:00
state - > continuation ( state - > private_data , True ) ;
2005-06-09 02:10:34 +04:00
talloc_destroy ( state - > mem_ctx ) ;
}
enum winbindd_result winbindd_dual_init_connection ( struct winbindd_domain * domain ,
struct winbindd_cli_state * state )
{
/* Ensure null termination */
state - > request . domain_name
[ sizeof ( state - > request . domain_name ) - 1 ] = ' \0 ' ;
state - > request . data . init_conn . dcname
[ sizeof ( state - > request . data . init_conn . dcname ) - 1 ] = ' \0 ' ;
2005-08-28 13:19:10 +04:00
if ( strlen ( state - > request . data . init_conn . dcname ) > 0 ) {
fstrcpy ( domain - > dcname , state - > request . data . init_conn . dcname ) ;
}
2005-06-09 02:10:34 +04:00
2006-10-06 21:33:57 +04:00
init_dc_connection ( domain ) ;
2005-06-09 02:10:34 +04:00
2006-10-06 21:33:57 +04:00
if ( ! domain - > initialized ) {
/* If we return error here we can't do any cached authentication,
but we may be in disconnected mode and can ' t initialize correctly .
Do what the previous code did and just return without initialization ,
once we go online we ' ll re - initialize .
*/
DEBUG ( 5 , ( " winbindd_dual_init_connection: %s returning without initialization "
" online = %d \n " , domain - > name , ( int ) domain - > online ) ) ;
}
2005-06-09 02:10:34 +04:00
fstrcpy ( state - > response . data . domain_info . name , domain - > name ) ;
fstrcpy ( state - > response . data . domain_info . alt_name , domain - > alt_name ) ;
2007-12-16 00:47:30 +03:00
sid_to_fstring ( state - > response . data . domain_info . sid , & domain - > sid ) ;
2005-06-09 02:10:34 +04:00
state - > response . data . domain_info . native_mode
= domain - > native_mode ;
state - > response . data . domain_info . active_directory
= domain - > active_directory ;
state - > response . data . domain_info . primary
= domain - > primary ;
return WINBINDD_OK ;
}
2002-08-17 21:00:51 +04:00
/* Look up global info for the winbind daemon */
2007-10-19 04:40:25 +04:00
bool init_domain_list ( void )
2000-05-09 15:43:00 +04:00
{
2001-12-10 05:25:19 +03:00
struct winbindd_domain * domain ;
2006-04-02 10:25:11 +04:00
int role = lp_server_role ( ) ;
2001-10-12 12:28:08 +04:00
2002-01-11 08:33:45 +03:00
/* Free existing list */
free_domain_list ( ) ;
2007-09-20 22:37:34 +04:00
/* BUILTIN domain */
domain = add_trusted_domain ( " BUILTIN " , NULL , & passdb_methods ,
& global_sid_Builtin ) ;
if ( domain ) {
2007-10-08 16:25:57 +04:00
setup_domain_child ( domain ,
2007-12-13 14:27:57 +03:00
& domain - > child ) ;
2007-09-20 22:37:34 +04:00
}
/* Local SAM */
domain = add_trusted_domain ( get_global_sam_name ( ) , NULL ,
& passdb_methods , get_global_sam_sid ( ) ) ;
if ( domain ) {
if ( role ! = ROLE_DOMAIN_MEMBER ) {
domain - > primary = True ;
}
2007-10-08 16:25:57 +04:00
setup_domain_child ( domain ,
2007-12-13 14:27:57 +03:00
& domain - > child ) ;
2007-09-20 22:37:34 +04:00
}
2004-01-08 11:19:18 +03:00
/* Add ourselves as the first entry. */
2004-04-20 06:37:49 +04:00
2006-04-02 10:25:11 +04:00
if ( role = = ROLE_DOMAIN_MEMBER ) {
2005-06-09 02:10:34 +04:00
DOM_SID our_sid ;
2003-12-31 08:26:29 +03:00
2005-06-09 02:10:34 +04:00
if ( ! secrets_fetch_domain_sid ( lp_workgroup ( ) , & our_sid ) ) {
2006-03-16 18:21:41 +03:00
DEBUG ( 0 , ( " Could not fetch our SID - did we join? \n " ) ) ;
return False ;
2005-06-09 02:10:34 +04:00
}
2003-08-09 03:53:13 +04:00
2005-06-09 02:10:34 +04:00
domain = add_trusted_domain ( lp_workgroup ( ) , lp_realm ( ) ,
& cache_methods , & our_sid ) ;
2007-07-24 12:59:36 +04:00
if ( domain ) {
domain - > primary = True ;
2007-10-08 16:25:57 +04:00
setup_domain_child ( domain ,
2007-12-13 14:27:57 +03:00
& domain - > child ) ;
2007-10-08 16:25:57 +04:00
2007-07-24 12:59:36 +04:00
/* Even in the parent winbindd we'll need to
talk to the DC , so try and see if we can
contact it . Theoretically this isn ' t neccessary
as the init_dc_connection ( ) in init_child_recv ( )
will do this , but we can start detecting the DC
early here . */
set_domain_online_request ( domain ) ;
}
2001-12-10 05:25:19 +03:00
}
2003-01-16 02:32:47 +03:00
2006-03-16 14:32:01 +03:00
return True ;
2000-05-09 15:43:00 +04:00
}
2007-05-07 00:16:12 +04:00
void check_domain_trusted ( const char * name , const DOM_SID * user_sid )
{
struct winbindd_domain * domain ;
DOM_SID dom_sid ;
uint32 rid ;
domain = find_domain_from_name_noinit ( name ) ;
if ( domain )
return ;
sid_copy ( & dom_sid , user_sid ) ;
if ( ! sid_split_rid ( & dom_sid , & rid ) )
return ;
/* add the newly discovered trusted domain */
domain = add_trusted_domain ( name , NULL , & cache_methods ,
& dom_sid ) ;
if ( ! domain )
return ;
/* assume this is a trust from a one-way transitive
forest trust */
domain - > active_directory = True ;
2008-01-29 19:49:38 +03:00
domain - > domain_flags = NETR_TRUST_FLAG_OUTBOUND ;
domain - > domain_type = NETR_TRUST_TYPE_UPLEVEL ;
2007-05-07 00:16:12 +04:00
domain - > internal = False ;
domain - > online = True ;
2007-10-08 16:25:57 +04:00
setup_domain_child ( domain ,
2007-12-13 14:27:57 +03:00
& domain - > child ) ;
2007-05-07 00:16:12 +04:00
wcache_tdc_add_domain ( domain ) ;
return ;
}
2003-12-31 03:31:43 +03:00
/**
* Given a domain name , return the struct winbindd domain info for it
*
* @ note Do * not * pass lp_workgroup ( ) to this function . domain_list
* may modify it ' s value , and free that pointer . Instead , our local
2004-01-05 07:10:28 +03:00
* domain may be found by calling find_our_domain ( ) .
2003-12-31 03:31:43 +03:00
* directly .
*
*
* @ return The domain structure for the named domain , if it is working .
*/
2002-01-11 08:33:45 +03:00
2005-06-09 02:10:34 +04:00
struct winbindd_domain * find_domain_from_name_noinit ( const char * domain_name )
2002-01-11 08:33:45 +03:00
{
struct winbindd_domain * domain ;
/* Search through list */
for ( domain = domain_list ( ) ; domain ! = NULL ; domain = domain - > next ) {
if ( strequal ( domain_name , domain - > name ) | |
2005-06-09 02:10:34 +04:00
( domain - > alt_name [ 0 ] & &
strequal ( domain_name , domain - > alt_name ) ) ) {
2002-01-11 08:33:45 +03:00
return domain ;
2003-12-31 03:31:43 +03:00
}
2002-01-11 08:33:45 +03:00
}
/* Not found */
return NULL ;
}
2005-06-09 02:10:34 +04:00
struct winbindd_domain * find_domain_from_name ( const char * domain_name )
{
struct winbindd_domain * domain ;
domain = find_domain_from_name_noinit ( domain_name ) ;
if ( domain = = NULL )
return NULL ;
if ( ! domain - > initialized )
2006-10-06 21:33:57 +04:00
init_dc_connection ( domain ) ;
2005-06-09 02:10:34 +04:00
return domain ;
}
2002-01-11 08:33:45 +03:00
/* Given a domain sid, return the struct winbindd domain info for it */
2005-06-09 02:10:34 +04:00
struct winbindd_domain * find_domain_from_sid_noinit ( const DOM_SID * sid )
2002-01-11 08:33:45 +03:00
{
struct winbindd_domain * domain ;
/* Search through list */
for ( domain = domain_list ( ) ; domain ! = NULL ; domain = domain - > next ) {
2007-03-22 00:08:15 +03:00
if ( sid_compare_domain ( sid , & domain - > sid ) = = 0 )
2002-01-11 08:33:45 +03:00
return domain ;
}
/* Not found */
return NULL ;
}
2000-05-09 15:43:00 +04:00
2003-12-31 08:26:29 +03:00
/* Given a domain sid, return the struct winbindd domain info for it */
2005-06-09 02:10:34 +04:00
struct winbindd_domain * find_domain_from_sid ( const DOM_SID * sid )
{
struct winbindd_domain * domain ;
domain = find_domain_from_sid_noinit ( sid ) ;
if ( domain = = NULL )
return NULL ;
if ( ! domain - > initialized )
2006-10-06 21:33:57 +04:00
init_dc_connection ( domain ) ;
2005-06-09 02:10:34 +04:00
return domain ;
}
2004-01-05 19:58:37 +03:00
struct winbindd_domain * find_our_domain ( void )
2003-12-31 08:26:29 +03:00
{
struct winbindd_domain * domain ;
/* Search through list */
for ( domain = domain_list ( ) ; domain ! = NULL ; domain = domain - > next ) {
if ( domain - > primary )
return domain ;
}
2007-06-16 01:58:49 +04:00
smb_panic ( " Could not find our domain " ) ;
2003-12-31 08:26:29 +03:00
return NULL ;
}
2007-01-03 00:48:47 +03:00
struct winbindd_domain * find_root_domain ( void )
{
struct winbindd_domain * ours = find_our_domain ( ) ;
if ( ! ours )
return NULL ;
if ( strlen ( ours - > forest_name ) = = 0 )
return NULL ;
return find_domain_from_name ( ours - > forest_name ) ;
}
2005-06-09 02:10:34 +04:00
struct winbindd_domain * find_builtin_domain ( void )
{
DOM_SID sid ;
struct winbindd_domain * domain ;
string_to_sid ( & sid , " S-1-5-32 " ) ;
domain = find_domain_from_sid ( & sid ) ;
2007-06-16 01:58:49 +04:00
if ( domain = = NULL ) {
smb_panic ( " Could not find BUILTIN domain " ) ;
}
2005-06-09 02:10:34 +04:00
return domain ;
}
2004-04-20 06:37:49 +04:00
/* Find the appropriate domain to lookup a name or SID */
struct winbindd_domain * find_lookup_domain_from_sid ( const DOM_SID * sid )
{
2007-05-22 01:33:51 +04:00
/* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
if ( sid_check_is_in_unix_groups ( sid ) | |
sid_check_is_unix_groups ( sid ) | |
sid_check_is_in_unix_users ( sid ) | |
sid_check_is_unix_users ( sid ) )
{
return find_domain_from_sid ( get_global_sam_sid ( ) ) ;
}
2004-04-20 06:37:49 +04:00
/* A DC can't ask the local smbd for remote SIDs, here winbindd is the
* one to contact the external DC ' s . On member servers the internal
* domains are different : These are part of the local SAM . */
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " find_lookup_domain_from_sid(%s) \n " , sid_string_dbg ( sid ) ) ) ;
2005-12-08 22:34:22 +03:00
if ( IS_DC | | is_internal_domain ( sid ) | | is_in_internal_domain ( sid ) ) {
DEBUG ( 10 , ( " calling find_domain_from_sid \n " ) ) ;
2004-04-20 06:37:49 +04:00
return find_domain_from_sid ( sid ) ;
2007-05-22 01:33:51 +04:00
}
2007-05-22 00:36:22 +04:00
2004-04-20 06:37:49 +04:00
/* On a member server a query for SID or name can always go to our
* primary DC . */
2005-12-08 22:34:22 +03:00
DEBUG ( 10 , ( " calling find_our_domain \n " ) ) ;
2004-04-20 06:37:49 +04:00
return find_our_domain ( ) ;
}
struct winbindd_domain * find_lookup_domain_from_name ( const char * domain_name )
{
2007-05-22 00:36:22 +04:00
if ( strequal ( domain_name , unix_users_domain_name ( ) ) | |
strequal ( domain_name , unix_groups_domain_name ( ) ) )
{
return find_domain_from_name_noinit ( get_global_sam_name ( ) ) ;
}
2007-05-22 01:33:51 +04:00
if ( IS_DC | | strequal ( domain_name , " BUILTIN " ) | |
strequal ( domain_name , get_global_sam_name ( ) ) )
return find_domain_from_name_noinit ( domain_name ) ;
/* The "Unix User" and "Unix Group" domain our handled by passdb */
2004-04-20 06:37:49 +04:00
return find_our_domain ( ) ;
}
2001-12-10 05:25:19 +03:00
/* Lookup a sid in a domain from a name */
2002-01-11 08:33:45 +03:00
2007-10-19 04:40:25 +04:00
bool winbindd_lookup_sid_by_name ( TALLOC_CTX * mem_ctx ,
2007-05-30 23:47:35 +04:00
enum winbindd_cmd orig_cmd ,
2005-06-09 02:10:34 +04:00
struct winbindd_domain * domain ,
2004-04-20 06:37:49 +04:00
const char * domain_name ,
2002-01-11 08:33:45 +03:00
const char * name , DOM_SID * sid ,
2006-09-08 18:28:06 +04:00
enum lsa_SidType * type )
2000-05-09 15:43:00 +04:00
{
2001-11-21 12:59:15 +03:00
NTSTATUS result ;
2001-10-12 12:28:08 +04:00
2001-11-21 12:59:15 +03:00
/* Lookup name */
2007-05-30 23:47:35 +04:00
result = domain - > methods - > name_to_sid ( domain , mem_ctx , orig_cmd ,
domain_name , name , sid , type ) ;
2003-04-23 15:54:56 +04:00
2007-02-13 13:42:53 +03:00
/* Return sid and type if lookup successful */
2001-12-10 02:59:42 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2001-11-23 12:04:09 +03:00
* type = SID_NAME_UNKNOWN ;
2001-11-21 12:59:15 +03:00
}
2001-10-12 12:28:08 +04:00
2001-12-03 11:17:46 +03:00
return NT_STATUS_IS_OK ( result ) ;
2001-11-21 12:59:15 +03:00
}
2001-11-23 06:54:07 +03:00
/**
* @ brief Lookup a name in a domain from a sid .
*
* @ param sid Security ID you want to look up .
* @ param name On success , set to the name corresponding to @ p sid .
2002-01-20 04:24:59 +03:00
* @ param dom_name On success , set to the ' domain name ' corresponding to @ p sid .
2001-11-23 06:54:07 +03:00
* @ param type On success , contains the type of name : alias , group or
* user .
* @ retval True if the name exists , in which case @ p name and @ p type
* are set , otherwise False .
* */
2007-10-19 04:40:25 +04:00
bool winbindd_lookup_name_by_sid ( TALLOC_CTX * mem_ctx ,
2007-05-06 23:01:54 +04:00
struct winbindd_domain * domain ,
2005-06-09 02:10:34 +04:00
DOM_SID * sid ,
2006-12-12 17:52:13 +03:00
char * * dom_name ,
char * * name ,
2006-09-08 18:28:06 +04:00
enum lsa_SidType * type )
2000-05-09 15:43:00 +04:00
{
2001-11-21 12:59:15 +03:00
NTSTATUS result ;
2001-10-12 12:28:08 +04:00
2006-12-13 19:39:50 +03:00
* dom_name = NULL ;
* name = NULL ;
2001-11-21 12:59:15 +03:00
/* Lookup name */
2006-12-12 17:52:13 +03:00
result = domain - > methods - > sid_to_name ( domain , mem_ctx , sid , dom_name , name , type ) ;
2000-05-09 15:43:00 +04:00
2001-11-21 12:59:15 +03:00
/* Return name and type if successful */
2001-10-05 04:20:06 +04:00
2006-12-12 17:52:13 +03:00
if ( NT_STATUS_IS_OK ( result ) ) {
return True ;
2001-11-21 12:59:15 +03:00
}
2006-12-12 17:52:13 +03:00
* type = SID_NAME_UNKNOWN ;
2001-10-05 04:20:06 +04:00
2006-12-12 17:52:13 +03:00
return False ;
2000-05-09 15:43:00 +04:00
}
/* Free state information held for {set,get,end}{pw,gr}ent() functions */
void free_getent_state ( struct getent_state * state )
{
2001-11-22 11:31:50 +03:00
struct getent_state * temp ;
2000-05-09 15:43:00 +04:00
2001-11-22 11:31:50 +03:00
/* Iterate over state list */
2000-05-09 15:43:00 +04:00
2001-11-22 11:31:50 +03:00
temp = state ;
2000-05-09 15:43:00 +04:00
2001-11-22 11:31:50 +03:00
while ( temp ! = NULL ) {
struct getent_state * next ;
2000-05-09 15:43:00 +04:00
2001-11-22 11:31:50 +03:00
/* Free sam entries then list entry */
2000-05-09 15:43:00 +04:00
2001-11-22 11:31:50 +03:00
SAFE_FREE ( state - > sam_entries ) ;
DLIST_REMOVE ( state , state ) ;
next = temp - > next ;
2000-05-09 15:43:00 +04:00
2001-11-22 11:31:50 +03:00
SAFE_FREE ( temp ) ;
temp = next ;
}
2000-05-09 15:43:00 +04:00
}
2003-12-31 03:31:43 +03:00
/* Is this a domain which we may assume no DOMAIN\ prefix? */
2007-10-19 04:40:25 +04:00
static bool assume_domain ( const char * domain )
2006-07-20 22:02:51 +04:00
{
/* never assume the domain on a standalone server */
if ( lp_server_role ( ) = = ROLE_STANDALONE )
return False ;
/* domain member servers may possibly assume for the domain name */
if ( lp_server_role ( ) = = ROLE_DOMAIN_MEMBER ) {
if ( ! strequal ( lp_workgroup ( ) , domain ) )
return False ;
if ( lp_winbind_use_default_domain ( ) | | lp_winbind_trusted_domains_only ( ) )
return True ;
}
/* only left with a domain controller */
2003-12-31 03:31:43 +03:00
2006-07-20 22:02:51 +04:00
if ( strequal ( get_global_sam_name ( ) , domain ) ) {
2003-12-31 03:31:43 +03:00
return True ;
2006-07-20 22:02:51 +04:00
}
2003-12-31 03:31:43 +03:00
return False ;
}
2005-09-16 17:01:25 +04:00
/* Parse a string of the form DOMAIN\user into a domain and a user */
2001-05-07 08:32:40 +04:00
2007-10-19 04:40:25 +04:00
bool parse_domain_user ( const char * domuser , fstring domain , fstring user )
2001-05-07 08:32:40 +04:00
{
2001-12-05 07:17:39 +03:00
char * p = strchr ( domuser , * lp_winbind_separator ( ) ) ;
2001-10-14 12:31:54 +04:00
2003-07-09 20:44:47 +04:00
if ( ! p ) {
2002-01-18 05:37:55 +03:00
fstrcpy ( user , domuser ) ;
2006-07-20 22:02:51 +04:00
2003-12-31 03:31:43 +03:00
if ( assume_domain ( lp_workgroup ( ) ) ) {
2003-07-09 20:44:47 +04:00
fstrcpy ( domain , lp_workgroup ( ) ) ;
2007-08-28 00:09:37 +04:00
} else if ( ( p = strchr ( domuser , ' @ ' ) ) ! = NULL ) {
fstrcpy ( domain , " " ) ;
2003-12-31 03:31:43 +03:00
} else {
2006-02-13 18:12:22 +03:00
return False ;
2003-12-31 03:31:43 +03:00
}
2006-02-13 18:12:22 +03:00
} else {
2002-01-18 05:37:55 +03:00
fstrcpy ( user , p + 1 ) ;
fstrcpy ( domain , domuser ) ;
domain [ PTR_DIFF ( p , domuser ) ] = 0 ;
}
2003-07-09 20:44:47 +04:00
2003-07-03 23:11:31 +04:00
strupper_m ( domain ) ;
2003-07-09 20:44:47 +04:00
2001-12-05 07:17:39 +03:00
return True ;
2001-05-07 08:32:40 +04:00
}
2002-01-18 05:37:55 +03:00
2007-10-19 04:40:25 +04:00
bool parse_domain_user_talloc ( TALLOC_CTX * mem_ctx , const char * domuser ,
2005-06-09 02:10:34 +04:00
char * * domain , char * * user )
{
fstring fstr_domain , fstr_user ;
2006-02-13 18:12:22 +03:00
if ( ! parse_domain_user ( domuser , fstr_domain , fstr_user ) ) {
return False ;
}
2005-06-09 02:10:34 +04:00
* domain = talloc_strdup ( mem_ctx , fstr_domain ) ;
* user = talloc_strdup ( mem_ctx , fstr_user ) ;
return ( ( * domain ! = NULL ) & & ( * user ! = NULL ) ) ;
}
2006-10-09 23:20:21 +04:00
/* Ensure an incoming username from NSS is fully qualified. Replace the
incoming fstring with DOMAIN < separator > user . Returns the same
values as parse_domain_user ( ) but also replaces the incoming username .
Used to ensure all names are fully qualified within winbindd .
Used by the NSS protocols of auth , chauthtok , logoff and ccache_ntlm_auth .
The protocol definitions of auth_crap , chng_pswd_auth_crap
really should be changed to use this instead of doing things
by hand . JRA . */
2007-10-19 04:40:25 +04:00
bool canonicalize_username ( fstring username_inout , fstring domain , fstring user )
2006-10-09 23:20:21 +04:00
{
if ( ! parse_domain_user ( username_inout , domain , user ) ) {
return False ;
}
slprintf ( username_inout , sizeof ( fstring ) - 1 , " %s%c%s " ,
domain , * lp_winbind_separator ( ) ,
user ) ;
return True ;
}
2002-01-18 05:37:55 +03:00
/*
Fill DOMAIN \ \ USERNAME entry accounting ' winbind use default domain ' and
' winbind separator ' options .
This means :
- omit DOMAIN when ' winbind use default domain = true ' and DOMAIN is
2003-12-31 03:31:43 +03:00
lp_workgroup ( )
If we are a PDC or BDC , and this is for our domain , do likewise .
Also , if omit DOMAIN if ' winbind trusted domains only = true ' , as the
username is then unqualified in unix
2006-09-14 13:58:20 +04:00
We always canonicalize as UPPERCASE DOMAIN , lowercase username .
2002-01-18 05:37:55 +03:00
*/
2007-10-19 04:40:25 +04:00
void fill_domain_username ( fstring name , const char * domain , const char * user , bool can_assume )
2002-01-18 05:37:55 +03:00
{
2005-06-09 02:10:34 +04:00
fstring tmp_user ;
fstrcpy ( tmp_user , user ) ;
2005-09-16 20:37:45 +04:00
strlower_m ( tmp_user ) ;
2004-10-23 00:15:24 +04:00
2006-03-15 03:10:38 +03:00
if ( can_assume & & assume_domain ( domain ) ) {
2006-09-14 13:58:20 +04:00
strlcpy ( name , tmp_user , sizeof ( fstring ) ) ;
2002-01-18 05:37:55 +03:00
} else {
2004-10-23 00:15:24 +04:00
slprintf ( name , sizeof ( fstring ) - 1 , " %s%c%s " ,
domain , * lp_winbind_separator ( ) ,
2005-06-09 02:10:34 +04:00
tmp_user ) ;
2002-01-18 05:37:55 +03:00
}
}
2002-11-02 04:36:42 +03:00
/*
* Winbindd socket accessor functions
*/
2007-09-19 21:19:57 +04:00
const char * get_winbind_pipe_dir ( void )
{
return lp_parm_const_string ( - 1 , " winbindd " , " socket dir " , WINBINDD_SOCKET_DIR ) ;
}
2003-03-24 12:54:13 +03:00
char * get_winbind_priv_pipe_dir ( void )
{
return lock_path ( WINBINDD_PRIV_SOCKET_SUBDIR ) ;
}
2007-10-11 00:34:30 +04:00
/* Open the winbindd socket */
static int _winbindd_socket = - 1 ;
static int _winbindd_priv_socket = - 1 ;
int open_winbindd_socket ( void )
{
if ( _winbindd_socket = = - 1 ) {
_winbindd_socket = create_pipe_sock (
get_winbind_pipe_dir ( ) , WINBINDD_SOCKET_NAME , 0755 ) ;
DEBUG ( 10 , ( " open_winbindd_socket: opened socket fd %d \n " ,
_winbindd_socket ) ) ;
}
return _winbindd_socket ;
}
int open_winbindd_priv_socket ( void )
{
if ( _winbindd_priv_socket = = - 1 ) {
_winbindd_priv_socket = create_pipe_sock (
get_winbind_priv_pipe_dir ( ) , WINBINDD_SOCKET_NAME , 0750 ) ;
DEBUG ( 10 , ( " open_winbindd_priv_socket: opened socket fd %d \n " ,
_winbindd_priv_socket ) ) ;
}
return _winbindd_priv_socket ;
}
/* Close the winbindd socket */
void close_winbindd_socket ( void )
{
if ( _winbindd_socket ! = - 1 ) {
DEBUG ( 10 , ( " close_winbindd_socket: closing socket fd %d \n " ,
_winbindd_socket ) ) ;
close ( _winbindd_socket ) ;
_winbindd_socket = - 1 ;
}
if ( _winbindd_priv_socket ! = - 1 ) {
DEBUG ( 10 , ( " close_winbindd_socket: closing socket fd %d \n " ,
_winbindd_priv_socket ) ) ;
close ( _winbindd_priv_socket ) ;
_winbindd_priv_socket = - 1 ;
}
}
2002-11-02 04:36:42 +03:00
/*
* Client list accessor functions
*/
static struct winbindd_cli_state * _client_list ;
static int _num_clients ;
/* Return list of all connected clients */
struct winbindd_cli_state * winbindd_client_list ( void )
{
return _client_list ;
}
/* Add a connection to the list */
void winbindd_add_client ( struct winbindd_cli_state * cli )
{
DLIST_ADD ( _client_list , cli ) ;
_num_clients + + ;
}
/* Remove a client from the list */
void winbindd_remove_client ( struct winbindd_cli_state * cli )
{
DLIST_REMOVE ( _client_list , cli ) ;
_num_clients - - ;
}
/* Close all open clients */
void winbindd_kill_all_clients ( void )
{
struct winbindd_cli_state * cl = winbindd_client_list ( ) ;
DEBUG ( 10 , ( " winbindd_kill_all_clients: going postal \n " ) ) ;
while ( cl ) {
struct winbindd_cli_state * next ;
next = cl - > next ;
winbindd_remove_client ( cl ) ;
cl = next ;
}
}
/* Return number of open clients */
int winbindd_num_clients ( void )
{
return _num_clients ;
}
2003-04-23 15:54:56 +04:00
2006-04-28 18:48:22 +04:00
NTSTATUS lookup_usergroups_cached ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
const DOM_SID * user_sid ,
uint32 * p_num_groups , DOM_SID * * user_sids )
{
2008-02-17 04:08:12 +03:00
struct netr_SamInfo3 * info3 = NULL ;
2006-04-28 18:48:22 +04:00
NTSTATUS status = NT_STATUS_NO_MEMORY ;
size_t num_groups = 0 ;
2008-04-04 04:53:40 +04:00
2006-04-28 18:48:22 +04:00
DEBUG ( 3 , ( " : lookup_usergroups_cached \n " ) ) ;
2008-04-04 04:53:40 +04:00
2006-04-28 18:48:22 +04:00
* user_sids = NULL ;
2006-05-18 23:34:25 +04:00
* p_num_groups = 0 ;
2006-04-28 18:48:22 +04:00
info3 = netsamlogon_cache_get ( mem_ctx , user_sid ) ;
if ( info3 = = NULL ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2008-02-17 04:08:12 +03:00
if ( info3 - > base . groups . count = = 0 ) {
2007-05-03 16:29:32 +04:00
TALLOC_FREE ( info3 ) ;
2006-04-28 18:48:22 +04:00
return NT_STATUS_UNSUCCESSFUL ;
}
2008-04-04 04:53:40 +04:00
/* Skip Domain local groups outside our domain.
We ' ll get these from the getsidaliases ( ) RPC call . */
status = sid_array_from_info3 ( mem_ctx , info3 ,
user_sids ,
& num_groups ,
true , true ) ;
2008-01-09 02:11:31 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-05-03 16:29:32 +04:00
TALLOC_FREE ( info3 ) ;
2008-01-09 02:11:31 +03:00
return status ;
2006-12-09 05:58:18 +03:00
}
2006-04-28 18:48:22 +04:00
2007-05-03 16:29:32 +04:00
TALLOC_FREE ( info3 ) ;
2006-04-28 18:48:22 +04:00
* p_num_groups = num_groups ;
status = ( user_sids ! = NULL ) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY ;
2006-05-18 23:34:25 +04:00
DEBUG ( 3 , ( " : lookup_usergroups_cached succeeded \n " ) ) ;
2006-04-28 18:48:22 +04:00
return status ;
}
2007-01-31 08:38:36 +03:00
/*********************************************************************
We use this to remove spaces from user and group names
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void ws_name_replace ( char * name , char replace )
{
char replace_char [ 2 ] = { 0x0 , 0x0 } ;
if ( ! lp_winbind_normalize_names ( ) | | ( replace = = ' \0 ' ) )
return ;
replace_char [ 0 ] = replace ;
all_string_sub ( name , " " , replace_char , 0 ) ;
return ;
}
/*********************************************************************
We use this to do the inverse of ws_name_replace ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void ws_name_return ( char * name , char replace )
{
char replace_char [ 2 ] = { 0x0 , 0x0 } ;
if ( ! lp_winbind_normalize_names ( ) | | ( replace = = ' \0 ' ) )
return ;
replace_char [ 0 ] = replace ;
all_string_sub ( name , replace_char , " " , 0 ) ;
return ;
}
2007-05-06 23:37:13 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-01-25 21:21:14 +03:00
bool winbindd_can_contact_domain ( struct winbindd_domain * domain )
2007-05-06 23:37:13 +04:00
{
2008-01-25 21:21:14 +03:00
struct winbindd_tdc_domain * tdc = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
bool ret = false ;
2007-05-06 23:37:13 +04:00
/* We can contact the domain if it is our primary domain */
2008-01-25 21:21:14 +03:00
if ( domain - > primary ) {
return true ;
}
2007-05-06 23:37:13 +04:00
2008-01-25 21:21:14 +03:00
/* Trust the TDC cache and not the winbindd_domain flags */
2007-05-06 23:37:13 +04:00
2008-01-25 21:21:14 +03:00
if ( ( tdc = wcache_tdc_fetch_domain ( frame , domain - > name ) ) = = NULL ) {
DEBUG ( 10 , ( " winbindd_can_contact_domain: %s not found in cache \n " ,
domain - > name ) ) ;
return false ;
}
2007-05-06 23:37:13 +04:00
2008-01-25 21:21:14 +03:00
/* Can always contact a domain that is in out forest */
2007-05-06 23:37:13 +04:00
2008-01-29 19:49:38 +03:00
if ( tdc - > trust_flags & NETR_TRUST_FLAG_IN_FOREST ) {
2008-01-25 21:21:14 +03:00
ret = true ;
goto done ;
2007-05-06 23:37:13 +04:00
}
2008-01-25 18:40:17 +03:00
/*
* On a _member_ server , we cannot contact the domain if it
* is running AD and we have no inbound trust .
*/
2007-05-06 23:37:13 +04:00
2008-01-25 21:21:14 +03:00
if ( ! IS_DC & &
2008-01-25 18:40:17 +03:00
domain - > active_directory & &
2008-01-29 19:49:38 +03:00
( ( tdc - > trust_flags & NETR_TRUST_FLAG_INBOUND ) ! = NETR_TRUST_FLAG_INBOUND ) )
2007-05-06 23:37:13 +04:00
{
2008-01-25 21:21:14 +03:00
DEBUG ( 10 , ( " winbindd_can_contact_domain: %s is an AD domain "
" and we have no inbound trust. \n " , domain - > name ) ) ;
goto done ;
2007-05-06 23:37:13 +04:00
}
2008-01-25 21:21:14 +03:00
2007-05-06 23:37:13 +04:00
/* Assume everything else is ok (probably not true but what
can you do ? ) */
2008-01-25 21:21:14 +03:00
ret = true ;
done :
talloc_destroy ( frame ) ;
2007-05-06 23:37:13 +04:00
2008-01-25 21:21:14 +03:00
return ret ;
2007-05-06 23:37:13 +04:00
}
2007-08-29 16:43:23 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool winbindd_internal_child ( struct winbindd_child * child )
2007-08-29 16:43:23 +04:00
{
2007-08-29 18:35:32 +04:00
if ( ( child = = idmap_child ( ) ) | | ( child = = locator_child ( ) ) ) {
2007-08-29 16:43:23 +04:00
return True ;
}
return False ;
}
2007-08-30 20:24:51 +04:00
2007-09-04 18:06:33 +04:00
# ifdef HAVE_KRB5_LOCATE_PLUGIN_H
2007-08-30 20:24:51 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-09-04 18:06:33 +04:00
static void winbindd_set_locator_kdc_env ( const struct winbindd_domain * domain )
2007-08-30 20:24:51 +04:00
{
char * var = NULL ;
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
2007-08-30 20:24:51 +04:00
const char * kdc = NULL ;
2007-09-04 18:06:33 +04:00
int lvl = 11 ;
if ( ! domain | | ! domain - > alt_name | | ! * domain - > alt_name ) {
return ;
}
2007-08-30 20:24:51 +04:00
2007-09-04 18:06:33 +04:00
if ( domain - > initialized & & ! domain - > active_directory ) {
DEBUG ( lvl , ( " winbindd_set_locator_kdc_env: %s not AD \n " ,
domain - > alt_name ) ) ;
2007-08-30 20:24:51 +04:00
return ;
}
2007-10-25 01:16:54 +04:00
print_sockaddr ( addr , sizeof ( addr ) , & domain - > dcaddr ) ;
kdc = addr ;
if ( ! * kdc ) {
2007-09-04 18:06:33 +04:00
DEBUG ( lvl , ( " winbindd_set_locator_kdc_env: %s no DC IP \n " ,
domain - > alt_name ) ) ;
2007-08-30 20:24:51 +04:00
kdc = domain - > dcname ;
}
if ( ! kdc | | ! * kdc ) {
2007-09-04 18:06:33 +04:00
DEBUG ( lvl , ( " winbindd_set_locator_kdc_env: %s no DC at all \n " ,
domain - > alt_name ) ) ;
2007-08-30 20:24:51 +04:00
return ;
}
2007-11-24 19:27:54 +03:00
if ( asprintf_strupper_m ( & var , " %s_%s " , WINBINDD_LOCATOR_KDC_ADDRESS ,
domain - > alt_name ) = = - 1 ) {
2007-08-30 20:24:51 +04:00
return ;
}
2007-09-04 18:06:33 +04:00
DEBUG ( lvl , ( " winbindd_set_locator_kdc_env: setting var: %s to: %s \n " ,
2007-08-30 20:24:51 +04:00
var , kdc ) ) ;
setenv ( var , kdc , 1 ) ;
free ( var ) ;
}
2007-09-04 18:06:33 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void winbindd_set_locator_kdc_envs ( const struct winbindd_domain * domain )
{
struct winbindd_domain * our_dom = find_our_domain ( ) ;
winbindd_set_locator_kdc_env ( domain ) ;
if ( domain ! = our_dom ) {
winbindd_set_locator_kdc_env ( our_dom ) ;
}
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void winbindd_unset_locator_kdc_env ( const struct winbindd_domain * domain )
{
char * var = NULL ;
if ( ! domain | | ! domain - > alt_name | | ! * domain - > alt_name ) {
return ;
}
2007-11-24 19:27:54 +03:00
if ( asprintf_strupper_m ( & var , " %s_%s " , WINBINDD_LOCATOR_KDC_ADDRESS ,
domain - > alt_name ) = = - 1 ) {
2007-09-04 18:06:33 +04:00
return ;
}
unsetenv ( var ) ;
free ( var ) ;
}
2007-09-04 18:32:28 +04:00
# else
void winbindd_set_locator_kdc_envs ( const struct winbindd_domain * domain )
{
return ;
}
void winbindd_unset_locator_kdc_env ( const struct winbindd_domain * domain )
{
return ;
}
2007-09-04 18:06:33 +04:00
# endif /* HAVE_KRB5_LOCATE_PLUGIN_H */