2001-10-05 04:20:06 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-10-05 04:20:06 +04:00
Winbind daemon connection manager
2005-06-09 02:10:34 +04:00
Copyright ( C ) Tim Potter 2001
Copyright ( C ) Andrew Bartlett 2002
Copyright ( C ) Gerald ( Jerry ) Carter 2003 - 2005.
Copyright ( C ) Volker Lendecke 2004 - 2005
2006-12-07 02:14:15 +03:00
Copyright ( C ) Jeremy Allison 2006
2008-08-19 12:14:59 +04:00
2001-10-05 04:20:06 +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
2001-10-05 04:20:06 +04:00
( at your option ) any later version .
2008-08-19 12:14:59 +04:00
2001-10-05 04:20:06 +04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2001-11-28 02:48:44 +03:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2001-10-05 04:20:06 +04:00
GNU General Public License for more details .
2008-08-19 12:14:59 +04:00
2001-10-05 04:20:06 +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/>.
2001-10-05 04:20:06 +04:00
*/
/*
We need to manage connections to domain controllers without having to
mess up the main winbindd code with other issues . The aim of the
connection manager is to :
2008-08-19 12:14:59 +04:00
2001-10-05 04:20:06 +04:00
- make connections to domain controllers and cache them
- re - establish connections when networks or servers go down
- centralise the policy on connection timeouts , domain controller
2001-11-28 02:48:44 +03:00
selection etc
2001-10-05 04:20:06 +04:00
- manage re - entrancy for when winbindd becomes able to handle
2001-11-28 02:48:44 +03:00
multiple outstanding rpc requests
2008-08-19 12:14:59 +04:00
2001-10-05 04:20:06 +04:00
Why not have connection management as part of the rpc layer like tng ?
Good question . This code may morph into libsmb / rpc_cache . c or something
2001-11-28 02:48:44 +03:00
like that but at the moment it ' s simply staying as part of winbind . I
2001-10-05 04:20:06 +04:00
think the TNG architecture of forcing every user of the rpc layer to use
2001-11-28 02:48:44 +03:00
the connection caching system is a bad idea . It should be an optional
2001-11-15 09:55:56 +03:00
method of using the routines .
2001-10-05 04:20:06 +04:00
The TNG design is quite good but I disagree with some aspects of the
implementation . - tpot
*/
/*
TODO :
- I ' m pretty annoyed by all the make_nmb_name ( ) stuff . It should be
moved down into another function .
2001-10-08 04:34:14 +04:00
- Take care when destroying cli_structs as they can be shared between
various sam handles .
2001-10-05 04:20:06 +04:00
*/
2003-11-12 04:51:10 +03:00
# include "includes.h"
2001-10-05 04:20:06 +04:00
# include "winbindd.h"
2009-03-16 13:27:58 +03:00
# include "../libcli/auth/libcli_auth.h"
2009-11-26 20:21:28 +03:00
# include "../librpc/gen_ndr/cli_netlogon.h"
2010-05-18 20:26:03 +04:00
# include "rpc_client/cli_netlogon.h"
2009-11-26 20:21:28 +03:00
# include "../librpc/gen_ndr/cli_samr.h"
# include "../librpc/gen_ndr/cli_lsa.h"
2010-05-18 20:26:16 +04:00
# include "rpc_client/cli_lsarpc.h"
2009-11-26 20:21:28 +03:00
# include "../librpc/gen_ndr/cli_dssetup.h"
2010-02-23 19:11:37 +03:00
# include "libads/sitename_cache.h"
2010-05-05 03:39:16 +04:00
# include "librpc/gen_ndr/messaging.h"
2010-05-18 21:40:31 +04:00
# include "libsmb/clidgram.h"
2001-10-05 04:20:06 +04:00
2002-07-15 14:35:28 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
2006-12-13 01:41:42 +03:00
struct dc_name_ip {
fstring name ;
2007-10-25 01:16:54 +04:00
struct sockaddr_storage ss ;
2006-12-13 01:41:42 +03:00
} ;
2006-12-18 23:37:26 +03:00
extern struct winbindd_methods reconnect_methods ;
2007-10-19 04:40:25 +04:00
extern bool override_logfile ;
2006-12-18 23:37:26 +03:00
2006-12-07 02:14:15 +03:00
static NTSTATUS init_dc_connection_network ( struct winbindd_domain * domain ) ;
2006-10-06 21:33:57 +04:00
static void set_dc_type_and_flags ( struct winbindd_domain * domain ) ;
2008-01-07 16:51:11 +03:00
static bool get_dcs ( TALLOC_CTX * mem_ctx , struct winbindd_domain * domain ,
2006-12-13 01:41:42 +03:00
struct dc_name_ip * * dcs , int * num_dcs ) ;
2006-09-07 01:43:31 +04:00
2006-12-07 02:14:15 +03:00
/****************************************************************
2006-12-13 01:41:42 +03:00
Child failed to find DC ' s . Reschedule check .
2006-12-07 02:14:15 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-16 18:45:09 +04:00
static void msg_failed_to_go_online ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
2006-12-07 02:14:15 +03:00
{
2006-12-13 01:41:42 +03:00
struct winbindd_domain * domain ;
2007-05-16 18:45:09 +04:00
const char * domainname = ( const char * ) data - > data ;
2006-12-07 08:48:01 +03:00
2007-05-16 18:45:09 +04:00
if ( data - > data = = NULL | | data - > length = = 0 ) {
2006-12-13 01:41:42 +03:00
return ;
}
DEBUG ( 5 , ( " msg_fail_to_go_online: received for domain %s. \n " , domainname ) ) ;
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
if ( domain - > internal ) {
continue ;
2006-12-07 02:14:15 +03:00
}
2006-12-13 01:41:42 +03:00
if ( strequal ( domain - > name , domainname ) ) {
if ( domain - > online ) {
/* We're already online, ignore. */
DEBUG ( 5 , ( " msg_fail_to_go_online: domain %s "
" already online. \n " , domainname ) ) ;
continue ;
}
/* Reschedule the online check. */
set_domain_offline ( domain ) ;
break ;
}
}
}
/****************************************************************
Actually cause a reconnect from a message .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-16 18:45:09 +04:00
static void msg_try_to_go_online ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
2006-12-13 01:41:42 +03:00
{
struct winbindd_domain * domain ;
2007-05-16 18:45:09 +04:00
const char * domainname = ( const char * ) data - > data ;
2006-12-13 01:41:42 +03:00
2007-05-16 18:45:09 +04:00
if ( data - > data = = NULL | | data - > length = = 0 ) {
2006-12-13 01:41:42 +03:00
return ;
}
DEBUG ( 5 , ( " msg_try_to_go_online: received for domain %s. \n " , domainname ) ) ;
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
if ( domain - > internal ) {
continue ;
}
if ( strequal ( domain - > name , domainname ) ) {
if ( domain - > online ) {
/* We're already online, ignore. */
DEBUG ( 5 , ( " msg_try_to_go_online: domain %s "
" already online. \n " , domainname ) ) ;
continue ;
}
/* This call takes care of setting the online
flag to true if we connected , or re - adding
the offline handler if false . Bypasses online
check so always does network calls . */
init_dc_connection_network ( domain ) ;
break ;
}
}
}
/****************************************************************
Fork a child to try and contact a DC . Do this as contacting a
DC requires blocking lookups and we don ' t want to block our
parent .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool fork_child_dc_connect ( struct winbindd_domain * domain )
2006-12-13 01:41:42 +03:00
{
struct dc_name_ip * dcs = NULL ;
int num_dcs = 0 ;
TALLOC_CTX * mem_ctx = NULL ;
pid_t parent_pid = sys_getpid ( ) ;
2009-01-07 04:34:06 +03:00
char * lfile = NULL ;
2006-12-13 01:41:42 +03:00
2008-08-21 03:24:22 +04:00
if ( domain - > dc_probe_pid ! = ( pid_t ) - 1 ) {
/*
* We might already have a DC probe
* child working , check .
*/
if ( process_exists_by_pid ( domain - > dc_probe_pid ) ) {
DEBUG ( 10 , ( " fork_child_dc_connect: pid %u already "
" checking for DC's. \n " ,
( unsigned int ) domain - > dc_probe_pid ) ) ;
return true ;
}
domain - > dc_probe_pid = ( pid_t ) - 1 ;
}
2006-12-13 01:41:42 +03:00
2008-08-21 03:24:22 +04:00
domain - > dc_probe_pid = sys_fork ( ) ;
if ( domain - > dc_probe_pid = = ( pid_t ) - 1 ) {
2006-12-13 01:41:42 +03:00
DEBUG ( 0 , ( " fork_child_dc_connect: Could not fork: %s \n " , strerror ( errno ) ) ) ;
return False ;
}
2008-08-21 03:24:22 +04:00
if ( domain - > dc_probe_pid ! = ( pid_t ) 0 ) {
2006-12-13 01:41:42 +03:00
/* Parent */
2007-05-16 18:45:09 +04:00
messaging_register ( winbind_messaging_context ( ) , NULL ,
MSG_WINBIND_TRY_TO_GO_ONLINE ,
msg_try_to_go_online ) ;
messaging_register ( winbind_messaging_context ( ) , NULL ,
MSG_WINBIND_FAILED_TO_GO_ONLINE ,
msg_failed_to_go_online ) ;
2006-12-13 01:41:42 +03:00
return True ;
}
/* Child. */
/* Leave messages blocked - we will never process one. */
2009-01-07 04:34:06 +03:00
if ( ! override_logfile ) {
if ( asprintf ( & lfile , " %s/log.winbindd-dc-connect " , get_dyn_LOGFILEBASE ( ) ) = = - 1 ) {
DEBUG ( 0 , ( " fork_child_dc_connect: out of memory. \n " ) ) ;
2009-01-14 02:42:56 +03:00
_exit ( 1 ) ;
2009-01-07 04:34:06 +03:00
}
}
if ( ! winbindd_reinit_after_fork ( lfile ) ) {
2008-08-21 03:24:22 +04:00
messaging_send_buf ( winbind_messaging_context ( ) ,
pid_to_procid ( parent_pid ) ,
MSG_WINBIND_FAILED_TO_GO_ONLINE ,
( uint8 * ) domain - > name ,
strlen ( domain - > name ) + 1 ) ;
2009-01-14 02:42:56 +03:00
_exit ( 1 ) ;
2006-12-07 02:14:15 +03:00
}
2009-01-07 04:34:06 +03:00
SAFE_FREE ( lfile ) ;
2006-12-13 01:41:42 +03:00
mem_ctx = talloc_init ( " fork_child_dc_connect " ) ;
if ( ! mem_ctx ) {
DEBUG ( 0 , ( " talloc_init failed. \n " ) ) ;
2008-08-21 03:24:22 +04:00
messaging_send_buf ( winbind_messaging_context ( ) ,
pid_to_procid ( parent_pid ) ,
MSG_WINBIND_FAILED_TO_GO_ONLINE ,
( uint8 * ) domain - > name ,
strlen ( domain - > name ) + 1 ) ;
2009-01-14 02:42:56 +03:00
_exit ( 1 ) ;
2006-12-13 01:41:42 +03:00
}
if ( ( ! get_dcs ( mem_ctx , domain , & dcs , & num_dcs ) ) | | ( num_dcs = = 0 ) ) {
/* Still offline ? Can't find DC's. */
2007-05-15 14:50:44 +04:00
messaging_send_buf ( winbind_messaging_context ( ) ,
pid_to_procid ( parent_pid ) ,
MSG_WINBIND_FAILED_TO_GO_ONLINE ,
( uint8 * ) domain - > name ,
strlen ( domain - > name ) + 1 ) ;
2006-12-13 01:41:42 +03:00
_exit ( 0 ) ;
}
/* We got a DC. Send a message to our parent to get it to
try and do the same . */
2007-05-15 14:50:44 +04:00
messaging_send_buf ( winbind_messaging_context ( ) ,
pid_to_procid ( parent_pid ) ,
MSG_WINBIND_TRY_TO_GO_ONLINE ,
( uint8 * ) domain - > name ,
strlen ( domain - > name ) + 1 ) ;
2006-12-13 01:41:42 +03:00
_exit ( 0 ) ;
2006-12-07 02:14:15 +03:00
}
2006-09-07 01:43:31 +04:00
/****************************************************************
Handler triggered if we ' re offline to try and detect a DC .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-01-17 15:59:14 +03:00
static void check_domain_online_handler ( struct event_context * ctx ,
struct timed_event * te ,
2009-01-05 12:22:50 +03:00
struct timeval now ,
2006-09-07 01:43:31 +04:00
void * private_data )
{
struct winbindd_domain * domain =
( struct winbindd_domain * ) private_data ;
2007-05-07 01:10:30 +04:00
DEBUG ( 10 , ( " check_domain_online_handler: called for domain "
" %s (online = %s) \n " , domain - > name ,
domain - > online ? " True " : " False " ) ) ;
2006-09-07 01:43:31 +04:00
2007-06-21 18:04:55 +04:00
TALLOC_FREE ( domain - > check_online_event ) ;
2006-09-07 01:43:31 +04:00
2006-09-28 22:08:03 +04:00
/* Are we still in "startup" mode ? */
2009-01-05 12:22:50 +03:00
if ( domain - > startup & & ( now . tv_sec > domain - > startup_time + 30 ) ) {
2006-09-28 22:08:03 +04:00
/* No longer in "startup" mode. */
DEBUG ( 10 , ( " check_domain_online_handler: domain %s no longer in 'startup' mode. \n " ,
domain - > name ) ) ;
domain - > startup = False ;
}
2006-09-07 01:43:31 +04:00
/* We've been told to stay offline, so stay
that way . */
if ( get_global_winbindd_state_offline ( ) ) {
DEBUG ( 10 , ( " check_domain_online_handler: domain %s remaining globally offline \n " ,
domain - > name ) ) ;
return ;
}
2006-12-13 01:41:42 +03:00
/* Fork a child to test if it can contact a DC.
If it can then send ourselves a message to
cause a reconnect . */
2006-12-07 02:14:15 +03:00
2006-12-13 01:41:42 +03:00
fork_child_dc_connect ( domain ) ;
}
/****************************************************************
2006-12-13 04:11:29 +03:00
If we ' re still offline setup the timeout check .
2006-12-13 01:41:42 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void calc_new_online_timeout_check ( struct winbindd_domain * domain )
{
2008-08-21 03:24:22 +04:00
int wbr = lp_winbind_reconnect_delay ( ) ;
2006-12-13 01:41:42 +03:00
if ( domain - > startup ) {
domain - > check_online_timeout = 10 ;
2008-08-21 03:24:22 +04:00
} else if ( domain - > check_online_timeout < wbr ) {
domain - > check_online_timeout = wbr ;
2006-12-13 01:41:42 +03:00
}
2006-09-07 01:43:31 +04:00
}
/****************************************************************
Set domain offline and also add handler to put us back online
if we detect a DC .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void set_domain_offline ( struct winbindd_domain * domain )
{
DEBUG ( 10 , ( " set_domain_offline: called for domain %s \n " ,
domain - > name ) ) ;
2007-06-21 18:04:55 +04:00
TALLOC_FREE ( domain - > check_online_event ) ;
2006-09-07 01:43:31 +04:00
2006-10-10 08:00:42 +04:00
if ( domain - > internal ) {
DEBUG ( 3 , ( " set_domain_offline: domain %s is internal - logic error. \n " ,
domain - > name ) ) ;
return ;
}
2006-09-07 01:43:31 +04:00
domain - > online = False ;
2006-12-07 02:14:15 +03:00
/* Offline domains are always initialized. They're
re - initialized when they go back online . */
domain - > initialized = True ;
2006-09-07 01:43:31 +04:00
/* We only add the timeout handler that checks and
allows us to go back online when we ' ve not
been told to remain offline . */
if ( get_global_winbindd_state_offline ( ) ) {
DEBUG ( 10 , ( " set_domain_offline: domain %s remaining globally offline \n " ,
domain - > name ) ) ;
return ;
}
2009-07-26 22:56:58 +04:00
/* If we're in startup mode, check again in 10 seconds, not in
2008-08-21 03:24:22 +04:00
lp_winbind_reconnect_delay ( ) seconds ( which is 30 seconds by default ) . */
2006-09-28 22:08:03 +04:00
2006-12-07 08:48:01 +03:00
calc_new_online_timeout_check ( domain ) ;
2006-12-07 02:14:15 +03:00
2007-01-20 00:29:46 +03:00
domain - > check_online_event = event_add_timed ( winbind_event_context ( ) ,
NULL ,
2006-12-07 02:14:15 +03:00
timeval_current_ofs ( domain - > check_online_timeout , 0 ) ,
2006-09-07 01:43:31 +04:00
check_domain_online_handler ,
domain ) ;
/* The above *has* to succeed for winbindd to work. */
if ( ! domain - > check_online_event ) {
2007-06-16 01:58:49 +04:00
smb_panic ( " set_domain_offline: failed to add online handler " ) ;
2006-09-07 01:43:31 +04:00
}
DEBUG ( 10 , ( " set_domain_offline: added event handler for domain %s \n " ,
domain - > name ) ) ;
2007-05-07 01:10:30 +04:00
/* Send an offline message to the idmap child when our
primary domain goes offline */
if ( domain - > primary ) {
struct winbindd_child * idmap = idmap_child ( ) ;
2008-08-19 12:14:59 +04:00
2007-05-07 01:10:30 +04:00
if ( idmap - > pid ! = 0 ) {
2007-05-15 14:50:44 +04:00
messaging_send_buf ( winbind_messaging_context ( ) ,
pid_to_procid ( idmap - > pid ) ,
MSG_WINBIND_OFFLINE ,
( uint8 * ) domain - > name ,
strlen ( domain - > name ) + 1 ) ;
2007-05-07 01:10:30 +04:00
}
}
return ;
2006-09-07 01:43:31 +04:00
}
/****************************************************************
Set domain online - if allowed .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-09-14 13:11:30 +04:00
static void set_domain_online ( struct winbindd_domain * domain )
2006-09-07 01:43:31 +04:00
{
2006-09-07 05:07:43 +04:00
DEBUG ( 10 , ( " set_domain_online: called for domain %s \n " ,
2006-09-07 01:43:31 +04:00
domain - > name ) ) ;
2006-10-10 08:00:42 +04:00
if ( domain - > internal ) {
2007-02-19 20:47:50 +03:00
DEBUG ( 3 , ( " set_domain_online: domain %s is internal - logic error. \n " ,
2006-10-10 08:00:42 +04:00
domain - > name ) ) ;
return ;
}
2006-09-07 01:43:31 +04:00
if ( get_global_winbindd_state_offline ( ) ) {
DEBUG ( 10 , ( " set_domain_online: domain %s remaining globally offline \n " ,
domain - > name ) ) ;
return ;
}
2007-09-04 18:06:33 +04:00
winbindd_set_locator_kdc_envs ( domain ) ;
2006-09-13 17:55:19 +04:00
/* If we are waiting to get a krb5 ticket, trigger immediately. */
2008-12-30 11:56:36 +03:00
ccache_regain_all_now ( ) ;
2006-09-28 22:08:03 +04:00
/* Ok, we're out of any startup mode now... */
domain - > startup = False ;
2006-10-06 06:04:57 +04:00
2006-10-06 21:33:57 +04:00
if ( domain - > online = = False ) {
/* We were offline - now we're online. We default to
using the MS - RPC backend if we started offline ,
and if we ' re going online for the first time we
should really re - initialize the backends and the
checks to see if we ' re talking to an AD or NT domain .
*/
domain - > initialized = False ;
/* 'reconnect_methods' is the MS-RPC backend. */
if ( domain - > backend = = & reconnect_methods ) {
domain - > backend = NULL ;
}
2006-10-06 06:04:57 +04:00
}
2006-10-06 21:33:57 +04:00
2006-12-07 02:14:15 +03:00
/* Ensure we have no online timeout checks. */
domain - > check_online_timeout = 0 ;
2007-06-21 18:04:55 +04:00
TALLOC_FREE ( domain - > check_online_event ) ;
2006-12-07 02:14:15 +03:00
2006-12-13 01:41:42 +03:00
/* Ensure we ignore any pending child messages. */
2007-05-20 01:53:28 +04:00
messaging_deregister ( winbind_messaging_context ( ) ,
MSG_WINBIND_TRY_TO_GO_ONLINE , NULL ) ;
messaging_deregister ( winbind_messaging_context ( ) ,
MSG_WINBIND_FAILED_TO_GO_ONLINE , NULL ) ;
2006-12-13 01:41:42 +03:00
2006-10-06 21:33:57 +04:00
domain - > online = True ;
2007-05-07 01:10:30 +04:00
/* Send an online message to the idmap child when our
primary domain comes online */
if ( domain - > primary ) {
struct winbindd_child * idmap = idmap_child ( ) ;
2008-08-19 12:14:59 +04:00
2007-05-07 01:10:30 +04:00
if ( idmap - > pid ! = 0 ) {
2007-05-15 14:50:44 +04:00
messaging_send_buf ( winbind_messaging_context ( ) ,
pid_to_procid ( idmap - > pid ) ,
MSG_WINBIND_ONLINE ,
( uint8 * ) domain - > name ,
strlen ( domain - > name ) + 1 ) ;
2007-05-07 01:10:30 +04:00
}
}
return ;
2006-09-07 01:43:31 +04:00
}
2006-09-14 13:11:30 +04:00
/****************************************************************
2006-09-14 18:26:33 +04:00
Requested to set a domain online .
2006-09-14 13:11:30 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void set_domain_online_request ( struct winbindd_domain * domain )
{
2006-12-19 03:48:39 +03:00
struct timeval tev ;
2006-09-14 13:11:30 +04:00
DEBUG ( 10 , ( " set_domain_online_request: called for domain %s \n " ,
domain - > name ) ) ;
if ( get_global_winbindd_state_offline ( ) ) {
DEBUG ( 10 , ( " set_domain_online_request: domain %s remaining globally offline \n " ,
domain - > name ) ) ;
return ;
}
2009-08-22 19:13:09 +04:00
if ( domain - > internal ) {
DEBUG ( 10 , ( " set_domain_online_request: Internal domains are "
" always online \n " ) ) ;
return ;
}
2006-09-14 18:26:33 +04:00
/* We've been told it's safe to go online and
2006-09-28 22:08:03 +04:00
try and connect to a DC . But I don ' t believe it
because network manager seems to lie .
2006-09-14 18:26:33 +04:00
Wait at least 5 seconds . Heuristics suck . . . */
2006-09-14 13:11:30 +04:00
2008-12-30 11:34:20 +03:00
GetTimeOfDay ( & tev ) ;
/* Go into "startup" mode again. */
domain - > startup_time = tev . tv_sec ;
domain - > startup = True ;
tev . tv_sec + = 5 ;
2006-09-14 18:26:33 +04:00
if ( ! domain - > check_online_event ) {
2006-12-19 03:48:39 +03:00
/* If we've come from being globally offline we
don ' t have a check online event handler set .
We need to add one now we ' re trying to go
back online . */
2006-09-14 13:11:30 +04:00
2006-12-19 03:48:39 +03:00
DEBUG ( 10 , ( " set_domain_online_request: domain %s was globally offline. \n " ,
domain - > name ) ) ;
2006-09-14 13:11:30 +04:00
}
2006-12-19 03:48:39 +03:00
2008-12-30 11:34:20 +03:00
TALLOC_FREE ( domain - > check_online_event ) ;
2006-12-19 03:48:39 +03:00
2008-12-30 11:34:20 +03:00
domain - > check_online_event = event_add_timed ( winbind_event_context ( ) ,
NULL ,
tev ,
check_domain_online_handler ,
domain ) ;
2007-01-17 15:59:14 +03:00
2008-12-30 11:34:20 +03:00
/* The above *has* to succeed for winbindd to work. */
if ( ! domain - > check_online_event ) {
smb_panic ( " set_domain_online_request: failed to add online handler " ) ;
}
2006-09-14 13:11:30 +04:00
}
2006-09-07 01:43:31 +04:00
/****************************************************************
Add - ve connection cache entries for domain and realm .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void winbind_add_failed_connection_entry ( const struct winbindd_domain * domain ,
const char * server ,
NTSTATUS result )
{
add_failed_connection_entry ( domain - > name , server , result ) ;
2006-09-07 07:44:05 +04:00
/* If this was the saf name for the last thing we talked to,
remove it . */
2006-11-17 02:48:46 +03:00
saf_delete ( domain - > name ) ;
2006-09-07 01:43:31 +04:00
if ( * domain - > alt_name ) {
add_failed_connection_entry ( domain - > alt_name , server , result ) ;
2006-11-17 02:48:46 +03:00
saf_delete ( domain - > alt_name ) ;
2006-09-07 01:43:31 +04:00
}
2007-09-04 18:06:33 +04:00
winbindd_unset_locator_kdc_env ( domain ) ;
2006-09-07 01:43:31 +04:00
}
2005-07-27 21:30:23 +04:00
2001-12-11 08:19:15 +03:00
/* Choose between anonymous or authenticated connections. We need to use
an authenticated connection if DCs have the RestrictAnonymous registry
entry set > 0 , or the " Additional restrictions for anonymous
2002-02-15 16:28:59 +03:00
connections " set in the win2k Local Security Policy.
2008-08-19 12:14:59 +04:00
2002-02-15 16:28:59 +03:00
Caller to free ( ) result in domain , username , password
*/
2001-12-11 08:19:15 +03:00
2002-02-15 16:28:59 +03:00
static void cm_get_ipc_userpass ( char * * username , char * * domain , char * * password )
2001-12-11 08:19:15 +03:00
{
2006-08-16 21:14:16 +04:00
* username = ( char * ) secrets_fetch ( SECRETS_AUTH_USER , NULL ) ;
* domain = ( char * ) secrets_fetch ( SECRETS_AUTH_DOMAIN , NULL ) ;
* password = ( char * ) secrets_fetch ( SECRETS_AUTH_PASSWORD , NULL ) ;
2008-08-19 12:14:59 +04:00
2002-02-15 16:28:59 +03:00
if ( * username & & * * username ) {
2002-11-02 04:06:10 +03:00
if ( ! * domain | | ! * * domain )
2002-02-15 16:28:59 +03:00
* domain = smb_xstrdup ( lp_workgroup ( ) ) ;
2008-08-19 12:14:59 +04:00
2002-11-02 04:06:10 +03:00
if ( ! * password | | ! * * password )
* password = smb_xstrdup ( " " ) ;
2005-04-01 02:02:38 +04:00
DEBUG ( 3 , ( " cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s \\ %s] \n " ,
2002-11-02 04:06:10 +03:00
* domain , * username ) ) ;
2002-02-15 16:28:59 +03:00
} else {
2005-04-01 02:02:38 +04:00
DEBUG ( 3 , ( " cm_get_ipc_userpass: No auth-user defined \n " ) ) ;
2002-02-15 16:28:59 +03:00
* username = smb_xstrdup ( " " ) ;
* domain = smb_xstrdup ( " " ) ;
* password = smb_xstrdup ( " " ) ;
}
2001-12-11 08:19:15 +03:00
}
2008-01-07 16:51:11 +03:00
static bool get_dc_name_via_netlogon ( struct winbindd_domain * domain ,
2007-10-25 01:16:54 +04:00
fstring dcname ,
struct sockaddr_storage * dc_ss )
2004-04-20 06:37:49 +04:00
{
2006-01-30 20:47:24 +03:00
struct winbindd_domain * our_domain = NULL ;
struct rpc_pipe_client * netlogon_pipe = NULL ;
2004-04-20 06:37:49 +04:00
NTSTATUS result ;
2006-10-06 20:13:10 +04:00
WERROR werr ;
2004-04-20 06:37:49 +04:00
TALLOC_CTX * mem_ctx ;
2006-10-07 01:35:26 +04:00
unsigned int orig_timeout ;
2008-02-07 12:24:18 +03:00
const char * tmp = NULL ;
const char * p ;
2004-04-20 06:37:49 +04:00
2005-06-09 02:10:34 +04:00
/* Hmmmm. We can only open one connection to the NETLOGON pipe at the
* moment . . . . */
2005-09-30 21:13:37 +04:00
if ( IS_DC ) {
2004-04-20 06:37:49 +04:00
return False ;
2005-09-30 21:13:37 +04:00
}
2004-04-20 06:37:49 +04:00
2005-09-30 21:13:37 +04:00
if ( domain - > primary ) {
2004-04-20 06:37:49 +04:00
return False ;
2005-09-30 21:13:37 +04:00
}
2004-04-20 06:37:49 +04:00
2005-06-09 02:10:34 +04:00
our_domain = find_our_domain ( ) ;
2004-04-20 06:37:49 +04:00
2005-09-30 21:13:37 +04:00
if ( ( mem_ctx = talloc_init ( " get_dc_name_via_netlogon " ) ) = = NULL ) {
2004-04-20 06:37:49 +04:00
return False ;
2005-06-09 02:10:34 +04:00
}
2005-09-30 21:13:37 +04:00
result = cm_connect_netlogon ( our_domain , & netlogon_pipe ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
2006-12-16 04:32:57 +03:00
talloc_destroy ( mem_ctx ) ;
2004-04-20 06:37:49 +04:00
return False ;
2005-09-30 21:13:37 +04:00
}
2004-04-20 06:37:49 +04:00
2006-10-07 01:35:26 +04:00
/* This call can take a long time - allow the server to time out.
35 seconds should do it . */
2008-04-20 01:27:35 +04:00
orig_timeout = rpccli_set_timeout ( netlogon_pipe , 35000 ) ;
2008-01-07 16:51:11 +03:00
2008-01-04 22:31:07 +03:00
if ( our_domain - > active_directory ) {
2008-02-09 01:28:02 +03:00
struct netr_DsRGetDCNameInfo * domain_info = NULL ;
result = rpccli_netr_DsRGetDCName ( netlogon_pipe ,
mem_ctx ,
our_domain - > dcname ,
domain - > name ,
NULL ,
NULL ,
DS_RETURN_DNS_NAME ,
& domain_info ,
& werr ) ;
2009-01-14 22:47:45 +03:00
if ( NT_STATUS_IS_OK ( result ) & & W_ERROR_IS_OK ( werr ) ) {
2008-01-20 11:03:32 +03:00
tmp = talloc_strdup (
2008-02-09 01:28:02 +03:00
mem_ctx , domain_info - > dc_unc ) ;
2008-01-20 11:03:32 +03:00
if ( tmp = = NULL ) {
DEBUG ( 0 , ( " talloc_strdup failed \n " ) ) ;
talloc_destroy ( mem_ctx ) ;
return false ;
}
2008-01-04 22:31:07 +03:00
if ( strlen ( domain - > alt_name ) = = 0 ) {
2008-01-07 16:51:11 +03:00
fstrcpy ( domain - > alt_name ,
domain_info - > domain_name ) ;
2008-01-04 22:31:07 +03:00
}
if ( strlen ( domain - > forest_name ) = = 0 ) {
2008-01-07 16:51:11 +03:00
fstrcpy ( domain - > forest_name ,
2008-02-09 01:28:02 +03:00
domain_info - > forest_name ) ;
2008-01-04 22:31:07 +03:00
}
2008-01-07 16:51:11 +03:00
}
2008-01-04 22:31:07 +03:00
} else {
2008-02-07 12:24:18 +03:00
result = rpccli_netr_GetAnyDCName ( netlogon_pipe , mem_ctx ,
our_domain - > dcname ,
domain - > name ,
& tmp ,
& werr ) ;
2008-01-04 22:31:07 +03:00
}
2004-04-20 06:37:49 +04:00
2006-10-07 01:35:26 +04:00
/* And restore our original timeout. */
2008-04-20 01:27:35 +04:00
rpccli_set_timeout ( netlogon_pipe , orig_timeout ) ;
2006-10-07 01:35:26 +04:00
2008-02-07 12:24:18 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " rpccli_netr_GetAnyDCName failed: %s \n " ,
nt_errstr ( result ) ) ) ;
talloc_destroy ( mem_ctx ) ;
return false ;
}
2006-10-06 20:13:10 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2008-02-07 12:24:18 +03:00
DEBUG ( 10 , ( " rpccli_netr_GetAnyDCName failed: %s \n " ,
2008-11-01 19:19:26 +03:00
win_errstr ( werr ) ) ) ;
2008-01-20 11:03:32 +03:00
talloc_destroy ( mem_ctx ) ;
2008-02-07 12:24:18 +03:00
return false ;
2005-10-27 15:01:29 +04:00
}
2004-04-20 06:37:49 +04:00
2008-02-07 12:24:18 +03:00
/* rpccli_netr_GetAnyDCName gives us a name with \\ */
2008-05-08 16:23:20 +04:00
p = strip_hostname ( tmp ) ;
2004-04-20 06:37:49 +04:00
fstrcpy ( dcname , p ) ;
2008-01-20 11:03:32 +03:00
talloc_destroy ( mem_ctx ) ;
2008-02-07 12:24:18 +03:00
DEBUG ( 10 , ( " rpccli_netr_GetAnyDCName returned %s \n " , dcname ) ) ;
2005-10-27 15:01:29 +04:00
2009-07-28 22:51:58 +04:00
if ( ! resolve_name ( dcname , dc_ss , 0x20 , true ) ) {
2004-04-20 06:37:49 +04:00
return False ;
2005-09-30 21:13:37 +04:00
}
2004-04-20 06:37:49 +04:00
return True ;
}
2007-12-11 18:32:38 +03:00
/**
* Helper function to assemble trust password and account name
*/
static NTSTATUS get_trust_creds ( const struct winbindd_domain * domain ,
char * * machine_password ,
char * * machine_account ,
char * * machine_krb5_principal )
{
const char * account_name ;
2008-01-25 21:18:05 +03:00
const char * name = NULL ;
2008-08-19 12:14:59 +04:00
2008-01-25 21:18:05 +03:00
/* If we are a DC and this is not our own domain */
if ( IS_DC ) {
name = domain - > name ;
} else {
struct winbindd_domain * our_domain = find_our_domain ( ) ;
2007-12-11 18:32:38 +03:00
2008-01-25 21:18:05 +03:00
if ( ! our_domain )
return NT_STATUS_INVALID_SERVER_STATE ;
2008-08-19 12:14:59 +04:00
2008-01-25 21:18:05 +03:00
name = our_domain - > name ;
}
2008-08-19 12:14:59 +04:00
2008-01-25 21:18:05 +03:00
if ( ! get_trust_pw_clear ( name , machine_password ,
2007-12-11 18:32:38 +03:00
& account_name , NULL ) )
{
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
if ( ( machine_account ! = NULL ) & &
( asprintf ( machine_account , " %s$ " , account_name ) = = - 1 ) )
{
return NT_STATUS_NO_MEMORY ;
}
2008-05-24 00:19:58 +04:00
/* For now assume our machine account only exists in our domain */
2008-01-23 14:03:51 +03:00
if ( machine_krb5_principal ! = NULL )
2007-12-11 18:32:38 +03:00
{
2008-06-03 20:18:44 +04:00
struct winbindd_domain * our_domain = find_our_domain ( ) ;
if ( ! our_domain ) {
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
2008-08-19 12:14:59 +04:00
2008-01-23 14:03:51 +03:00
if ( asprintf ( machine_krb5_principal , " %s$@%s " ,
2008-06-03 20:18:44 +04:00
account_name , our_domain - > alt_name ) = = - 1 )
2008-01-23 14:03:51 +03:00
{
return NT_STATUS_NO_MEMORY ;
}
strupper_m ( * machine_krb5_principal ) ;
2007-12-11 18:32:38 +03:00
}
return NT_STATUS_OK ;
}
2004-11-18 14:57:49 +03:00
/************************************************************************
Given a fd with a just - connected TCP connection to a DC , open a connection
to the pipe .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-02-15 16:28:59 +03:00
2004-11-18 14:57:49 +03:00
static NTSTATUS cm_prepare_connection ( const struct winbindd_domain * domain ,
const int sockfd ,
const char * controller ,
struct cli_state * * cli ,
2007-10-19 04:40:25 +04:00
bool * retry )
2001-10-05 04:20:06 +04:00
{
2007-12-11 17:39:36 +03:00
char * machine_password = NULL ;
char * machine_krb5_principal = NULL ;
char * machine_account = NULL ;
char * ipc_username = NULL ;
char * ipc_domain = NULL ;
char * ipc_password = NULL ;
2002-02-15 16:28:59 +03:00
2008-03-10 23:08:29 +03:00
struct named_mutex * mutex ;
2001-11-15 22:40:00 +03:00
2004-11-18 14:57:49 +03:00
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
2002-10-02 03:07:12 +04:00
2004-11-18 14:57:49 +03:00
struct sockaddr peeraddr ;
socklen_t peeraddr_len ;
2004-04-20 06:37:49 +04:00
2009-05-08 01:07:55 +04:00
struct sockaddr_in * peeraddr_in =
( struct sockaddr_in * ) ( void * ) & peeraddr ;
2004-04-20 06:37:49 +04:00
2006-09-07 20:51:17 +04:00
DEBUG ( 10 , ( " cm_prepare_connection: connecting to DC %s for domain %s \n " ,
controller , domain - > name ) ) ;
2004-11-18 14:57:49 +03:00
* retry = True ;
2008-03-10 23:08:29 +03:00
mutex = grab_named_mutex ( talloc_tos ( ) , controller ,
WINBIND_SERVER_MUTEX_WAIT_TIME ) ;
if ( mutex = = NULL ) {
2005-12-12 17:08:42 +03:00
DEBUG ( 0 , ( " cm_prepare_connection: mutex grab failed for %s \n " ,
2004-11-18 14:57:49 +03:00
controller ) ) ;
result = NT_STATUS_POSSIBLE_DEADLOCK ;
goto done ;
}
2006-07-11 22:01:26 +04:00
if ( ( * cli = cli_initialise ( ) ) = = NULL ) {
2004-11-18 14:57:49 +03:00
DEBUG ( 1 , ( " Could not cli_initialize \n " ) ) ;
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
( * cli ) - > timeout = 10000 ; /* 10 seconds */
( * cli ) - > fd = sockfd ;
fstrcpy ( ( * cli ) - > desthost , controller ) ;
( * cli ) - > use_kerberos = True ;
peeraddr_len = sizeof ( peeraddr ) ;
2010-05-15 01:21:47 +04:00
if ( ( getpeername ( ( * cli ) - > fd , & peeraddr , & peeraddr_len ) ! = 0 ) ) {
DEBUG ( 0 , ( " cm_prepare_connection: getpeername failed with: %s \n " ,
strerror ( errno ) ) ) ;
result = NT_STATUS_UNSUCCESSFUL ;
goto done ;
}
if ( ( peeraddr_len ! = sizeof ( struct sockaddr_in ) )
# ifdef HAVE_IPV6
& & ( peeraddr_len ! = sizeof ( struct sockaddr_in6 ) )
# endif
) {
DEBUG ( 0 , ( " cm_prepare_connection: got unexpected peeraddr len %d \n " ,
peeraddr_len ) ) ;
result = NT_STATUS_UNSUCCESSFUL ;
goto done ;
}
if ( ( peeraddr_in - > sin_family ! = PF_INET )
# ifdef HAVE_IPV6
& & ( peeraddr_in - > sin_family ! = PF_INET6 )
# endif
) {
DEBUG ( 0 , ( " cm_prepare_connection: got unexpected family %d \n " ,
peeraddr_in - > sin_family ) ) ;
2006-05-26 16:28:55 +04:00
result = NT_STATUS_UNSUCCESSFUL ;
2004-11-18 14:57:49 +03:00
goto done ;
2005-01-06 20:50:51 +03:00
}
2004-11-18 14:57:49 +03:00
if ( ntohs ( peeraddr_in - > sin_port ) = = 139 ) {
struct nmb_name calling ;
struct nmb_name called ;
make_nmb_name ( & calling , global_myname ( ) , 0x0 ) ;
make_nmb_name ( & called , " *SMBSERVER " , 0x20 ) ;
if ( ! cli_session_request ( * cli , & calling , & called ) ) {
DEBUG ( 8 , ( " cli_session_request failed for %s \n " ,
controller ) ) ;
2006-05-26 16:28:55 +04:00
result = NT_STATUS_UNSUCCESSFUL ;
2004-11-18 14:57:49 +03:00
goto done ;
2003-01-16 23:08:26 +03:00
}
2004-11-18 14:57:49 +03:00
}
2003-08-20 02:47:10 +04:00
2008-09-11 20:57:49 +04:00
result = cli_negprot ( * cli ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 1 , ( " cli_negprot failed: %s \n " , nt_errstr ( result ) ) ) ;
2004-11-18 14:57:49 +03:00
goto done ;
}
2007-12-11 17:39:36 +03:00
2008-05-26 14:38:48 +04:00
if ( ! is_dc_trusted_domain_situation ( domain - > name ) & &
2007-12-11 17:39:36 +03:00
( * cli ) - > protocol > = PROTOCOL_NT1 & &
( * cli ) - > capabilities & CAP_EXTENDED_SECURITY )
{
2004-11-18 14:57:49 +03:00
ADS_STATUS ads_status ;
2005-09-30 21:13:37 +04:00
2007-12-11 18:32:38 +03:00
result = get_trust_creds ( domain , & machine_password ,
& machine_account ,
& machine_krb5_principal ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
2008-04-09 11:48:59 +04:00
goto anon_fallback ;
2007-12-11 17:39:36 +03:00
}
2005-09-30 21:13:37 +04:00
if ( lp_security ( ) = = SEC_ADS ) {
/* Try a krb5 session */
( * cli ) - > use_kerberos = True ;
DEBUG ( 5 , ( " connecting to %s from %s with kerberos principal "
2008-05-24 01:01:45 +04:00
" [%s] and realm [%s] \n " , controller , global_myname ( ) ,
machine_krb5_principal , domain - > alt_name ) ) ;
2005-09-30 21:13:37 +04:00
2007-09-04 18:06:33 +04:00
winbindd_set_locator_kdc_envs ( domain ) ;
2005-09-30 21:13:37 +04:00
ads_status = cli_session_setup_spnego ( * cli ,
machine_krb5_principal ,
2008-05-24 01:01:45 +04:00
machine_password ,
lp_workgroup ( ) ,
2009-09-09 04:29:58 +04:00
domain - > alt_name ) ;
2005-09-30 21:13:37 +04:00
if ( ! ADS_ERR_OK ( ads_status ) ) {
DEBUG ( 4 , ( " failed kerberos session setup with %s \n " ,
ads_errstr ( ads_status ) ) ) ;
}
result = ads_ntstatus ( ads_status ) ;
if ( NT_STATUS_IS_OK ( result ) ) {
/* Ensure creds are stored for NTLMSSP authenticated pipe access. */
2009-03-14 03:49:24 +03:00
result = cli_init_creds ( * cli , machine_account , lp_workgroup ( ) , machine_password ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
2005-09-30 21:13:37 +04:00
goto session_setup_done ;
}
}
/* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
( * cli ) - > use_kerberos = False ;
DEBUG ( 5 , ( " connecting to %s from %s with username "
" [%s] \\ [%s] \n " , controller , global_myname ( ) ,
2008-05-24 01:01:45 +04:00
lp_workgroup ( ) , machine_account ) ) ;
2004-11-18 14:57:49 +03:00
ads_status = cli_session_setup_spnego ( * cli ,
2005-09-30 21:13:37 +04:00
machine_account ,
2004-11-18 14:57:49 +03:00
machine_password ,
2008-05-24 01:01:45 +04:00
lp_workgroup ( ) ,
NULL ) ;
2005-09-30 21:13:37 +04:00
if ( ! ADS_ERR_OK ( ads_status ) ) {
DEBUG ( 4 , ( " authenticated session setup failed with %s \n " ,
ads_errstr ( ads_status ) ) ) ;
}
2004-11-18 14:57:49 +03:00
result = ads_ntstatus ( ads_status ) ;
2005-09-30 21:13:37 +04:00
if ( NT_STATUS_IS_OK ( result ) ) {
/* Ensure creds are stored for NTLMSSP authenticated pipe access. */
2009-03-14 03:49:24 +03:00
result = cli_init_creds ( * cli , machine_account , lp_workgroup ( ) , machine_password ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
2005-09-30 21:13:37 +04:00
goto session_setup_done ;
}
2004-11-18 14:57:49 +03:00
}
2003-08-20 08:25:09 +04:00
2007-12-11 17:39:36 +03:00
/* Fall back to non-kerberos session setup with auth_user */
2004-11-18 14:57:49 +03:00
( * cli ) - > use_kerberos = False ;
2007-12-11 10:52:20 +03:00
cm_get_ipc_userpass ( & ipc_username , & ipc_domain , & ipc_password ) ;
2004-11-18 14:57:49 +03:00
if ( ( ( ( * cli ) - > sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE ) ! = 0 ) & &
( strlen ( ipc_username ) > 0 ) ) {
/* Only try authenticated if we have a username */
DEBUG ( 5 , ( " connecting to %s from %s with username "
" [%s] \\ [%s] \n " , controller , global_myname ( ) ,
ipc_domain , ipc_username ) ) ;
2006-08-16 21:14:16 +04:00
if ( NT_STATUS_IS_OK ( cli_session_setup (
* cli , ipc_username ,
ipc_password , strlen ( ipc_password ) + 1 ,
ipc_password , strlen ( ipc_password ) + 1 ,
ipc_domain ) ) ) {
2005-09-30 21:13:37 +04:00
/* Successful logon with given username. */
2009-03-14 03:49:24 +03:00
result = cli_init_creds ( * cli , ipc_username , ipc_domain , ipc_password ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
2004-11-18 14:57:49 +03:00
goto session_setup_done ;
2005-09-30 21:13:37 +04:00
} else {
DEBUG ( 4 , ( " authenticated session setup with user %s \\ %s failed. \n " ,
ipc_domain , ipc_username ) ) ;
2003-08-20 02:47:10 +04:00
}
2004-11-18 14:57:49 +03:00
}
2008-04-09 11:48:59 +04:00
anon_fallback :
2004-11-18 14:57:49 +03:00
/* Fall back to anonymous connection, this might fail later */
2008-08-23 00:49:46 +04:00
DEBUG ( 10 , ( " cm_prepare_connection: falling back to anonymous "
" connection for DC %s \n " ,
controller ) ) ;
2004-11-18 14:57:49 +03:00
2006-08-16 21:14:16 +04:00
if ( NT_STATUS_IS_OK ( cli_session_setup ( * cli , " " , NULL , 0 ,
NULL , 0 , " " ) ) ) {
2004-11-18 14:57:49 +03:00
DEBUG ( 5 , ( " Connected anonymously \n " ) ) ;
2009-03-14 03:49:24 +03:00
result = cli_init_creds ( * cli , " " , " " , " " ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
2004-11-18 14:57:49 +03:00
goto session_setup_done ;
}
result = cli_nt_error ( * cli ) ;
if ( NT_STATUS_IS_OK ( result ) )
result = NT_STATUS_UNSUCCESSFUL ;
2003-08-20 02:47:10 +04:00
2004-11-18 14:57:49 +03:00
/* We can't session setup */
goto done ;
session_setup_done :
2006-02-04 00:19:24 +03:00
/* cache the server name for later connections */
2006-02-15 21:45:25 +03:00
saf_store ( domain - > name , ( * cli ) - > desthost ) ;
2006-09-06 01:11:08 +04:00
if ( domain - > alt_name & & ( * cli ) - > use_kerberos ) {
2006-09-05 10:32:46 +04:00
saf_store ( domain - > alt_name , ( * cli ) - > desthost ) ;
}
2006-02-04 00:19:24 +03:00
2007-09-04 18:06:33 +04:00
winbindd_set_locator_kdc_envs ( domain ) ;
2009-01-26 10:37:13 +03:00
result = cli_tcon_andx ( * cli , " IPC$ " , " IPC " , " " , 0 ) ;
2004-11-18 14:57:49 +03:00
2009-01-26 10:37:13 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2004-11-18 14:57:49 +03:00
DEBUG ( 1 , ( " failed tcon_X with %s \n " , nt_errstr ( result ) ) ) ;
goto done ;
2002-10-17 21:10:24 +04:00
}
2001-10-05 04:20:06 +04:00
2008-03-10 23:08:29 +03:00
TALLOC_FREE ( mutex ) ;
2004-11-18 14:57:49 +03:00
* retry = False ;
2004-06-03 22:00:22 +04:00
2004-11-18 14:57:49 +03:00
/* set the domain if empty; needed for schannel connections */
2009-03-14 03:49:24 +03:00
if ( ! ( * cli ) - > domain [ 0 ] ) {
result = cli_set_domain ( ( * cli ) , domain - > name ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
return result ;
}
2005-09-30 21:13:37 +04:00
}
2004-11-18 14:57:49 +03:00
result = NT_STATUS_OK ;
done :
2008-03-10 23:08:29 +03:00
TALLOC_FREE ( mutex ) ;
2005-09-30 21:13:37 +04:00
SAFE_FREE ( machine_account ) ;
2004-11-18 14:57:49 +03:00
SAFE_FREE ( machine_password ) ;
SAFE_FREE ( machine_krb5_principal ) ;
2002-02-15 16:28:59 +03:00
SAFE_FREE ( ipc_username ) ;
SAFE_FREE ( ipc_domain ) ;
SAFE_FREE ( ipc_password ) ;
2001-11-15 06:33:12 +03:00
2006-05-26 16:28:55 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2006-09-07 01:43:31 +04:00
winbind_add_failed_connection_entry ( domain , controller , result ) ;
2006-05-26 16:28:55 +04:00
if ( ( * cli ) ! = NULL ) {
cli_shutdown ( * cli ) ;
* cli = NULL ;
}
2005-09-30 21:13:37 +04:00
}
2004-11-18 14:57:49 +03:00
return result ;
}
2008-09-04 02:31:39 +04:00
/*******************************************************************
Add a dcname and sockaddr_storage pair to the end of a dc_name_ip
array .
Keeps the list unique by not adding duplicate entries .
@ param [ in ] mem_ctx talloc memory context to allocate from
@ param [ in ] domain_name domain of the DC
@ param [ in ] dcname name of the DC to add to the list
@ param [ in ] pss Internet address and port pair to add to the list
@ param [ in , out ] dcs array of dc_name_ip structures to add to
@ param [ in , out ] num_dcs number of dcs returned in the dcs array
@ return true if the list was added to , false otherwise
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool add_one_dc_unique ( TALLOC_CTX * mem_ctx , const char * domain_name ,
2007-10-25 01:16:54 +04:00
const char * dcname , struct sockaddr_storage * pss ,
2004-11-18 14:57:49 +03:00
struct dc_name_ip * * dcs , int * num )
{
2008-09-04 02:31:39 +04:00
int i = 0 ;
2005-10-27 15:01:29 +04:00
if ( ! NT_STATUS_IS_OK ( check_negative_conn_cache ( domain_name , dcname ) ) ) {
DEBUG ( 10 , ( " DC %s was in the negative conn cache \n " , dcname ) ) ;
2004-11-18 14:57:49 +03:00
return False ;
2005-10-27 15:01:29 +04:00
}
2004-11-18 14:57:49 +03:00
2008-09-04 02:31:39 +04:00
/* Make sure there's no duplicates in the list */
for ( i = 0 ; i < * num ; i + + )
2009-05-08 01:07:55 +04:00
if ( sockaddr_equal (
( struct sockaddr * ) ( void * ) & ( * dcs ) [ i ] . ss ,
( struct sockaddr * ) ( void * ) pss ) )
2008-09-04 02:31:39 +04:00
return False ;
2004-12-07 21:25:53 +03:00
* dcs = TALLOC_REALLOC_ARRAY ( mem_ctx , * dcs , struct dc_name_ip , ( * num ) + 1 ) ;
2004-11-18 14:57:49 +03:00
if ( * dcs = = NULL )
return False ;
fstrcpy ( ( * dcs ) [ * num ] . name , dcname ) ;
2007-10-25 01:16:54 +04:00
( * dcs ) [ * num ] . ss = * pss ;
2004-11-18 14:57:49 +03:00
* num + = 1 ;
return True ;
}
2007-10-19 04:40:25 +04:00
static bool add_sockaddr_to_array ( TALLOC_CTX * mem_ctx ,
2007-10-25 01:16:54 +04:00
struct sockaddr_storage * pss , uint16 port ,
struct sockaddr_storage * * addrs , int * num )
2004-11-18 14:57:49 +03:00
{
2007-10-25 01:16:54 +04:00
* addrs = TALLOC_REALLOC_ARRAY ( mem_ctx , * addrs , struct sockaddr_storage , ( * num ) + 1 ) ;
2004-11-18 14:57:49 +03:00
2006-12-09 05:58:18 +03:00
if ( * addrs = = NULL ) {
* num = 0 ;
2004-11-18 14:57:49 +03:00
return False ;
2006-12-09 05:58:18 +03:00
}
2004-11-18 14:57:49 +03:00
2007-10-25 01:16:54 +04:00
( * addrs ) [ * num ] = * pss ;
2008-10-24 03:35:53 +04:00
set_sockaddr_port ( ( struct sockaddr * ) & ( * addrs ) [ * num ] , port ) ;
2007-11-21 21:10:52 +03:00
2004-11-18 14:57:49 +03:00
* num + = 1 ;
return True ;
}
2005-02-11 17:31:14 +03:00
/*******************************************************************
convert an ip to a name
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-04-21 19:51:36 +04:00
static bool dcip_to_name ( TALLOC_CTX * mem_ctx ,
const struct winbindd_domain * domain ,
2007-10-25 01:16:54 +04:00
struct sockaddr_storage * pss ,
fstring name )
2004-11-18 14:57:49 +03:00
{
2006-03-28 17:34:13 +04:00
struct ip_service ip_list ;
2008-09-23 23:08:25 +04:00
uint32_t nt_version = NETLOGON_NT_VERSION_1 ;
2006-03-28 17:34:13 +04:00
2007-10-25 01:16:54 +04:00
ip_list . ss = * pss ;
2006-03-28 17:34:13 +04:00
ip_list . port = 0 ;
2005-06-09 02:10:34 +04:00
2006-08-31 05:20:21 +04:00
# ifdef WITH_ADS
/* For active directory servers, try to get the ldap server name.
None of these failures should be considered critical for now */
2006-09-03 07:46:07 +04:00
if ( lp_security ( ) = = SEC_ADS ) {
2006-08-31 05:20:21 +04:00
ADS_STRUCT * ads ;
2008-06-27 18:22:39 +04:00
ADS_STATUS ads_status ;
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) , pss ) ;
2006-08-31 05:20:21 +04:00
2008-06-27 18:22:39 +04:00
ads = ads_init ( domain - > alt_name , domain - > name , addr ) ;
2006-08-31 05:20:21 +04:00
ads - > auth . flags | = ADS_AUTH_NO_BIND ;
2008-06-27 18:22:39 +04:00
ads_status = ads_connect ( ads ) ;
if ( ADS_ERR_OK ( ads_status ) ) {
2006-08-31 05:20:21 +04:00
/* We got a cldap packet. */
fstrcpy ( name , ads - > config . ldap_server_name ) ;
namecache_store ( name , 0x20 , 1 , & ip_list ) ;
2006-09-02 05:23:08 +04:00
DEBUG ( 10 , ( " dcip_to_name: flags = 0x%x \n " , ( unsigned int ) ads - > config . flags ) ) ;
2006-10-04 19:05:00 +04:00
2008-04-21 21:59:27 +04:00
if ( domain - > primary & & ( ads - > config . flags & NBT_SERVER_KDC ) ) {
2007-09-08 18:56:11 +04:00
if ( ads_closest_dc ( ads ) ) {
char * sitename = sitename_fetch ( ads - > config . realm ) ;
/* We're going to use this KDC for this realm/domain.
If we are using sites , then force the krb5 libs
to use this KDC . */
create_local_private_krb5_conf_for_domain ( domain - > alt_name ,
domain - > name ,
sitename ,
2010-05-15 01:23:34 +04:00
pss ,
name ) ;
2007-09-08 18:56:11 +04:00
SAFE_FREE ( sitename ) ;
} else {
/* use an off site KDC */
create_local_private_krb5_conf_for_domain ( domain - > alt_name ,
domain - > name ,
NULL ,
2010-05-15 01:23:34 +04:00
pss ,
name ) ;
2007-09-08 18:56:11 +04:00
}
2007-09-04 18:06:33 +04:00
winbindd_set_locator_kdc_envs ( domain ) ;
2006-09-15 18:18:52 +04:00
/* Ensure we contact this DC also. */
2006-12-21 03:43:21 +03:00
saf_store ( domain - > name , name ) ;
saf_store ( domain - > alt_name , name ) ;
2006-08-31 05:20:21 +04:00
}
2006-10-04 19:05:00 +04:00
2006-08-31 05:20:21 +04:00
ads_destroy ( & ads ) ;
return True ;
}
ads_destroy ( & ads ) ;
}
# endif
/* try GETDC requests next */
2007-10-25 01:16:54 +04:00
2008-04-21 19:51:36 +04:00
if ( send_getdc_request ( mem_ctx , winbind_messaging_context ( ) ,
2008-05-05 20:04:41 +04:00
pss , domain - > name , & domain - > sid ,
nt_version ) ) {
2008-04-21 12:55:23 +04:00
const char * dc_name = NULL ;
2005-10-22 01:46:49 +04:00
int i ;
smb_msleep ( 100 ) ;
for ( i = 0 ; i < 5 ; i + + ) {
2008-04-24 23:37:42 +04:00
if ( receive_getdc_response ( mem_ctx , pss , domain - > name ,
2008-05-07 20:57:43 +04:00
& nt_version ,
2008-04-24 23:37:42 +04:00
& dc_name , NULL ) ) {
2008-04-21 12:55:23 +04:00
fstrcpy ( name , dc_name ) ;
2006-03-28 17:34:13 +04:00
namecache_store ( name , 0x20 , 1 , & ip_list ) ;
2006-05-26 16:28:55 +04:00
return True ;
2006-03-28 17:34:13 +04:00
}
2005-10-22 01:46:49 +04:00
smb_msleep ( 500 ) ;
}
2005-06-09 02:10:34 +04:00
}
/* try node status request */
2004-11-18 14:57:49 +03:00
2007-10-25 01:16:54 +04:00
if ( name_status_find ( domain - > name , 0x1c , 0x20 , pss , name ) ) {
2006-03-28 17:34:13 +04:00
namecache_store ( name , 0x20 , 1 , & ip_list ) ;
2006-05-26 16:28:55 +04:00
return True ;
2006-03-28 17:34:13 +04:00
}
2006-05-26 16:28:55 +04:00
return False ;
2004-11-18 14:57:49 +03:00
}
2005-02-11 17:31:14 +03:00
/*******************************************************************
2008-09-04 02:31:39 +04:00
Retrieve a list of IP addresses for domain controllers .
The array is sorted in the preferred connection order .
@ param [ in ] mem_ctx talloc memory context to allocate from
@ param [ in ] domain domain to retrieve DCs for
@ param [ out ] dcs array of dcs that will be returned
@ param [ out ] num_dcs number of dcs returned in the dcs array
@ return always true
2005-02-11 17:31:14 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-01-07 16:51:11 +03:00
static bool get_dcs ( TALLOC_CTX * mem_ctx , struct winbindd_domain * domain ,
2004-11-18 14:57:49 +03:00
struct dc_name_ip * * dcs , int * num_dcs )
{
fstring dcname ;
2007-10-25 01:16:54 +04:00
struct sockaddr_storage ss ;
2005-02-11 17:31:14 +03:00
struct ip_service * ip_list = NULL ;
int iplist_size = 0 ;
int i ;
2007-10-19 04:40:25 +04:00
bool is_our_domain ;
2006-08-30 22:48:49 +04:00
enum security_types sec = ( enum security_types ) lp_security ( ) ;
2004-11-18 14:57:49 +03:00
is_our_domain = strequal ( domain - > name , lp_workgroup ( ) ) ;
2008-09-04 02:31:39 +04:00
/* If not our domain, get the preferred DC, by asking our primary DC */
2007-10-25 01:16:54 +04:00
if ( ! is_our_domain
& & get_dc_name_via_netlogon ( domain , dcname , & ss )
2008-09-04 02:31:39 +04:00
& & add_one_dc_unique ( mem_ctx , domain - > name , dcname , & ss , dcs ,
num_dcs ) )
2005-02-11 17:31:14 +03:00
{
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) , & ss ) ;
2005-10-27 15:01:29 +04:00
DEBUG ( 10 , ( " Retrieved DC %s at %s via netlogon \n " ,
2007-10-25 01:16:54 +04:00
dcname , addr ) ) ;
2005-02-11 17:31:14 +03:00
return True ;
2004-11-18 14:57:49 +03:00
}
2006-08-30 22:48:49 +04:00
if ( sec = = SEC_ADS ) {
2007-01-17 21:25:35 +03:00
char * sitename = NULL ;
2006-08-30 22:48:49 +04:00
/* We need to make sure we know the local site before
doing any DNS queries , as this will restrict the
get_sorted_dc_list ( ) call below to only fetching
DNS records for the correct site . */
/* Find any DC to get the site record.
We deliberately don ' t care about the
return here . */
2007-01-17 21:25:35 +03:00
2007-10-25 01:16:54 +04:00
get_dc_name ( domain - > name , domain - > alt_name , dcname , & ss ) ;
2004-11-18 14:57:49 +03:00
2007-01-31 23:05:48 +03:00
sitename = sitename_fetch ( domain - > alt_name ) ;
2007-01-17 22:11:45 +03:00
if ( sitename ) {
2007-01-17 21:25:35 +03:00
2007-01-17 22:11:45 +03:00
/* Do the site-specific AD dns lookup first. */
2008-09-04 02:31:39 +04:00
get_sorted_dc_list ( domain - > alt_name , sitename , & ip_list ,
& iplist_size , True ) ;
2007-01-17 21:25:35 +03:00
2008-09-04 02:31:39 +04:00
/* Add ips to the DC array. We don't look up the name
of the DC in this function , but we fill in the char *
of the ip now to make the failed connection cache
work */
2007-01-17 22:11:45 +03:00
for ( i = 0 ; i < iplist_size ; i + + ) {
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) ,
& ip_list [ i ] . ss ) ;
add_one_dc_unique ( mem_ctx ,
domain - > name ,
addr ,
& ip_list [ i ] . ss ,
dcs ,
num_dcs ) ;
2007-01-17 22:11:45 +03:00
}
2007-01-17 21:25:35 +03:00
2007-01-17 22:11:45 +03:00
SAFE_FREE ( ip_list ) ;
SAFE_FREE ( sitename ) ;
iplist_size = 0 ;
}
2007-01-17 21:25:35 +03:00
2008-09-04 02:31:39 +04:00
/* Now we add DCs from the main AD DNS lookup. */
get_sorted_dc_list ( domain - > alt_name , NULL , & ip_list ,
& iplist_size , True ) ;
2007-01-17 21:25:35 +03:00
for ( i = 0 ; i < iplist_size ; i + + ) {
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) ,
& ip_list [ i ] . ss ) ;
add_one_dc_unique ( mem_ctx ,
domain - > name ,
addr ,
& ip_list [ i ] . ss ,
dcs ,
num_dcs ) ;
2007-01-17 21:25:35 +03:00
}
2004-11-18 14:57:49 +03:00
2008-09-04 02:31:39 +04:00
SAFE_FREE ( ip_list ) ;
iplist_size = 0 ;
}
2004-11-18 14:57:49 +03:00
2008-09-04 02:31:39 +04:00
/* Try standard netbios queries if no ADS */
if ( * num_dcs = = 0 ) {
get_sorted_dc_list ( domain - > name , NULL , & ip_list , & iplist_size ,
False ) ;
2005-06-09 02:10:34 +04:00
2008-09-04 02:31:39 +04:00
for ( i = 0 ; i < iplist_size ; i + + ) {
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) ,
& ip_list [ i ] . ss ) ;
add_one_dc_unique ( mem_ctx ,
domain - > name ,
addr ,
& ip_list [ i ] . ss ,
dcs ,
num_dcs ) ;
}
2005-01-14 15:17:18 +03:00
2008-09-04 02:31:39 +04:00
SAFE_FREE ( ip_list ) ;
iplist_size = 0 ;
2002-02-15 16:28:59 +03:00
}
2001-11-15 22:40:00 +03:00
2004-11-18 14:57:49 +03:00
return True ;
}
2008-09-04 02:31:39 +04:00
/*******************************************************************
Find and make a connection to a DC in the given domain .
@ param [ in ] mem_ctx talloc memory context to allocate from
@ param [ in ] domain domain to find a dc in
@ param [ out ] dcname NetBIOS or FQDN of DC that ' s connected to
@ param [ out ] pss DC Internet address and port
@ param [ out ] fd fd of the open socket connected to the newly found dc
@ return true when a DC connection is made , false otherwise
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool find_new_dc ( TALLOC_CTX * mem_ctx ,
2008-01-07 16:51:11 +03:00
struct winbindd_domain * domain ,
2007-10-25 01:16:54 +04:00
fstring dcname , struct sockaddr_storage * pss , int * fd )
2004-11-18 14:57:49 +03:00
{
struct dc_name_ip * dcs = NULL ;
int num_dcs = 0 ;
2005-02-11 17:31:14 +03:00
const char * * dcnames = NULL ;
2004-11-18 14:57:49 +03:00
int num_dcnames = 0 ;
2007-10-25 01:16:54 +04:00
struct sockaddr_storage * addrs = NULL ;
2004-11-18 14:57:49 +03:00
int num_addrs = 0 ;
int i , fd_index ;
2008-06-09 01:19:44 +04:00
* fd = - 1 ;
2006-05-26 16:28:55 +04:00
again :
2004-11-18 14:57:49 +03:00
if ( ! get_dcs ( mem_ctx , domain , & dcs , & num_dcs ) | | ( num_dcs = = 0 ) )
return False ;
for ( i = 0 ; i < num_dcs ; i + + ) {
2006-12-09 05:58:18 +03:00
if ( ! add_string_to_array ( mem_ctx , dcs [ i ] . name ,
& dcnames , & num_dcnames ) ) {
return False ;
}
2007-10-25 01:16:54 +04:00
if ( ! add_sockaddr_to_array ( mem_ctx , & dcs [ i ] . ss , 445 ,
2006-12-09 05:58:18 +03:00
& addrs , & num_addrs ) ) {
return False ;
}
2004-11-18 14:57:49 +03:00
2006-12-09 05:58:18 +03:00
if ( ! add_string_to_array ( mem_ctx , dcs [ i ] . name ,
& dcnames , & num_dcnames ) ) {
return False ;
}
2007-10-25 01:16:54 +04:00
if ( ! add_sockaddr_to_array ( mem_ctx , & dcs [ i ] . ss , 139 ,
2006-12-09 05:58:18 +03:00
& addrs , & num_addrs ) ) {
return False ;
}
2004-11-18 14:57:49 +03:00
}
if ( ( num_dcnames = = 0 ) | | ( num_dcnames ! = num_addrs ) )
return False ;
2006-06-19 23:41:56 +04:00
if ( ( addrs = = NULL ) | | ( dcnames = = NULL ) )
return False ;
2006-09-06 23:02:39 +04:00
/* 5 second timeout. */
2007-10-25 01:16:54 +04:00
if ( ! open_any_socket_out ( addrs , num_addrs , 5000 , & fd_index , fd ) ) {
2004-11-18 14:57:49 +03:00
for ( i = 0 ; i < num_dcs ; i + + ) {
2007-10-25 01:16:54 +04:00
char ab [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( ab , sizeof ( ab ) , & dcs [ i ] . ss ) ;
2006-09-14 18:26:33 +04:00
DEBUG ( 10 , ( " find_new_dc: open_any_socket_out failed for "
2006-09-15 18:05:28 +04:00
" domain %s address %s. Error was %s \n " ,
2007-10-25 01:16:54 +04:00
domain - > name , ab , strerror ( errno ) ) ) ;
2006-09-07 01:43:31 +04:00
winbind_add_failed_connection_entry ( domain ,
2005-02-11 17:31:14 +03:00
dcs [ i ] . name , NT_STATUS_UNSUCCESSFUL ) ;
2004-11-18 14:57:49 +03:00
}
return False ;
}
2007-10-25 01:16:54 +04:00
* pss = addrs [ fd_index ] ;
2004-11-18 14:57:49 +03:00
2007-10-25 01:16:54 +04:00
if ( * dcnames [ fd_index ] ! = ' \0 ' & & ! is_ipaddress ( dcnames [ fd_index ] ) ) {
2006-05-26 16:28:55 +04:00
/* Ok, we've got a name for the DC */
2005-02-11 17:31:14 +03:00
fstrcpy ( dcname , dcnames [ fd_index ] ) ;
2006-05-26 16:28:55 +04:00
return True ;
}
2005-02-11 17:31:14 +03:00
2006-05-26 16:28:55 +04:00
/* Try to figure out the name */
2008-04-21 19:51:36 +04:00
if ( dcip_to_name ( mem_ctx , domain , pss , dcname ) ) {
2006-05-26 16:28:55 +04:00
return True ;
}
/* We can not continue without the DC's name */
2006-09-07 01:43:31 +04:00
winbind_add_failed_connection_entry ( domain , dcs [ fd_index ] . name ,
2006-05-26 16:28:55 +04:00
NT_STATUS_UNSUCCESSFUL ) ;
2008-06-09 01:19:44 +04:00
/* Throw away all arrays as we're doing this again. */
TALLOC_FREE ( dcs ) ;
num_dcs = 0 ;
TALLOC_FREE ( dcnames ) ;
num_dcnames = 0 ;
2008-08-19 12:14:59 +04:00
2008-06-09 01:19:44 +04:00
TALLOC_FREE ( addrs ) ;
num_addrs = 0 ;
2008-08-06 08:02:45 +04:00
close ( * fd ) ;
2008-06-09 01:19:44 +04:00
* fd = - 1 ;
2006-05-26 16:28:55 +04:00
goto again ;
2004-11-18 14:57:49 +03:00
}
static NTSTATUS cm_open_connection ( struct winbindd_domain * domain ,
struct winbindd_cm_conn * new_conn )
{
TALLOC_CTX * mem_ctx ;
NTSTATUS result ;
2006-02-04 00:19:24 +03:00
char * saf_servername = saf_fetch ( domain - > name ) ;
2004-11-18 14:57:49 +03:00
int retries ;
2006-09-03 03:06:21 +04:00
if ( ( mem_ctx = talloc_init ( " cm_open_connection " ) ) = = NULL ) {
SAFE_FREE ( saf_servername ) ;
2006-09-07 01:43:31 +04:00
set_domain_offline ( domain ) ;
2004-11-18 14:57:49 +03:00
return NT_STATUS_NO_MEMORY ;
2006-09-03 03:06:21 +04:00
}
2004-11-18 14:57:49 +03:00
2006-02-04 00:19:24 +03:00
/* we have to check the server affinity cache here since
later we selecte a DC based on response time and not preference */
2008-08-19 12:14:59 +04:00
2006-09-03 03:06:21 +04:00
/* Check the negative connection cache
before talking to it . It going down may have
triggered the reconnection . */
if ( saf_servername & & NT_STATUS_IS_OK ( check_negative_conn_cache ( domain - > name , saf_servername ) ) ) {
2006-09-07 20:51:17 +04:00
DEBUG ( 10 , ( " cm_open_connection: saf_servername is '%s' for domain %s \n " ,
saf_servername , domain - > name ) ) ;
2006-02-04 00:19:24 +03:00
/* convert an ip address to a name */
2007-10-25 01:16:54 +04:00
if ( is_ipaddress ( saf_servername ) ) {
2006-02-04 00:19:24 +03:00
fstring saf_name ;
2007-10-25 01:16:54 +04:00
struct sockaddr_storage ss ;
2006-02-04 00:19:24 +03:00
2007-10-25 01:16:54 +04:00
if ( ! interpret_string_addr ( & ss , saf_servername ,
AI_NUMERICHOST ) ) {
return NT_STATUS_UNSUCCESSFUL ;
}
2008-04-21 19:51:36 +04:00
if ( dcip_to_name ( mem_ctx , domain , & ss , saf_name ) ) {
2006-05-26 16:28:55 +04:00
fstrcpy ( domain - > dcname , saf_name ) ;
} else {
2006-09-07 01:43:31 +04:00
winbind_add_failed_connection_entry (
domain , saf_servername ,
2006-05-26 16:28:55 +04:00
NT_STATUS_UNSUCCESSFUL ) ;
}
2006-09-03 03:06:21 +04:00
} else {
2006-02-04 00:19:24 +03:00
fstrcpy ( domain - > dcname , saf_servername ) ;
}
SAFE_FREE ( saf_servername ) ;
}
2004-11-18 14:57:49 +03:00
for ( retries = 0 ; retries < 3 ; retries + + ) {
int fd = - 1 ;
2007-10-19 04:40:25 +04:00
bool retry = False ;
2004-11-18 14:57:49 +03:00
result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ;
2006-09-07 20:51:17 +04:00
DEBUG ( 10 , ( " cm_open_connection: dcname is '%s' for domain %s \n " ,
domain - > dcname , domain - > name ) ) ;
if ( * domain - > dcname
2006-02-04 01:19:41 +03:00
& & NT_STATUS_IS_OK ( check_negative_conn_cache ( domain - > name , domain - > dcname ) )
2009-07-28 22:51:58 +04:00
& & ( resolve_name ( domain - > dcname , & domain - > dcaddr , 0x20 , true ) ) )
2006-02-04 00:19:24 +03:00
{
2007-10-25 01:16:54 +04:00
struct sockaddr_storage * addrs = NULL ;
2006-02-04 00:19:24 +03:00
int num_addrs = 0 ;
int dummy = 0 ;
2007-10-25 01:16:54 +04:00
if ( ! add_sockaddr_to_array ( mem_ctx , & domain - > dcaddr , 445 , & addrs , & num_addrs ) ) {
2006-12-09 05:58:18 +03:00
set_domain_offline ( domain ) ;
2006-12-16 04:32:57 +03:00
talloc_destroy ( mem_ctx ) ;
2006-12-09 05:58:18 +03:00
return NT_STATUS_NO_MEMORY ;
}
2007-10-25 01:16:54 +04:00
if ( ! add_sockaddr_to_array ( mem_ctx , & domain - > dcaddr , 139 , & addrs , & num_addrs ) ) {
2006-12-09 05:58:18 +03:00
set_domain_offline ( domain ) ;
2006-12-16 04:32:57 +03:00
talloc_destroy ( mem_ctx ) ;
2006-12-09 05:58:18 +03:00
return NT_STATUS_NO_MEMORY ;
}
2006-02-04 00:19:24 +03:00
2006-09-06 23:02:39 +04:00
/* 5 second timeout. */
if ( ! open_any_socket_out ( addrs , num_addrs , 5000 , & dummy , & fd ) ) {
2004-11-18 14:57:49 +03:00
fd = - 1 ;
}
}
2006-02-04 00:19:24 +03:00
if ( ( fd = = - 1 )
2006-02-04 01:19:41 +03:00
& & ! find_new_dc ( mem_ctx , domain , domain - > dcname , & domain - > dcaddr , & fd ) )
2006-02-04 00:19:24 +03:00
{
2006-02-04 01:19:41 +03:00
/* This is the one place where we will
set the global winbindd offline state
to true , if a " WINBINDD_OFFLINE " entry
is found in the winbindd cache . */
set_global_winbindd_state_offline ( ) ;
2004-11-18 14:57:49 +03:00
break ;
2006-02-04 00:19:24 +03:00
}
2004-11-18 14:57:49 +03:00
new_conn - > cli = NULL ;
2005-06-09 02:10:34 +04:00
result = cm_prepare_connection ( domain , fd , domain - > dcname ,
& new_conn - > cli , & retry ) ;
2004-11-18 14:57:49 +03:00
if ( ! retry )
break ;
}
2006-02-04 01:19:41 +03:00
if ( NT_STATUS_IS_OK ( result ) ) {
2007-09-04 18:06:33 +04:00
winbindd_set_locator_kdc_envs ( domain ) ;
2006-02-04 01:19:41 +03:00
if ( domain - > online = = False ) {
/* We're changing state from offline to online. */
set_global_winbindd_state_online ( ) ;
}
2006-09-07 01:43:31 +04:00
set_domain_online ( domain ) ;
} else {
/* Ensure we setup the retry handler. */
set_domain_offline ( domain ) ;
2006-02-04 01:19:41 +03:00
}
2004-11-18 14:57:49 +03:00
talloc_destroy ( mem_ctx ) ;
return result ;
2001-10-05 04:20:06 +04:00
}
2006-02-04 01:19:41 +03:00
/* Close down all open pipes on a connection. */
2001-10-27 08:48:22 +04:00
2005-06-09 02:10:34 +04:00
void invalidate_cm_connection ( struct winbindd_cm_conn * conn )
2001-10-27 08:48:22 +04:00
{
2006-09-06 23:02:39 +04:00
/* We're closing down a possibly dead
connection . Don ' t have impossibly long ( 10 s ) timeouts . */
if ( conn - > cli ) {
cli_set_timeout ( conn - > cli , 1000 ) ; /* 1 second. */
}
2005-06-09 02:10:34 +04:00
if ( conn - > samr_pipe ! = NULL ) {
2010-07-06 17:33:50 +04:00
if ( is_valid_policy_hnd ( & conn - > sam_connect_handle ) ) {
rpccli_samr_Close ( conn - > samr_pipe , talloc_tos ( ) ,
& conn - > sam_connect_handle ) ;
}
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( conn - > samr_pipe ) ;
/* Ok, it must be dead. Drop timeout to 0.5 sec. */
if ( conn - > cli ) {
cli_set_timeout ( conn - > cli , 500 ) ;
2006-09-06 23:02:39 +04:00
}
2002-02-15 16:28:59 +03:00
}
2005-06-09 02:10:34 +04:00
if ( conn - > lsa_pipe ! = NULL ) {
2010-07-06 17:33:50 +04:00
if ( is_valid_policy_hnd ( & conn - > lsa_policy ) ) {
rpccli_lsa_Close ( conn - > lsa_pipe , talloc_tos ( ) ,
& conn - > lsa_policy ) ;
}
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( conn - > lsa_pipe ) ;
/* Ok, it must be dead. Drop timeout to 0.5 sec. */
if ( conn - > cli ) {
cli_set_timeout ( conn - > cli , 500 ) ;
2006-09-06 23:02:39 +04:00
}
2002-03-18 13:53:02 +03:00
}
2009-09-13 01:30:39 +04:00
if ( conn - > lsa_pipe_tcp ! = NULL ) {
2010-07-06 17:33:50 +04:00
if ( is_valid_policy_hnd ( & conn - > lsa_policy ) ) {
rpccli_lsa_Close ( conn - > lsa_pipe , talloc_tos ( ) ,
& conn - > lsa_policy ) ;
}
2009-09-13 01:30:39 +04:00
TALLOC_FREE ( conn - > lsa_pipe_tcp ) ;
/* Ok, it must be dead. Drop timeout to 0.5 sec. */
if ( conn - > cli ) {
cli_set_timeout ( conn - > cli , 500 ) ;
}
}
2005-06-09 02:10:34 +04:00
if ( conn - > netlogon_pipe ! = NULL ) {
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( conn - > netlogon_pipe ) ;
/* Ok, it must be dead. Drop timeout to 0.5 sec. */
if ( conn - > cli ) {
cli_set_timeout ( conn - > cli , 500 ) ;
2006-09-06 23:02:39 +04:00
}
2002-02-11 04:29:07 +03:00
}
2001-10-27 08:48:22 +04:00
2005-09-30 21:13:37 +04:00
if ( conn - > cli ) {
2005-06-09 02:10:34 +04:00
cli_shutdown ( conn - > cli ) ;
2005-09-30 21:13:37 +04:00
}
2005-06-09 02:10:34 +04:00
conn - > cli = NULL ;
}
2001-10-05 04:20:06 +04:00
2005-06-09 02:10:34 +04:00
void close_conns_after_fork ( void )
2001-10-05 04:20:06 +04:00
{
2005-06-09 02:10:34 +04:00
struct winbindd_domain * domain ;
2003-05-15 00:48:48 +04:00
2005-06-09 02:10:34 +04:00
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
2010-03-31 22:54:18 +04:00
struct cli_state * cli = domain - > conn . cli ;
2003-05-08 12:02:52 +04:00
2010-03-31 22:54:18 +04:00
/*
* first close the low level SMB TCP connection
* so that we don ' t generate any SMBclose
* requests in invalidate_cm_connection ( )
*/
if ( cli & & cli - > fd ! = - 1 ) {
close ( domain - > conn . cli - > fd ) ;
domain - > conn . cli - > fd = - 1 ;
}
2003-05-08 12:02:52 +04:00
2010-03-31 22:54:18 +04:00
invalidate_cm_connection ( & domain - > conn ) ;
2005-06-09 02:10:34 +04:00
}
}
2003-05-08 12:02:52 +04:00
2007-10-19 04:40:25 +04:00
static bool connection_ok ( struct winbindd_domain * domain )
2003-05-08 12:02:52 +04:00
{
2010-03-25 17:14:02 +03:00
bool ok ;
2003-05-08 12:02:52 +04:00
2010-03-25 17:14:02 +03:00
ok = cli_state_is_connected ( domain - > conn . cli ) ;
if ( ! ok ) {
DEBUG ( 3 , ( " connection_ok: Connection to %s for domain %s is not connected \n " ,
2005-06-09 02:10:34 +04:00
domain - > dcname , domain - > name ) ) ;
return False ;
}
2001-10-05 04:20:06 +04:00
2006-09-14 13:11:30 +04:00
if ( domain - > online = = False ) {
DEBUG ( 3 , ( " connection_ok: Domain %s is offline \n " , domain - > name ) ) ;
return False ;
}
2005-06-09 02:10:34 +04:00
return True ;
}
2006-10-06 21:33:57 +04:00
2006-12-07 02:14:15 +03:00
/* Initialize a new connection up to the RPC BIND.
Bypass online status check so always does network calls . */
2003-05-08 12:02:52 +04:00
2006-12-07 02:14:15 +03:00
static NTSTATUS init_dc_connection_network ( struct winbindd_domain * domain )
2003-05-08 12:02:52 +04:00
{
2006-10-06 21:33:57 +04:00
NTSTATUS result ;
2006-10-10 08:00:42 +04:00
/* Internal connections never use the network. */
2010-04-01 11:29:38 +04:00
if ( domain - > internal ) {
domain - > initialized = True ;
return NT_STATUS_OK ;
}
if ( ! winbindd_can_contact_domain ( domain ) ) {
invalidate_cm_connection ( & domain - > conn ) ;
2006-10-10 08:00:42 +04:00
domain - > initialized = True ;
return NT_STATUS_OK ;
}
2006-10-06 21:33:57 +04:00
if ( connection_ok ( domain ) ) {
if ( ! domain - > initialized ) {
set_dc_type_and_flags ( domain ) ;
}
2003-05-08 12:02:52 +04:00
return NT_STATUS_OK ;
2006-10-06 21:33:57 +04:00
}
2003-05-08 12:02:52 +04:00
2005-06-09 02:10:34 +04:00
invalidate_cm_connection ( & domain - > conn ) ;
2006-10-06 21:33:57 +04:00
result = cm_open_connection ( domain , & domain - > conn ) ;
if ( NT_STATUS_IS_OK ( result ) & & ! domain - > initialized ) {
set_dc_type_and_flags ( domain ) ;
}
return result ;
2003-05-08 12:02:52 +04:00
}
2002-10-05 01:42:04 +04:00
2006-12-07 02:14:15 +03:00
NTSTATUS init_dc_connection ( struct winbindd_domain * domain )
{
2010-04-23 21:42:33 +04:00
if ( domain - > internal ) {
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
}
2006-12-07 02:14:15 +03:00
if ( domain - > initialized & & ! domain - > online ) {
/* We check for online status elsewhere. */
return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ;
}
return init_dc_connection_network ( domain ) ;
}
2010-04-01 11:29:38 +04:00
static NTSTATUS init_dc_connection_rpc ( struct winbindd_domain * domain )
{
NTSTATUS status ;
status = init_dc_connection ( domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ! domain - > internal & & domain - > conn . cli = = NULL ) {
/* happens for trusted domains without inbound trust */
return NT_STATUS_TRUSTED_DOMAIN_FAILURE ;
}
return NT_STATUS_OK ;
}
2007-05-06 23:37:13 +04:00
/******************************************************************************
Set the trust flags ( direction and forest location ) for a domain
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool set_dc_type_and_flags_trustinfo ( struct winbindd_domain * domain )
2007-05-06 23:37:13 +04:00
{
struct winbindd_domain * our_domain ;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
2008-01-29 16:20:20 +03:00
struct netr_DomainTrustList trusts ;
2007-05-06 23:37:13 +04:00
int i ;
2008-01-29 19:49:38 +03:00
uint32 flags = ( NETR_TRUST_FLAG_IN_FOREST |
NETR_TRUST_FLAG_OUTBOUND |
NETR_TRUST_FLAG_INBOUND ) ;
2007-05-06 23:37:13 +04:00
struct rpc_pipe_client * cli ;
TALLOC_CTX * mem_ctx = NULL ;
DEBUG ( 5 , ( " set_dc_type_and_flags_trustinfo: domain %s \n " , domain - > name ) ) ;
2008-08-19 12:14:59 +04:00
2007-05-06 23:37:13 +04:00
/* Our primary domain doesn't need to worry about trust flags.
Force it to go through the network setup */
if ( domain - > primary ) {
return False ;
}
2008-08-19 12:14:59 +04:00
2007-05-06 23:37:13 +04:00
our_domain = find_our_domain ( ) ;
2008-08-19 12:14:59 +04:00
2007-05-06 23:37:13 +04:00
if ( ! connection_ok ( our_domain ) ) {
DEBUG ( 3 , ( " set_dc_type_and_flags_trustinfo: No connection to our domain! \n " ) ) ;
return False ;
}
/* This won't work unless our domain is AD */
2008-08-19 12:14:59 +04:00
2007-05-06 23:37:13 +04:00
if ( ! our_domain - > active_directory ) {
return False ;
}
2008-08-19 12:14:59 +04:00
2007-05-06 23:37:13 +04:00
/* Use DsEnumerateDomainTrusts to get us the trust direction
and type */
result = cm_connect_netlogon ( our_domain , & cli ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 5 , ( " set_dc_type_and_flags_trustinfo: Could not open "
" a connection to %s for PIPE_NETLOGON (%s) \n " ,
domain - > name , nt_errstr ( result ) ) ) ;
return False ;
}
if ( ( mem_ctx = talloc_init ( " set_dc_type_and_flags_trustinfo " ) ) = = NULL ) {
DEBUG ( 0 , ( " set_dc_type_and_flags_trustinfo: talloc_init() failed! \n " ) ) ;
return False ;
}
2008-01-29 16:20:20 +03:00
result = rpccli_netr_DsrEnumerateDomainTrusts ( cli , mem_ctx ,
2008-04-19 23:56:43 +04:00
cli - > desthost ,
2008-01-29 16:20:20 +03:00
flags ,
& trusts ,
NULL ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 0 , ( " set_dc_type_and_flags_trustinfo: "
" failed to query trusted domain list: %s \n " ,
nt_errstr ( result ) ) ) ;
talloc_destroy ( mem_ctx ) ;
return false ;
}
2007-05-06 23:37:13 +04:00
/* Now find the domain name and get the flags */
2008-01-29 16:20:20 +03:00
for ( i = 0 ; i < trusts . count ; i + + ) {
if ( strequal ( domain - > name , trusts . array [ i ] . netbios_name ) ) {
domain - > domain_flags = trusts . array [ i ] . trust_flags ;
domain - > domain_type = trusts . array [ i ] . trust_type ;
domain - > domain_trust_attribs = trusts . array [ i ] . trust_attributes ;
2008-01-29 19:49:38 +03:00
if ( domain - > domain_type = = NETR_TRUST_TYPE_UPLEVEL )
2007-05-06 23:37:13 +04:00
domain - > active_directory = True ;
/* This flag is only set if the domain is *our*
primary domain and the primary domain is in
native mode */
2008-01-29 19:49:38 +03:00
domain - > native_mode = ( domain - > domain_flags & NETR_TRUST_FLAG_NATIVE ) ;
2007-05-06 23:37:13 +04:00
DEBUG ( 5 , ( " set_dc_type_and_flags_trustinfo: domain %s is %sin "
" native mode. \n " , domain - > name ,
domain - > native_mode ? " " : " NOT " ) ) ;
DEBUG ( 5 , ( " set_dc_type_and_flags_trustinfo: domain %s is %s "
" running active directory. \n " , domain - > name ,
domain - > active_directory ? " " : " NOT " ) ) ;
domain - > initialized = True ;
break ;
}
}
2008-08-19 12:14:59 +04:00
2007-05-06 23:37:13 +04:00
talloc_destroy ( mem_ctx ) ;
2008-08-19 12:14:59 +04:00
2007-05-06 23:37:13 +04:00
return domain - > initialized ;
}
2005-10-27 15:16:36 +04:00
/******************************************************************************
We can ' sense ' certain things about the DC by it ' s replies to certain
questions .
2004-01-08 11:19:18 +03:00
2005-10-27 15:16:36 +04:00
This tells us if this particular remote server is Active Directory , and if it
is native mode .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-10-05 01:42:04 +04:00
2007-05-06 23:37:13 +04:00
static void set_dc_type_and_flags_connect ( struct winbindd_domain * domain )
2002-10-05 01:42:04 +04:00
{
NTSTATUS result ;
2008-01-25 15:26:10 +03:00
WERROR werr ;
2004-01-08 22:56:40 +03:00
TALLOC_CTX * mem_ctx = NULL ;
2009-03-17 13:22:41 +03:00
struct rpc_pipe_client * cli = NULL ;
2009-03-19 00:49:41 +03:00
struct policy_handle pol ;
2008-01-25 15:26:10 +03:00
union dssetup_DsRoleInfo info ;
2008-02-08 03:52:27 +03:00
union lsa_PolicyInformation * lsa_info = NULL ;
2005-06-09 02:10:34 +04:00
2006-10-06 21:33:57 +04:00
if ( ! connection_ok ( domain ) ) {
2005-06-09 02:10:34 +04:00
return ;
}
2007-11-30 00:24:54 +03:00
mem_ctx = talloc_init ( " set_dc_type_and_flags on domain %s \n " ,
domain - > name ) ;
if ( ! mem_ctx ) {
DEBUG ( 1 , ( " set_dc_type_and_flags_connect: talloc_init() failed \n " ) ) ;
return ;
}
2007-05-06 23:37:13 +04:00
DEBUG ( 5 , ( " set_dc_type_and_flags_connect: domain %s \n " , domain - > name ) ) ;
2006-10-06 21:33:57 +04:00
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_noauth ( domain - > conn . cli ,
& ndr_table_dssetup . syntax_id ,
& cli ) ;
2005-06-09 02:10:34 +04:00
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2007-05-06 23:37:13 +04:00
DEBUG ( 5 , ( " set_dc_type_and_flags_connect: Could not bind to "
2008-01-25 15:26:10 +03:00
" PI_DSSETUP on domain %s: (%s) \n " ,
2004-01-05 07:10:28 +03:00
domain - > name , nt_errstr ( result ) ) ) ;
2007-02-16 16:30:19 +03:00
/* if this is just a non-AD domain we need to continue
* identifying so that we can in the end return with
* domain - > initialized = True - gd */
2008-01-25 15:26:10 +03:00
goto no_dssetup ;
2002-10-05 01:42:04 +04:00
}
2005-06-09 02:10:34 +04:00
2008-01-25 15:26:10 +03:00
result = rpccli_dssetup_DsRoleGetPrimaryDomainInformation ( cli , mem_ctx ,
DS_ROLE_BASIC_INFORMATION ,
& info ,
& werr ) ;
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( cli ) ;
2005-06-09 02:10:34 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2007-05-06 23:37:13 +04:00
DEBUG ( 5 , ( " set_dc_type_and_flags_connect: rpccli_ds_getprimarydominfo "
2006-10-06 21:33:57 +04:00
" on domain %s failed: (%s) \n " ,
domain - > name , nt_errstr ( result ) ) ) ;
2007-09-11 03:12:27 +04:00
/* older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for
2008-01-25 15:26:10 +03:00
* every opcode on the DSSETUP pipe , continue with
* no_dssetup mode here as well to get domain - > initialized
2007-09-11 03:12:27 +04:00
* set - gd */
if ( NT_STATUS_V ( result ) = = DCERPC_FAULT_OP_RNG_ERROR ) {
2008-01-25 15:26:10 +03:00
goto no_dssetup ;
2007-09-11 03:12:27 +04:00
}
2007-11-30 00:24:54 +03:00
TALLOC_FREE ( mem_ctx ) ;
2005-06-09 02:10:34 +04:00
return ;
2002-10-05 01:42:04 +04:00
}
2008-01-25 15:26:10 +03:00
if ( ( info . basic . flags & DS_ROLE_PRIMARY_DS_RUNNING ) & &
! ( info . basic . flags & DS_ROLE_PRIMARY_DS_MIXED_MODE ) ) {
2004-01-08 11:19:18 +03:00
domain - > native_mode = True ;
2006-10-06 21:33:57 +04:00
} else {
domain - > native_mode = False ;
}
2002-10-05 01:42:04 +04:00
2008-01-25 15:26:10 +03:00
no_dssetup :
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_noauth ( domain - > conn . cli ,
& ndr_table_lsarpc . syntax_id , & cli ) ;
2004-01-08 11:19:18 +03:00
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2007-05-06 23:37:13 +04:00
DEBUG ( 5 , ( " set_dc_type_and_flags_connect: Could not bind to "
2006-10-06 21:33:57 +04:00
" PI_LSARPC on domain %s: (%s) \n " ,
domain - > name , nt_errstr ( result ) ) ) ;
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( cli ) ;
2007-11-30 00:24:54 +03:00
TALLOC_FREE ( mem_ctx ) ;
2005-06-09 02:10:34 +04:00
return ;
}
2004-01-08 11:19:18 +03:00
2005-06-09 02:10:34 +04:00
result = rpccli_lsa_open_policy2 ( cli , mem_ctx , True ,
2009-04-15 03:12:13 +04:00
SEC_FLAG_MAXIMUM_ALLOWED , & pol ) ;
2008-08-19 12:14:59 +04:00
2005-06-09 02:10:34 +04:00
if ( NT_STATUS_IS_OK ( result ) ) {
/* This particular query is exactly what Win2k clients use
to determine that the DC is active directory */
2008-02-08 03:52:27 +03:00
result = rpccli_lsa_QueryInfoPolicy2 ( cli , mem_ctx ,
& pol ,
LSA_POLICY_INFO_DNS ,
& lsa_info ) ;
2005-06-09 02:10:34 +04:00
}
if ( NT_STATUS_IS_OK ( result ) ) {
2006-10-06 21:33:57 +04:00
domain - > active_directory = True ;
2008-02-08 03:52:27 +03:00
if ( lsa_info - > dns . name . string ) {
fstrcpy ( domain - > name , lsa_info - > dns . name . string ) ;
}
2005-06-09 02:10:34 +04:00
2008-02-08 03:52:27 +03:00
if ( lsa_info - > dns . dns_domain . string ) {
fstrcpy ( domain - > alt_name ,
lsa_info - > dns . dns_domain . string ) ;
}
2005-06-09 02:10:34 +04:00
2008-01-04 22:31:07 +03:00
/* See if we can set some domain trust flags about
ourself */
2008-02-08 03:52:27 +03:00
if ( lsa_info - > dns . dns_forest . string ) {
fstrcpy ( domain - > forest_name ,
lsa_info - > dns . dns_forest . string ) ;
2007-01-03 01:14:26 +03:00
2008-01-04 22:31:07 +03:00
if ( strequal ( domain - > forest_name , domain - > alt_name ) ) {
2008-03-31 22:39:54 +04:00
domain - > domain_flags | = NETR_TRUST_FLAG_TREEROOT ;
2008-01-04 22:31:07 +03:00
}
}
2008-02-08 03:52:27 +03:00
if ( lsa_info - > dns . sid ) {
sid_copy ( & domain - > sid , lsa_info - > dns . sid ) ;
}
2005-06-09 02:10:34 +04:00
} else {
2006-10-06 21:33:57 +04:00
domain - > active_directory = False ;
2005-06-09 02:10:34 +04:00
result = rpccli_lsa_open_policy ( cli , mem_ctx , True ,
2009-04-15 03:12:13 +04:00
SEC_FLAG_MAXIMUM_ALLOWED ,
2005-06-09 02:10:34 +04:00
& pol ) ;
2008-02-08 04:12:30 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2005-06-09 02:10:34 +04:00
goto done ;
2008-02-08 04:12:30 +03:00
}
result = rpccli_lsa_QueryInfoPolicy ( cli , mem_ctx ,
& pol ,
LSA_POLICY_INFO_ACCOUNT_DOMAIN ,
& lsa_info ) ;
2004-01-08 11:19:18 +03:00
if ( NT_STATUS_IS_OK ( result ) ) {
2003-06-21 08:05:01 +04:00
2008-02-08 04:12:30 +03:00
if ( lsa_info - > account_domain . name . string ) {
fstrcpy ( domain - > name ,
lsa_info - > account_domain . name . string ) ;
}
if ( lsa_info - > account_domain . sid ) {
sid_copy ( & domain - > sid , lsa_info - > account_domain . sid ) ;
}
2004-01-08 11:19:18 +03:00
}
}
done :
2005-02-11 17:31:14 +03:00
2007-05-06 23:37:13 +04:00
DEBUG ( 5 , ( " set_dc_type_and_flags_connect: domain %s is %sin native mode. \n " ,
2006-10-06 21:33:57 +04:00
domain - > name , domain - > native_mode ? " " : " NOT " ) ) ;
2007-05-06 23:37:13 +04:00
DEBUG ( 5 , ( " set_dc_type_and_flags_connect: domain %s is %srunning active directory. \n " ,
2006-10-06 21:33:57 +04:00
domain - > name , domain - > active_directory ? " " : " NOT " ) ) ;
2009-09-17 11:43:36 +04:00
domain - > can_do_ncacn_ip_tcp = domain - > active_directory ;
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( cli ) ;
2007-11-30 00:24:54 +03:00
TALLOC_FREE ( mem_ctx ) ;
2004-04-20 06:37:49 +04:00
domain - > initialized = True ;
2002-10-05 01:42:04 +04:00
}
2007-05-06 23:37:13 +04:00
/**********************************************************************
Set the domain_flags ( trust attributes , domain operating modes , etc . . .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void set_dc_type_and_flags ( struct winbindd_domain * domain )
{
/* we always have to contact our primary domain */
if ( domain - > primary ) {
DEBUG ( 10 , ( " set_dc_type_and_flags: setting up flags for "
" primary domain \n " ) ) ;
set_dc_type_and_flags_connect ( domain ) ;
return ;
}
/* Use our DC to get the information if possible */
if ( ! set_dc_type_and_flags_trustinfo ( domain ) ) {
/* Otherwise, fallback to contacting the
domain directly */
set_dc_type_and_flags_connect ( domain ) ;
}
return ;
}
/**********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-04-14 13:33:04 +04:00
static bool cm_get_schannel_creds ( struct winbindd_domain * domain ,
struct netlogon_creds_CredentialState * * ppdc )
2005-06-09 02:10:34 +04:00
{
2005-09-30 21:13:37 +04:00
NTSTATUS result ;
struct rpc_pipe_client * netlogon_pipe ;
2002-10-05 01:42:04 +04:00
2005-09-30 21:13:37 +04:00
if ( lp_client_schannel ( ) = = False ) {
2005-06-09 02:10:34 +04:00
return False ;
2005-09-30 21:13:37 +04:00
}
2002-10-05 01:42:04 +04:00
2005-09-30 21:13:37 +04:00
result = cm_connect_netlogon ( domain , & netlogon_pipe ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
return False ;
}
2009-04-14 13:33:04 +04:00
/* Return a pointer to the struct netlogon_creds_CredentialState from the
2005-09-30 21:13:37 +04:00
netlogon pipe . */
2008-08-22 19:17:04 +04:00
if ( ! domain - > conn . netlogon_pipe - > dc ) {
return false ;
}
2005-09-30 21:13:37 +04:00
* ppdc = domain - > conn . netlogon_pipe - > dc ;
return True ;
2005-06-09 02:10:34 +04:00
}
2001-10-05 04:20:06 +04:00
2005-06-09 02:10:34 +04:00
NTSTATUS cm_connect_sam ( struct winbindd_domain * domain , TALLOC_CTX * mem_ctx ,
2009-03-19 00:49:41 +03:00
struct rpc_pipe_client * * cli , struct policy_handle * sam_handle )
2002-02-15 16:28:59 +03:00
{
struct winbindd_cm_conn * conn ;
2006-12-23 03:17:15 +03:00
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
2009-04-14 13:33:04 +04:00
struct netlogon_creds_CredentialState * p_creds ;
2007-12-11 18:34:39 +03:00
char * machine_password = NULL ;
char * machine_account = NULL ;
char * domain_name = NULL ;
2001-10-05 04:20:06 +04:00
2010-07-06 19:02:33 +04:00
if ( strequal ( domain - > name , get_global_sam_name ( ) ) ) {
result = open_internal_samr_conn ( mem_ctx , domain , cli , sam_handle ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
return result ;
}
return NT_STATUS_OK ;
}
2010-04-01 11:29:38 +04:00
result = init_dc_connection_rpc ( domain ) ;
2005-09-30 21:13:37 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2003-06-21 08:05:01 +04:00
return result ;
2005-09-30 21:13:37 +04:00
}
2002-04-04 06:39:57 +04:00
2005-06-09 02:10:34 +04:00
conn = & domain - > conn ;
2003-06-21 08:05:01 +04:00
2010-03-25 17:15:57 +03:00
if ( rpccli_is_connected ( conn - > samr_pipe ) ) {
2005-10-27 16:51:24 +04:00
goto done ;
}
2010-03-25 17:17:07 +03:00
TALLOC_FREE ( conn - > samr_pipe ) ;
2008-08-22 19:17:04 +04:00
2005-10-27 16:51:24 +04:00
/*
* No SAMR pipe yet . Attempt to get an NTLMSSP SPNEGO authenticated
* sign and sealed pipe using the machine account password by
* preference . If we can ' t - try schannel , if that fails , try
* anonymous .
*/
if ( ( conn - > cli - > user_name [ 0 ] = = ' \0 ' ) | |
( conn - > cli - > domain [ 0 ] = = ' \0 ' ) | |
2009-03-14 03:49:24 +03:00
( conn - > cli - > password = = NULL | | conn - > cli - > password [ 0 ] = = ' \0 ' ) )
2007-12-11 18:34:39 +03:00
{
result = get_trust_creds ( domain , & machine_password ,
& machine_account , NULL ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " cm_connect_sam: No no user available for "
" domain %s, trying schannel \n " , conn - > cli - > domain ) ) ;
goto schannel ;
}
domain_name = domain - > name ;
} else {
2009-03-14 03:49:24 +03:00
machine_password = SMB_STRDUP ( conn - > cli - > password ) ;
2007-12-18 02:33:48 +03:00
machine_account = SMB_STRDUP ( conn - > cli - > user_name ) ;
2007-12-11 18:34:39 +03:00
domain_name = conn - > cli - > domain ;
2005-10-27 16:51:24 +04:00
}
2007-12-18 02:33:48 +03:00
if ( ! machine_password | | ! machine_account ) {
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
2007-12-11 18:34:39 +03:00
2005-10-27 16:51:24 +04:00
/* We have an authenticated connection. Use a NTLMSSP SPNEGO
authenticated SAMR pipe with sign & seal . */
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_spnego_ntlmssp ( conn - > cli ,
& ndr_table_samr . syntax_id ,
2009-09-11 00:23:21 +04:00
NCACN_NP ,
2009-09-14 22:39:54 +04:00
DCERPC_AUTH_LEVEL_PRIVACY ,
2008-07-20 13:04:31 +04:00
domain_name ,
machine_account ,
machine_password ,
& conn - > samr_pipe ) ;
2005-10-27 16:51:24 +04:00
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2005-10-27 16:51:24 +04:00
DEBUG ( 10 , ( " cm_connect_sam: failed to connect to SAMR "
" pipe for domain %s using NTLMSSP "
" authenticated pipe: user %s \\ %s. Error was "
2007-12-11 18:34:39 +03:00
" %s \n " , domain - > name , domain_name ,
machine_account , nt_errstr ( result ) ) ) ;
2005-10-27 16:51:24 +04:00
goto schannel ;
}
2005-09-30 21:13:37 +04:00
2005-10-27 16:51:24 +04:00
DEBUG ( 10 , ( " cm_connect_sam: connected to SAMR pipe for "
" domain %s using NTLMSSP authenticated "
" pipe: user %s \\ %s \n " , domain - > name ,
2007-12-11 18:34:39 +03:00
domain_name , machine_account ) ) ;
2005-09-30 21:13:37 +04:00
2008-02-04 21:43:07 +03:00
result = rpccli_samr_Connect2 ( conn - > samr_pipe , mem_ctx ,
2008-04-19 23:56:43 +04:00
conn - > samr_pipe - > desthost ,
2009-04-15 03:12:13 +04:00
SEC_FLAG_MAXIMUM_ALLOWED ,
2008-02-04 21:43:07 +03:00
& conn - > sam_connect_handle ) ;
2005-10-27 16:51:24 +04:00
if ( NT_STATUS_IS_OK ( result ) ) {
goto open_domain ;
}
2008-02-04 21:43:07 +03:00
DEBUG ( 10 , ( " cm_connect_sam: ntlmssp-sealed rpccli_samr_Connect2 "
2005-10-27 16:51:24 +04:00
" failed for domain %s, error was %s. Trying schannel \n " ,
domain - > name , nt_errstr ( result ) ) ) ;
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( conn - > samr_pipe ) ;
2001-10-05 04:20:06 +04:00
2005-10-27 16:51:24 +04:00
schannel :
2001-10-05 04:20:06 +04:00
2005-10-27 16:51:24 +04:00
/* Fall back to schannel if it's a W2K pre-SP1 box. */
2009-04-14 13:33:04 +04:00
if ( ! cm_get_schannel_creds ( domain , & p_creds ) ) {
2006-12-23 03:17:15 +03:00
/* If this call fails - conn->cli can now be NULL ! */
2005-10-27 16:51:24 +04:00
DEBUG ( 10 , ( " cm_connect_sam: Could not get schannel auth info "
2006-12-23 03:17:15 +03:00
" for domain %s, trying anon \n " , domain - > name ) ) ;
2005-10-27 16:51:24 +04:00
goto anonymous ;
}
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_schannel_with_key
2009-09-11 00:32:34 +04:00
( conn - > cli , & ndr_table_samr . syntax_id , NCACN_NP ,
2009-09-14 22:39:54 +04:00
DCERPC_AUTH_LEVEL_PRIVACY ,
2009-04-20 18:50:49 +04:00
domain - > name , & p_creds , & conn - > samr_pipe ) ;
2005-10-27 16:51:24 +04:00
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2005-10-27 16:51:24 +04:00
DEBUG ( 10 , ( " cm_connect_sam: failed to connect to SAMR pipe for "
" domain %s using schannel. Error was %s \n " ,
domain - > name , nt_errstr ( result ) ) ) ;
goto anonymous ;
}
DEBUG ( 10 , ( " cm_connect_sam: connected to SAMR pipe for domain %s using "
" schannel. \n " , domain - > name ) ) ;
2008-02-04 21:43:07 +03:00
result = rpccli_samr_Connect2 ( conn - > samr_pipe , mem_ctx ,
2008-04-19 23:56:43 +04:00
conn - > samr_pipe - > desthost ,
2009-04-15 03:12:13 +04:00
SEC_FLAG_MAXIMUM_ALLOWED ,
2008-02-04 21:43:07 +03:00
& conn - > sam_connect_handle ) ;
2005-10-27 16:51:24 +04:00
if ( NT_STATUS_IS_OK ( result ) ) {
goto open_domain ;
}
2008-02-04 21:43:07 +03:00
DEBUG ( 10 , ( " cm_connect_sam: schannel-sealed rpccli_samr_Connect2 failed "
2005-10-27 16:51:24 +04:00
" for domain %s, error was %s. Trying anonymous \n " ,
domain - > name , nt_errstr ( result ) ) ) ;
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( conn - > samr_pipe ) ;
2005-10-27 16:51:24 +04:00
anonymous :
/* Finally fall back to anonymous. */
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_noauth ( conn - > cli , & ndr_table_samr . syntax_id ,
& conn - > samr_pipe ) ;
2005-10-27 16:51:24 +04:00
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2005-10-27 16:51:24 +04:00
goto done ;
}
2001-10-05 04:20:06 +04:00
2008-02-04 21:43:07 +03:00
result = rpccli_samr_Connect2 ( conn - > samr_pipe , mem_ctx ,
2008-04-19 23:56:43 +04:00
conn - > samr_pipe - > desthost ,
2009-04-15 03:12:13 +04:00
SEC_FLAG_MAXIMUM_ALLOWED ,
2008-02-04 21:43:07 +03:00
& conn - > sam_connect_handle ) ;
2005-10-27 16:51:24 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2008-02-04 21:43:07 +03:00
DEBUG ( 10 , ( " cm_connect_sam: rpccli_samr_Connect2 failed "
2005-10-27 16:51:24 +04:00
" for domain %s Error was %s \n " ,
domain - > name , nt_errstr ( result ) ) ) ;
goto done ;
2005-06-09 02:10:34 +04:00
}
2001-10-05 04:20:06 +04:00
2005-10-27 16:51:24 +04:00
open_domain :
2008-02-01 13:12:05 +03:00
result = rpccli_samr_OpenDomain ( conn - > samr_pipe ,
mem_ctx ,
& conn - > sam_connect_handle ,
2009-04-15 03:12:13 +04:00
SEC_FLAG_MAXIMUM_ALLOWED ,
2008-02-01 13:12:05 +03:00
& domain - > sid ,
& conn - > sam_domain_handle ) ;
2005-10-27 16:51:24 +04:00
2005-06-09 02:10:34 +04:00
done :
2005-09-30 21:13:37 +04:00
2009-09-24 23:35:38 +04:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_ACCESS_DENIED ) ) {
/*
* if we got access denied , we might just have no access rights
* to talk to the remote samr server server ( e . g . when we are a
* PDC and we are connecting a w2k8 pdc via an interdomain
* trust ) . In that case do not invalidate the whole connection
* stack
*/
TALLOC_FREE ( conn - > samr_pipe ) ;
ZERO_STRUCT ( conn - > sam_domain_handle ) ;
return result ;
} else if ( ! NT_STATUS_IS_OK ( result ) ) {
2005-06-09 02:10:34 +04:00
invalidate_cm_connection ( conn ) ;
2005-09-30 21:13:37 +04:00
return result ;
2005-06-09 02:10:34 +04:00
}
2003-06-21 08:05:01 +04:00
2005-06-09 02:10:34 +04:00
* cli = conn - > samr_pipe ;
* sam_handle = conn - > sam_domain_handle ;
2007-12-11 18:34:39 +03:00
SAFE_FREE ( machine_password ) ;
SAFE_FREE ( machine_account ) ;
2005-06-09 02:10:34 +04:00
return result ;
2001-10-05 04:20:06 +04:00
}
2009-09-13 01:30:39 +04:00
/**********************************************************************
open an schanneld ncacn_ip_tcp connection to LSA
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cm_connect_lsa_tcp ( struct winbindd_domain * domain ,
TALLOC_CTX * mem_ctx ,
struct rpc_pipe_client * * cli )
{
struct winbindd_cm_conn * conn ;
NTSTATUS status ;
DEBUG ( 10 , ( " cm_connect_lsa_tcp \n " ) ) ;
2010-04-01 11:29:38 +04:00
status = init_dc_connection_rpc ( domain ) ;
2009-09-13 01:30:39 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-09-23 08:23:50 +04:00
return status ;
2009-09-13 01:30:39 +04:00
}
conn = & domain - > conn ;
if ( conn - > lsa_pipe_tcp & &
conn - > lsa_pipe_tcp - > transport - > transport = = NCACN_IP_TCP & &
2010-01-06 07:13:35 +03:00
conn - > lsa_pipe_tcp - > auth - > auth_level = = DCERPC_AUTH_LEVEL_PRIVACY & &
2010-03-25 17:15:57 +03:00
rpccli_is_connected ( conn - > lsa_pipe_tcp ) ) {
2009-09-13 01:30:39 +04:00
goto done ;
}
TALLOC_FREE ( conn - > lsa_pipe_tcp ) ;
status = cli_rpc_pipe_open_schannel ( conn - > cli ,
& ndr_table_lsarpc . syntax_id ,
NCACN_IP_TCP ,
DCERPC_AUTH_LEVEL_PRIVACY ,
domain - > name ,
& conn - > lsa_pipe_tcp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " cli_rpc_pipe_open_schannel failed: %s \n " ,
nt_errstr ( status ) ) ) ;
goto done ;
}
done :
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( conn - > lsa_pipe_tcp ) ;
return status ;
}
* cli = conn - > lsa_pipe_tcp ;
return status ;
}
2005-06-09 02:10:34 +04:00
NTSTATUS cm_connect_lsa ( struct winbindd_domain * domain , TALLOC_CTX * mem_ctx ,
2009-03-19 00:49:41 +03:00
struct rpc_pipe_client * * cli , struct policy_handle * lsa_policy )
2005-06-09 02:10:34 +04:00
{
2001-11-15 22:40:00 +03:00
struct winbindd_cm_conn * conn ;
2006-12-23 03:17:15 +03:00
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
2009-04-14 13:33:04 +04:00
struct netlogon_creds_CredentialState * p_creds ;
2001-10-08 04:34:14 +04:00
2010-04-01 11:29:38 +04:00
result = init_dc_connection_rpc ( domain ) ;
2005-06-09 02:10:34 +04:00
if ( ! NT_STATUS_IS_OK ( result ) )
2003-06-21 08:05:01 +04:00
return result ;
2005-06-09 02:10:34 +04:00
conn = & domain - > conn ;
2001-10-08 04:34:14 +04:00
2010-03-25 17:15:57 +03:00
if ( rpccli_is_connected ( conn - > lsa_pipe ) ) {
2005-10-27 16:51:24 +04:00
goto done ;
}
2010-03-25 17:17:07 +03:00
TALLOC_FREE ( conn - > lsa_pipe ) ;
2005-10-27 16:51:24 +04:00
if ( ( conn - > cli - > user_name [ 0 ] = = ' \0 ' ) | |
( conn - > cli - > domain [ 0 ] = = ' \0 ' ) | |
2009-03-14 03:49:24 +03:00
( conn - > cli - > password = = NULL | | conn - > cli - > password [ 0 ] = = ' \0 ' ) ) {
2005-10-27 16:51:24 +04:00
DEBUG ( 10 , ( " cm_connect_lsa: No no user available for "
" domain %s, trying schannel \n " , conn - > cli - > domain ) ) ;
goto schannel ;
}
/* We have an authenticated connection. Use a NTLMSSP SPNEGO
* authenticated LSA pipe with sign & seal . */
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_spnego_ntlmssp
2009-09-11 00:23:21 +04:00
( conn - > cli , & ndr_table_lsarpc . syntax_id , NCACN_NP ,
2009-09-14 22:39:54 +04:00
DCERPC_AUTH_LEVEL_PRIVACY ,
2009-03-14 03:49:24 +03:00
conn - > cli - > domain , conn - > cli - > user_name , conn - > cli - > password ,
2008-07-20 13:04:31 +04:00
& conn - > lsa_pipe ) ;
2005-10-27 16:51:24 +04:00
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2005-10-27 16:51:24 +04:00
DEBUG ( 10 , ( " cm_connect_lsa: failed to connect to LSA pipe for "
" domain %s using NTLMSSP authenticated pipe: user "
" %s \\ %s. Error was %s. Trying schannel. \n " ,
domain - > name , conn - > cli - > domain ,
conn - > cli - > user_name , nt_errstr ( result ) ) ) ;
goto schannel ;
}
2005-09-30 21:13:37 +04:00
2005-10-27 16:51:24 +04:00
DEBUG ( 10 , ( " cm_connect_lsa: connected to LSA pipe for domain %s using "
" NTLMSSP authenticated pipe: user %s \\ %s \n " ,
domain - > name , conn - > cli - > domain , conn - > cli - > user_name ) ) ;
2001-10-08 04:34:14 +04:00
2005-10-27 16:51:24 +04:00
result = rpccli_lsa_open_policy ( conn - > lsa_pipe , mem_ctx , True ,
2009-04-15 03:12:13 +04:00
SEC_FLAG_MAXIMUM_ALLOWED ,
2005-10-27 16:51:24 +04:00
& conn - > lsa_policy ) ;
if ( NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
2001-10-08 04:34:14 +04:00
2005-10-27 16:51:24 +04:00
DEBUG ( 10 , ( " cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
" schannel \n " ) ) ;
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( conn - > lsa_pipe ) ;
2005-10-27 16:51:24 +04:00
schannel :
/* Fall back to schannel if it's a W2K pre-SP1 box. */
2009-04-14 13:33:04 +04:00
if ( ! cm_get_schannel_creds ( domain , & p_creds ) ) {
2006-12-23 03:17:15 +03:00
/* If this call fails - conn->cli can now be NULL ! */
2006-02-09 13:17:38 +03:00
DEBUG ( 10 , ( " cm_connect_lsa: Could not get schannel auth info "
2006-12-23 03:17:15 +03:00
" for domain %s, trying anon \n " , domain - > name ) ) ;
2005-10-27 16:51:24 +04:00
goto anonymous ;
}
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_schannel_with_key
2009-09-11 00:32:34 +04:00
( conn - > cli , & ndr_table_lsarpc . syntax_id , NCACN_NP ,
2009-09-14 22:39:54 +04:00
DCERPC_AUTH_LEVEL_PRIVACY ,
2009-04-20 19:04:33 +04:00
domain - > name , & p_creds , & conn - > lsa_pipe ) ;
2005-10-27 16:51:24 +04:00
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2005-10-27 16:51:24 +04:00
DEBUG ( 10 , ( " cm_connect_lsa: failed to connect to LSA pipe for "
" domain %s using schannel. Error was %s \n " ,
domain - > name , nt_errstr ( result ) ) ) ;
goto anonymous ;
}
DEBUG ( 10 , ( " cm_connect_lsa: connected to LSA pipe for domain %s using "
" schannel. \n " , domain - > name ) ) ;
result = rpccli_lsa_open_policy ( conn - > lsa_pipe , mem_ctx , True ,
2009-04-15 03:12:13 +04:00
SEC_FLAG_MAXIMUM_ALLOWED ,
2005-10-27 16:51:24 +04:00
& conn - > lsa_policy ) ;
if ( NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
DEBUG ( 10 , ( " cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
" anonymous \n " ) ) ;
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( conn - > lsa_pipe ) ;
2005-10-27 16:51:24 +04:00
anonymous :
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_noauth ( conn - > cli ,
& ndr_table_lsarpc . syntax_id ,
& conn - > lsa_pipe ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
2005-10-27 16:51:24 +04:00
result = NT_STATUS_PIPE_NOT_AVAILABLE ;
goto done ;
2005-06-09 02:10:34 +04:00
}
2001-10-08 04:34:14 +04:00
2005-10-27 16:51:24 +04:00
result = rpccli_lsa_open_policy ( conn - > lsa_pipe , mem_ctx , True ,
2009-04-15 03:12:13 +04:00
SEC_FLAG_MAXIMUM_ALLOWED ,
2005-10-27 16:51:24 +04:00
& conn - > lsa_policy ) ;
2005-06-09 02:10:34 +04:00
done :
if ( ! NT_STATUS_IS_OK ( result ) ) {
invalidate_cm_connection ( conn ) ;
2006-12-23 03:17:15 +03:00
return result ;
2005-06-09 02:10:34 +04:00
}
2003-06-21 08:05:01 +04:00
2005-06-09 02:10:34 +04:00
* cli = conn - > lsa_pipe ;
* lsa_policy = conn - > lsa_policy ;
return result ;
2001-10-05 04:20:06 +04:00
}
2005-09-30 21:13:37 +04:00
/****************************************************************************
Open the netlogon pipe to this DC . Use schannel if specified in client conf .
session key stored in conn - > netlogon_pipe - > dc - > sess_key .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-11-05 03:21:17 +03:00
2005-10-27 15:16:36 +04:00
NTSTATUS cm_connect_netlogon ( struct winbindd_domain * domain ,
struct rpc_pipe_client * * cli )
2005-06-09 02:10:34 +04:00
{
struct winbindd_cm_conn * conn ;
NTSTATUS result ;
2004-01-15 09:55:10 +03:00
2008-04-02 04:29:48 +04:00
uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS ;
2005-06-09 02:10:34 +04:00
uint8 mach_pwd [ 16 ] ;
2009-10-13 12:15:34 +04:00
enum netr_SchannelType sec_chan_type ;
2005-06-09 02:10:34 +04:00
const char * account_name ;
2006-01-30 20:47:24 +03:00
struct rpc_pipe_client * netlogon_pipe = NULL ;
* cli = NULL ;
2005-06-09 02:10:34 +04:00
2010-04-01 11:29:38 +04:00
result = init_dc_connection_rpc ( domain ) ;
2005-09-30 21:13:37 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2003-05-08 12:02:52 +04:00
return result ;
2005-09-30 21:13:37 +04:00
}
2001-11-05 03:21:17 +03:00
2005-06-09 02:10:34 +04:00
conn = & domain - > conn ;
2001-11-05 03:21:17 +03:00
2010-03-25 17:15:57 +03:00
if ( rpccli_is_connected ( conn - > netlogon_pipe ) ) {
2005-06-09 02:10:34 +04:00
* cli = conn - > netlogon_pipe ;
return NT_STATUS_OK ;
}
2001-11-14 09:18:13 +03:00
2010-03-25 17:17:07 +03:00
TALLOC_FREE ( conn - > netlogon_pipe ) ;
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_noauth ( conn - > cli ,
& ndr_table_netlogon . syntax_id ,
& netlogon_pipe ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
2005-09-30 21:13:37 +04:00
return result ;
}
2001-11-14 09:18:13 +03:00
2007-09-11 20:15:36 +04:00
if ( ( ! IS_DC ) & & ( ! domain - > primary ) ) {
2007-05-06 23:48:13 +04:00
/* Clear the schannel request bit and drop down */
neg_flags & = ~ NETLOGON_NEG_SCHANNEL ;
goto no_schannel ;
}
2007-12-11 14:47:28 +03:00
2005-09-30 21:13:37 +04:00
if ( lp_client_schannel ( ) ! = False ) {
2005-06-09 02:10:34 +04:00
neg_flags | = NETLOGON_NEG_SCHANNEL ;
2005-09-30 21:13:37 +04:00
}
2005-06-10 07:26:39 +04:00
2007-12-11 16:07:32 +03:00
if ( ! get_trust_pw_hash ( domain - > name , mach_pwd , & account_name ,
& sec_chan_type ) )
2005-09-27 23:39:13 +04:00
{
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( netlogon_pipe ) ;
2007-12-11 15:05:44 +03:00
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
2005-09-30 21:13:37 +04:00
}
2001-11-14 09:18:13 +03:00
2005-11-04 03:03:55 +03:00
result = rpccli_netlogon_setup_creds (
netlogon_pipe ,
2005-10-27 15:16:36 +04:00
domain - > dcname , /* server name. */
domain - > name , /* domain name */
2005-11-04 03:03:55 +03:00
global_myname ( ) , /* client name */
2005-10-27 15:16:36 +04:00
account_name , /* machine account */
mach_pwd , /* machine password */
sec_chan_type , /* from get_trust_pw */
& neg_flags ) ;
2003-06-11 02:11:30 +04:00
2005-09-30 21:13:37 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( netlogon_pipe ) ;
2005-06-09 02:10:34 +04:00
return result ;
}
2003-06-11 02:11:30 +04:00
2005-06-09 02:10:34 +04:00
if ( ( lp_client_schannel ( ) = = True ) & &
2005-09-30 21:13:37 +04:00
( ( neg_flags & NETLOGON_NEG_SCHANNEL ) = = 0 ) ) {
2005-06-09 02:10:34 +04:00
DEBUG ( 3 , ( " Server did not offer schannel \n " ) ) ;
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( netlogon_pipe ) ;
2005-06-09 02:10:34 +04:00
return NT_STATUS_ACCESS_DENIED ;
}
2003-06-11 02:11:30 +04:00
2007-05-06 23:48:13 +04:00
no_schannel :
2005-06-09 02:10:34 +04:00
if ( ( lp_client_schannel ( ) = = False ) | |
2005-09-30 21:13:37 +04:00
( ( neg_flags & NETLOGON_NEG_SCHANNEL ) = = 0 ) ) {
2008-03-19 18:09:37 +03:00
/*
* NetSamLogonEx only works for schannel
*/
domain - > can_do_samlogon_ex = False ;
2005-10-27 15:16:36 +04:00
/* We're done - just keep the existing connection to NETLOGON
* open */
2005-09-30 21:13:37 +04:00
conn - > netlogon_pipe = netlogon_pipe ;
2005-06-09 02:10:34 +04:00
* cli = conn - > netlogon_pipe ;
return NT_STATUS_OK ;
}
2003-06-11 02:11:30 +04:00
2005-09-30 21:13:37 +04:00
/* Using the credentials from the first pipe, open a signed and sealed
second netlogon pipe . The session key is stored in the schannel
part of the new pipe auth struct .
*/
2008-07-20 13:04:31 +04:00
result = cli_rpc_pipe_open_schannel_with_key (
2009-09-11 00:32:34 +04:00
conn - > cli , & ndr_table_netlogon . syntax_id , NCACN_NP ,
2009-09-14 22:39:54 +04:00
DCERPC_AUTH_LEVEL_PRIVACY , domain - > name , & netlogon_pipe - > dc ,
2008-07-20 13:04:31 +04:00
& conn - > netlogon_pipe ) ;
2005-09-30 21:13:37 +04:00
/* We can now close the initial netlogon pipe. */
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( netlogon_pipe ) ;
2003-06-11 02:11:30 +04:00
2008-07-20 13:04:31 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2005-10-27 15:16:36 +04:00
DEBUG ( 3 , ( " Could not open schannel'ed NETLOGON pipe. Error "
" was %s \n " , nt_errstr ( result ) ) ) ;
2008-08-19 12:14:59 +04:00
2010-03-25 17:25:47 +03:00
invalidate_cm_connection ( conn ) ;
return result ;
2003-06-11 02:11:30 +04:00
}
2008-03-19 18:09:37 +03:00
/*
2009-11-24 18:51:30 +03:00
* Always try netr_LogonSamLogonEx . We will fall back for NT4
* which gives DCERPC_FAULT_OP_RNG_ERROR ( function not
* supported ) . We used to only try SamLogonEx for AD , but
* Samba DCs can also do it . And because we don ' t distinguish
* between Samba and NT4 , always try it once .
2008-03-19 18:09:37 +03:00
*/
2009-11-24 18:51:30 +03:00
domain - > can_do_samlogon_ex = true ;
2008-03-19 18:09:37 +03:00
2005-06-09 02:10:34 +04:00
* cli = conn - > netlogon_pipe ;
return NT_STATUS_OK ;
2003-06-11 02:11:30 +04:00
}