2009-05-25 13:55:51 +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 >
2009-05-25 13:55:51 +04:00
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 .
2009-05-25 13:55:51 +04:00
2000-05-09 15:43:00 +04: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 .
2009-05-25 13:55:51 +04:00
2000-05-09 15:43:00 +04: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/>.
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"
2016-12-27 15:52:00 +03:00
# include "lib/util_unixsids.h"
2010-08-05 04:25:37 +04:00
# include "secrets.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2011-02-08 12:45:39 +03:00
# include "../libcli/auth/pam_errors.h"
2011-03-22 18:50:02 +03:00
# include "passdb/machine_sid.h"
2014-05-26 03:58:38 +04:00
# include "passdb.h"
2015-01-23 18:59:07 +03:00
# include "source4/lib/messaging/messaging.h"
# include "librpc/gen_ndr/ndr_lsa.h"
2017-11-29 17:55:12 +03:00
# include "librpc/gen_ndr/ndr_drsblobs.h"
2015-06-12 02:57:07 +03:00
# include "auth/credentials/credentials.h"
2016-11-29 18:41:27 +03:00
# include "libsmb/samlogon_cache.h"
2020-07-03 09:11:20 +03:00
# include "lib/util/smb_strtox.h"
2020-08-07 21:17:34 +03:00
# include "lib/util/string_wrappers.h"
2021-01-03 23:53:49 +03:00
# include "lib/global_contexts.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
2001-11-23 06:54:07 +03:00
/**
2015-01-20 10:39:58 +03:00
* @ file winbindd_util . c
2001-11-23 06:54:07 +03:00
*
* Winbind daemon for NT domain authentication nss module .
* */
2018-01-18 13:30:53 +03:00
static bool add_trusted_domains_dc ( void ) ;
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
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
2009-12-28 20:03:14 +03:00
static 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 ;
2009-05-25 13:55:51 +04:00
2002-01-11 08:33:45 +03:00
DLIST_REMOVE ( _domain_list , domain ) ;
2013-02-18 19:36:22 +04:00
TALLOC_FREE ( domain ) ;
2002-01-11 08:33:45 +03:00
domain = next ;
2001-11-21 12:59:15 +03:00
}
}
2015-01-20 12:07:59 +03:00
/**
* Iterator for winbindd ' s domain list .
* To be used ( e . g . ) in tevent based loops .
*/
struct winbindd_domain * wb_next_domain ( struct winbindd_domain * domain )
{
if ( domain = = NULL ) {
domain = domain_list ( ) ;
} else {
domain = domain - > next ;
}
2015-03-28 11:31:05 +03:00
if ( ( domain ! = NULL ) & &
( lp_server_role ( ) ! = ROLE_ACTIVE_DIRECTORY_DC ) & &
sid_check_is_our_sam ( & domain - > sid ) )
{
2015-01-20 12:07:59 +03:00
domain = domain - > next ;
}
2015-03-28 11:31:05 +03:00
2015-01-20 12:07:59 +03:00
return domain ;
}
2010-05-21 05:25:01 +04:00
static bool is_internal_domain ( const struct dom_sid * sid )
2004-04-07 16:43:44 +04:00
{
2004-04-20 06:37:49 +04:00
if ( sid = = NULL )
return False ;
2012-07-12 17:55:21 +04:00
return ( sid_check_is_our_sam ( sid ) | | sid_check_is_builtin ( sid ) ) ;
2004-04-07 16:43:44 +04:00
}
2014-01-07 03:22:59 +04:00
/* Add a trusted domain to our list of domains.
If the domain already exists in the list ,
return it and don ' t re - initialize . */
2017-12-16 13:34:23 +03:00
static NTSTATUS add_trusted_domain ( const char * domain_name ,
const char * dns_name ,
const struct dom_sid * sid ,
uint32_t trust_type ,
uint32_t trust_flags ,
uint32_t trust_attribs ,
2017-11-29 17:10:38 +03:00
enum netr_SchannelType secure_channel_type ,
2018-01-18 10:38:59 +03:00
struct winbindd_domain * routing_domain ,
2017-12-16 13:34:23 +03:00
struct winbindd_domain * * _d )
2000-05-09 15:43:00 +04:00
{
2018-01-10 14:14:57 +03:00
struct winbindd_domain * domain = NULL ;
2014-01-07 03:15:37 +04:00
int role = lp_server_role ( ) ;
2018-12-14 23:09:51 +03:00
struct dom_sid_buf buf ;
2016-02-10 01:26:45 +03:00
if ( is_null_sid ( sid ) ) {
2017-12-15 23:09:15 +03:00
DBG_ERR ( " Got null SID for domain [%s] \n " , domain_name ) ;
2017-12-16 13:34:23 +03:00
return NT_STATUS_INVALID_PARAMETER ;
2016-02-10 01:26:45 +03:00
}
2009-05-12 01:07:24 +04:00
2021-01-11 18:15:15 +03:00
if ( ! is_allowed_domain ( domain_name ) ) {
return NT_STATUS_NO_SUCH_DOMAIN ;
2008-09-17 09:37:54 +04:00
}
2017-12-16 13:34:23 +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 .
*/
2002-01-11 08:33:45 +03:00
for ( domain = _domain_list ; domain ; domain = domain - > next ) {
2017-12-15 23:13:52 +03:00
if ( strequal ( domain_name , domain - > name ) ) {
2009-05-25 13:55:51 +04:00
break ;
2001-11-22 11:31:50 +03:00
}
2017-12-15 23:13:52 +03:00
}
if ( domain ! = NULL ) {
struct winbindd_domain * check_domain = NULL ;
2007-05-06 23:17:30 +04:00
2017-12-15 23:13:52 +03:00
for ( check_domain = _domain_list ;
check_domain ! = NULL ;
check_domain = check_domain - > next )
{
if ( check_domain = = domain ) {
continue ;
}
if ( dom_sid_equal ( & check_domain - > sid , sid ) ) {
2009-05-25 13:55:51 +04:00
break ;
2002-09-25 19:19:00 +04:00
}
}
2007-05-06 23:17:30 +04:00
2017-12-15 23:13:52 +03:00
if ( check_domain ! = NULL ) {
DBG_ERR ( " SID [%s] already used by domain [%s], "
" expected [%s] \n " ,
2018-12-14 23:09:51 +03:00
dom_sid_str_buf ( sid , & buf ) ,
check_domain - > name ,
2017-12-15 23:13:52 +03:00
domain - > name ) ;
2017-12-16 13:34:23 +03:00
return NT_STATUS_INVALID_PARAMETER ;
2017-12-15 23:13:52 +03:00
}
}
2018-01-10 14:14:57 +03:00
if ( ( domain ! = NULL ) & & ( dns_name ! = NULL ) ) {
2017-12-15 23:13:52 +03:00
struct winbindd_domain * check_domain = NULL ;
for ( check_domain = _domain_list ;
check_domain ! = NULL ;
check_domain = check_domain - > next )
{
if ( check_domain = = domain ) {
continue ;
}
2018-01-10 14:14:57 +03:00
if ( strequal ( check_domain - > alt_name , dns_name ) ) {
2017-12-15 23:13:52 +03:00
break ;
}
}
if ( check_domain ! = NULL ) {
DBG_ERR ( " DNS name [%s] used by domain [%s], "
" expected [%s] \n " ,
2018-01-10 14:14:57 +03:00
dns_name , check_domain - > name ,
2017-12-15 23:13:52 +03:00
domain - > name ) ;
2017-12-16 13:34:23 +03:00
return NT_STATUS_INVALID_PARAMETER ;
2004-01-08 11:19:18 +03:00
}
2001-11-22 11:31:50 +03:00
}
2009-05-12 01:07:24 +04:00
2009-12-28 20:11:34 +03:00
if ( domain ! = NULL ) {
2017-12-16 13:34:23 +03:00
* _d = domain ;
return NT_STATUS_OK ;
2009-05-25 13:55:51 +04:00
}
2009-05-12 01:07:24 +04:00
2001-11-22 11:31:50 +03:00
/* Create new domain entry */
2013-02-18 19:36:22 +04:00
domain = talloc_zero ( NULL , struct winbindd_domain ) ;
if ( domain = = NULL ) {
2017-12-16 13:34:23 +03:00
return NT_STATUS_NO_MEMORY ;
2013-02-18 19:36:22 +04:00
}
2000-05-09 15:43:00 +04:00
2013-02-18 19:36:22 +04:00
domain - > children = talloc_zero_array ( domain ,
struct winbindd_child ,
lp_winbind_max_domain_connections ( ) ) ;
2010-04-07 19:45:12 +04:00
if ( domain - > children = = NULL ) {
2013-02-18 19:36:22 +04:00
TALLOC_FREE ( domain ) ;
2017-12-16 13:34:23 +03:00
return NT_STATUS_NO_MEMORY ;
2013-02-18 19:36:22 +04:00
}
2018-02-14 17:04:01 +03:00
domain - > queue = tevent_queue_create ( domain , " winbind_domain " ) ;
if ( domain - > queue = = NULL ) {
TALLOC_FREE ( domain ) ;
return NT_STATUS_NO_MEMORY ;
}
2018-02-13 18:04:44 +03:00
domain - > binding_handle = wbint_binding_handle ( domain , domain , NULL ) ;
if ( domain - > binding_handle = = NULL ) {
TALLOC_FREE ( domain ) ;
return NT_STATUS_NO_MEMORY ;
}
2013-02-18 19:36:22 +04:00
domain - > name = talloc_strdup ( domain , domain_name ) ;
if ( domain - > name = = NULL ) {
TALLOC_FREE ( domain ) ;
2017-12-16 13:34:23 +03:00
return NT_STATUS_NO_MEMORY ;
2010-04-07 19:45:12 +04:00
}
2018-01-10 14:14:57 +03:00
if ( dns_name ! = NULL ) {
domain - > alt_name = talloc_strdup ( domain , dns_name ) ;
2013-02-18 19:36:22 +04:00
if ( domain - > alt_name = = NULL ) {
TALLOC_FREE ( domain ) ;
2017-12-16 13:34:23 +03:00
return NT_STATUS_NO_MEMORY ;
2013-02-18 19:36:22 +04:00
}
2002-08-17 21:00:51 +04:00
}
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 ) ;
2017-11-29 17:10:38 +03:00
domain - > secure_channel_type = secure_channel_type ;
2001-12-10 02:59:42 +03:00
domain - > sequence_number = DOM_SEQUENCE_NONE ;
domain - > last_seq_check = 0 ;
2016-02-10 01:26:45 +03: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 ;
2008-08-21 03:24:22 +04:00
domain - > dc_probe_pid = ( pid_t ) - 1 ;
2017-12-16 13:34:23 +03:00
domain - > domain_flags = trust_flags ;
domain - > domain_type = trust_type ;
domain - > domain_trust_attribs = trust_attribs ;
2017-11-29 17:10:38 +03:00
domain - > secure_channel_type = secure_channel_type ;
2018-01-18 10:38:59 +03:00
domain - > routing_domain = routing_domain ;
2017-12-15 23:09:15 +03:00
sid_copy ( & domain - > sid , sid ) ;
2008-07-13 14:07:40 +04:00
2014-01-07 03:15:37 +04:00
/* Is this our primary domain ? */
2017-03-09 20:49:39 +03:00
if ( role = = ROLE_DOMAIN_MEMBER ) {
domain - > primary = strequal ( domain_name , lp_workgroup ( ) ) ;
} else {
domain - > primary = strequal ( domain_name , get_global_sam_name ( ) ) ;
2014-01-07 03:15:37 +04:00
}
2014-12-23 12:43:03 +03:00
if ( domain - > primary ) {
if ( role = = ROLE_ACTIVE_DIRECTORY_DC ) {
domain - > active_directory = true ;
}
if ( lp_security ( ) = = SEC_ADS ) {
domain - > active_directory = true ;
}
2016-02-10 01:32:23 +03:00
} else if ( ! domain - > internal ) {
if ( domain - > domain_type = = LSA_TRUST_TYPE_UPLEVEL ) {
domain - > active_directory = true ;
}
2014-12-23 12:43:03 +03:00
}
2018-01-15 16:30:48 +03:00
domain - > can_do_ncacn_ip_tcp = domain - > active_directory ;
2001-11-22 11:31:50 +03:00
/* Link to domain list */
2016-02-05 13:32:18 +03:00
DLIST_ADD_END ( _domain_list , domain ) ;
2009-05-12 01:07:24 +04:00
2007-05-06 23:17:30 +04:00
wcache_tdc_add_domain ( domain ) ;
2009-05-12 01:07:24 +04:00
2014-01-07 03:22:59 +04:00
setup_domain_child ( domain ) ;
2017-12-16 13:34:23 +03:00
DBG_NOTICE ( " Added domain [%s] [%s] [%s] \n " ,
domain - > name , domain - > alt_name ,
2018-12-14 23:09:51 +03:00
dom_sid_str_buf ( & domain - > sid , & buf ) ) ;
2009-05-12 01:07:24 +04:00
2017-12-16 13:34:23 +03:00
* _d = domain ;
return NT_STATUS_OK ;
2000-05-09 15:43:00 +04:00
}
2017-12-13 19:11:25 +03:00
bool set_routing_domain ( struct winbindd_domain * domain ,
2018-01-15 14:03:11 +03:00
struct winbindd_domain * routing_domain )
2017-12-13 19:11:25 +03:00
{
if ( domain - > routing_domain = = NULL ) {
domain - > routing_domain = routing_domain ;
return true ;
}
if ( domain - > routing_domain ! = routing_domain ) {
return false ;
}
return true ;
}
2017-11-29 12:10:38 +03:00
bool add_trusted_domain_from_auth ( uint16_t validation_level ,
struct info3_text * info3 ,
struct info6_text * info6 )
{
struct winbindd_domain * domain = NULL ;
struct dom_sid domain_sid ;
const char * dns_domainname = NULL ;
NTSTATUS status ;
bool ok ;
/*
* We got a successfull auth from a domain that might not yet be in our
* domain list . If we ' re a member we trust our DC who authenticated the
* user from that domain and add the domain to our list on - the - fly . If
* we ' re a DC we rely on configured trusts and don ' t add on - the - fly .
*/
if ( IS_DC ) {
return true ;
}
ok = dom_sid_parse ( info3 - > dom_sid , & domain_sid ) ;
if ( ! ok ) {
DBG_NOTICE ( " dom_sid_parse [%s] failed \n " , info3 - > dom_sid ) ;
return false ;
}
if ( validation_level = = 6 ) {
2018-01-24 01:19:32 +03:00
if ( ! strequal ( info6 - > dns_domainname , " " ) ) {
dns_domainname = info6 - > dns_domainname ;
}
2017-11-29 12:10:38 +03:00
}
status = add_trusted_domain ( info3 - > logon_dom ,
dns_domainname ,
& domain_sid ,
0 ,
NETR_TRUST_FLAG_OUTBOUND ,
0 ,
SEC_CHAN_NULL ,
2018-01-18 10:38:59 +03:00
find_default_route_domain ( ) ,
2017-11-29 12:10:38 +03:00
& domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_NO_SUCH_DOMAIN ) )
{
DBG_DEBUG ( " Adding domain [%s] with sid [%s] failed \n " ,
info3 - > logon_dom , info3 - > dom_sid ) ;
return false ;
}
return true ;
}
2009-12-30 12:25:41 +03:00
bool domain_is_forest_root ( const struct winbindd_domain * domain )
{
const uint32_t fr_flags =
( NETR_TRUST_FLAG_TREEROOT | NETR_TRUST_FLAG_IN_FOREST ) ;
return ( ( domain - > domain_flags & fr_flags ) = = fr_flags ) ;
}
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 {
2010-04-25 12:36:58 +04:00
struct winbindd_domain * domain ;
2010-04-25 13:40:30 +04:00
struct winbindd_request request ;
2005-06-09 02:10:34 +04:00
} ;
2010-04-25 13:40:30 +04:00
static void trustdom_list_done ( struct tevent_req * req ) ;
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
{
2005-06-09 02:10:34 +04:00
struct trustdom_state * state ;
2010-04-25 13:40:30 +04:00
struct tevent_req * req ;
2005-06-09 02:10:34 +04:00
2011-06-07 05:44:43 +04:00
state = talloc_zero ( NULL , struct trustdom_state ) ;
2010-04-25 12:25:55 +04:00
if ( state = = NULL ) {
2010-04-25 13:40:30 +04:00
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
2002-11-06 03:10:04 +03:00
return ;
}
2010-04-25 13:40:30 +04:00
state - > domain = domain ;
2003-02-14 03:31:30 +03:00
2010-04-25 13:40:30 +04:00
state - > request . length = sizeof ( state - > request ) ;
state - > request . cmd = WINBINDD_LIST_TRUSTDOM ;
2002-08-17 21:00:51 +04:00
2018-08-21 21:06:16 +03:00
req = wb_domain_request_send ( state , global_event_context ( ) ,
2010-04-25 13:40:30 +04:00
domain , & state - > request ) ;
if ( req = = NULL ) {
DEBUG ( 1 , ( " wb_domain_request_send failed \n " ) ) ;
2010-04-25 12:25:55 +04:00
TALLOC_FREE ( state ) ;
2002-08-17 21:00:51 +04:00
return ;
2005-06-09 02:10:34 +04:00
}
2010-04-25 13:40:30 +04:00
tevent_req_set_callback ( req , trustdom_list_done , state ) ;
2005-06-09 02:10:34 +04:00
}
2010-04-25 13:40:30 +04:00
static void trustdom_list_done ( struct tevent_req * req )
2005-06-09 02:10:34 +04:00
{
2010-04-25 13:40:30 +04:00
struct trustdom_state * state = tevent_req_callback_data (
req , struct trustdom_state ) ;
struct winbindd_response * response ;
int res , err ;
2005-06-09 02:10:34 +04:00
char * p ;
2016-02-10 01:38:11 +03:00
ptrdiff_t extra_len ;
2017-03-02 10:13:57 +03:00
bool within_forest = false ;
2017-12-16 13:34:23 +03:00
NTSTATUS status ;
2017-03-02 10:13:57 +03:00
/*
* Only when we enumerate our primary domain
* or our forest root domain , we should keep
* the NETR_TRUST_FLAG_IN_FOREST flag , in
* all other cases we need to clear it as the domain
* is not part of our forest .
*/
if ( state - > domain - > primary ) {
within_forest = true ;
} else if ( domain_is_forest_root ( state - > domain ) ) {
within_forest = true ;
}
2005-06-09 02:10:34 +04:00
2010-04-25 13:40:30 +04:00
res = wb_domain_request_recv ( req , state , & response , & err ) ;
if ( ( res = = - 1 ) | | ( response - > result ! = WINBINDD_OK ) ) {
2016-02-03 10:07:02 +03:00
DBG_WARNING ( " Could not receive trusts for domain %s \n " ,
state - > domain - > name ) ;
2010-04-25 12:25:55 +04:00
TALLOC_FREE ( state ) ;
2005-06-09 02:10:34 +04:00
return ;
}
2016-02-10 01:38:11 +03:00
if ( response - > length < sizeof ( struct winbindd_response ) ) {
DBG_ERR ( " ill-formed trustdom response - short length \n " ) ;
TALLOC_FREE ( state ) ;
return ;
}
extra_len = response - > length - sizeof ( struct winbindd_response ) ;
2006-08-18 18:05:25 +04:00
p = ( char * ) response - > extra_data . data ;
2005-06-09 02:10:34 +04:00
2016-02-10 01:38:11 +03:00
while ( ( p - ( char * ) response - > extra_data . data ) < extra_len ) {
2017-12-16 13:34:23 +03:00
struct winbindd_domain * domain = NULL ;
char * name , * q , * sidstr , * alt_name ;
struct dom_sid sid ;
uint32_t trust_type ;
uint32_t trust_attribs ;
uint32_t trust_flags ;
2019-01-28 16:07:39 +03:00
int error = 0 ;
2016-02-10 01:38:11 +03:00
DBG_DEBUG ( " parsing response line '%s' \n " , p ) ;
2017-12-16 13:34:23 +03:00
name = p ;
2005-06-09 02:10:34 +04:00
alt_name = strchr ( p , ' \\ ' ) ;
if ( alt_name = = NULL ) {
2016-02-10 01:38:11 +03:00
DBG_ERR ( " Got invalid trustdom response \n " ) ;
2005-06-09 02:10:34 +04:00
break ;
}
* alt_name = ' \0 ' ;
alt_name + = 1 ;
sidstr = strchr ( alt_name , ' \\ ' ) ;
if ( sidstr = = NULL ) {
2016-02-10 01:38:11 +03:00
DBG_ERR ( " Got invalid trustdom response \n " ) ;
2005-06-09 02:10:34 +04:00
break ;
}
* sidstr = ' \0 ' ;
sidstr + = 1 ;
2016-02-10 01:38:11 +03:00
/* use the real alt_name if we have one, else pass in NULL */
2017-12-16 13:34:23 +03:00
if ( strequal ( alt_name , " (null) " ) ) {
alt_name = NULL ;
2016-02-10 01:38:11 +03:00
}
2005-06-09 02:10:34 +04:00
2016-02-10 01:38:11 +03:00
q = strtok ( sidstr , " \\ " ) ;
if ( q = = NULL ) {
DBG_ERR ( " Got invalid trustdom response \n " ) ;
break ;
}
2017-12-16 13:34:23 +03:00
if ( ! string_to_sid ( & sid , sidstr ) ) {
2009-07-30 03:13:44 +04:00
DEBUG ( 0 , ( " Got invalid trustdom response \n " ) ) ;
break ;
2005-06-09 02:10:34 +04:00
}
2016-02-10 01:38:11 +03:00
q = strtok ( NULL , " \\ " ) ;
if ( q = = NULL ) {
DBG_ERR ( " Got invalid trustdom response \n " ) ;
break ;
}
2019-06-04 10:04:15 +03:00
trust_flags = ( uint32_t ) smb_strtoul ( q ,
NULL ,
10 ,
& error ,
SMB_STR_STANDARD ) ;
2019-01-28 16:07:39 +03:00
if ( error ! = 0 ) {
DBG_ERR ( " Failed to convert trust_flags \n " ) ;
break ;
}
2016-02-10 01:38:11 +03:00
q = strtok ( NULL , " \\ " ) ;
if ( q = = NULL ) {
DBG_ERR ( " Got invalid trustdom response \n " ) ;
break ;
}
2019-06-04 10:04:15 +03:00
trust_type = ( uint32_t ) smb_strtoul ( q ,
NULL ,
10 ,
& error ,
SMB_STR_STANDARD ) ;
2019-01-28 16:07:39 +03:00
if ( error ! = 0 ) {
DBG_ERR ( " Failed to convert trust_type \n " ) ;
break ;
}
2016-02-10 01:38:11 +03:00
q = strtok ( NULL , " \n " ) ;
if ( q = = NULL ) {
DBG_ERR ( " Got invalid trustdom response \n " ) ;
break ;
}
2005-06-09 02:10:34 +04:00
2019-06-04 10:04:15 +03:00
trust_attribs = ( uint32_t ) smb_strtoul ( q ,
NULL ,
10 ,
& error ,
SMB_STR_STANDARD ) ;
2019-01-28 16:07:39 +03:00
if ( error ! = 0 ) {
DBG_ERR ( " Failed to convert trust_attribs \n " ) ;
break ;
}
2005-06-09 02:10:34 +04:00
2017-03-02 10:13:57 +03:00
if ( ! within_forest ) {
2017-12-16 13:34:23 +03:00
trust_flags & = ~ NETR_TRUST_FLAG_IN_FOREST ;
2017-03-02 10:13:57 +03:00
}
if ( ! state - > domain - > primary ) {
2017-12-16 13:34:23 +03:00
trust_flags & = ~ NETR_TRUST_FLAG_PRIMARY ;
2017-03-02 10:13:57 +03:00
}
2012-12-06 17:31:45 +04:00
/*
* We always call add_trusted_domain ( ) cause on an existing
* domain structure , it will update the SID if necessary .
* This is important because we need the SID for sibling
* domains .
*/
2017-12-16 13:34:23 +03:00
status = add_trusted_domain ( name ,
alt_name ,
& sid ,
trust_type ,
trust_flags ,
trust_attribs ,
2017-11-29 17:10:38 +03:00
SEC_CHAN_NULL ,
2018-01-18 10:38:59 +03:00
find_default_route_domain ( ) ,
2017-12-16 13:34:23 +03:00
& domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_NO_SUCH_DOMAIN ) )
{
DBG_NOTICE ( " add_trusted_domain returned %s \n " ,
nt_errstr ( status ) ) ;
return ;
}
2012-12-06 17:31:45 +04:00
2016-02-10 01:38:11 +03:00
p = q + strlen ( q ) + 1 ;
2002-08-17 21:00:51 +04:00
}
2009-05-25 13:55:51 +04:00
/*
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 )
*/
2010-04-25 12:36:58 +04:00
if ( state - > domain - > 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 */
2010-04-25 12:36:58 +04:00
if ( ! domain_is_forest_root ( state - > domain ) )
2007-05-06 23:17:30 +04:00
rescan_forest_root_trusts ( ) ;
else
rescan_forest_trusts ( ) ;
2010-04-25 12:36:58 +04:00
} else if ( domain_is_forest_root ( state - > domain ) ) {
2007-05-06 23:17:30 +04:00
/* 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 ( ) ;
}
2009-05-12 01:07:24 +04:00
2010-04-25 12:25:55 +04:00
TALLOC_FREE ( state ) ;
2009-05-12 01:07:24 +04:00
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 ;
2018-05-18 15:47:24 +03:00
size_t i ;
2017-12-16 13:34:23 +03:00
NTSTATUS status ;
2007-05-06 23:17:30 +04:00
/* 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 ;
2009-05-25 13:55:51 +04:00
/* Find the forest root. Don't necessarily trust
the domain_list ( ) as our primary domain may not
2007-05-06 23:17:30 +04:00
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
}
2009-05-12 01:07:24 +04:00
2007-05-06 23:17:30 +04:00
/* Here's the forest root */
d = find_domain_from_name_noinit ( dom_list [ i ] . domain_name ) ;
2017-12-16 13:34:23 +03:00
if ( d = = NULL ) {
status = add_trusted_domain ( dom_list [ i ] . domain_name ,
dom_list [ i ] . dns_name ,
& dom_list [ i ] . sid ,
dom_list [ i ] . trust_type ,
dom_list [ i ] . trust_flags ,
dom_list [ i ] . trust_attribs ,
2017-11-29 17:10:38 +03:00
SEC_CHAN_NULL ,
2018-01-18 10:38:59 +03:00
find_default_route_domain ( ) ,
2017-12-16 13:34:23 +03:00
& d ) ;
if ( ! NT_STATUS_IS_OK ( status ) & &
NT_STATUS_EQUAL ( status , NT_STATUS_NO_SUCH_DOMAIN ) )
{
DBG_ERR ( " add_trusted_domain returned %s \n " ,
nt_errstr ( status ) ) ;
return ;
}
2007-05-06 23:17:30 +04:00
}
2008-09-17 09:37:54 +04:00
if ( d = = NULL ) {
continue ;
}
2007-05-06 23:17:30 +04:00
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 ;
2009-05-25 13:55:51 +04:00
d - > domain_type = dom_list [ i ] . trust_type ;
d - > domain_trust_attribs = dom_list [ i ] . trust_attribs ;
2009-05-12 01:07:24 +04:00
2007-05-06 23:17:30 +04:00
add_trusted_domains ( d ) ;
2009-05-25 13:55:51 +04:00
break ;
2007-05-06 23:17:30 +04:00
}
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 ;
2018-05-18 15:47:24 +03:00
size_t i ;
2017-12-16 13:34:23 +03:00
NTSTATUS status ;
2007-05-06 23:17:30 +04:00
/* 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 + + ) {
2015-04-24 05:04:23 +03:00
uint32_t flags = dom_list [ i ] . trust_flags ;
uint32_t type = dom_list [ i ] . trust_type ;
uint32_t attribs = dom_list [ i ] . trust_attribs ;
2009-05-12 01:07:24 +04:00
2007-05-06 23:17:30 +04:00
d = find_domain_from_name_noinit ( dom_list [ i ] . domain_name ) ;
/* ignore our primary and internal domains */
if ( d & & ( d - > internal | | d - > primary ) )
2009-05-25 13:55:51 +04:00
continue ;
2008-01-29 19:49:38 +03:00
if ( ( flags & NETR_TRUST_FLAG_INBOUND ) & &
2014-09-23 21:02:57 +04:00
( type = = LSA_TRUST_TYPE_UPLEVEL ) & &
2019-09-12 17:39:10 +03:00
( attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE ) )
2007-05-06 23:17:30 +04:00
{
/* add the trusted domain if we don't know
about it */
2017-12-16 13:34:23 +03:00
if ( d = = NULL ) {
status = add_trusted_domain (
dom_list [ i ] . domain_name ,
dom_list [ i ] . dns_name ,
& dom_list [ i ] . sid ,
type ,
flags ,
attribs ,
2017-11-29 17:10:38 +03:00
SEC_CHAN_NULL ,
2018-01-18 10:38:59 +03:00
find_default_route_domain ( ) ,
2017-12-16 13:34:23 +03:00
& d ) ;
if ( ! NT_STATUS_IS_OK ( status ) & &
NT_STATUS_EQUAL ( status ,
NT_STATUS_NO_SUCH_DOMAIN ) )
{
DBG_ERR ( " add_trusted_domain: %s \n " ,
nt_errstr ( status ) ) ;
return ;
}
2007-05-06 23:17:30 +04:00
}
2008-09-17 09:37:54 +04:00
if ( d = = NULL ) {
continue ;
}
2009-05-12 01:07:24 +04:00
2007-05-06 23:17:30 +04:00
DEBUG ( 10 , ( " Following trust path for domain %s (%s) \n " ,
d - > name , d - > alt_name ) ) ;
add_trusted_domains ( d ) ;
}
}
TALLOC_FREE ( dom_list ) ;
2009-05-25 13:55:51 +04:00
return ;
2007-05-06 23:17:30 +04:00
}
/*********************************************************************
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-26 00:34:48 +04:00
void rescan_trusted_domains ( struct tevent_context * ev , struct tevent_timer * te ,
struct timeval now , void * private_data )
2004-02-10 06:51:19 +03:00
{
2009-05-26 00:34:48 +04:00
TALLOC_FREE ( te ) ;
2009-05-12 01:07:24 +04:00
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 ( ) */
2009-05-12 01:07:24 +04:00
2005-06-09 02:10:34 +04:00
add_trusted_domains ( find_our_domain ( ) ) ;
2004-02-10 06:51:19 +03:00
2009-05-26 00:34:48 +04:00
te = tevent_add_timer (
ev , NULL , timeval_current_ofs ( WINBINDD_RESCAN_FREQ , 0 ) ,
rescan_trusted_domains , NULL ) ;
/*
* If te = = NULL , there ' s not much we can do here . Don ' t fail , the
* only thing we miss is new trusted domains .
*/
2009-05-12 01:07:24 +04:00
2009-05-25 13:55:51 +04:00
return ;
2004-02-10 06:51:19 +03:00
}
2005-06-09 02:10:34 +04:00
enum winbindd_result winbindd_dual_init_connection ( struct winbindd_domain * domain ,
struct winbindd_cli_state * state )
{
/* Ensure null termination */
2009-05-08 00:46:27 +04:00
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-06-09 02:10:34 +04:00
2009-05-08 00:46:27 +04:00
if ( strlen ( state - > request - > data . init_conn . dcname ) > 0 ) {
2018-02-15 18:00:33 +03:00
TALLOC_FREE ( domain - > dcname ) ;
domain - > dcname = talloc_strdup ( domain ,
state - > request - > data . init_conn . dcname ) ;
if ( domain - > dcname = = NULL ) {
return WINBINDD_ERROR ;
}
2005-08-28 13:19:10 +04:00
}
2005-06-09 02:10:34 +04:00
2014-05-26 03:58:38 +04:00
init_dc_connection ( domain , false ) ;
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
2009-06-14 14:41:46 +04:00
fstrcpy ( state - > response - > data . domain_info . name , domain - > name ) ;
fstrcpy ( state - > response - > data . domain_info . alt_name , domain - > alt_name ) ;
sid_to_fstring ( state - > response - > data . domain_info . sid , & domain - > sid ) ;
2009-05-12 01:07:24 +04:00
2009-06-14 14:41:46 +04:00
state - > response - > data . domain_info . native_mode
2005-06-09 02:10:34 +04:00
= domain - > native_mode ;
2009-06-14 14:41:46 +04:00
state - > response - > data . domain_info . active_directory
2005-06-09 02:10:34 +04:00
= domain - > active_directory ;
2009-06-14 14:41:46 +04:00
state - > response - > data . domain_info . primary
2005-06-09 02:10:34 +04:00
= domain - > primary ;
return WINBINDD_OK ;
}
2015-01-23 18:59:07 +03:00
static void wb_imsg_new_trusted_domain ( struct imessaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
2019-09-18 19:19:37 +03:00
size_t num_fds ,
int * fds ,
2015-01-23 18:59:07 +03:00
DATA_BLOB * data )
{
2018-01-18 13:30:53 +03:00
bool ok ;
2015-01-23 18:59:07 +03:00
2019-09-18 19:19:37 +03:00
if ( num_fds ! = 0 ) {
DBG_WARNING ( " Received %zu fds, ignoring message \n " , num_fds ) ;
return ;
}
2018-01-18 13:30:53 +03:00
DBG_NOTICE ( " Rescanning trusted domains \n " ) ;
2017-12-16 13:34:23 +03:00
2018-01-18 13:30:53 +03:00
ok = add_trusted_domains_dc ( ) ;
if ( ! ok ) {
DBG_ERR ( " Failed to reload trusted domains \n " ) ;
2015-01-23 18:59:07 +03:00
}
}
2015-06-12 02:57:07 +03:00
/*
* We did not get the secret when we queried secrets . tdb , so read it
* from secrets . tdb and re - sync the databases
*/
static bool migrate_secrets_tdb_to_ldb ( struct winbindd_domain * domain )
{
bool ok ;
struct cli_credentials * creds ;
NTSTATUS can_migrate = pdb_get_trust_credentials ( domain - > name ,
NULL , domain , & creds ) ;
if ( ! NT_STATUS_IS_OK ( can_migrate ) ) {
DEBUG ( 0 , ( " Failed to fetch our own, local AD domain join "
" password for winbindd's internal use, both from "
" secrets.tdb and secrets.ldb: %s \n " ,
nt_errstr ( can_migrate ) ) ) ;
return false ;
}
/*
* NOTE : It is very unlikely we end up here if there is an
* oldpass , because a new password is created at
* classicupgrade , so this is not a concern .
*/
ok = secrets_store_machine_pw_sync ( cli_credentials_get_password ( creds ) ,
NULL /* oldpass */ ,
cli_credentials_get_domain ( creds ) ,
cli_credentials_get_realm ( creds ) ,
cli_credentials_get_salt_principal ( creds ) ,
0 , /* Supported enc types, unused */
& domain - > sid ,
cli_credentials_get_password_last_changed_time ( creds ) ,
cli_credentials_get_secure_channel_type ( creds ) ,
false /* do_delete: Do not delete */ ) ;
TALLOC_FREE ( creds ) ;
if ( ok = = false ) {
DEBUG ( 0 , ( " Failed to write our our own, "
" local AD domain join password for "
" winbindd's internal use into secrets.tdb \n " ) ) ;
return false ;
}
return true ;
}
2018-01-18 13:28:20 +03:00
static bool add_trusted_domains_dc ( void )
{
struct winbindd_domain * domain = NULL ;
struct pdb_trusted_domain * * domains = NULL ;
uint32_t num_domains = 0 ;
uint32_t i ;
NTSTATUS status ;
if ( ! ( pdb_capabilities ( ) & PDB_CAP_TRUSTED_DOMAINS_EX ) ) {
struct trustdom_info * * ti = NULL ;
status = pdb_enum_trusteddoms ( talloc_tos ( ) , & num_domains , & ti ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " pdb_enum_trusteddoms() failed - %s \n " ,
nt_errstr ( status ) ) ;
return false ;
}
for ( i = 0 ; i < num_domains ; i + + ) {
status = add_trusted_domain ( ti [ i ] - > name ,
NULL ,
& ti [ i ] - > sid ,
LSA_TRUST_TYPE_DOWNLEVEL ,
NETR_TRUST_FLAG_OUTBOUND ,
0 ,
SEC_CHAN_DOMAIN ,
NULL ,
& domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_NOTICE ( " add_trusted_domain returned %s \n " ,
nt_errstr ( status ) ) ;
return false ;
}
/* Even in the parent winbindd we'll need to
talk to the DC , so try and see if we can
2019-10-26 03:41:09 +03:00
contact it . Theoretically this isn ' t necessary
2018-01-18 13:28:20 +03:00
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 ) ;
}
return true ;
}
status = pdb_enum_trusted_domains ( talloc_tos ( ) , & num_domains , & domains ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " pdb_enum_trusted_domains() failed - %s \n " ,
nt_errstr ( status ) ) ;
return false ;
}
for ( i = 0 ; i < num_domains ; i + + ) {
enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN ;
uint32_t trust_flags = 0 ;
if ( domains [ i ] - > trust_type = = LSA_TRUST_TYPE_UPLEVEL ) {
sec_chan_type = SEC_CHAN_DNS_DOMAIN ;
}
if ( ! ( domains [ i ] - > trust_direction & LSA_TRUST_DIRECTION_OUTBOUND ) ) {
sec_chan_type = SEC_CHAN_NULL ;
}
if ( domains [ i ] - > trust_direction & LSA_TRUST_DIRECTION_INBOUND ) {
trust_flags | = NETR_TRUST_FLAG_INBOUND ;
}
if ( domains [ i ] - > trust_direction & LSA_TRUST_DIRECTION_OUTBOUND ) {
trust_flags | = NETR_TRUST_FLAG_OUTBOUND ;
}
if ( domains [ i ] - > trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST ) {
trust_flags | = NETR_TRUST_FLAG_IN_FOREST ;
}
2018-02-01 13:06:10 +03:00
if ( domains [ i ] - > trust_attributes & LSA_TRUST_ATTRIBUTE_CROSS_ORGANIZATION ) {
/*
* We don ' t support selective authentication yet .
*/
DBG_WARNING ( " Ignoring CROSS_ORGANIZATION trust to "
" domain[%s/%s] \n " ,
domains [ i ] - > netbios_name ,
domains [ i ] - > domain_name ) ;
continue ;
}
2018-01-18 13:28:20 +03:00
status = add_trusted_domain ( domains [ i ] - > netbios_name ,
domains [ i ] - > domain_name ,
& domains [ i ] - > security_identifier ,
domains [ i ] - > trust_type ,
trust_flags ,
domains [ i ] - > trust_attributes ,
sec_chan_type ,
NULL ,
& domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_NOTICE ( " add_trusted_domain returned %s \n " ,
nt_errstr ( status ) ) ;
return false ;
}
if ( domains [ i ] - > trust_type = = LSA_TRUST_TYPE_UPLEVEL ) {
domain - > active_directory = true ;
}
domain - > domain_type = domains [ i ] - > trust_type ;
domain - > domain_trust_attribs = domains [ i ] - > trust_attributes ;
if ( sec_chan_type ! = SEC_CHAN_NULL ) {
/* Even in the parent winbindd we'll need to
talk to the DC , so try and see if we can
2019-10-26 03:41:09 +03:00
contact it . Theoretically this isn ' t necessary
2018-01-18 13:28:20 +03:00
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 ) ;
}
}
for ( i = 0 ; i < num_domains ; i + + ) {
struct ForestTrustInfo fti ;
uint32_t fi ;
enum ndr_err_code ndr_err ;
struct winbindd_domain * routing_domain = NULL ;
if ( domains [ i ] - > trust_type ! = LSA_TRUST_TYPE_UPLEVEL ) {
continue ;
}
if ( ! ( domains [ i ] - > trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE ) ) {
continue ;
}
if ( domains [ i ] - > trust_forest_trust_info . length = = 0 ) {
continue ;
}
routing_domain = find_domain_from_name_noinit (
domains [ i ] - > netbios_name ) ;
if ( routing_domain = = NULL ) {
DBG_ERR ( " Can't find winbindd domain [%s] \n " ,
domains [ i ] - > netbios_name ) ;
return false ;
}
ndr_err = ndr_pull_struct_blob_all (
& domains [ i ] - > trust_forest_trust_info ,
talloc_tos ( ) , & fti ,
( ndr_pull_flags_fn_t ) ndr_pull_ForestTrustInfo ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DBG_ERR ( " ndr_pull_ForestTrustInfo(%s) - %s \n " ,
domains [ i ] - > netbios_name ,
ndr_map_error2string ( ndr_err ) ) ;
return false ;
}
for ( fi = 0 ; fi < fti . count ; fi + + ) {
struct ForestTrustInfoRecord * rec =
& fti . records [ fi ] . record ;
struct ForestTrustDataDomainInfo * drec = NULL ;
if ( rec - > type ! = FOREST_TRUST_DOMAIN_INFO ) {
continue ;
}
drec = & rec - > data . info ;
if ( rec - > flags & LSA_NB_DISABLED_MASK ) {
continue ;
}
if ( rec - > flags & LSA_SID_DISABLED_MASK ) {
continue ;
}
/*
* TODO :
* also try to find a matching
* LSA_TLN_DISABLED_MASK ? ? ?
*/
domain = find_domain_from_name_noinit ( drec - > netbios_name . string ) ;
if ( domain ! = NULL ) {
continue ;
}
status = add_trusted_domain ( drec - > netbios_name . string ,
drec - > dns_name . string ,
& drec - > sid ,
LSA_TRUST_TYPE_UPLEVEL ,
NETR_TRUST_FLAG_OUTBOUND ,
0 ,
SEC_CHAN_NULL ,
routing_domain ,
& domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_NOTICE ( " add_trusted_domain returned %s \n " ,
nt_errstr ( status ) ) ;
return false ;
}
if ( domain = = NULL ) {
continue ;
}
}
}
return true ;
}
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
{
2006-04-02 10:25:11 +04:00
int role = lp_server_role ( ) ;
2017-03-29 12:13:46 +03:00
struct pdb_domain_info * pdb_domain_info = NULL ;
2017-12-16 13:34:23 +03:00
struct winbindd_domain * domain = NULL ;
2015-01-23 18:59:07 +03:00
NTSTATUS status ;
2018-01-18 13:28:20 +03:00
bool ok ;
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 */
2017-12-16 13:34:23 +03:00
status = add_trusted_domain ( " BUILTIN " ,
NULL ,
& global_sid_Builtin ,
LSA_TRUST_TYPE_DOWNLEVEL ,
0 , /* trust_flags */
0 , /* trust_attribs */
2017-11-29 17:10:38 +03:00
SEC_CHAN_LOCAL ,
2018-01-18 10:38:59 +03:00
NULL ,
2017-12-16 13:34:23 +03:00
& domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " add_trusted_domain BUILTIN returned %s \n " ,
nt_errstr ( status ) ) ;
return false ;
}
2007-09-20 22:37:34 +04:00
/* Local SAM */
2017-03-29 12:13:46 +03:00
/*
* In case the passdb backend is passdb_dsdb the domain SID comes from
* dsdb , not from secrets . tdb . As we use the domain SID in various
* places , we must ensure the domain SID is migrated from dsdb to
* secrets . tdb before get_global_sam_sid ( ) is called the first time .
*
* The migration is done as part of the passdb_dsdb initialisation ,
* calling pdb_get_domain_info ( ) triggers it .
*/
pdb_domain_info = pdb_get_domain_info ( talloc_tos ( ) ) ;
2014-05-16 10:10:23 +04:00
if ( role = = ROLE_ACTIVE_DIRECTORY_DC ) {
2017-12-16 13:34:23 +03:00
uint32_t trust_flags ;
bool is_root ;
2014-05-26 03:58:38 +04:00
enum netr_SchannelType sec_chan_type ;
const char * account_name ;
struct samr_Password current_nt_hash ;
2015-06-12 02:54:21 +03:00
if ( pdb_domain_info = = NULL ) {
DEBUG ( 0 , ( " Failed to fetch our own, local AD "
" domain info from sam.ldb \n " ) ) ;
return false ;
}
2017-12-16 13:34:23 +03:00
trust_flags = NETR_TRUST_FLAG_PRIMARY ;
trust_flags | = NETR_TRUST_FLAG_IN_FOREST ;
trust_flags | = NETR_TRUST_FLAG_NATIVE ;
trust_flags | = NETR_TRUST_FLAG_OUTBOUND ;
is_root = strequal ( pdb_domain_info - > dns_domain ,
pdb_domain_info - > dns_forest ) ;
if ( is_root ) {
trust_flags | = NETR_TRUST_FLAG_TREEROOT ;
}
status = add_trusted_domain ( pdb_domain_info - > name ,
pdb_domain_info - > dns_domain ,
& pdb_domain_info - > sid ,
LSA_TRUST_TYPE_UPLEVEL ,
trust_flags ,
LSA_TRUST_ATTRIBUTE_WITHIN_FOREST ,
2017-11-29 17:10:38 +03:00
SEC_CHAN_BDC ,
2018-01-18 10:38:59 +03:00
NULL ,
2017-12-16 13:34:23 +03:00
& domain ) ;
2015-06-12 02:54:21 +03:00
TALLOC_FREE ( pdb_domain_info ) ;
2017-12-16 13:34:23 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " Failed to add our own, local AD "
" domain to winbindd's internal list \n " ) ;
2014-05-26 03:58:38 +04:00
return false ;
}
/*
* We need to call this to find out if we are an RODC
*/
ok = get_trust_pw_hash ( domain - > name ,
current_nt_hash . hash ,
& account_name ,
& sec_chan_type ) ;
if ( ! ok ) {
2015-06-12 02:57:07 +03:00
/*
* If get_trust_pw_hash ( ) fails , then try and
* fetch the password from the more recent of
* secrets . { ldb , tdb } using the
* pdb_get_trust_credentials ( )
*/
ok = migrate_secrets_tdb_to_ldb ( domain ) ;
2017-03-09 20:27:55 +03:00
if ( ! ok ) {
2015-06-12 02:57:07 +03:00
DEBUG ( 0 , ( " Failed to migrate our own, "
" local AD domain join password for "
" winbindd's internal use into "
" secrets.tdb \n " ) ) ;
return false ;
}
ok = get_trust_pw_hash ( domain - > name ,
current_nt_hash . hash ,
& account_name ,
& sec_chan_type ) ;
2017-03-09 20:27:55 +03:00
if ( ! ok ) {
2015-06-12 02:57:07 +03:00
DEBUG ( 0 , ( " Failed to find our our own, just "
" written local AD domain join "
" password for winbindd's internal "
" use in secrets.tdb \n " ) ) ;
return false ;
}
2014-05-26 03:58:38 +04:00
}
2017-11-29 17:10:38 +03:00
domain - > secure_channel_type = sec_chan_type ;
2014-05-26 03:58:38 +04:00
if ( sec_chan_type = = SEC_CHAN_RODC ) {
domain - > rodc = true ;
}
2014-05-16 10:10:23 +04:00
} else {
2017-12-16 13:34:23 +03:00
uint32_t trust_flags ;
2017-11-29 17:10:38 +03:00
enum netr_SchannelType secure_channel_type ;
2017-12-16 13:34:23 +03:00
trust_flags = NETR_TRUST_FLAG_OUTBOUND ;
if ( role ! = ROLE_DOMAIN_MEMBER ) {
trust_flags | = NETR_TRUST_FLAG_PRIMARY ;
}
2017-11-29 17:10:38 +03:00
if ( role > ROLE_DOMAIN_MEMBER ) {
secure_channel_type = SEC_CHAN_BDC ;
} else {
secure_channel_type = SEC_CHAN_LOCAL ;
}
2017-12-16 13:34:23 +03:00
status = add_trusted_domain ( get_global_sam_name ( ) ,
NULL ,
get_global_sam_sid ( ) ,
LSA_TRUST_TYPE_DOWNLEVEL ,
trust_flags ,
0 , /* trust_attribs */
2017-11-29 17:10:38 +03:00
secure_channel_type ,
2018-01-18 10:38:59 +03:00
NULL ,
2017-12-16 13:34:23 +03:00
& domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " Failed to add local SAM to "
" domain to winbindd's internal list \n " ) ;
return false ;
}
2014-05-16 10:10:23 +04:00
}
2018-01-18 13:28:20 +03:00
if ( IS_DC ) {
ok = add_trusted_domains_dc ( ) ;
if ( ! ok ) {
DBG_ERR ( " init_domain_list_dc failed \n " ) ;
return false ;
}
}
2004-04-20 06:37:49 +04:00
2006-04-02 10:25:11 +04:00
if ( role = = ROLE_DOMAIN_MEMBER ) {
2010-05-21 05:25:01 +04:00
struct dom_sid our_sid ;
2017-12-16 13:34:23 +03:00
uint32_t trust_type ;
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
}
2009-05-12 01:07:24 +04:00
2017-12-16 13:34:23 +03:00
if ( lp_realm ( ) ! = NULL ) {
trust_type = LSA_TRUST_TYPE_UPLEVEL ;
} else {
trust_type = LSA_TRUST_TYPE_DOWNLEVEL ;
2007-07-24 12:59:36 +04:00
}
2017-12-16 13:34:23 +03:00
status = add_trusted_domain ( lp_workgroup ( ) ,
lp_realm ( ) ,
& our_sid ,
trust_type ,
NETR_TRUST_FLAG_PRIMARY |
NETR_TRUST_FLAG_OUTBOUND ,
0 , /* trust_attribs */
2017-11-29 17:10:38 +03:00
SEC_CHAN_WKSTA ,
2018-01-18 10:38:59 +03:00
NULL ,
2017-12-16 13:34:23 +03:00
& domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " Failed to add local SAM to "
" domain to winbindd's internal list \n " ) ;
return false ;
}
/* Even in the parent winbindd we'll need to
talk to the DC , so try and see if we can
2019-10-26 03:41:09 +03:00
contact it . Theoretically this isn ' t necessary
2017-12-16 13:34:23 +03:00
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
2015-01-23 18:59:07 +03:00
status = imessaging_register ( winbind_imessaging_context ( ) , NULL ,
2018-01-18 18:35:13 +03:00
MSG_WINBIND_RELOAD_TRUSTED_DOMAINS ,
2015-01-23 18:59:07 +03:00
wb_imsg_new_trusted_domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2018-01-18 13:28:20 +03:00
DBG_ERR ( " imessaging_register failed %s \n " , nt_errstr ( status ) ) ;
2015-01-23 18:59:07 +03:00
return false ;
}
2006-03-16 14:32:01 +03:00
return True ;
2000-05-09 15:43:00 +04:00
}
2009-05-25 13:55:51 +04:00
/**
* Given a domain name , return the struct winbindd domain info for it
2003-12-31 03:31:43 +03:00
*
* @ 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 ) {
2017-12-01 14:23:50 +03:00
if ( strequal ( domain_name , domain - > name ) ) {
return domain ;
}
if ( domain - > alt_name = = NULL ) {
continue ;
}
if ( 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 ;
}
2017-11-29 17:23:36 +03:00
/**
* Given a domain name , return the struct winbindd domain if it ' s a direct
* outgoing trust
*
* @ return The domain structure for the named domain , if it is a direct outgoing trust
*/
struct winbindd_domain * find_trust_from_name_noinit ( const char * domain_name )
{
struct winbindd_domain * domain = NULL ;
domain = find_domain_from_name_noinit ( domain_name ) ;
if ( domain = = NULL ) {
return NULL ;
}
if ( domain - > secure_channel_type ! = SEC_CHAN_NULL ) {
return domain ;
}
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 )
2014-05-26 03:58:38 +04:00
init_dc_connection ( domain , false ) ;
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 */
2010-05-21 05:25:01 +04:00
struct winbindd_domain * find_domain_from_sid_noinit ( const struct 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 ) {
2010-08-26 17:48:50 +04:00
if ( dom_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
2017-11-29 17:23:36 +03:00
/**
* Given a domain sid , return the struct winbindd domain if it ' s a direct
* outgoing trust
*
* @ return The domain structure for the specified domain , if it is a direct outgoing trust
*/
struct winbindd_domain * find_trust_from_sid_noinit ( const struct dom_sid * sid )
{
struct winbindd_domain * domain = NULL ;
domain = find_domain_from_sid_noinit ( sid ) ;
if ( domain = = NULL ) {
return NULL ;
}
if ( domain - > secure_channel_type ! = SEC_CHAN_NULL ) {
return domain ;
}
return NULL ;
}
2003-12-31 08:26:29 +03:00
/* Given a domain sid, return the struct winbindd domain info for it */
2010-05-21 05:25:01 +04:00
struct winbindd_domain * find_domain_from_sid ( const struct dom_sid * sid )
2005-06-09 02:10:34 +04:00
{
struct winbindd_domain * domain ;
domain = find_domain_from_sid_noinit ( sid ) ;
if ( domain = = NULL )
return NULL ;
if ( ! domain - > initialized )
2014-05-26 03:58:38 +04:00
init_dc_connection ( domain , false ) ;
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 ;
}
2017-12-13 19:08:10 +03:00
struct winbindd_domain * find_default_route_domain ( void )
{
if ( ! IS_DC ) {
return find_our_domain ( ) ;
}
2018-01-31 10:22:07 +03:00
DBG_DEBUG ( " Routing logic not yet implemented on a DC \n " ) ;
2017-12-13 19:08:10 +03:00
return NULL ;
}
2004-04-20 06:37:49 +04:00
/* Find the appropriate domain to lookup a name or SID */
2010-05-21 05:25:01 +04:00
struct winbindd_domain * find_lookup_domain_from_sid ( const struct dom_sid * sid )
2004-04-20 06:37:49 +04:00
{
2018-12-14 23:09:51 +03:00
struct dom_sid_buf buf ;
DBG_DEBUG ( " SID [%s] \n " , dom_sid_str_buf ( sid , & buf ) ) ;
2017-03-31 00:41:59 +03:00
/*
* SIDs in the S - 1 - 22 - { 1 , 2 } domain and well - known SIDs should be handled
* by our passdb .
*/
2007-05-22 01:33:51 +04:00
2009-05-25 13:55:51 +04:00
if ( sid_check_is_in_unix_groups ( sid ) | |
2007-05-22 01:33:51 +04:00
sid_check_is_unix_groups ( sid ) | |
sid_check_is_in_unix_users ( sid ) | |
2017-03-31 00:41:59 +03:00
sid_check_is_unix_users ( sid ) | |
2018-11-28 19:20:41 +03:00
sid_check_is_our_sam ( sid ) | |
sid_check_is_in_our_sam ( sid ) )
2007-05-22 01:33:51 +04:00
{
return find_domain_from_sid ( get_global_sam_sid ( ) ) ;
}
2018-11-28 19:20:41 +03:00
if ( sid_check_is_builtin ( sid ) | |
sid_check_is_in_builtin ( sid ) | |
sid_check_is_wellknown_domain ( sid , NULL ) | |
sid_check_is_in_wellknown_domain ( sid ) )
{
return find_domain_from_sid ( & global_sid_Builtin ) ;
2009-05-25 13:55:51 +04:00
}
2007-05-22 00:36:22 +04:00
2018-01-15 14:06:50 +03:00
if ( IS_DC ) {
struct winbindd_domain * domain = NULL ;
domain = find_domain_from_sid_noinit ( sid ) ;
if ( domain = = NULL ) {
return NULL ;
}
if ( domain - > secure_channel_type ! = SEC_CHAN_NULL ) {
return domain ;
}
return domain - > routing_domain ;
}
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 )
{
2018-11-28 17:39:21 +03:00
bool predefined ;
2007-05-22 00:36:22 +04:00
if ( strequal ( domain_name , unix_users_domain_name ( ) ) | |
strequal ( domain_name , unix_groups_domain_name ( ) ) )
{
2009-08-01 00:47:48 +04:00
/*
2021-02-22 21:32:00 +03:00
* The " Unix User " and " Unix Group " domain are handled by
2009-08-01 00:47:48 +04:00
* passdb
*/
2007-05-22 00:36:22 +04:00
return find_domain_from_name_noinit ( get_global_sam_name ( ) ) ;
}
2018-01-15 14:06:50 +03:00
if ( strequal ( domain_name , " BUILTIN " ) | |
2018-11-27 19:32:09 +03:00
strequal ( domain_name , get_global_sam_name ( ) ) ) {
2007-05-22 01:33:51 +04:00
return find_domain_from_name_noinit ( domain_name ) ;
2018-11-27 19:32:09 +03:00
}
2007-05-22 01:33:51 +04:00
2018-11-28 17:39:21 +03:00
predefined = dom_sid_lookup_is_predefined_domain ( domain_name ) ;
if ( predefined ) {
return find_domain_from_name_noinit ( builtin_domain_name ( ) ) ;
}
2018-01-15 14:06:50 +03:00
if ( IS_DC ) {
struct winbindd_domain * domain = NULL ;
domain = find_domain_from_name_noinit ( domain_name ) ;
if ( domain = = NULL ) {
return NULL ;
}
if ( domain - > secure_channel_type ! = SEC_CHAN_NULL ) {
return domain ;
}
return domain - > routing_domain ;
}
2007-05-22 01:33:51 +04:00
2004-04-20 06:37:49 +04:00
return find_our_domain ( ) ;
}
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 ;
2017-12-07 12:54:21 +03:00
if ( lp_winbind_use_default_domain ( ) )
2006-07-20 22:02:51 +04:00
return True ;
2009-05-25 13:55:51 +04:00
}
2006-07-20 22:02:51 +04:00
/* 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
}
2009-05-12 01:07:24 +04:00
2003-12-31 03:31:43 +03:00
return False ;
}
2018-04-26 13:17:12 +03:00
/* Parse a DOMAIN\user or UPN string into a domain, namespace and a user */
bool parse_domain_user ( const char * domuser ,
fstring namespace ,
fstring domain ,
fstring user )
2001-05-07 08:32:40 +04:00
{
2018-04-26 13:17:12 +03:00
char * p = NULL ;
if ( strlen ( domuser ) = = 0 ) {
return false ;
}
2001-10-14 12:31:54 +04:00
2018-04-26 13:17:12 +03:00
p = strchr ( domuser , * lp_winbind_separator ( ) ) ;
if ( p ! = NULL ) {
fstrcpy ( user , p + 1 ) ;
fstrcpy ( domain , domuser ) ;
domain [ PTR_DIFF ( p , domuser ) ] = ' \0 ' ;
fstrcpy ( namespace , domain ) ;
} else {
2002-01-18 05:37:55 +03:00
fstrcpy ( user , domuser ) ;
2006-07-20 22:02:51 +04:00
2018-04-26 13:17:12 +03:00
domain [ 0 ] = ' \0 ' ;
namespace [ 0 ] = ' \0 ' ;
p = strchr ( domuser , ' @ ' ) ;
if ( p ! = NULL ) {
/* upn */
fstrcpy ( namespace , p + 1 ) ;
} else if ( assume_domain ( lp_workgroup ( ) ) ) {
2003-07-09 20:44:47 +04:00
fstrcpy ( domain , lp_workgroup ( ) ) ;
2018-04-26 13:17:12 +03:00
fstrcpy ( namespace , domain ) ;
2018-07-02 17:38:01 +03:00
} else {
fstrcpy ( namespace , lp_netbios_name ( ) ) ;
2003-12-31 03:31:43 +03:00
}
2002-01-18 05:37:55 +03:00
}
2009-05-12 01:07:24 +04:00
2012-08-09 02:35:28 +04:00
return strupper_m ( domain ) ;
2001-05-07 08:32:40 +04:00
}
2002-01-18 05:37:55 +03:00
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 . */
2018-04-26 18:32:42 +03:00
bool canonicalize_username ( fstring username_inout ,
fstring namespace ,
fstring domain ,
fstring user )
2006-10-09 23:20:21 +04:00
{
2018-04-26 13:17:12 +03:00
bool ok ;
ok = parse_domain_user ( username_inout , namespace , domain , user ) ;
if ( ! ok ) {
2006-10-09 23:20:21 +04:00
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 .
2015-03-28 11:31:05 +03:00
On an AD DC we always fill DOMAIN \ \ USERNAME .
2006-09-14 13:58:20 +04:00
We always canonicalize as UPPERCASE DOMAIN , lowercase username .
2002-01-18 05:37:55 +03:00
*/
2008-09-22 12:37:11 +04:00
/**
* talloc version of fill_domain_username ( )
* return NULL on talloc failure .
*/
char * fill_domain_username_talloc ( TALLOC_CTX * mem_ctx ,
const char * domain ,
const char * user ,
bool can_assume )
{
char * tmp_user , * name ;
2015-03-28 11:31:05 +03:00
if ( lp_server_role ( ) = = ROLE_ACTIVE_DIRECTORY_DC ) {
can_assume = false ;
}
2019-06-24 10:25:48 +03:00
if ( user = = NULL ) {
return NULL ;
}
2008-09-22 12:37:11 +04:00
tmp_user = talloc_strdup ( mem_ctx , user ) ;
2012-08-09 04:01:00 +04:00
if ( ! strlower_m ( tmp_user ) ) {
TALLOC_FREE ( tmp_user ) ;
return NULL ;
}
2008-09-22 12:37:11 +04:00
if ( can_assume & & assume_domain ( domain ) ) {
name = tmp_user ;
} else {
name = talloc_asprintf ( mem_ctx , " %s%c%s " ,
domain ,
* lp_winbind_separator ( ) ,
tmp_user ) ;
TALLOC_FREE ( tmp_user ) ;
}
return name ;
}
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 ;
}
2015-07-13 21:08:16 +03:00
/* Return list-tail of all connected clients */
struct winbindd_cli_state * winbindd_client_list_tail ( void )
{
return DLIST_TAIL ( _client_list ) ;
}
/* Return previous (read:newer) client in list */
struct winbindd_cli_state *
winbindd_client_list_prev ( struct winbindd_cli_state * cli )
{
return DLIST_PREV ( cli ) ;
}
2002-11-02 04:36:42 +03:00
/* Add a connection to the list */
void winbindd_add_client ( struct winbindd_cli_state * cli )
{
2015-07-13 21:33:41 +03:00
cli - > last_access = time ( NULL ) ;
2002-11-02 04:36:42 +03:00
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 - - ;
}
2015-07-13 21:08:16 +03:00
/* Move a client to head or list */
void winbindd_promote_client ( struct winbindd_cli_state * cli )
{
2015-07-13 21:33:41 +03:00
cli - > last_access = time ( NULL ) ;
2015-07-13 21:08:16 +03:00
DLIST_PROMOTE ( _client_list , cli ) ;
}
2002-11-02 04:36:42 +03:00
/* Return number of open clients */
int winbindd_num_clients ( void )
{
return _num_clients ;
}
2003-04-23 15:54:56 +04:00
2016-11-04 17:33:11 +03:00
NTSTATUS lookup_usergroups_cached ( TALLOC_CTX * mem_ctx ,
2010-05-21 05:25:01 +04:00
const struct dom_sid * user_sid ,
2010-08-26 14:54:13 +04:00
uint32_t * p_num_groups , struct dom_sid * * user_sids )
2006-04-28 18:48:22 +04:00
{
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 ;
2010-08-26 14:54:13 +04:00
uint32_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 ;
}
2012-07-21 04:12:09 +04:00
/*
* Before bug # 7843 the " Domain Local " groups were added with a
* lookupuseraliases call , but this isn ' t done anymore for our domain
* so we need to resolve resource groups here .
*
* When to use Resource Groups :
* http : //technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
*/
2008-04-04 04:53:40 +04:00
status = sid_array_from_info3 ( mem_ctx , info3 ,
user_sids ,
& num_groups ,
2012-07-21 04:12:09 +04:00
false ) ;
2008-04-04 04:53:40 +04:00
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 ;
2009-05-12 01:07:24 +04:00
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-09-16 00:41:37 +04:00
NTSTATUS normalize_name_map ( TALLOC_CTX * mem_ctx ,
2017-11-27 14:42:44 +03:00
const char * domain_name ,
2009-08-16 14:07:32 +04:00
const char * name ,
2008-09-16 00:41:37 +04:00
char * * normalized )
2007-01-31 08:38:36 +03:00
{
2017-11-27 14:42:44 +03:00
struct winbindd_domain * domain = NULL ;
2008-09-16 00:41:37 +04:00
NTSTATUS nt_status ;
2007-01-31 08:38:36 +03:00
2008-09-16 00:41:37 +04:00
if ( ! name | | ! normalized ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2007-01-31 08:38:36 +03:00
2008-09-16 00:41:37 +04:00
if ( ! lp_winbind_normalize_names ( ) ) {
return NT_STATUS_PROCEDURE_NOT_FOUND ;
}
2017-11-27 14:42:44 +03:00
domain = find_domain_from_name_noinit ( domain_name ) ;
if ( domain = = NULL ) {
DBG_ERR ( " Failed to find domain '%s' \n " , domain_name ) ;
return NT_STATUS_NO_SUCH_DOMAIN ;
}
2008-09-16 00:41:37 +04:00
/* Alias support and whitespace replacement are mutually
exclusive */
nt_status = resolve_username_to_alias ( mem_ctx , domain ,
name , normalized ) ;
if ( NT_STATUS_IS_OK ( nt_status ) ) {
/* special return code to let the caller know we
mapped to an alias */
return NT_STATUS_FILE_RENAMED ;
}
/* check for an unreachable domain */
if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
DEBUG ( 5 , ( " normalize_name_map: Setting domain %s offline \n " ,
domain - > name ) ) ;
set_domain_offline ( domain ) ;
return nt_status ;
}
/* deal with whitespace */
* normalized = talloc_strdup ( mem_ctx , name ) ;
if ( ! ( * normalized ) ) {
return NT_STATUS_NO_MEMORY ;
}
all_string_sub ( * normalized , " " , " _ " , 0 ) ;
return NT_STATUS_OK ;
2007-01-31 08:38:36 +03:00
}
/*********************************************************************
2008-09-16 00:41:37 +04:00
We use this to do the inverse of normalize_name_map ( )
2007-01-31 08:38:36 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-09-16 00:41:37 +04:00
NTSTATUS normalize_name_unmap ( TALLOC_CTX * mem_ctx ,
2021-02-23 18:27:44 +03:00
const char * name ,
2008-09-16 00:41:37 +04:00
char * * normalized )
2007-01-31 08:38:36 +03:00
{
2008-09-16 00:41:37 +04:00
NTSTATUS nt_status ;
struct winbindd_domain * domain = find_our_domain ( ) ;
if ( ! name | | ! normalized ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2009-05-12 01:07:24 +04:00
2008-09-16 00:41:37 +04:00
if ( ! lp_winbind_normalize_names ( ) ) {
return NT_STATUS_PROCEDURE_NOT_FOUND ;
}
2007-01-31 08:38:36 +03:00
2008-09-16 00:41:37 +04:00
/* Alias support and whitespace replacement are mutally
exclusive */
/* When mapping from an alias to a username, we don't know the
domain . But we only need a domain structure to cache
a successful lookup , so just our own domain structure for
the seqnum . */
nt_status = resolve_alias_to_username ( mem_ctx , domain ,
name , normalized ) ;
if ( NT_STATUS_IS_OK ( nt_status ) ) {
/* Special return code to let the caller know we mapped
from an alias */
return NT_STATUS_FILE_RENAMED ;
}
/* check for an unreachable domain */
if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
DEBUG ( 5 , ( " normalize_name_unmap: Setting domain %s offline \n " ,
domain - > name ) ) ;
set_domain_offline ( domain ) ;
return nt_status ;
}
/* deal with whitespace */
* normalized = talloc_strdup ( mem_ctx , name ) ;
if ( ! ( * normalized ) ) {
return NT_STATUS_NO_MEMORY ;
}
all_string_sub ( * normalized , " _ " , " " , 0 ) ;
return NT_STATUS_OK ;
2007-01-31 08:38:36 +03:00
}
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 ) {
2012-07-17 23:31:31 +04:00
ret = true ;
goto done ;
2008-01-25 21:21:14 +03:00
}
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 ) ) ;
2012-07-17 23:31:31 +04:00
ret = false ;
goto done ;
2008-01-25 21:21:14 +03:00
}
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
}
2009-05-12 01:07:24 +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
2009-05-25 13:55:51 +04: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
2009-05-25 13:55:51 +04:00
ret = true ;
2008-01-25 21:21:14 +03:00
2009-05-25 13:55:51 +04:00
done :
2008-01-25 21:21:14 +03:00
talloc_destroy ( frame ) ;
2009-05-12 01:07:24 +04:00
2009-05-25 13:55:51 +04:00
return ret ;
2007-05-06 23:37:13 +04:00
}
2007-08-29 16:43:23 +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 */
2008-08-25 15:15:41 +04:00
void set_auth_errors ( struct winbindd_response * resp , NTSTATUS result )
{
resp - > data . auth . nt_status = NT_STATUS_V ( result ) ;
fstrcpy ( resp - > data . auth . nt_status_string , nt_errstr ( result ) ) ;
/* we might have given a more useful error above */
if ( * resp - > data . auth . error_string = = ' \0 ' )
fstrcpy ( resp - > data . auth . error_string ,
get_friendly_nt_error_msg ( result ) ) ;
resp - > data . auth . pam_error = nt_status_to_pam ( result ) ;
}
2009-12-24 14:52:24 +03:00
bool is_domain_offline ( const struct winbindd_domain * domain )
{
if ( get_global_winbindd_state_offline ( ) ) {
return true ;
}
return ! domain - > online ;
}
2011-03-08 16:23:15 +03:00
2011-03-22 18:37:41 +03:00
bool is_domain_online ( const struct winbindd_domain * domain )
{
return ! is_domain_offline ( domain ) ;
}
2012-11-09 14:32:47 +04:00
/**
* Parse an char array into a list of sids .
*
* The input sidstr should consist of 0 - terminated strings
* representing sids , separated by newline characters ' \n ' .
* The list is terminated by an empty string , i . e .
* character ' \0 ' directly following a character ' \n '
* ( or ' \0 ' right at the start of sidstr ) .
*/
2011-03-08 16:23:15 +03:00
bool parse_sidlist ( TALLOC_CTX * mem_ctx , const char * sidstr ,
struct dom_sid * * sids , uint32_t * num_sids )
{
const char * p ;
p = sidstr ;
if ( p = = NULL )
return False ;
while ( p [ 0 ] ! = ' \0 ' ) {
struct dom_sid sid ;
const char * q = NULL ;
if ( ! dom_sid_parse_endp ( p , & sid , & q ) ) {
DEBUG ( 1 , ( " Could not parse sid %s \n " , p ) ) ;
return false ;
}
2016-12-01 19:16:14 +03:00
if ( q [ 0 ] ! = ' \n ' ) {
2011-03-08 16:23:15 +03:00
DEBUG ( 1 , ( " Got invalid sidstr: %s \n " , p ) ) ;
return false ;
}
if ( ! NT_STATUS_IS_OK ( add_sid_to_array ( mem_ctx , & sid , sids ,
num_sids ) ) )
{
return False ;
}
p = q + 1 ;
}
return True ;
}
2015-08-14 18:14:53 +03:00
bool parse_xidlist ( TALLOC_CTX * mem_ctx , const char * xidstr ,
struct unixid * * pxids , uint32_t * pnum_xids )
{
const char * p ;
struct unixid * xids = NULL ;
uint32_t num_xids = 0 ;
p = xidstr ;
if ( p = = NULL ) {
return false ;
}
while ( p [ 0 ] ! = ' \0 ' ) {
struct unixid * tmp ;
struct unixid xid ;
unsigned long long id ;
char * endp ;
2019-01-28 16:07:39 +03:00
int error = 0 ;
2015-08-14 18:14:53 +03:00
switch ( p [ 0 ] ) {
case ' U ' :
xid = ( struct unixid ) { . type = ID_TYPE_UID } ;
break ;
case ' G ' :
xid = ( struct unixid ) { . type = ID_TYPE_GID } ;
break ;
default :
return false ;
}
p + = 1 ;
2019-06-04 10:04:15 +03:00
id = smb_strtoull ( p , & endp , 10 , & error , SMB_STR_STANDARD ) ;
2019-01-28 16:07:39 +03:00
if ( error ! = 0 ) {
2015-08-14 18:14:53 +03:00
goto fail ;
}
if ( * endp ! = ' \n ' ) {
goto fail ;
}
p = endp + 1 ;
xid . id = id ;
if ( ( unsigned long long ) xid . id ! = id ) {
goto fail ;
}
tmp = talloc_realloc ( mem_ctx , xids , struct unixid , num_xids + 1 ) ;
if ( tmp = = NULL ) {
return 0 ;
}
xids = tmp ;
xids [ num_xids ] = xid ;
num_xids + = 1 ;
}
* pxids = xids ;
* pnum_xids = num_xids ;
return true ;
fail :
TALLOC_FREE ( xids ) ;
return false ;
}