2002-04-24 13:59:48 +04:00
/*
Unix SMB / CIFS implementation .
2005-10-22 01:25:26 +04:00
Winbind child daemons
2002-04-24 13:59:48 +04:00
Copyright ( C ) Andrew Tridgell 2002
2005-06-09 02:10:34 +04:00
Copyright ( C ) Volker Lendecke 2004 , 2005
2002-04-24 13:59:48 +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
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/*
2005-10-22 01:25:26 +04:00
* We fork a child per domain to be able to act non - blocking in the main
* winbind daemon . A domain controller thousands of miles away being being
* slow replying with a 10.000 user list should not hold up netlogon calls
* that can be handled locally .
2002-04-24 13:59:48 +04:00
*/
2003-11-12 04:51:10 +03:00
# include "includes.h"
2002-04-24 13:59:48 +04:00
# include "winbindd.h"
2002-06-18 13:20:13 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
2005-06-09 02:10:34 +04:00
/* Read some data from a client connection */
2005-09-30 21:13:37 +04:00
static void child_read_request ( struct winbindd_cli_state * state )
2005-06-09 02:10:34 +04:00
{
2005-09-30 21:13:37 +04:00
ssize_t len ;
2005-06-09 02:10:34 +04:00
/* Read data */
2005-09-30 21:13:37 +04:00
len = read_data ( state - > sock , ( char * ) & state - > request ,
sizeof ( state - > request ) ) ;
2005-06-09 02:10:34 +04:00
2005-09-30 21:13:37 +04:00
if ( len ! = sizeof ( state - > request ) ) {
2006-09-12 04:46:35 +04:00
DEBUG ( len > 0 ? 0 : 3 , ( " Got invalid request length: %d \n " , ( int ) len ) ) ;
2005-09-30 21:13:37 +04:00
state - > finished = True ;
return ;
}
if ( state - > request . extra_len = = 0 ) {
2006-04-12 18:10:39 +04:00
state - > request . extra_data . data = NULL ;
2005-09-30 21:13:37 +04:00
return ;
}
DEBUG ( 10 , ( " Need to read %d extra bytes \n " , ( int ) state - > request . extra_len ) ) ;
2006-04-12 18:10:39 +04:00
state - > request . extra_data . data =
2005-09-30 21:13:37 +04:00
SMB_MALLOC_ARRAY ( char , state - > request . extra_len + 1 ) ;
2006-04-12 18:10:39 +04:00
if ( state - > request . extra_data . data = = NULL ) {
2005-09-30 21:13:37 +04:00
DEBUG ( 0 , ( " malloc failed \n " ) ) ;
state - > finished = True ;
return ;
}
/* Ensure null termination */
2006-04-12 18:10:39 +04:00
state - > request . extra_data . data [ state - > request . extra_len ] = ' \0 ' ;
2005-09-30 21:13:37 +04:00
2006-04-12 18:10:39 +04:00
len = read_data ( state - > sock , state - > request . extra_data . data ,
2005-09-30 21:13:37 +04:00
state - > request . extra_len ) ;
if ( len ! = state - > request . extra_len ) {
DEBUG ( 0 , ( " Could not read extra data \n " ) ) ;
2005-06-09 02:10:34 +04:00
state - > finished = True ;
return ;
}
}
/*
* Machinery for async requests sent to children . You set up a
* winbindd_request , select a child to query , and issue a async_request
* call . When the request is completed , the callback function you specified is
* called back with the private pointer you gave to async_request .
*/
struct winbindd_async_request {
struct winbindd_async_request * next , * prev ;
TALLOC_CTX * mem_ctx ;
struct winbindd_child * child ;
struct winbindd_request * request ;
struct winbindd_response * response ;
2005-06-25 00:25:18 +04:00
void ( * continuation ) ( void * private_data , BOOL success ) ;
void * private_data ;
2005-06-09 02:10:34 +04:00
} ;
2005-09-30 21:13:37 +04:00
static void async_main_request_sent ( void * private_data , BOOL success ) ;
2005-06-25 00:25:18 +04:00
static void async_request_sent ( void * private_data , BOOL success ) ;
static void async_reply_recv ( void * private_data , BOOL success ) ;
2005-06-09 02:10:34 +04:00
static void schedule_async_request ( struct winbindd_child * child ) ;
void async_request ( TALLOC_CTX * mem_ctx , struct winbindd_child * child ,
struct winbindd_request * request ,
struct winbindd_response * response ,
2005-06-25 00:25:18 +04:00
void ( * continuation ) ( void * private_data , BOOL success ) ,
void * private_data )
2005-06-09 02:10:34 +04:00
{
struct winbindd_async_request * state , * tmp ;
SMB_ASSERT ( continuation ! = NULL ) ;
state = TALLOC_P ( mem_ctx , struct winbindd_async_request ) ;
if ( state = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
2005-06-25 00:25:18 +04:00
continuation ( private_data , False ) ;
2005-06-09 02:10:34 +04:00
return ;
}
state - > mem_ctx = mem_ctx ;
state - > child = child ;
state - > request = request ;
state - > response = response ;
state - > continuation = continuation ;
2005-06-25 00:25:18 +04:00
state - > private_data = private_data ;
2005-06-09 02:10:34 +04:00
DLIST_ADD_END ( child - > requests , state , tmp ) ;
schedule_async_request ( child ) ;
return ;
}
2005-09-30 21:13:37 +04:00
static void async_main_request_sent ( void * private_data , BOOL success )
2005-06-09 02:10:34 +04:00
{
struct winbindd_async_request * state =
2005-06-25 00:25:18 +04:00
talloc_get_type_abort ( private_data , struct winbindd_async_request ) ;
2005-06-09 02:10:34 +04:00
if ( ! success ) {
DEBUG ( 5 , ( " Could not send async request \n " ) ) ;
state - > response - > length = sizeof ( struct winbindd_response ) ;
state - > response - > result = WINBINDD_ERROR ;
2005-06-25 00:25:18 +04:00
state - > continuation ( state - > private_data , False ) ;
2005-06-09 02:10:34 +04:00
return ;
}
2005-09-30 21:13:37 +04:00
if ( state - > request - > extra_len = = 0 ) {
async_request_sent ( private_data , True ) ;
return ;
}
2006-04-12 18:10:39 +04:00
setup_async_write ( & state - > child - > event , state - > request - > extra_data . data ,
2005-09-30 21:13:37 +04:00
state - > request - > extra_len ,
async_request_sent , state ) ;
}
static void async_request_sent ( void * private_data_data , BOOL success )
{
struct winbindd_async_request * state =
talloc_get_type_abort ( private_data_data , struct winbindd_async_request ) ;
if ( ! success ) {
DEBUG ( 5 , ( " Could not send async request \n " ) ) ;
state - > response - > length = sizeof ( struct winbindd_response ) ;
state - > response - > result = WINBINDD_ERROR ;
state - > continuation ( state - > private_data , False ) ;
return ;
}
2005-06-09 02:10:34 +04:00
/* Request successfully sent to the child, setup the wait for reply */
setup_async_read ( & state - > child - > event ,
& state - > response - > result ,
sizeof ( state - > response - > result ) ,
async_reply_recv , state ) ;
}
2005-06-25 00:25:18 +04:00
static void async_reply_recv ( void * private_data , BOOL success )
2005-06-09 02:10:34 +04:00
{
struct winbindd_async_request * state =
2005-06-25 00:25:18 +04:00
talloc_get_type_abort ( private_data , struct winbindd_async_request ) ;
2005-06-09 02:10:34 +04:00
struct winbindd_child * child = state - > child ;
state - > response - > length = sizeof ( struct winbindd_response ) ;
if ( ! success ) {
DEBUG ( 5 , ( " Could not receive async reply \n " ) ) ;
state - > response - > result = WINBINDD_ERROR ;
2005-06-20 17:42:29 +04:00
return ;
2005-06-09 02:10:34 +04:00
}
2005-08-28 13:19:10 +04:00
SMB_ASSERT ( cache_retrieve_response ( child - > pid ,
state - > response ) ) ;
2005-06-09 02:10:34 +04:00
2006-02-04 01:19:41 +03:00
cache_cleanup_response ( child - > pid ) ;
2005-06-09 02:10:34 +04:00
DLIST_REMOVE ( child - > requests , state ) ;
schedule_async_request ( child ) ;
2005-06-25 00:25:18 +04:00
state - > continuation ( state - > private_data , True ) ;
2005-06-09 02:10:34 +04:00
}
static BOOL fork_domain_child ( struct winbindd_child * child ) ;
static void schedule_async_request ( struct winbindd_child * child )
{
struct winbindd_async_request * request = child - > requests ;
if ( request = = NULL ) {
return ;
}
if ( child - > event . flags ! = 0 ) {
return ; /* Busy */
}
if ( ( child - > pid = = 0 ) & & ( ! fork_domain_child ( child ) ) ) {
/* Cancel all outstanding requests */
while ( request ! = NULL ) {
/* request might be free'd in the continuation */
struct winbindd_async_request * next = request - > next ;
2005-06-25 00:25:18 +04:00
request - > continuation ( request - > private_data , False ) ;
2005-06-09 02:10:34 +04:00
request = next ;
}
return ;
}
setup_async_write ( & child - > event , request - > request ,
sizeof ( * request - > request ) ,
2005-09-30 21:13:37 +04:00
async_main_request_sent , request ) ;
2006-02-04 01:19:41 +03:00
talloc_destroy ( child - > mem_ctx ) ;
2005-06-09 02:10:34 +04:00
return ;
}
struct domain_request_state {
TALLOC_CTX * mem_ctx ;
struct winbindd_domain * domain ;
struct winbindd_request * request ;
struct winbindd_response * response ;
2005-09-30 21:13:37 +04:00
void ( * continuation ) ( void * private_data_data , BOOL success ) ;
void * private_data_data ;
2005-06-09 02:10:34 +04:00
} ;
2005-09-30 21:13:37 +04:00
static void domain_init_recv ( void * private_data_data , BOOL success ) ;
2005-06-09 02:10:34 +04:00
void async_domain_request ( TALLOC_CTX * mem_ctx ,
struct winbindd_domain * domain ,
struct winbindd_request * request ,
struct winbindd_response * response ,
2005-09-30 21:13:37 +04:00
void ( * continuation ) ( void * private_data_data , BOOL success ) ,
void * private_data_data )
2005-06-09 02:10:34 +04:00
{
struct domain_request_state * state ;
if ( domain - > initialized ) {
async_request ( mem_ctx , & domain - > child , request , response ,
2005-09-30 21:13:37 +04:00
continuation , private_data_data ) ;
2005-06-09 02:10:34 +04:00
return ;
}
state = TALLOC_P ( mem_ctx , struct domain_request_state ) ;
if ( state = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
2005-09-30 21:13:37 +04:00
continuation ( private_data_data , False ) ;
2005-06-09 02:10:34 +04:00
return ;
}
state - > mem_ctx = mem_ctx ;
state - > domain = domain ;
state - > request = request ;
state - > response = response ;
state - > continuation = continuation ;
2005-09-30 21:13:37 +04:00
state - > private_data_data = private_data_data ;
2005-06-09 02:10:34 +04:00
init_child_connection ( domain , domain_init_recv , state ) ;
}
2005-09-30 21:13:37 +04:00
static void recvfrom_child ( void * private_data_data , BOOL success )
2005-06-20 17:42:29 +04:00
{
struct winbindd_cli_state * state =
2005-09-30 21:13:37 +04:00
talloc_get_type_abort ( private_data_data , struct winbindd_cli_state ) ;
2005-06-20 17:42:29 +04:00
enum winbindd_result result = state - > response . result ;
/* This is an optimization: The child has written directly to the
* response buffer . The request itself is still in pending state ,
* state that in the result code . */
state - > response . result = WINBINDD_PENDING ;
if ( ( ! success ) | | ( result ! = WINBINDD_OK ) ) {
request_error ( state ) ;
return ;
}
request_ok ( state ) ;
}
void sendto_child ( struct winbindd_cli_state * state ,
struct winbindd_child * child )
{
async_request ( state - > mem_ctx , child , & state - > request ,
& state - > response , recvfrom_child , state ) ;
}
void sendto_domain ( struct winbindd_cli_state * state ,
struct winbindd_domain * domain )
{
async_domain_request ( state - > mem_ctx , domain ,
& state - > request , & state - > response ,
recvfrom_child , state ) ;
}
2005-09-30 21:13:37 +04:00
static void domain_init_recv ( void * private_data_data , BOOL success )
2005-06-09 02:10:34 +04:00
{
struct domain_request_state * state =
2005-09-30 21:13:37 +04:00
talloc_get_type_abort ( private_data_data , struct domain_request_state ) ;
2005-06-09 02:10:34 +04:00
if ( ! success ) {
DEBUG ( 5 , ( " Domain init returned an error \n " ) ) ;
2005-09-30 21:13:37 +04:00
state - > continuation ( state - > private_data_data , False ) ;
2005-06-09 02:10:34 +04:00
return ;
}
async_request ( state - > mem_ctx , & state - > domain - > child ,
state - > request , state - > response ,
2005-09-30 21:13:37 +04:00
state - > continuation , state - > private_data_data ) ;
2005-06-09 02:10:34 +04:00
}
struct winbindd_child_dispatch_table {
enum winbindd_cmd cmd ;
enum winbindd_result ( * fn ) ( struct winbindd_domain * domain ,
struct winbindd_cli_state * state ) ;
const char * winbindd_cmd_name ;
} ;
static struct winbindd_child_dispatch_table child_dispatch_table [ ] = {
2005-08-17 17:40:06 +04:00
{ WINBINDD_LOOKUPSID , winbindd_dual_lookupsid , " LOOKUPSID " } ,
{ WINBINDD_LOOKUPNAME , winbindd_dual_lookupname , " LOOKUPNAME " } ,
2006-07-11 22:01:26 +04:00
{ WINBINDD_LOOKUPRIDS , winbindd_dual_lookuprids , " LOOKUPRIDS " } ,
2005-08-17 17:40:06 +04:00
{ WINBINDD_LIST_TRUSTDOM , winbindd_dual_list_trusted_domains , " LIST_TRUSTDOM " } ,
{ WINBINDD_INIT_CONNECTION , winbindd_dual_init_connection , " INIT_CONNECTION " } ,
{ WINBINDD_GETDCNAME , winbindd_dual_getdcname , " GETDCNAME " } ,
{ WINBINDD_SHOW_SEQUENCE , winbindd_dual_show_sequence , " SHOW_SEQUENCE " } ,
{ WINBINDD_PAM_AUTH , winbindd_dual_pam_auth , " PAM_AUTH " } ,
{ WINBINDD_PAM_AUTH_CRAP , winbindd_dual_pam_auth_crap , " AUTH_CRAP " } ,
2006-02-04 01:19:41 +03:00
{ WINBINDD_PAM_LOGOFF , winbindd_dual_pam_logoff , " PAM_LOGOFF " } ,
2006-07-13 13:29:25 +04:00
{ WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP , winbindd_dual_pam_chng_pswd_auth_crap , " CHNG_PSWD_AUTH_CRAP " } ,
2005-08-17 17:40:06 +04:00
{ WINBINDD_CHECK_MACHACC , winbindd_dual_check_machine_acct , " CHECK_MACHACC " } ,
{ WINBINDD_DUAL_SID2UID , winbindd_dual_sid2uid , " DUAL_SID2UID " } ,
{ WINBINDD_DUAL_SID2GID , winbindd_dual_sid2gid , " DUAL_SID2GID " } ,
2006-08-08 19:33:09 +04:00
{ WINBINDD_DUAL_UID2SID , winbindd_dual_uid2sid , " DUAL_UID2SID " } ,
{ WINBINDD_DUAL_GID2SID , winbindd_dual_gid2sid , " DUAL_GID2SID " } ,
2005-08-17 17:40:06 +04:00
{ WINBINDD_DUAL_UID2NAME , winbindd_dual_uid2name , " DUAL_UID2NAME " } ,
{ WINBINDD_DUAL_NAME2UID , winbindd_dual_name2uid , " DUAL_NAME2UID " } ,
{ WINBINDD_DUAL_GID2NAME , winbindd_dual_gid2name , " DUAL_GID2NAME " } ,
{ WINBINDD_DUAL_NAME2GID , winbindd_dual_name2gid , " DUAL_NAME2GID " } ,
{ WINBINDD_DUAL_IDMAPSET , winbindd_dual_idmapset , " DUAL_IDMAPSET " } ,
{ WINBINDD_DUAL_USERINFO , winbindd_dual_userinfo , " DUAL_USERINFO " } ,
2006-02-04 01:19:41 +03:00
{ WINBINDD_ALLOCATE_UID , winbindd_dual_allocate_uid , " ALLOCATE_UID " } ,
{ WINBINDD_ALLOCATE_GID , winbindd_dual_allocate_gid , " ALLOCATE_GID " } ,
2005-08-17 17:40:06 +04:00
{ WINBINDD_GETUSERDOMGROUPS , winbindd_dual_getuserdomgroups , " GETUSERDOMGROUPS " } ,
{ WINBINDD_DUAL_GETSIDALIASES , winbindd_dual_getsidaliases , " GETSIDALIASES " } ,
2006-08-19 05:04:54 +04:00
{ WINBINDD_CCACHE_NTLMAUTH , winbindd_dual_ccache_ntlm_auth , " CCACHE_NTLM_AUTH " } ,
2005-06-09 02:10:34 +04:00
/* End of list */
{ WINBINDD_NUM_CMDS , NULL , " NONE " }
} ;
static void child_process_request ( struct winbindd_domain * domain ,
struct winbindd_cli_state * state )
{
struct winbindd_child_dispatch_table * table ;
/* Free response data - we may be interrupted and receive another
command before being able to send this data off . */
state - > response . result = WINBINDD_ERROR ;
state - > response . length = sizeof ( struct winbindd_response ) ;
state - > mem_ctx = talloc_init ( " winbind request " ) ;
if ( state - > mem_ctx = = NULL )
return ;
/* Process command */
for ( table = child_dispatch_table ; table - > fn ; table + + ) {
if ( state - > request . cmd = = table - > cmd ) {
DEBUG ( 10 , ( " process_request: request fn %s \n " ,
table - > winbindd_cmd_name ) ) ;
state - > response . result = table - > fn ( domain , state ) ;
break ;
}
}
if ( ! table - > fn ) {
DEBUG ( 10 , ( " process_request: unknown request fn number %d \n " ,
( int ) state - > request . cmd ) ) ;
state - > response . result = WINBINDD_ERROR ;
}
talloc_destroy ( state - > mem_ctx ) ;
}
void setup_domain_child ( struct winbindd_domain * domain ,
struct winbindd_child * child ,
const char * explicit_logfile )
{
if ( explicit_logfile ! = NULL ) {
pstr_sprintf ( child - > logfilename , " %s/log.winbindd-%s " ,
dyn_LOGFILEBASE , explicit_logfile ) ;
} else if ( domain ! = NULL ) {
pstr_sprintf ( child - > logfilename , " %s/log.wb-%s " ,
dyn_LOGFILEBASE , domain - > name ) ;
} else {
smb_panic ( " Internal error: domain == NULL && "
" explicit_logfile == NULL " ) ;
}
child - > domain = domain ;
}
struct winbindd_child * children = NULL ;
void winbind_child_died ( pid_t pid )
{
struct winbindd_child * child ;
for ( child = children ; child ! = NULL ; child = child - > next ) {
if ( child - > pid = = pid ) {
break ;
}
}
if ( child = = NULL ) {
DEBUG ( 0 , ( " Unknown child %d died! \n " , pid ) ) ;
return ;
}
remove_fd_event ( & child - > event ) ;
close ( child - > event . fd ) ;
child - > event . fd = 0 ;
child - > event . flags = 0 ;
child - > pid = 0 ;
schedule_async_request ( child ) ;
}
2006-02-04 01:19:41 +03:00
/* Forward the online/offline messages to our children. */
void winbind_msg_offline ( int msg_type , struct process_id src , void * buf , size_t len )
{
struct winbindd_child * child ;
DEBUG ( 10 , ( " winbind_msg_offline: got offline message. \n " ) ) ;
if ( ! lp_winbind_offline_logon ( ) ) {
DEBUG ( 10 , ( " winbind_msg_offline: rejecting offline message. \n " ) ) ;
return ;
}
/* Set our global state as offline. */
if ( ! set_global_winbindd_state_offline ( ) ) {
DEBUG ( 10 , ( " winbind_msg_offline: offline request failed. \n " ) ) ;
return ;
}
for ( child = children ; child ! = NULL ; child = child - > next ) {
DEBUG ( 10 , ( " winbind_msg_offline: sending message to pid %u. \n " ,
( unsigned int ) child - > pid ) ) ;
message_send_pid ( pid_to_procid ( child - > pid ) , MSG_WINBIND_OFFLINE , NULL , 0 , False ) ;
}
}
/* Forward the online/offline messages to our children. */
void winbind_msg_online ( int msg_type , struct process_id src , void * buf , size_t len )
{
struct winbindd_child * child ;
DEBUG ( 10 , ( " winbind_msg_online: got online message. \n " ) ) ;
if ( ! lp_winbind_offline_logon ( ) ) {
DEBUG ( 10 , ( " winbind_msg_online: rejecting online message. \n " ) ) ;
return ;
}
/* Set our global state as online. */
set_global_winbindd_state_online ( ) ;
for ( child = children ; child ! = NULL ; child = child - > next ) {
DEBUG ( 10 , ( " winbind_msg_online: sending message to pid %u. \n " ,
( unsigned int ) child - > pid ) ) ;
message_send_pid ( pid_to_procid ( child - > pid ) , MSG_WINBIND_ONLINE , NULL , 0 , False ) ;
}
}
2006-05-04 16:37:13 +04:00
/* Forward the online/offline messages to our children. */
void winbind_msg_onlinestatus ( int msg_type , struct process_id src , void * buf , size_t len )
{
struct winbindd_child * child ;
DEBUG ( 10 , ( " winbind_msg_onlinestatus: got onlinestatus message. \n " ) ) ;
for ( child = children ; child ! = NULL ; child = child - > next ) {
if ( child - > domain & & child - > domain - > primary ) {
DEBUG ( 10 , ( " winbind_msg_onlinestatus: "
" sending message to pid %u of primary domain. \n " ,
( unsigned int ) child - > pid ) ) ;
message_send_pid ( pid_to_procid ( child - > pid ) ,
MSG_WINBIND_ONLINESTATUS , buf , len , False ) ;
break ;
}
}
}
2006-02-04 01:19:41 +03:00
static void account_lockout_policy_handler ( struct timed_event * te ,
const struct timeval * now ,
void * private_data )
{
2006-08-18 18:05:25 +04:00
struct winbindd_child * child =
( struct winbindd_child * ) private_data ;
2006-02-04 01:19:41 +03:00
struct winbindd_methods * methods ;
SAM_UNK_INFO_12 lockout_policy ;
NTSTATUS result ;
DEBUG ( 10 , ( " account_lockout_policy_handler called \n " ) ) ;
2006-03-17 13:14:33 +03:00
if ( child - > lockout_policy_event ) {
TALLOC_FREE ( child - > lockout_policy_event ) ;
2006-02-04 01:19:41 +03:00
}
methods = child - > domain - > methods ;
result = methods - > lockout_policy ( child - > domain , child - > mem_ctx , & lockout_policy ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " account_lockout_policy_handler: failed to call lockout_policy \n " ) ) ;
return ;
}
2006-03-17 13:14:33 +03:00
child - > lockout_policy_event = add_timed_event ( child - > mem_ctx ,
timeval_current_ofs ( 3600 , 0 ) ,
" account_lockout_policy_handler " ,
account_lockout_policy_handler ,
child ) ;
2006-02-04 01:19:41 +03:00
}
/* Deal with a request to go offline. */
static void child_msg_offline ( int msg_type , struct process_id src , void * buf , size_t len )
{
struct winbindd_domain * domain ;
DEBUG ( 5 , ( " child_msg_offline received. \n " ) ) ;
if ( ! lp_winbind_offline_logon ( ) ) {
DEBUG ( 10 , ( " child_msg_offline: rejecting offline message. \n " ) ) ;
return ;
}
/* Set our global state as offline. */
if ( ! set_global_winbindd_state_offline ( ) ) {
DEBUG ( 10 , ( " child_msg_offline: offline request failed. \n " ) ) ;
return ;
}
/* Mark all our domains as offline. */
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
DEBUG ( 5 , ( " child_msg_offline: marking %s offline. \n " , domain - > name ) ) ;
2006-09-07 01:43:31 +04:00
set_domain_offline ( domain ) ;
}
}
/* Ensure any negative cache entries with the netbios or realm names are removed. */
static void winbindd_flush_negative_conn_cache ( struct winbindd_domain * domain )
{
check_negative_conn_cache_timeout ( domain - > name , domain - > dcname , 0 ) ;
if ( * domain - > alt_name ) {
check_negative_conn_cache_timeout ( domain - > alt_name , domain - > dcname , 0 ) ;
2006-02-04 01:19:41 +03:00
}
}
/* Deal with a request to go online. */
static void child_msg_online ( int msg_type , struct process_id src , void * buf , size_t len )
{
struct winbindd_domain * domain ;
DEBUG ( 5 , ( " child_msg_online received. \n " ) ) ;
if ( ! lp_winbind_offline_logon ( ) ) {
DEBUG ( 10 , ( " child_msg_online: rejecting online message. \n " ) ) ;
return ;
}
/* Set our global state as online. */
set_global_winbindd_state_online ( ) ;
2006-03-16 16:37:23 +03:00
winbindd_flush_nscd_cache ( ) ;
2006-03-13 18:13:35 +03:00
2006-09-14 13:11:30 +04:00
/* Try and mark everything online - delete any negative cache entries
to force a reconnect now . */
2006-02-04 01:19:41 +03:00
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
DEBUG ( 5 , ( " child_msg_online: marking %s online. \n " , domain - > name ) ) ;
2006-09-07 01:43:31 +04:00
winbindd_flush_negative_conn_cache ( domain ) ;
2006-09-14 13:11:30 +04:00
set_domain_online_request ( domain ) ;
2006-02-04 01:19:41 +03:00
}
}
2006-05-04 16:37:13 +04:00
static const char * collect_onlinestatus ( TALLOC_CTX * mem_ctx )
{
struct winbindd_domain * domain ;
char * buf = NULL ;
if ( ( buf = talloc_asprintf ( mem_ctx , " global:%s " ,
2006-09-07 01:43:31 +04:00
get_global_winbindd_state_offline ( ) ?
2006-05-04 16:37:13 +04:00
" Offline " : " Online " ) ) = = NULL ) {
return NULL ;
}
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
if ( ( buf = talloc_asprintf_append ( buf , " %s:%s " ,
domain - > name ,
domain - > online ?
" Online " : " Offline " ) ) = = NULL ) {
return NULL ;
}
}
buf = talloc_asprintf_append ( buf , " \n " ) ;
2006-05-10 15:39:54 +04:00
DEBUG ( 5 , ( " collect_onlinestatus: %s " , buf ) ) ;
2006-05-04 16:37:13 +04:00
return buf ;
}
static void child_msg_onlinestatus ( int msg_type , struct process_id src , void * buf , size_t len )
{
TALLOC_CTX * mem_ctx ;
const char * message ;
struct process_id * sender ;
DEBUG ( 5 , ( " winbind_msg_onlinestatus received. \n " ) ) ;
if ( ! buf ) {
return ;
}
sender = ( struct process_id * ) buf ;
mem_ctx = talloc_init ( " winbind_msg_onlinestatus " ) ;
if ( mem_ctx = = NULL ) {
return ;
}
message = collect_onlinestatus ( mem_ctx ) ;
2006-06-23 00:33:42 +04:00
if ( message = = NULL ) {
talloc_destroy ( mem_ctx ) ;
return ;
}
2006-05-04 16:37:13 +04:00
message_send_pid ( * sender , MSG_WINBIND_ONLINESTATUS ,
message , strlen ( message ) + 1 , True ) ;
talloc_destroy ( mem_ctx ) ;
}
2005-06-09 02:10:34 +04:00
static BOOL fork_domain_child ( struct winbindd_child * child )
{
int fdpair [ 2 ] ;
struct winbindd_cli_state state ;
extern BOOL override_logfile ;
2005-06-09 11:45:29 +04:00
if ( socketpair ( AF_UNIX , SOCK_STREAM , 0 , fdpair ) ! = 0 ) {
2005-06-09 02:10:34 +04:00
DEBUG ( 0 , ( " Could not open child pipe: %s \n " ,
strerror ( errno ) ) ) ;
return False ;
}
ZERO_STRUCT ( state ) ;
state . pid = getpid ( ) ;
2006-02-04 01:19:41 +03:00
/* Ensure we don't process messages whilst we're
changing the disposition for the child . */
message_block ( ) ;
2005-06-09 02:10:34 +04:00
child - > pid = sys_fork ( ) ;
if ( child - > pid = = - 1 ) {
DEBUG ( 0 , ( " Could not fork: %s \n " , strerror ( errno ) ) ) ;
2006-02-04 01:19:41 +03:00
message_unblock ( ) ;
2005-06-09 02:10:34 +04:00
return False ;
}
if ( child - > pid ! = 0 ) {
/* Parent */
close ( fdpair [ 0 ] ) ;
child - > next = child - > prev = NULL ;
DLIST_ADD ( children , child ) ;
child - > event . fd = fdpair [ 1 ] ;
child - > event . flags = 0 ;
child - > requests = NULL ;
add_fd_event ( & child - > event ) ;
2006-02-04 01:19:41 +03:00
/* We're ok with online/offline messages now. */
message_unblock ( ) ;
2005-06-09 02:10:34 +04:00
return True ;
}
/* Child */
state . sock = fdpair [ 0 ] ;
close ( fdpair [ 1 ] ) ;
/* tdb needs special fork handling */
2006-04-07 02:31:45 +04:00
if ( tdb_reopen_all ( 1 ) = = - 1 ) {
2005-06-09 02:10:34 +04:00
DEBUG ( 0 , ( " tdb_reopen_all failed. \n " ) ) ;
_exit ( 0 ) ;
}
close_conns_after_fork ( ) ;
if ( ! override_logfile ) {
lp_set_logfile ( child - > logfilename ) ;
reopen_logs ( ) ;
}
2006-02-04 01:19:41 +03:00
/* Don't handle the same messages as our parent. */
message_deregister ( MSG_SMB_CONF_UPDATED ) ;
message_deregister ( MSG_SHUTDOWN ) ;
message_deregister ( MSG_WINBIND_OFFLINE ) ;
message_deregister ( MSG_WINBIND_ONLINE ) ;
2006-05-04 16:37:13 +04:00
message_deregister ( MSG_WINBIND_ONLINESTATUS ) ;
2006-02-04 01:19:41 +03:00
/* The child is ok with online/offline messages now. */
message_unblock ( ) ;
child - > mem_ctx = talloc_init ( " child_mem_ctx " ) ;
if ( child - > mem_ctx = = NULL ) {
return False ;
}
2006-06-23 00:31:02 +04:00
if ( child - > domain ! = NULL & & lp_winbind_offline_logon ( ) ) {
2006-02-04 01:19:41 +03:00
/* We might be in the idmap child...*/
2006-03-17 13:14:33 +03:00
child - > lockout_policy_event = add_timed_event (
2006-02-04 01:19:41 +03:00
child - > mem_ctx , timeval_zero ( ) ,
" account_lockout_policy_handler " ,
account_lockout_policy_handler ,
child ) ;
}
/* Handle online/offline messages. */
message_register ( MSG_WINBIND_OFFLINE , child_msg_offline ) ;
message_register ( MSG_WINBIND_ONLINE , child_msg_online ) ;
2006-05-04 16:37:13 +04:00
message_register ( MSG_WINBIND_ONLINESTATUS , child_msg_onlinestatus ) ;
2006-02-04 01:19:41 +03:00
2005-06-09 02:10:34 +04:00
while ( 1 ) {
2006-02-04 01:19:41 +03:00
int ret ;
fd_set read_fds ;
struct timeval t ;
struct timeval * tp ;
struct timeval now ;
2005-06-09 02:10:34 +04:00
/* free up any talloc memory */
2006-02-20 20:59:58 +03:00
lp_TALLOC_FREE ( ) ;
main_loop_TALLOC_FREE ( ) ;
2005-06-09 02:10:34 +04:00
2006-02-04 01:19:41 +03:00
run_events ( ) ;
GetTimeOfDay ( & now ) ;
2006-04-14 07:55:42 +04:00
tp = get_timed_events_timeout ( & t ) ;
2006-02-04 01:19:41 +03:00
if ( tp ) {
2006-04-14 07:55:42 +04:00
DEBUG ( 11 , ( " select will use timeout of %u.%u seconds \n " ,
( unsigned int ) tp - > tv_sec , ( unsigned int ) tp - > tv_usec ) ) ;
2006-02-04 01:19:41 +03:00
}
/* Handle messages */
message_dispatch ( ) ;
FD_ZERO ( & read_fds ) ;
FD_SET ( state . sock , & read_fds ) ;
ret = sys_select ( state . sock + 1 , & read_fds , NULL , NULL , tp ) ;
if ( ret = = 0 ) {
2006-02-09 13:17:38 +03:00
DEBUG ( 11 , ( " nothing is ready yet, continue \n " ) ) ;
2006-02-04 01:19:41 +03:00
continue ;
}
if ( ret = = - 1 & & errno = = EINTR ) {
/* We got a signal - continue. */
continue ;
}
if ( ret = = - 1 & & errno ! = EINTR ) {
DEBUG ( 0 , ( " select error occured \n " ) ) ;
perror ( " select " ) ;
return False ;
}
2005-06-09 02:10:34 +04:00
/* fetch a request from the main daemon */
2005-09-30 21:13:37 +04:00
child_read_request ( & state ) ;
2005-06-09 02:10:34 +04:00
if ( state . finished ) {
/* we lost contact with our parent */
exit ( 0 ) ;
}
2005-09-30 21:13:37 +04:00
DEBUG ( 4 , ( " child daemon request %d \n " , ( int ) state . request . cmd ) ) ;
2005-06-09 02:10:34 +04:00
2005-09-30 21:13:37 +04:00
ZERO_STRUCT ( state . response ) ;
state . request . null_term = ' \0 ' ;
child_process_request ( child - > domain , & state ) ;
2005-06-09 02:10:34 +04:00
2006-04-12 18:10:39 +04:00
SAFE_FREE ( state . request . extra_data . data ) ;
2005-06-09 02:10:34 +04:00
2005-09-30 21:13:37 +04:00
cache_store_response ( sys_getpid ( ) , & state . response ) ;
2005-06-09 02:10:34 +04:00
2006-04-12 18:10:39 +04:00
SAFE_FREE ( state . response . extra_data . data ) ;
2005-06-09 02:10:34 +04:00
2005-09-30 21:13:37 +04:00
/* We just send the result code back, the result
* structure needs to be fetched via the
* winbindd_cache . Hmm . That needs fixing . . . */
2005-06-09 02:10:34 +04:00
2006-08-18 18:05:25 +04:00
if ( write_data ( state . sock ,
( const char * ) & state . response . result ,
2005-09-30 21:13:37 +04:00
sizeof ( state . response . result ) ) ! =
sizeof ( state . response . result ) ) {
DEBUG ( 0 , ( " Could not write result \n " ) ) ;
exit ( 1 ) ;
2005-06-09 02:10:34 +04:00
}
}
}