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
2009-05-08 01:25:49 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2002-04-24 13:59:48 +04:00
( at your option ) any later version .
2009-05-08 01:25:49 +04:00
2002-04-24 13:59:48 +04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2009-05-08 01:25:49 +04:00
2002-04-24 13:59:48 +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/>.
2002-04-24 13:59:48 +04:00
*/
/*
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
2007-10-19 04:40:25 +04:00
extern bool override_logfile ;
2008-02-01 21:50:04 +03:00
extern struct winbindd_methods cache_methods ;
2006-12-12 20:38:42 +03:00
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
{
2008-01-26 12:39:21 +03:00
NTSTATUS status ;
2005-09-30 21:13:37 +04:00
2005-06-09 02:10:34 +04:00
/* Read data */
2008-01-26 12:39:21 +03:00
status = read_data ( state - > sock , ( char * ) & state - > request ,
sizeof ( state - > request ) ) ;
2005-06-09 02:10:34 +04:00
2008-01-26 12:39:21 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " child_read_request: read_data failed: %s \n " ,
nt_errstr ( status ) ) ) ;
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
2008-01-26 12:39:21 +03:00
status = read_data ( state - > sock , state - > request . extra_data . data ,
state - > request . extra_len ) ;
2005-09-30 21:13:37 +04:00
2008-01-26 12:39:21 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " Could not read extra data: %s \n " ,
nt_errstr ( status ) ) ) ;
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 ;
2007-10-19 04:40:25 +04:00
void ( * continuation ) ( void * private_data , bool success ) ;
2007-06-12 02:28:27 +04:00
struct timed_event * reply_timeout_event ;
2007-06-21 22:44:14 +04:00
pid_t child_pid ; /* pid of the child we're waiting on. Used to detect
a restart of the child ( child - > pid ! = child_pid ) . */
2005-06-25 00:25:18 +04:00
void * private_data ;
2005-06-09 02:10:34 +04:00
} ;
2008-07-25 14:08:03 +04:00
static void async_request_fail ( struct winbindd_async_request * state ) ;
2007-10-19 04:40:25 +04:00
static void async_main_request_sent ( void * private_data , bool success ) ;
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 ,
2007-10-19 04:40:25 +04:00
void ( * continuation ) ( void * private_data , bool success ) ,
2005-06-25 00:25:18 +04:00
void * private_data )
2005-06-09 02:10:34 +04:00
{
2006-09-18 11:52:16 +04:00
struct winbindd_async_request * state ;
2005-06-09 02:10:34 +04:00
SMB_ASSERT ( continuation ! = NULL ) ;
2008-10-06 12:57:13 +04:00
DEBUG ( 10 , ( " Sending request to child pid %d (domain=%s) \n " ,
( int ) child - > pid ,
( child - > domain ! = NULL ) ? child - > domain - > name : " '' " ) ) ;
2005-06-09 02:10:34 +04:00
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 ;
2008-07-25 14:08:03 +04:00
state - > reply_timeout_event = NULL ;
2005-06-09 02:10:34 +04:00
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
2006-09-18 11:52:16 +04:00
DLIST_ADD_END ( child - > requests , state , struct winbindd_async_request * ) ;
2005-06-09 02:10:34 +04:00
schedule_async_request ( child ) ;
return ;
}
2007-10-19 04:40:25 +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 " ) ) ;
2008-07-25 14:08:03 +04:00
async_request_fail ( state ) ;
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 ) ;
}
2007-06-12 02:28:27 +04:00
/****************************************************************
Handler triggered if the child winbindd doesn ' t respond within
a given timeout .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void async_request_timeout_handler ( struct event_context * ctx ,
struct timed_event * te ,
2009-01-05 12:22:50 +03:00
struct timeval now ,
2007-06-12 02:28:27 +04:00
void * private_data )
{
struct winbindd_async_request * state =
talloc_get_type_abort ( private_data , struct winbindd_async_request ) ;
2007-06-21 22:44:14 +04:00
DEBUG ( 0 , ( " async_request_timeout_handler: child pid %u is not responding. "
" Closing connection to it. \n " ,
2009-02-24 03:22:43 +03:00
( unsigned int ) state - > child_pid ) ) ;
2007-06-12 02:28:27 +04:00
2007-06-21 22:44:14 +04:00
/* Deal with the reply - set to error. */
2007-06-12 02:28:27 +04:00
async_reply_recv ( private_data , False ) ;
2007-06-21 22:44:14 +04:00
}
2007-06-12 02:28:27 +04:00
2007-06-21 22:44:14 +04:00
/**************************************************************
Common function called on both async send and recv fail .
Cleans up the child and schedules the next request .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-06-12 02:28:27 +04:00
2007-06-21 22:44:14 +04:00
static void async_request_fail ( struct winbindd_async_request * state )
{
DLIST_REMOVE ( state - > child - > requests , state ) ;
2007-06-12 23:53:51 +04:00
2007-06-21 23:40:51 +04:00
TALLOC_FREE ( state - > reply_timeout_event ) ;
2007-06-21 22:44:14 +04:00
2008-09-24 03:39:57 +04:00
/* If child exists and is not already reaped,
send kill signal to child . */
2007-06-21 22:44:14 +04:00
2008-09-24 03:39:57 +04:00
if ( ( state - > child - > pid ! = ( pid_t ) 0 ) & &
( state - > child - > pid ! = ( pid_t ) - 1 ) & &
( state - > child - > pid = = state - > child_pid ) ) {
2007-06-21 22:44:14 +04:00
kill ( state - > child_pid , SIGTERM ) ;
/*
* Close the socket to the child .
*/
winbind_child_died ( state - > child_pid ) ;
}
2007-06-12 23:53:51 +04:00
2007-06-21 22:44:14 +04:00
state - > response - > length = sizeof ( struct winbindd_response ) ;
state - > response - > result = WINBINDD_ERROR ;
state - > continuation ( state - > private_data , False ) ;
2007-06-12 02:28:27 +04:00
}
2007-10-19 04:40:25 +04:00
static void async_request_sent ( void * private_data_data , bool success )
2005-09-30 21:13:37 +04:00
{
struct winbindd_async_request * state =
talloc_get_type_abort ( private_data_data , struct winbindd_async_request ) ;
if ( ! success ) {
2007-06-21 22:44:14 +04:00
DEBUG ( 5 , ( " Could not send async request to child pid %u \n " ,
( unsigned int ) state - > child_pid ) ) ;
async_request_fail ( state ) ;
2005-09-30 21:13:37 +04:00
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 ) ;
2007-06-12 02:28:27 +04:00
2007-06-12 23:19:35 +04:00
/*
2007-06-21 22:44:14 +04:00
* Set up a timeout of 300 seconds for the response .
2007-06-12 23:19:35 +04:00
* If we don ' t get it close the child socket and
* report failure .
2007-06-12 02:28:27 +04:00
*/
2007-06-12 23:19:35 +04:00
state - > reply_timeout_event = event_add_timed ( winbind_event_context ( ) ,
NULL ,
2007-06-21 22:44:14 +04:00
timeval_current_ofs ( 300 , 0 ) ,
2007-06-12 23:19:35 +04:00
async_request_timeout_handler ,
state ) ;
2007-06-12 02:28:27 +04:00
if ( ! state - > reply_timeout_event ) {
2007-06-12 23:19:35 +04:00
smb_panic ( " async_request_sent: failed to add timeout handler. \n " ) ;
2007-06-12 02:28:27 +04:00
}
2005-06-09 02:10:34 +04:00
}
2007-10-19 04:40:25 +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 ;
2007-06-21 18:04:55 +04:00
TALLOC_FREE ( state - > reply_timeout_event ) ;
2007-06-12 02:28:27 +04:00
2005-06-09 02:10:34 +04:00
state - > response - > length = sizeof ( struct winbindd_response ) ;
if ( ! success ) {
2007-06-21 22:44:14 +04:00
DEBUG ( 5 , ( " Could not receive async reply from child pid %u \n " ,
( unsigned int ) state - > child_pid ) ) ;
2006-12-23 05:26:18 +03:00
2007-06-21 22:44:14 +04:00
cache_cleanup_response ( state - > child_pid ) ;
async_request_fail ( state ) ;
2005-06-20 17:42:29 +04:00
return ;
2005-06-09 02:10:34 +04:00
}
2007-06-21 22:44:14 +04:00
SMB_ASSERT ( cache_retrieve_response ( state - > child_pid ,
2005-08-28 13:19:10 +04:00
state - > response ) ) ;
2005-06-09 02:10:34 +04:00
2007-06-21 22:44:14 +04:00
cache_cleanup_response ( state - > child_pid ) ;
2009-05-08 01:25:49 +04:00
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
}
2007-10-19 04:40:25 +04:00
static bool fork_domain_child ( struct winbindd_child * child ) ;
2005-06-09 02:10:34 +04:00
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 */
}
2008-10-08 22:39:32 +04:00
/*
* This may be a reschedule , so we might
* have an existing timeout event pending on
* the first entry in the child - > requests list
* ( we only send one request at a time ) .
* Ensure we free it before we reschedule .
* Bug # 5814 , from hargagan < shargagan @ novell . com > .
* JRA .
*/
TALLOC_FREE ( request - > reply_timeout_event ) ;
2005-06-09 02:10:34 +04:00
if ( ( child - > pid = = 0 ) & & ( ! fork_domain_child ( child ) ) ) {
2008-09-24 03:39:57 +04:00
/* fork_domain_child failed.
Cancel all outstanding requests */
2005-06-09 02:10:34 +04:00
while ( request ! = NULL ) {
/* request might be free'd in the continuation */
struct winbindd_async_request * next = request - > next ;
2008-09-24 03:39:57 +04:00
async_request_fail ( request ) ;
2005-06-09 02:10:34 +04:00
request = next ;
}
return ;
}
2007-06-22 02:10:41 +04:00
/* Now we know who we're sending to - remember the pid. */
request - > child_pid = child - > pid ;
2005-06-09 02:10:34 +04:00
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
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 ;
2007-10-19 04:40:25 +04:00
void ( * continuation ) ( void * private_data_data , bool success ) ;
2005-09-30 21:13:37 +04:00
void * private_data_data ;
2005-06-09 02:10:34 +04:00
} ;
2007-10-19 04:40:25 +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 ,
2007-10-19 04:40:25 +04:00
void ( * continuation ) ( void * private_data_data , bool success ) ,
2005-09-30 21:13:37 +04:00
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 ) ;
}
2007-10-19 04:40:25 +04:00
static void domain_init_recv ( void * private_data_data , bool success )
2007-09-06 15:08:44 +04:00
{
struct domain_request_state * state =
talloc_get_type_abort ( private_data_data , struct domain_request_state ) ;
if ( ! success ) {
DEBUG ( 5 , ( " Domain init returned an error \n " ) ) ;
state - > continuation ( state - > private_data_data , False ) ;
return ;
}
async_request ( state - > mem_ctx , & state - > domain - > child ,
state - > request , state - > response ,
state - > continuation , state - > private_data_data ) ;
}
2007-10-19 04:40:25 +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 ) ;
}
2007-10-08 16:25:57 +04:00
static void child_process_request ( struct winbindd_child * child ,
2005-06-09 02:10:34 +04:00
struct winbindd_cli_state * state )
{
2007-10-08 16:25:57 +04:00
struct winbindd_domain * domain = child - > domain ;
const struct winbindd_child_dispatch_table * table = child - > table ;
2005-06-09 02:10:34 +04:00
/* 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 ) ;
2007-09-11 14:21:34 +04:00
/* as all requests in the child are sync, we can use talloc_tos() */
state - > mem_ctx = talloc_tos ( ) ;
2005-06-09 02:10:34 +04:00
/* Process command */
2007-12-07 18:00:45 +03:00
for ( ; table - > name ; table + + ) {
if ( state - > request . cmd = = table - > struct_cmd ) {
DEBUG ( 10 , ( " child_process_request: request fn %s \n " ,
table - > name ) ) ;
state - > response . result = table - > struct_fn ( domain , state ) ;
return ;
2005-06-09 02:10:34 +04:00
}
}
2007-12-07 18:00:45 +03:00
DEBUG ( 1 , ( " child_process_request: unknown request fn number %d \n " ,
( int ) state - > request . cmd ) ) ;
state - > response . result = WINBINDD_ERROR ;
2005-06-09 02:10:34 +04:00
}
2007-12-13 14:27:57 +03:00
void setup_child ( struct winbindd_child * child ,
const struct winbindd_child_dispatch_table * table ,
const char * logprefix ,
const char * logname )
2005-06-09 02:10:34 +04:00
{
2007-12-13 14:27:57 +03:00
if ( logprefix & & logname ) {
if ( asprintf ( & child - > logfilename , " %s/%s-%s " ,
get_dyn_LOGFILEBASE ( ) , logprefix , logname ) < 0 ) {
2007-12-04 04:57:46 +03:00
smb_panic ( " Internal error: asprintf failed " ) ;
}
2005-06-09 02:10:34 +04:00
} else {
2007-12-13 14:27:57 +03:00
smb_panic ( " Internal error: logprefix == NULL && "
" logname == NULL " ) ;
2005-06-09 02:10:34 +04:00
}
2007-12-13 14:27:57 +03:00
child - > domain = NULL ;
2007-10-08 16:25:57 +04:00
child - > table = table ;
2005-06-09 02:10:34 +04:00
}
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 ) {
2007-06-21 22:44:14 +04:00
DEBUG ( 5 , ( " Already reaped child %u died \n " , ( unsigned int ) pid ) ) ;
2005-06-09 02:10:34 +04:00
return ;
}
2008-04-30 19:09:43 +04:00
/* This will be re-added in fork_domain_child() */
DLIST_REMOVE ( children , child ) ;
2009-05-08 01:25:49 +04:00
2005-06-09 02:10:34 +04:00
remove_fd_event ( & child - > event ) ;
close ( child - > event . fd ) ;
child - > event . fd = 0 ;
child - > event . flags = 0 ;
child - > pid = 0 ;
2008-10-08 22:39:32 +04:00
if ( child - > requests ) {
/*
* schedule_async_request ( ) will also
* clear this event but the call is
* idempotent so it doesn ' t hurt to
* cover all possible future code
* paths . JRA .
*/
TALLOC_FREE ( child - > requests - > reply_timeout_event ) ;
}
2005-06-09 02:10:34 +04:00
schedule_async_request ( child ) ;
}
2006-10-10 04:50:41 +04:00
/* Ensure any negative cache entries with the netbios or realm names are removed. */
void winbindd_flush_negative_conn_cache ( struct winbindd_domain * domain )
{
flush_negative_conn_cache_for_domain ( domain - > name ) ;
if ( * domain - > alt_name ) {
flush_negative_conn_cache_for_domain ( domain - > alt_name ) ;
}
}
2008-07-01 22:37:13 +04:00
/*
* Parent winbindd process sets its own debug level first and then
* sends a message to all the winbindd children to adjust their debug
* level to that of parents .
*/
void winbind_msg_debug ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
struct winbindd_child * child ;
DEBUG ( 10 , ( " winbind_msg_debug: got debug message. \n " ) ) ;
2009-05-08 01:25:49 +04:00
2008-07-01 22:37:13 +04:00
debug_message ( msg_ctx , private_data , MSG_DEBUG , server_id , data ) ;
for ( child = children ; child ! = NULL ; child = child - > next ) {
DEBUG ( 10 , ( " winbind_msg_debug: sending message to pid %u. \n " ,
( unsigned int ) child - > pid ) ) ;
messaging_send_buf ( msg_ctx , pid_to_procid ( child - > pid ) ,
MSG_DEBUG ,
data - > data ,
strlen ( ( char * ) data - > data ) + 1 ) ;
}
}
2006-10-10 04:50:41 +04:00
/* Set our domains as offline and forward the offline message to our children. */
2007-05-16 18:45:09 +04:00
void winbind_msg_offline ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
2006-02-04 01:19:41 +03:00
{
struct winbindd_child * child ;
2006-10-10 04:50:41 +04:00
struct winbindd_domain * domain ;
2006-02-04 01:19:41 +03:00
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 ;
}
2006-10-10 04:50:41 +04:00
/* Set all our domains as offline. */
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
if ( domain - > internal ) {
continue ;
}
DEBUG ( 5 , ( " winbind_msg_offline: marking %s offline. \n " , domain - > name ) ) ;
set_domain_offline ( domain ) ;
}
2006-02-04 01:19:41 +03:00
for ( child = children ; child ! = NULL ; child = child - > next ) {
2007-08-29 16:43:23 +04:00
/* Don't send message to internal childs. We've already
2007-03-01 06:16:38 +03:00
done so above . */
2007-08-29 16:43:23 +04:00
if ( ! child - > domain | | winbindd_internal_child ( child ) ) {
2006-10-10 04:50:41 +04:00
continue ;
}
/* Or internal domains (this should not be possible....) */
if ( child - > domain - > internal ) {
continue ;
}
/* Each winbindd child should only process requests for one domain - make sure
we only set it online / offline for that domain . */
DEBUG ( 10 , ( " winbind_msg_offline: sending message to pid %u for domain %s. \n " ,
( unsigned int ) child - > pid , domain - > name ) ) ;
2007-05-16 18:45:09 +04:00
messaging_send_buf ( msg_ctx , pid_to_procid ( child - > pid ) ,
2007-05-15 14:50:44 +04:00
MSG_WINBIND_OFFLINE ,
( uint8 * ) child - > domain - > name ,
strlen ( child - > domain - > name ) + 1 ) ;
2006-02-04 01:19:41 +03:00
}
}
2006-10-10 04:50:41 +04:00
/* Set our domains as online and forward the online message to our children. */
2007-05-16 18:45:09 +04:00
void winbind_msg_online ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
2006-02-04 01:19:41 +03:00
{
struct winbindd_child * child ;
2006-10-10 04:50:41 +04:00
struct winbindd_domain * domain ;
2006-02-04 01:19:41 +03:00
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 ( ) ;
2006-10-06 06:04:57 +04:00
smb_nscd_flush_user_cache ( ) ;
smb_nscd_flush_group_cache ( ) ;
2006-10-10 04:50:41 +04:00
/* Set all our domains as online. */
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
if ( domain - > internal ) {
continue ;
}
DEBUG ( 5 , ( " winbind_msg_online: requesting %s to go online. \n " , domain - > name ) ) ;
winbindd_flush_negative_conn_cache ( domain ) ;
set_domain_online_request ( domain ) ;
2007-03-01 06:16:38 +03:00
2007-03-01 08:17:33 +03:00
/* Send an online message to the idmap child when our
primary domain comes back online */
2007-03-01 06:16:38 +03:00
if ( domain - > primary ) {
struct winbindd_child * idmap = idmap_child ( ) ;
2009-05-08 01:25:49 +04:00
2007-03-01 06:16:38 +03:00
if ( idmap - > pid ! = 0 ) {
2007-05-16 18:45:09 +04:00
messaging_send_buf ( msg_ctx ,
2007-05-15 14:50:44 +04:00
pid_to_procid ( idmap - > pid ) ,
MSG_WINBIND_ONLINE ,
( uint8 * ) domain - > name ,
strlen ( domain - > name ) + 1 ) ;
2007-03-01 06:16:38 +03:00
}
}
2006-10-10 04:50:41 +04:00
}
2006-02-04 01:19:41 +03:00
for ( child = children ; child ! = NULL ; child = child - > next ) {
2007-08-29 16:43:23 +04:00
/* Don't send message to internal childs. */
if ( ! child - > domain | | winbindd_internal_child ( child ) ) {
2006-10-10 04:50:41 +04:00
continue ;
}
/* Or internal domains (this should not be possible....) */
if ( child - > domain - > internal ) {
continue ;
}
/* Each winbindd child should only process requests for one domain - make sure
we only set it online / offline for that domain . */
DEBUG ( 10 , ( " winbind_msg_online: sending message to pid %u for domain %s. \n " ,
2006-10-10 20:15:01 +04:00
( unsigned int ) child - > pid , child - > domain - > name ) ) ;
2006-10-10 04:50:41 +04:00
2007-05-16 18:45:09 +04:00
messaging_send_buf ( msg_ctx , pid_to_procid ( child - > pid ) ,
2007-05-15 14:50:44 +04:00
MSG_WINBIND_ONLINE ,
( uint8 * ) child - > domain - > name ,
strlen ( child - > domain - > name ) + 1 ) ;
2006-02-04 01:19:41 +03:00
}
}
2006-05-04 16:37:13 +04:00
/* Forward the online/offline messages to our children. */
2007-05-16 18:45:09 +04:00
void winbind_msg_onlinestatus ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
2006-05-04 16:37:13 +04:00
{
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 ) ) ;
2007-05-16 18:45:09 +04:00
messaging_send_buf ( msg_ctx , pid_to_procid ( child - > pid ) ,
2007-05-15 14:50:44 +04:00
MSG_WINBIND_ONLINESTATUS ,
2007-05-16 18:45:09 +04:00
( uint8 * ) data - > data ,
data - > length ) ;
2006-05-04 16:37:13 +04:00
break ;
}
}
}
2007-06-21 17:05:56 +04:00
void winbind_msg_dump_event_list ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
struct winbindd_child * child ;
DEBUG ( 10 , ( " winbind_msg_dump_event_list received \n " ) ) ;
dump_event_list ( winbind_event_context ( ) ) ;
for ( child = children ; child ! = NULL ; child = child - > next ) {
DEBUG ( 10 , ( " winbind_msg_dump_event_list: sending message to pid %u \n " ,
( unsigned int ) child - > pid ) ) ;
messaging_send_buf ( msg_ctx , pid_to_procid ( child - > pid ) ,
MSG_DUMP_EVENT_LIST ,
NULL , 0 ) ;
}
}
2006-05-04 16:37:13 +04:00
2008-01-24 18:19:58 +03:00
void winbind_msg_dump_domain_list ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
TALLOC_CTX * mem_ctx ;
const char * message = NULL ;
struct server_id * sender = NULL ;
const char * domain = NULL ;
char * s = NULL ;
NTSTATUS status ;
struct winbindd_domain * dom = NULL ;
DEBUG ( 5 , ( " winbind_msg_dump_domain_list received. \n " ) ) ;
if ( ! data | | ! data - > data ) {
return ;
}
if ( data - > length < sizeof ( struct server_id ) ) {
return ;
}
mem_ctx = talloc_init ( " winbind_msg_dump_domain_list " ) ;
if ( ! mem_ctx ) {
return ;
}
sender = ( struct server_id * ) data - > data ;
if ( data - > length > sizeof ( struct server_id ) ) {
domain = ( const char * ) data - > data + sizeof ( struct server_id ) ;
}
if ( domain ) {
DEBUG ( 5 , ( " winbind_msg_dump_domain_list for domain: %s \n " ,
domain ) ) ;
message = NDR_PRINT_STRUCT_STRING ( mem_ctx , winbindd_domain ,
find_domain_from_name_noinit ( domain ) ) ;
if ( ! message ) {
talloc_destroy ( mem_ctx ) ;
return ;
}
messaging_send_buf ( msg_ctx , * sender ,
MSG_WINBIND_DUMP_DOMAIN_LIST ,
( uint8_t * ) message , strlen ( message ) + 1 ) ;
talloc_destroy ( mem_ctx ) ;
return ;
}
DEBUG ( 5 , ( " winbind_msg_dump_domain_list all domains \n " ) ) ;
for ( dom = domain_list ( ) ; dom ; dom = dom - > next ) {
message = NDR_PRINT_STRUCT_STRING ( mem_ctx , winbindd_domain , dom ) ;
if ( ! message ) {
talloc_destroy ( mem_ctx ) ;
return ;
}
s = talloc_asprintf_append ( s , " %s \n " , message ) ;
if ( ! s ) {
talloc_destroy ( mem_ctx ) ;
return ;
}
}
status = messaging_send_buf ( msg_ctx , * sender ,
MSG_WINBIND_DUMP_DOMAIN_LIST ,
( uint8_t * ) s , strlen ( s ) + 1 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " failed to send message: %s \n " ,
nt_errstr ( status ) ) ) ;
}
talloc_destroy ( mem_ctx ) ;
}
2007-01-17 15:59:14 +03:00
static void account_lockout_policy_handler ( struct event_context * ctx ,
struct timed_event * te ,
2009-01-05 12:22:50 +03:00
struct timeval now ,
2006-02-04 01:19:41 +03:00
void * private_data )
{
2006-08-18 18:05:25 +04:00
struct winbindd_child * child =
( struct winbindd_child * ) private_data ;
2006-12-16 04:32:57 +03:00
TALLOC_CTX * mem_ctx = NULL ;
2006-02-04 01:19:41 +03:00
struct winbindd_methods * methods ;
2008-02-05 19:25:07 +03:00
struct samr_DomInfo12 lockout_policy ;
2006-02-04 01:19:41 +03:00
NTSTATUS result ;
DEBUG ( 10 , ( " account_lockout_policy_handler called \n " ) ) ;
2007-06-21 18:04:55 +04:00
TALLOC_FREE ( child - > lockout_policy_event ) ;
2006-02-04 01:19:41 +03:00
2007-05-07 00:16:12 +04:00
if ( ! winbindd_can_contact_domain ( child - > domain ) ) {
DEBUG ( 10 , ( " account_lockout_policy_handler: Removing myself since I "
" do not have an incoming trust to domain %s \n " ,
child - > domain - > name ) ) ;
return ;
}
2006-02-04 01:19:41 +03:00
methods = child - > domain - > methods ;
2006-12-16 04:32:57 +03:00
mem_ctx = talloc_init ( " account_lockout_policy_handler ctx " ) ;
if ( ! mem_ctx ) {
result = NT_STATUS_NO_MEMORY ;
} else {
result = methods - > lockout_policy ( child - > domain , mem_ctx , & lockout_policy ) ;
}
2007-08-14 19:34:34 +04:00
TALLOC_FREE ( mem_ctx ) ;
2006-12-16 04:32:57 +03:00
2006-02-04 01:19:41 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2006-12-16 04:32:57 +03:00
DEBUG ( 10 , ( " account_lockout_policy_handler: lockout_policy failed error %s \n " ,
nt_errstr ( result ) ) ) ;
2006-02-04 01:19:41 +03:00
}
2007-01-17 15:59:14 +03:00
child - > lockout_policy_event = event_add_timed ( winbind_event_context ( ) , NULL ,
2006-03-17 13:14:33 +03:00
timeval_current_ofs ( 3600 , 0 ) ,
account_lockout_policy_handler ,
child ) ;
2006-02-04 01:19:41 +03:00
}
2008-08-21 03:20:22 +04:00
static time_t get_machine_password_timeout ( void )
{
/* until we have gpo support use lp setting */
return lp_machine_password_timeout ( ) ;
}
static bool calculate_next_machine_pwd_change ( const char * domain ,
struct timeval * t )
{
time_t pass_last_set_time ;
time_t timeout ;
time_t next_change ;
2008-08-23 15:12:05 +04:00
char * pw ;
2008-08-21 03:20:22 +04:00
2008-08-23 15:12:05 +04:00
pw = secrets_fetch_machine_password ( domain ,
2008-08-21 03:20:22 +04:00
& pass_last_set_time ,
2008-08-23 15:12:05 +04:00
NULL ) ;
if ( pw = = NULL ) {
2008-08-21 03:20:22 +04:00
DEBUG ( 0 , ( " cannot fetch own machine password ???? " ) ) ;
return false ;
}
2008-08-23 15:12:05 +04:00
SAFE_FREE ( pw ) ;
2008-08-21 03:20:22 +04:00
timeout = get_machine_password_timeout ( ) ;
if ( timeout = = 0 ) {
DEBUG ( 10 , ( " machine password never expires \n " ) ) ;
return false ;
}
if ( time ( NULL ) < ( pass_last_set_time + timeout ) ) {
next_change = pass_last_set_time + timeout ;
DEBUG ( 10 , ( " machine password still valid until: %s \n " ,
2008-10-12 01:57:44 +04:00
http_timestring ( talloc_tos ( ) , next_change ) ) ) ;
2008-08-21 03:20:22 +04:00
* t = timeval_set ( next_change , 0 ) ;
return true ;
}
DEBUG ( 10 , ( " machine password expired, needs immediate change \n " ) ) ;
* t = timeval_zero ( ) ;
return true ;
}
static void machine_password_change_handler ( struct event_context * ctx ,
struct timed_event * te ,
2009-01-05 12:22:50 +03:00
struct timeval now ,
2008-08-21 03:20:22 +04:00
void * private_data )
{
struct winbindd_child * child =
( struct winbindd_child * ) private_data ;
struct rpc_pipe_client * netlogon_pipe = NULL ;
2008-08-23 15:12:36 +04:00
TALLOC_CTX * frame ;
2008-08-21 03:20:22 +04:00
NTSTATUS result ;
struct timeval next_change ;
DEBUG ( 10 , ( " machine_password_change_handler called \n " ) ) ;
TALLOC_FREE ( child - > machine_password_change_event ) ;
if ( ! calculate_next_machine_pwd_change ( child - > domain - > name ,
& next_change ) ) {
return ;
}
if ( ! winbindd_can_contact_domain ( child - > domain ) ) {
DEBUG ( 10 , ( " machine_password_change_handler: Removing myself since I "
" do not have an incoming trust to domain %s \n " ,
child - > domain - > name ) ) ;
return ;
}
result = cm_connect_netlogon ( child - > domain , & netlogon_pipe ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " machine_password_change_handler: "
" failed to connect netlogon pipe: %s \n " ,
nt_errstr ( result ) ) ) ;
return ;
}
2008-08-23 15:12:36 +04:00
frame = talloc_stackframe ( ) ;
2008-08-21 03:20:22 +04:00
result = trust_pw_find_change_and_store_it ( netlogon_pipe ,
2008-08-23 15:12:36 +04:00
frame ,
2008-08-21 03:20:22 +04:00
child - > domain - > name ) ;
2008-08-23 15:12:36 +04:00
TALLOC_FREE ( frame ) ;
2008-08-21 03:20:22 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " machine_password_change_handler: "
" failed to change machine password: %s \n " ,
nt_errstr ( result ) ) ) ;
} else {
DEBUG ( 10 , ( " machine_password_change_handler: "
" successfully changed machine password \n " ) ) ;
}
child - > machine_password_change_event = event_add_timed ( winbind_event_context ( ) , NULL ,
next_change ,
machine_password_change_handler ,
child ) ;
}
2006-02-04 01:19:41 +03:00
/* Deal with a request to go offline. */
2007-05-16 18:45:09 +04:00
static void child_msg_offline ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
2006-02-04 01:19:41 +03:00
{
struct winbindd_domain * domain ;
2009-01-04 11:45:30 +03:00
struct winbindd_domain * primary_domain = NULL ;
2007-05-16 18:45:09 +04:00
const char * domainname = ( const char * ) data - > data ;
2006-02-04 01:19:41 +03:00
2007-05-16 18:45:09 +04:00
if ( data - > data = = NULL | | data - > length = = 0 ) {
2006-10-10 04:50:41 +04:00
return ;
}
DEBUG ( 5 , ( " child_msg_offline received for domain %s. \n " , domainname ) ) ;
2006-02-04 01:19:41 +03:00
if ( ! lp_winbind_offline_logon ( ) ) {
DEBUG ( 10 , ( " child_msg_offline: rejecting offline message. \n " ) ) ;
return ;
}
2009-01-04 11:45:30 +03:00
primary_domain = find_our_domain ( ) ;
2006-10-10 04:50:41 +04:00
/* Mark the requested domain offline. */
2006-02-04 01:19:41 +03:00
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
2006-10-10 04:50:41 +04:00
if ( domain - > internal ) {
continue ;
}
if ( strequal ( domain - > name , domainname ) ) {
DEBUG ( 5 , ( " child_msg_offline: marking %s offline. \n " , domain - > name ) ) ;
set_domain_offline ( domain ) ;
2009-01-04 11:45:30 +03:00
/* we are in the trusted domain, set the primary domain
* offline too */
if ( domain ! = primary_domain ) {
set_domain_offline ( primary_domain ) ;
}
2006-10-10 04:50:41 +04:00
}
2006-02-04 01:19:41 +03:00
}
}
/* Deal with a request to go online. */
2007-05-16 18:45:09 +04:00
static void child_msg_online ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
2006-02-04 01:19:41 +03:00
{
struct winbindd_domain * domain ;
2009-01-04 11:45:30 +03:00
struct winbindd_domain * primary_domain = NULL ;
2007-05-16 18:45:09 +04:00
const char * domainname = ( const char * ) data - > data ;
2006-02-04 01:19:41 +03:00
2007-05-16 18:45:09 +04:00
if ( data - > data = = NULL | | data - > length = = 0 ) {
2006-10-10 04:50:41 +04:00
return ;
}
DEBUG ( 5 , ( " child_msg_online received for domain %s. \n " , domainname ) ) ;
2006-02-04 01:19:41 +03:00
if ( ! lp_winbind_offline_logon ( ) ) {
DEBUG ( 10 , ( " child_msg_online: rejecting online message. \n " ) ) ;
return ;
}
2009-01-04 11:45:30 +03:00
primary_domain = find_our_domain ( ) ;
2006-02-04 01:19:41 +03:00
/* Set our global state as online. */
set_global_winbindd_state_online ( ) ;
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 ) {
2006-10-10 04:50:41 +04:00
if ( domain - > internal ) {
continue ;
}
if ( strequal ( domain - > name , domainname ) ) {
DEBUG ( 5 , ( " child_msg_online: requesting %s to go online. \n " , domain - > name ) ) ;
winbindd_flush_negative_conn_cache ( domain ) ;
set_domain_online_request ( domain ) ;
2009-01-04 11:45:30 +03:00
/* we can be in trusted domain, which will contact primary domain
* we have to bring primary domain online in trusted domain process
* see , winbindd_dual_pam_auth ( ) - - > winbindd_dual_pam_auth_samlogon ( )
* - - > contact_domain = find_our_domain ( )
* */
if ( domain ! = primary_domain ) {
winbindd_flush_negative_conn_cache ( primary_domain ) ;
set_domain_online_request ( primary_domain ) ;
}
2006-10-10 04:50:41 +04:00
}
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 ) {
2007-09-14 21:42:10 +04:00
if ( ( buf = talloc_asprintf_append_buffer ( buf , " %s:%s " ,
2006-05-04 16:37:13 +04:00
domain - > name ,
domain - > online ?
" Online " : " Offline " ) ) = = NULL ) {
return NULL ;
}
}
2007-09-14 21:42:10 +04:00
buf = talloc_asprintf_append_buffer ( buf , " \n " ) ;
2006-05-04 16:37:13 +04:00
2006-05-10 15:39:54 +04:00
DEBUG ( 5 , ( " collect_onlinestatus: %s " , buf ) ) ;
2006-05-04 16:37:13 +04:00
return buf ;
}
2007-05-16 18:45:09 +04:00
static void child_msg_onlinestatus ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
2006-05-04 16:37:13 +04:00
{
TALLOC_CTX * mem_ctx ;
const char * message ;
2007-05-07 13:35:35 +04:00
struct server_id * sender ;
2009-05-08 01:25:49 +04:00
2006-05-04 16:37:13 +04:00
DEBUG ( 5 , ( " winbind_msg_onlinestatus received. \n " ) ) ;
2007-05-16 18:45:09 +04:00
if ( ! data - > data ) {
2006-05-04 16:37:13 +04:00
return ;
}
2007-05-16 18:45:09 +04:00
sender = ( struct server_id * ) data - > data ;
2006-05-04 16:37:13 +04:00
mem_ctx = talloc_init ( " winbind_msg_onlinestatus " ) ;
if ( mem_ctx = = NULL ) {
return ;
}
2009-05-08 01:25:49 +04:00
2006-05-04 16:37:13 +04:00
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
2007-05-16 18:45:09 +04:00
messaging_send_buf ( msg_ctx , * sender , MSG_WINBIND_ONLINESTATUS ,
2007-05-15 14:50:44 +04:00
( uint8 * ) message , strlen ( message ) + 1 ) ;
2006-05-04 16:37:13 +04:00
talloc_destroy ( mem_ctx ) ;
}
2007-06-21 17:05:56 +04:00
static void child_msg_dump_event_list ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
DEBUG ( 5 , ( " child_msg_dump_event_list received \n " ) ) ;
dump_event_list ( winbind_event_context ( ) ) ;
}
2009-01-07 04:34:06 +03:00
bool winbindd_reinit_after_fork ( const char * logfilename )
2009-01-07 02:14:52 +03:00
{
struct winbindd_domain * domain ;
struct winbindd_child * cl ;
if ( ! reinit_after_fork ( winbind_messaging_context ( ) ,
winbind_event_context ( ) , true ) ) {
DEBUG ( 0 , ( " reinit_after_fork() failed \n " ) ) ;
2009-01-07 04:34:06 +03:00
return false ;
2009-01-07 02:14:52 +03:00
}
close_conns_after_fork ( ) ;
2009-01-07 04:34:06 +03:00
if ( ! override_logfile & & logfilename ) {
lp_set_logfile ( logfilename ) ;
2009-01-07 02:14:52 +03:00
reopen_logs ( ) ;
}
2009-01-22 16:54:21 +03:00
if ( ! winbindd_setup_sig_term_handler ( false ) )
return false ;
if ( ! winbindd_setup_sig_hup_handler ( override_logfile ? NULL :
logfilename ) )
return false ;
2009-01-07 02:14:52 +03:00
/* Don't handle the same messages as our parent. */
messaging_deregister ( winbind_messaging_context ( ) ,
MSG_SMB_CONF_UPDATED , NULL ) ;
messaging_deregister ( winbind_messaging_context ( ) ,
MSG_SHUTDOWN , NULL ) ;
messaging_deregister ( winbind_messaging_context ( ) ,
MSG_WINBIND_OFFLINE , NULL ) ;
messaging_deregister ( winbind_messaging_context ( ) ,
MSG_WINBIND_ONLINE , NULL ) ;
messaging_deregister ( winbind_messaging_context ( ) ,
MSG_WINBIND_ONLINESTATUS , NULL ) ;
messaging_deregister ( winbind_messaging_context ( ) ,
MSG_DUMP_EVENT_LIST , NULL ) ;
messaging_deregister ( winbind_messaging_context ( ) ,
MSG_WINBIND_DUMP_DOMAIN_LIST , NULL ) ;
messaging_deregister ( winbind_messaging_context ( ) ,
MSG_DEBUG , NULL ) ;
/* We have destroyed all events in the winbindd_event_context
* in reinit_after_fork ( ) , so clean out all possible pending
* event pointers . */
/* Deal with check_online_events. */
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
TALLOC_FREE ( domain - > check_online_event ) ;
}
/* Ensure we're not handling a credential cache event inherited
* from our parent . */
ccache_remove_all_after_fork ( ) ;
/* Destroy all possible events in child list. */
for ( cl = children ; cl ! = NULL ; cl = cl - > next ) {
struct winbindd_async_request * request ;
for ( request = cl - > requests ; request ; request = request - > next ) {
TALLOC_FREE ( request - > reply_timeout_event ) ;
}
TALLOC_FREE ( cl - > lockout_policy_event ) ;
TALLOC_FREE ( cl - > machine_password_change_event ) ;
2009-01-14 09:26:40 +03:00
2009-01-14 22:12:52 +03:00
/* Children should never be able to send
* each other messages , all messages must
2009-01-14 09:26:40 +03:00
* go through the parent .
*/
cl - > pid = ( pid_t ) 0 ;
2009-01-07 02:14:52 +03:00
}
2009-01-14 09:26:40 +03:00
/*
2009-01-14 22:12:52 +03:00
* This is a little tricky , children must not
* send an MSG_WINBIND_ONLINE message to idmap_child ( ) .
* If we are in a child of our primary domain or
* in the process created by fork_child_dc_connect ( ) ,
* and the primary domain cannot go online ,
* fork_child_dc_connection ( ) sends MSG_WINBIND_ONLINE
2009-01-14 09:26:40 +03:00
* periodically to idmap_child ( ) .
2009-01-14 22:12:52 +03:00
*
* The sequence is , fork_child_dc_connect ( ) - - - > getdcs ( ) - - - >
2009-01-14 09:26:40 +03:00
* get_dc_name_via_netlogon ( ) - - - > cm_connect_netlogon ( )
* - - - > init_dc_connection ( ) - - - > cm_open_connection - - - >
2009-01-14 22:12:52 +03:00
* set_domain_online ( ) , sends MSG_WINBIND_ONLINE to
* idmap_child ( ) . Disallow children sending messages
* to each other , all messages must go through the parent .
2009-01-14 09:26:40 +03:00
*/
cl = idmap_child ( ) ;
cl - > pid = ( pid_t ) 0 ;
2009-01-07 04:34:06 +03:00
return true ;
2009-01-07 02:14:52 +03:00
}
2007-06-21 17:05:56 +04:00
2007-10-19 04:40:25 +04:00
static bool fork_domain_child ( struct winbindd_child * child )
2005-06-09 02:10:34 +04:00
{
int fdpair [ 2 ] ;
struct winbindd_cli_state state ;
2008-06-03 02:26:37 +04:00
struct winbindd_domain * primary_domain = NULL ;
2005-06-09 02:10:34 +04:00
2008-01-25 03:21:56 +03:00
if ( child - > domain ) {
DEBUG ( 10 , ( " fork_domain_child called for domain '%s' \n " ,
child - > domain - > name ) ) ;
} else {
DEBUG ( 10 , ( " fork_domain_child called without domain. \n " ) ) ;
}
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 ) ;
2006-12-13 01:41:42 +03:00
state . pid = sys_getpid ( ) ;
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 ) ) ) ;
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 ;
add_fd_event ( & child - > event ) ;
return True ;
}
/* Child */
2008-07-13 14:07:40 +04:00
DEBUG ( 10 , ( " Child process %d \n " , ( int ) sys_getpid ( ) ) ) ;
2008-05-15 01:10:39 +04:00
/* Stop zombies in children */
CatchChild ( ) ;
2005-06-09 02:10:34 +04:00
state . sock = fdpair [ 0 ] ;
close ( fdpair [ 1 ] ) ;
2009-01-07 04:34:06 +03:00
if ( ! winbindd_reinit_after_fork ( child - > logfilename ) ) {
_exit ( 0 ) ;
}
/* Handle online/offline messages. */
messaging_register ( winbind_messaging_context ( ) , NULL ,
MSG_WINBIND_OFFLINE , child_msg_offline ) ;
messaging_register ( winbind_messaging_context ( ) , NULL ,
MSG_WINBIND_ONLINE , child_msg_online ) ;
messaging_register ( winbind_messaging_context ( ) , NULL ,
MSG_WINBIND_ONLINESTATUS , child_msg_onlinestatus ) ;
messaging_register ( winbind_messaging_context ( ) , NULL ,
MSG_DUMP_EVENT_LIST , child_msg_dump_event_list ) ;
messaging_register ( winbind_messaging_context ( ) , NULL ,
MSG_DEBUG , debug_message ) ;
2006-02-04 01:19:41 +03:00
2009-01-05 14:47:45 +03:00
primary_domain = find_our_domain ( ) ;
if ( primary_domain = = NULL ) {
smb_panic ( " no primary domain found " ) ;
}
2009-01-07 02:14:52 +03:00
2009-01-05 14:47:45 +03:00
/* It doesn't matter if we allow cache login,
* try to bring domain online after fork . */
2006-09-27 06:26:03 +04:00
if ( child - > domain ) {
child - > domain - > startup = True ;
2006-09-28 22:08:03 +04:00
child - > domain - > startup_time = time ( NULL ) ;
2009-01-05 14:47:45 +03:00
/* we can be in primary domain or in trusted domain
* If we are in trusted domain , set the primary domain
* in start - up mode */
if ( ! ( child - > domain - > internal ) ) {
set_domain_online_request ( child - > domain ) ;
if ( ! ( child - > domain - > primary ) ) {
primary_domain - > startup = True ;
primary_domain - > startup_time = time ( NULL ) ;
set_domain_online_request ( primary_domain ) ;
}
2006-12-08 21:07:44 +03:00
}
}
2009-05-08 01:25:49 +04:00
2009-01-14 09:26:40 +03:00
/*
* We are in idmap child , make sure that we set the
* check_online_event to bring primary domain online .
*/
if ( child = = idmap_child ( ) ) {
set_domain_online_request ( primary_domain ) ;
}
2006-12-08 21:07:44 +03:00
2007-01-30 19:51:42 +03:00
/* We might be in the idmap child...*/
2007-02-01 15:24:08 +03:00
if ( child - > domain & & ! ( child - > domain - > internal ) & &
lp_winbind_offline_logon ( ) ) {
2007-01-30 19:51:42 +03:00
set_domain_online_request ( child - > domain ) ;
2008-10-30 02:02:45 +03:00
if ( primary_domain & & ( primary_domain ! = child - > domain ) ) {
2008-06-03 02:26:37 +04:00
/* We need to talk to the primary
* domain as well as the trusted
* domain inside a trusted domain
* child .
* See the code in :
* set_dc_type_and_flags_trustinfo ( )
* for details .
*/
set_domain_online_request ( primary_domain ) ;
}
2007-01-30 19:51:42 +03:00
child - > lockout_policy_event = event_add_timed (
winbind_event_context ( ) , NULL , timeval_zero ( ) ,
account_lockout_policy_handler ,
child ) ;
}
2008-08-25 13:37:57 +04:00
if ( child - > domain & & child - > domain - > primary & &
2009-01-16 04:02:41 +03:00
! USE_KERBEROS_KEYTAB & &
2008-08-21 03:20:22 +04:00
lp_server_role ( ) = = ROLE_DOMAIN_MEMBER ) {
struct timeval next_change ;
if ( calculate_next_machine_pwd_change ( child - > domain - > name ,
& next_change ) ) {
child - > machine_password_change_event = event_add_timed (
winbind_event_context ( ) , NULL , next_change ,
machine_password_change_handler ,
child ) ;
}
}
2005-06-09 02:10:34 +04:00
while ( 1 ) {
2006-02-04 01:19:41 +03:00
int ret ;
2009-01-20 06:14:20 +03:00
fd_set r_fds ;
fd_set w_fds ;
int maxfd ;
2006-02-04 01:19:41 +03:00
struct timeval t ;
struct timeval * tp ;
struct timeval now ;
2007-08-30 23:48:31 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2005-06-09 02:10:34 +04:00
2009-01-20 06:14:20 +03:00
if ( run_events ( winbind_event_context ( ) , 0 , NULL , NULL ) ) {
TALLOC_FREE ( frame ) ;
continue ;
}
2006-02-04 01:19:41 +03:00
GetTimeOfDay ( & now ) ;
2006-09-28 22:08:03 +04:00
if ( child - > domain & & child - > domain - > startup & &
( now . tv_sec > child - > domain - > startup_time + 30 ) ) {
2006-09-15 18:05:28 +04:00
/* No longer in "startup" mode. */
DEBUG ( 10 , ( " fork_domain_child: domain %s no longer in 'startup' mode. \n " ,
child - > domain - > name ) ) ;
child - > domain - > startup = False ;
}
2009-01-20 06:14:20 +03:00
FD_ZERO ( & r_fds ) ;
FD_ZERO ( & w_fds ) ;
FD_SET ( state . sock , & r_fds ) ;
maxfd = state . sock ;
event_add_to_select_args ( winbind_event_context ( ) , & now ,
& r_fds , & w_fds , & t , & maxfd ) ;
2007-01-17 15:59:14 +03:00
tp = get_timed_events_timeout ( winbind_event_context ( ) , & 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
}
2009-01-20 06:14:20 +03:00
ret = sys_select ( maxfd + 1 , & r_fds , & w_fds , NULL , tp ) ;
2006-02-04 01:19:41 +03:00
2009-01-20 06:14:20 +03:00
if ( run_events ( winbind_event_context ( ) , ret , & r_fds , & w_fds ) ) {
/* We got a signal - continue. */
TALLOC_FREE ( frame ) ;
continue ;
}
2006-02-04 01:19:41 +03:00
if ( ret = = 0 ) {
2006-02-09 13:17:38 +03:00
DEBUG ( 11 , ( " nothing is ready yet, continue \n " ) ) ;
2007-08-30 23:48:31 +04:00
TALLOC_FREE ( frame ) ;
2006-02-04 01:19:41 +03:00
continue ;
}
if ( ret = = - 1 & & errno = = EINTR ) {
/* We got a signal - continue. */
2007-08-30 23:48:31 +04:00
TALLOC_FREE ( frame ) ;
2006-02-04 01:19:41 +03:00
continue ;
}
if ( ret = = - 1 & & errno ! = EINTR ) {
DEBUG ( 0 , ( " select error occured \n " ) ) ;
2007-08-30 23:48:31 +04:00
TALLOC_FREE ( frame ) ;
2006-02-04 01:19:41 +03:00
perror ( " select " ) ;
2009-01-14 02:42:56 +03:00
_exit ( 1 ) ;
2006-02-04 01:19:41 +03:00
}
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 */
2009-01-14 02:42:56 +03:00
_exit ( 0 ) ;
2005-06-09 02:10:34 +04:00
}
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 ' ;
2007-10-08 16:25:57 +04:00
child_process_request ( child , & 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
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
}
2007-08-30 23:48:31 +04:00
TALLOC_FREE ( frame ) ;
2005-06-09 02:10:34 +04:00
}
}