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"
2013-09-16 20:36:43 +04:00
# include "rpc_client/rpc_client.h"
2011-02-17 02:43:05 +03:00
# include "nsswitch/wb_reqtrans.h"
2010-08-05 04:25:37 +04:00
# include "secrets.h"
2010-10-01 12:08:15 +04:00
# include "../lib/util/select.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2011-02-04 00:05:30 +03:00
# include "system/select.h"
2011-03-24 17:31:06 +03:00
# include "messages.h"
2011-04-28 19:38:09 +04:00
# include "../lib/util/tevent_unix.h"
2012-07-23 06:47:01 +04:00
# include "lib/param/loadparm.h"
2015-10-12 16:57:34 +03:00
# include "lib/util/sys_rw.h"
# include "lib/util/sys_rw_data.h"
2018-03-20 03:14:38 +03:00
# include "passdb.h"
2002-04-24 13:59:48 +04:00
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 ;
2006-12-12 20:38:42 +03:00
2018-02-26 14:55:31 +03:00
static void forall_domain_children ( bool ( * fn ) ( struct winbindd_child * c ,
void * private_data ) ,
void * private_data )
{
struct winbindd_domain * d ;
for ( d = domain_list ( ) ; d ! = NULL ; d = d - > next ) {
int i ;
for ( i = 0 ; i < lp_winbind_max_domain_connections ( ) ; i + + ) {
struct winbindd_child * c = & d - > children [ i ] ;
bool ok ;
if ( c - > pid = = 0 ) {
continue ;
}
ok = fn ( c , private_data ) ;
if ( ! ok ) {
return ;
}
}
}
}
static void forall_children ( bool ( * fn ) ( struct winbindd_child * c ,
void * private_data ) ,
void * private_data )
{
struct winbindd_child * c ;
bool ok ;
c = idmap_child ( ) ;
if ( c - > pid ! = 0 ) {
ok = fn ( c , private_data ) ;
if ( ! ok ) {
return ;
}
}
c = locator_child ( ) ;
if ( c - > pid ! = 0 ) {
ok = fn ( c , private_data ) ;
if ( ! ok ) {
return ;
}
}
forall_domain_children ( fn , private_data ) ;
}
2005-06-09 02:10:34 +04:00
/* Read some data from a client connection */
2014-01-16 22:00:04 +04:00
static NTSTATUS child_read_request ( int sock , struct winbindd_request * wreq )
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
2014-11-19 17:06:49 +03:00
status = read_data_ntstatus ( sock , ( char * ) wreq , sizeof ( * wreq ) ) ;
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 ) ) ) ;
2009-05-25 22:17:23 +04:00
return status ;
2005-09-30 21:13:37 +04:00
}
2014-01-16 22:00:04 +04:00
if ( wreq - > extra_len = = 0 ) {
wreq - > extra_data . data = NULL ;
2009-05-25 22:17:23 +04:00
return NT_STATUS_OK ;
2005-09-30 21:13:37 +04:00
}
2014-01-16 22:00:04 +04:00
DEBUG ( 10 , ( " Need to read %d extra bytes \n " , ( int ) wreq - > extra_len ) ) ;
2005-09-30 21:13:37 +04:00
2014-01-16 22:00:04 +04:00
wreq - > extra_data . data = SMB_MALLOC_ARRAY ( char , wreq - > extra_len + 1 ) ;
if ( wreq - > extra_data . data = = NULL ) {
2005-09-30 21:13:37 +04:00
DEBUG ( 0 , ( " malloc failed \n " ) ) ;
2009-05-25 22:17:23 +04:00
return NT_STATUS_NO_MEMORY ;
2005-09-30 21:13:37 +04:00
}
/* Ensure null termination */
2014-01-16 22:00:04 +04:00
wreq - > extra_data . data [ wreq - > extra_len ] = ' \0 ' ;
2005-09-30 21:13:37 +04:00
2014-11-19 17:06:49 +03:00
status = read_data_ntstatus ( sock , wreq - > extra_data . data ,
wreq - > extra_len ) ;
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
}
2009-05-25 22:17:23 +04:00
return status ;
2005-06-09 02:10:34 +04:00
}
2014-01-16 22:00:05 +04:00
static NTSTATUS child_write_response ( int sock , struct winbindd_response * wrsp )
{
struct iovec iov [ 2 ] ;
int iov_count ;
iov [ 0 ] . iov_base = ( void * ) wrsp ;
iov [ 0 ] . iov_len = sizeof ( struct winbindd_response ) ;
iov_count = 1 ;
if ( wrsp - > length > sizeof ( struct winbindd_response ) ) {
iov [ 1 ] . iov_base = ( void * ) wrsp - > extra_data . data ;
iov [ 1 ] . iov_len = wrsp - > length - iov [ 0 ] . iov_len ;
iov_count = 2 ;
}
DEBUG ( 10 , ( " Writing %d bytes to parent \n " , ( int ) wrsp - > length ) ) ;
if ( write_data_iov ( sock , iov , iov_count ) ! = wrsp - > length ) {
DEBUG ( 0 , ( " Could not write result \n " ) ) ;
return NT_STATUS_INVALID_HANDLE ;
}
return NT_STATUS_OK ;
}
2005-06-09 02:10:34 +04:00
/*
2009-05-10 12:49:53 +04:00
* Do winbind child async request . This is not simply wb_simple_trans . We have
* to do the queueing ourselves because while a request is queued , the child
* might have crashed , and we have to re - fork it in the _trigger function .
2005-06-09 02:10:34 +04:00
*/
2009-05-10 12:49:53 +04:00
struct wb_child_request_state {
struct tevent_context * ev ;
2018-02-16 17:02:42 +03:00
struct tevent_req * queue_subreq ;
2015-06-24 10:55:06 +03:00
struct tevent_req * subreq ;
2005-06-09 02:10:34 +04:00
struct winbindd_child * child ;
struct winbindd_request * request ;
struct winbindd_response * response ;
} ;
2009-05-10 12:49:53 +04:00
static bool fork_domain_child ( struct winbindd_child * child ) ;
2005-06-09 02:10:34 +04:00
2018-02-16 17:02:42 +03:00
static void wb_child_request_waited ( struct tevent_req * subreq ) ;
2009-05-10 12:49:53 +04:00
static void wb_child_request_done ( struct tevent_req * subreq ) ;
2018-02-16 17:05:57 +03:00
static void wb_child_request_orphaned ( struct tevent_req * subreq ) ;
2008-10-06 12:57:13 +04:00
2015-06-24 10:55:06 +03:00
static void wb_child_request_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state ) ;
2009-05-10 12:49:53 +04:00
struct tevent_req * wb_child_request_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct winbindd_child * child ,
struct winbindd_request * request )
{
struct tevent_req * req ;
struct wb_child_request_state * state ;
2018-02-16 17:02:42 +03:00
struct tevent_req * subreq ;
2005-06-09 02:10:34 +04:00
2009-05-10 12:49:53 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct wb_child_request_state ) ;
if ( req = = NULL ) {
return NULL ;
2005-06-09 02:10:34 +04:00
}
2009-05-10 12:49:53 +04:00
state - > ev = ev ;
2005-06-09 02:10:34 +04:00
state - > child = child ;
state - > request = request ;
2018-02-16 17:02:42 +03:00
subreq = tevent_queue_wait_send ( state , ev , child - > queue ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
2009-05-10 12:49:53 +04:00
return tevent_req_post ( req , ev ) ;
}
2018-02-16 17:02:42 +03:00
tevent_req_set_callback ( subreq , wb_child_request_waited , req ) ;
state - > queue_subreq = subreq ;
2015-06-24 10:55:06 +03:00
tevent_req_set_cleanup_fn ( req , wb_child_request_cleanup ) ;
2009-05-10 12:49:53 +04:00
return req ;
2005-06-09 02:10:34 +04:00
}
2018-02-16 17:02:42 +03:00
static void wb_child_request_waited ( struct tevent_req * subreq )
2005-06-09 02:10:34 +04:00
{
2018-02-16 17:02:42 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2009-05-10 12:49:53 +04:00
struct wb_child_request_state * state = tevent_req_data (
req , struct wb_child_request_state ) ;
2018-02-16 17:02:42 +03:00
bool ok ;
ok = tevent_queue_wait_recv ( subreq ) ;
if ( ! ok ) {
tevent_req_oom ( req ) ;
return ;
}
/*
* We need to keep state - > queue_subreq
* in order to block the queue .
*/
subreq = NULL ;
2005-06-09 02:10:34 +04:00
2010-12-06 23:45:21 +03:00
if ( ( state - > child - > sock = = - 1 ) & & ( ! fork_domain_child ( state - > child ) ) ) {
2009-05-10 12:49:53 +04:00
tevent_req_error ( req , errno ) ;
2005-06-09 02:10:34 +04:00
return ;
}
2018-02-26 17:12:14 +03:00
tevent_fd_set_flags ( state - > child - > monitor_fde , 0 ) ;
2018-08-21 21:06:16 +03:00
subreq = wb_simple_trans_send ( state , global_event_context ( ) , NULL ,
2009-05-10 12:49:53 +04:00
state - > child - > sock , state - > request ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
2005-09-30 21:13:37 +04:00
return ;
}
2015-06-24 10:55:06 +03:00
state - > subreq = subreq ;
2009-05-10 12:49:53 +04:00
tevent_req_set_callback ( subreq , wb_child_request_done , req ) ;
2011-03-21 12:56:10 +03:00
tevent_req_set_endtime ( req , state - > ev , timeval_current_ofs ( 300 , 0 ) ) ;
2007-06-21 22:44:14 +04:00
}
2007-06-12 02:28:27 +04:00
2009-05-10 12:49:53 +04:00
static void wb_child_request_done ( struct tevent_req * subreq )
2007-06-21 22:44:14 +04:00
{
2009-05-10 12:49:53 +04:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_child_request_state * state = tevent_req_data (
req , struct wb_child_request_state ) ;
int ret , err ;
ret = wb_simple_trans_recv ( subreq , state , & state - > response , & err ) ;
2015-06-24 10:55:06 +03:00
/* Freeing the subrequest is deferred until the cleanup function,
* which has to know whether a subrequest exists , and consequently
* decide whether to shut down the pipe to the child process .
*/
2009-05-10 12:49:53 +04:00
if ( ret = = - 1 ) {
tevent_req_error ( req , err ) ;
return ;
2007-06-21 22:44:14 +04:00
}
2009-05-10 12:49:53 +04:00
tevent_req_done ( req ) ;
2007-06-12 02:28:27 +04:00
}
2018-02-16 17:05:57 +03:00
static void wb_child_request_orphaned ( struct tevent_req * subreq )
{
2018-02-14 17:04:01 +03:00
struct winbindd_child * child =
( struct winbindd_child * ) tevent_req_callback_data_void ( subreq ) ;
2018-02-16 17:05:57 +03:00
DBG_WARNING ( " cleanup orphaned subreq[%p] \n " , subreq ) ;
TALLOC_FREE ( subreq ) ;
2018-02-14 17:04:01 +03:00
if ( child - > domain ! = NULL ) {
/*
* If the child is attached to a domain ,
* we need to make sure the domain queue
* can move forward , after the orphaned
* request is done .
*/
tevent_queue_start ( child - > domain - > queue ) ;
}
2018-02-16 17:05:57 +03:00
}
2009-05-10 12:49:53 +04:00
int wb_child_request_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct winbindd_response * * presponse , int * err )
2005-09-30 21:13:37 +04:00
{
2009-05-10 12:49:53 +04:00
struct wb_child_request_state * state = tevent_req_data (
req , struct wb_child_request_state ) ;
2005-09-30 21:13:37 +04:00
2009-05-10 12:49:53 +04:00
if ( tevent_req_is_unix_error ( req , err ) ) {
return - 1 ;
2005-09-30 21:13:37 +04:00
}
2009-05-10 12:49:53 +04:00
* presponse = talloc_move ( mem_ctx , & state - > response ) ;
return 0 ;
2005-06-09 02:10:34 +04:00
}
2015-06-24 10:55:06 +03:00
static void wb_child_request_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
{
struct wb_child_request_state * state =
tevent_req_data ( req , struct wb_child_request_state ) ;
if ( state - > subreq = = NULL ) {
/* nothing to cleanup */
return ;
}
2018-02-16 17:05:57 +03:00
if ( req_state = = TEVENT_REQ_RECEIVED ) {
struct tevent_req * subreq = NULL ;
/*
* Our caller gave up , but we need to keep
* the low level request ( wb_simple_trans )
* in order to maintain the parent child protocol .
*
* We also need to keep the child queue blocked
* until we got the response from the child .
*/
subreq = talloc_move ( state - > child - > queue , & state - > subreq ) ;
talloc_move ( subreq , & state - > queue_subreq ) ;
tevent_req_set_callback ( subreq ,
wb_child_request_orphaned ,
2018-02-14 17:04:01 +03:00
state - > child ) ;
2018-02-16 17:05:57 +03:00
DBG_WARNING ( " keep orphaned subreq[%p] \n " , subreq ) ;
return ;
}
2015-06-24 10:55:06 +03:00
TALLOC_FREE ( state - > subreq ) ;
2018-02-16 17:02:42 +03:00
TALLOC_FREE ( state - > queue_subreq ) ;
2015-06-24 10:55:06 +03:00
2018-02-26 17:12:14 +03:00
tevent_fd_set_flags ( state - > child - > monitor_fde , TEVENT_FD_READ ) ;
2018-02-14 17:04:01 +03:00
if ( state - > child - > domain ! = NULL ) {
/*
* If the child is attached to a domain ,
* we need to make sure the domain queue
* can move forward , after the request
* is done .
*/
tevent_queue_start ( state - > child - > domain - > queue ) ;
}
2015-06-24 10:55:06 +03:00
if ( req_state = = TEVENT_REQ_DONE ) {
/* transmitted request and got response */
return ;
}
/*
* Failed to transmit and receive response , or request
* cancelled while being serviced .
* The basic parent / child communication broke , close
* our socket
*/
2018-02-26 17:12:14 +03:00
TALLOC_FREE ( state - > child - > monitor_fde ) ;
2015-06-24 10:55:06 +03:00
close ( state - > child - > sock ) ;
state - > child - > sock = - 1 ;
}
2018-02-26 17:12:14 +03:00
static void child_socket_readable ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags ,
void * private_data )
{
struct winbindd_child * child = private_data ;
if ( ( flags & TEVENT_FD_READ ) = = 0 ) {
return ;
}
TALLOC_FREE ( child - > monitor_fde ) ;
/*
* We ' re only active when there is no outstanding child
* request . Arriving here means the child closed its socket ,
* it died . Do the same here .
*/
SMB_ASSERT ( child - > sock ! = - 1 ) ;
close ( child - > sock ) ;
child - > sock = - 1 ;
}
2018-02-20 16:43:38 +03:00
static struct winbindd_child * choose_domain_child ( struct winbindd_domain * domain )
2010-04-07 19:45:12 +04:00
{
2018-02-09 12:27:55 +03:00
struct winbindd_child * shortest = & domain - > children [ 0 ] ;
struct winbindd_child * current ;
2010-04-07 19:45:12 +04:00
int i ;
for ( i = 0 ; i < lp_winbind_max_domain_connections ( ) ; i + + ) {
2018-02-09 12:27:55 +03:00
size_t shortest_len , current_len ;
2010-04-07 19:45:12 +04:00
2018-02-09 12:27:55 +03:00
current = & domain - > children [ i ] ;
current_len = tevent_queue_length ( current - > queue ) ;
2010-04-07 19:45:12 +04:00
2018-02-09 12:27:55 +03:00
if ( current_len = = 0 ) {
/* idle child */
return current ;
}
2010-04-07 19:45:12 +04:00
2018-02-09 12:27:55 +03:00
shortest_len = tevent_queue_length ( shortest - > queue ) ;
if ( current_len < shortest_len ) {
shortest = current ;
}
2010-04-07 19:45:12 +04:00
}
2018-02-09 12:27:55 +03:00
return shortest ;
2010-04-07 19:45:12 +04:00
}
struct dcerpc_binding_handle * dom_child_handle ( struct winbindd_domain * domain )
{
2018-02-13 18:04:44 +03:00
return domain - > binding_handle ;
2010-04-07 19:45:12 +04:00
}
2009-06-13 14:13:07 +04:00
struct wb_domain_request_state {
struct tevent_context * ev ;
2018-02-14 17:04:01 +03:00
struct tevent_queue_entry * queue_entry ;
2009-06-13 14:13:07 +04:00
struct winbindd_domain * domain ;
2010-04-07 19:45:12 +04:00
struct winbindd_child * child ;
2009-06-13 14:13:07 +04:00
struct winbindd_request * request ;
struct winbindd_request * init_req ;
struct winbindd_response * response ;
2018-02-14 17:04:01 +03:00
struct tevent_req * pending_subreq ;
2009-06-13 14:13:07 +04:00
} ;
2018-02-14 17:04:01 +03:00
static void wb_domain_request_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
{
struct wb_domain_request_state * state = tevent_req_data (
req , struct wb_domain_request_state ) ;
/*
* If we ' re completely done or got a failure .
* we should remove ourself from the domain queue ,
* after removing the child subreq from the child queue
* and give the next one in the queue the chance
* to check for an idle child .
*/
TALLOC_FREE ( state - > pending_subreq ) ;
TALLOC_FREE ( state - > queue_entry ) ;
tevent_queue_start ( state - > domain - > queue ) ;
}
static void wb_domain_request_trigger ( struct tevent_req * req ,
void * private_data ) ;
2009-06-13 14:13:07 +04:00
static void wb_domain_request_gotdc ( struct tevent_req * subreq ) ;
static void wb_domain_request_initialized ( struct tevent_req * subreq ) ;
static void wb_domain_request_done ( struct tevent_req * subreq ) ;
struct tevent_req * wb_domain_request_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct winbindd_domain * domain ,
struct winbindd_request * request )
{
2018-02-14 17:04:01 +03:00
struct tevent_req * req ;
2009-06-13 14:13:07 +04:00
struct wb_domain_request_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct wb_domain_request_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2018-02-14 17:09:51 +03:00
state - > domain = domain ;
state - > ev = ev ;
state - > request = request ;
2018-02-14 17:04:01 +03:00
tevent_req_set_cleanup_fn ( req , wb_domain_request_cleanup ) ;
state - > queue_entry = tevent_queue_add_entry (
domain - > queue , state - > ev , req ,
wb_domain_request_trigger , NULL ) ;
if ( tevent_req_nomem ( state - > queue_entry , req ) ) {
return tevent_req_post ( req , ev ) ;
}
return req ;
}
static void wb_domain_request_trigger ( struct tevent_req * req ,
void * private_data )
{
struct wb_domain_request_state * state = tevent_req_data (
req , struct wb_domain_request_state ) ;
struct winbindd_domain * domain = state - > domain ;
struct tevent_req * subreq = NULL ;
size_t shortest_queue_length ;
2010-04-07 19:45:12 +04:00
state - > child = choose_domain_child ( domain ) ;
2018-02-14 17:04:01 +03:00
shortest_queue_length = tevent_queue_length ( state - > child - > queue ) ;
if ( shortest_queue_length > 0 ) {
/*
* All children are busy , we need to stop
* the queue and untrigger our own queue
* entry . Once a pending request
* is done it calls tevent_queue_start
* and we get retriggered .
*/
state - > child = NULL ;
tevent_queue_stop ( state - > domain - > queue ) ;
tevent_queue_entry_untrigger ( state - > queue_entry ) ;
return ;
}
2010-04-07 19:45:12 +04:00
2009-06-13 14:13:07 +04:00
if ( domain - > initialized ) {
2018-02-14 17:09:51 +03:00
subreq = wb_child_request_send ( state , state - > ev , state - > child ,
state - > request ) ;
2009-06-13 14:13:07 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
2018-02-14 17:04:01 +03:00
return ;
2009-06-13 14:13:07 +04:00
}
tevent_req_set_callback ( subreq , wb_domain_request_done , req ) ;
2018-02-14 17:04:01 +03:00
state - > pending_subreq = subreq ;
/*
* Once the domain is initialized and
* once we placed our real request into the child queue ,
* we can remove ourself from the domain queue
* and give the next one in the queue the chance
* to check for an idle child .
*/
TALLOC_FREE ( state - > queue_entry ) ;
return ;
2009-06-13 14:13:07 +04:00
}
state - > init_req = talloc_zero ( state , struct winbindd_request ) ;
if ( tevent_req_nomem ( state - > init_req , req ) ) {
2018-02-14 17:04:01 +03:00
return ;
2009-06-13 14:13:07 +04:00
}
if ( IS_DC | | domain - > primary | | domain - > internal ) {
/* The primary domain has to find the DC name itself */
state - > init_req - > cmd = WINBINDD_INIT_CONNECTION ;
fstrcpy ( state - > init_req - > domain_name , domain - > name ) ;
2010-11-16 18:22:32 +03:00
state - > init_req - > data . init_conn . is_primary = domain - > primary ;
2009-06-13 14:13:07 +04:00
fstrcpy ( state - > init_req - > data . init_conn . dcname , " " ) ;
2018-02-14 17:09:51 +03:00
subreq = wb_child_request_send ( state , state - > ev , state - > child ,
2009-06-13 14:13:07 +04:00
state - > init_req ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
2018-02-14 17:04:01 +03:00
return ;
2009-06-13 14:13:07 +04:00
}
tevent_req_set_callback ( subreq , wb_domain_request_initialized ,
req ) ;
2018-02-14 17:04:01 +03:00
state - > pending_subreq = subreq ;
return ;
2009-06-13 14:13:07 +04:00
}
/*
2018-02-14 17:11:50 +03:00
* This is * not * the primary domain ,
* let ' s ask our DC about a DC name .
*
* We prefer getting a dns name in dc_unc ,
* which is indicated by DS_RETURN_DNS_NAME .
* For NT4 domains we still get the netbios name .
2009-06-13 14:13:07 +04:00
*/
2018-02-14 17:11:50 +03:00
subreq = wb_dsgetdcname_send ( state , state - > ev ,
state - > domain - > name ,
NULL , /* domain_guid */
NULL , /* site_name */
DS_RETURN_DNS_NAME ) ; /* flags */
2009-06-13 14:13:07 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
2018-02-14 17:04:01 +03:00
return ;
2009-06-13 14:13:07 +04:00
}
tevent_req_set_callback ( subreq , wb_domain_request_gotdc , req ) ;
2018-02-14 17:04:01 +03:00
state - > pending_subreq = subreq ;
return ;
2009-06-13 14:13:07 +04:00
}
static void wb_domain_request_gotdc ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_domain_request_state * state = tevent_req_data (
req , struct wb_domain_request_state ) ;
2018-02-14 17:11:50 +03:00
struct netr_DsRGetDCNameInfo * dcinfo = NULL ;
NTSTATUS status ;
const char * dcname = NULL ;
2009-06-13 14:13:07 +04:00
2018-02-14 17:04:01 +03:00
state - > pending_subreq = NULL ;
2018-02-14 17:11:50 +03:00
status = wb_dsgetdcname_recv ( subreq , state , & dcinfo ) ;
2009-06-13 14:13:07 +04:00
TALLOC_FREE ( subreq ) ;
2018-02-14 17:11:50 +03:00
if ( tevent_req_nterror ( req , status ) ) {
2009-06-13 14:13:07 +04:00
return ;
}
2018-02-14 17:11:50 +03:00
dcname = dcinfo - > dc_unc ;
while ( dcname ! = NULL & & * dcname = = ' \\ ' ) {
dcname + + ;
}
2009-06-13 14:13:07 +04:00
state - > init_req - > cmd = WINBINDD_INIT_CONNECTION ;
fstrcpy ( state - > init_req - > domain_name , state - > domain - > name ) ;
state - > init_req - > data . init_conn . is_primary = False ;
fstrcpy ( state - > init_req - > data . init_conn . dcname ,
2018-02-14 17:11:50 +03:00
dcname ) ;
2009-06-13 14:13:07 +04:00
2018-02-14 17:11:50 +03:00
TALLOC_FREE ( dcinfo ) ;
2009-06-13 14:13:07 +04:00
2010-04-07 19:45:12 +04:00
subreq = wb_child_request_send ( state , state - > ev , state - > child ,
2009-06-13 14:13:07 +04:00
state - > init_req ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , wb_domain_request_initialized , req ) ;
2018-02-14 17:04:01 +03:00
state - > pending_subreq = subreq ;
2009-06-13 14:13:07 +04:00
}
static void wb_domain_request_initialized ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_domain_request_state * state = tevent_req_data (
req , struct wb_domain_request_state ) ;
struct winbindd_response * response ;
int ret , err ;
2018-02-14 17:04:01 +03:00
state - > pending_subreq = NULL ;
2009-06-13 14:13:07 +04:00
ret = wb_child_request_recv ( subreq , talloc_tos ( ) , & response , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( ret = = - 1 ) {
tevent_req_error ( req , err ) ;
return ;
}
if ( ! string_to_sid ( & state - > domain - > sid ,
response - > data . domain_info . sid ) ) {
DEBUG ( 1 , ( " init_child_recv: Could not convert sid %s "
" from string \n " , response - > data . domain_info . sid ) ) ;
tevent_req_error ( req , EINVAL ) ;
return ;
}
2013-02-18 19:36:22 +04:00
talloc_free ( state - > domain - > name ) ;
state - > domain - > name = talloc_strdup ( state - > domain ,
response - > data . domain_info . name ) ;
if ( state - > domain - > name = = NULL ) {
tevent_req_error ( req , ENOMEM ) ;
return ;
}
2013-02-25 12:31:12 +04:00
if ( response - > data . domain_info . alt_name [ 0 ] ! = ' \0 ' ) {
talloc_free ( state - > domain - > alt_name ) ;
state - > domain - > alt_name = talloc_strdup ( state - > domain ,
response - > data . domain_info . alt_name ) ;
if ( state - > domain - > alt_name = = NULL ) {
tevent_req_error ( req , ENOMEM ) ;
return ;
}
2013-02-18 19:36:22 +04:00
}
2009-06-13 14:13:07 +04:00
state - > domain - > native_mode = response - > data . domain_info . native_mode ;
state - > domain - > active_directory =
response - > data . domain_info . active_directory ;
state - > domain - > initialized = true ;
TALLOC_FREE ( response ) ;
2010-04-07 19:45:12 +04:00
subreq = wb_child_request_send ( state , state - > ev , state - > child ,
2009-06-13 14:13:07 +04:00
state - > request ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , wb_domain_request_done , req ) ;
2018-02-14 17:04:01 +03:00
state - > pending_subreq = subreq ;
/*
* Once the domain is initialized and
* once we placed our real request into the child queue ,
* we can remove ourself from the domain queue
* and give the next one in the queue the chance
* to check for an idle child .
*/
TALLOC_FREE ( state - > queue_entry ) ;
2009-06-13 14:13:07 +04:00
}
static void wb_domain_request_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct wb_domain_request_state * state = tevent_req_data (
req , struct wb_domain_request_state ) ;
int ret , err ;
2018-02-14 17:04:01 +03:00
state - > pending_subreq = NULL ;
2009-06-13 14:13:07 +04:00
ret = wb_child_request_recv ( subreq , talloc_tos ( ) , & state - > response ,
& err ) ;
TALLOC_FREE ( subreq ) ;
if ( ret = = - 1 ) {
tevent_req_error ( req , err ) ;
return ;
}
tevent_req_done ( req ) ;
}
int wb_domain_request_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct winbindd_response * * presponse , int * err )
{
struct wb_domain_request_state * state = tevent_req_data (
req , struct wb_domain_request_state ) ;
if ( tevent_req_is_unix_error ( req , err ) ) {
return - 1 ;
}
* presponse = talloc_move ( mem_ctx , & state - > response ) ;
return 0 ;
}
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 . */
2009-06-14 14:41:46 +04:00
state - > response - > result = WINBINDD_ERROR ;
state - > response - > length = sizeof ( struct winbindd_response ) ;
2005-06-09 02:10:34 +04:00
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 + + ) {
2009-05-08 00:46:27 +04:00
if ( state - > request - > cmd = = table - > struct_cmd ) {
2007-12-07 18:00:45 +03:00
DEBUG ( 10 , ( " child_process_request: request fn %s \n " ,
table - > name ) ) ;
2009-06-14 14:41:46 +04:00
state - > response - > result = table - > struct_fn ( domain , state ) ;
2007-12-07 18:00:45 +03:00
return ;
2005-06-09 02:10:34 +04:00
}
}
2011-02-02 19:24:13 +03:00
DEBUG ( 1 , ( " child_process_request: unknown request fn number %d \n " ,
2009-05-08 00:46:27 +04:00
( int ) state - > request - > cmd ) ) ;
2009-06-14 14:41:46 +04:00
state - > response - > result = WINBINDD_ERROR ;
2005-06-09 02:10:34 +04:00
}
2009-08-24 02:13:02 +04:00
void setup_child ( struct winbindd_domain * domain , struct winbindd_child * child ,
2007-12-13 14:27:57 +03:00
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 ) {
2010-07-05 21:43:25 +04:00
char * logbase = NULL ;
2012-07-18 09:37:23 +04:00
if ( * lp_logfile ( talloc_tos ( ) ) ) {
2010-07-05 21:43:25 +04:00
char * end = NULL ;
2012-07-18 09:37:23 +04:00
if ( asprintf ( & logbase , " %s " , lp_logfile ( talloc_tos ( ) ) ) < 0 ) {
2010-07-05 21:43:25 +04:00
smb_panic ( " Internal error: asprintf failed " ) ;
}
if ( ( end = strrchr_m ( logbase , ' / ' ) ) ) {
* end = ' \0 ' ;
}
} else {
if ( asprintf ( & logbase , " %s " , get_dyn_LOGFILEBASE ( ) ) < 0 ) {
smb_panic ( " Internal error: asprintf failed " ) ;
}
}
2007-12-13 14:27:57 +03:00
if ( asprintf ( & child - > logfilename , " %s/%s-%s " ,
2010-07-05 21:43:25 +04:00
logbase , logprefix , logname ) < 0 ) {
SAFE_FREE ( logbase ) ;
2007-12-04 04:57:46 +03:00
smb_panic ( " Internal error: asprintf failed " ) ;
}
2010-07-05 21:43:25 +04:00
SAFE_FREE ( logbase ) ;
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
}
2018-02-26 14:55:31 +03:00
child - > pid = 0 ;
2010-12-06 23:45:21 +03:00
child - > sock = - 1 ;
2009-12-28 12:57:01 +03:00
child - > domain = domain ;
2007-10-08 16:25:57 +04:00
child - > table = table ;
2009-05-10 12:49:53 +04:00
child - > queue = tevent_queue_create ( NULL , " winbind_child " ) ;
SMB_ASSERT ( child - > queue ! = NULL ) ;
2018-02-13 18:04:44 +03:00
if ( domain = = NULL ) {
child - > binding_handle = wbint_binding_handle ( NULL , NULL , child ) ;
SMB_ASSERT ( child - > binding_handle ! = NULL ) ;
}
2005-06-09 02:10:34 +04:00
}
2018-02-26 14:59:06 +03:00
struct winbind_child_died_state {
pid_t pid ;
2005-06-09 02:10:34 +04:00
struct winbindd_child * child ;
2018-02-26 14:59:06 +03:00
} ;
2005-06-09 02:10:34 +04:00
2018-02-26 14:59:06 +03:00
static bool winbind_child_died_fn ( struct winbindd_child * child ,
void * private_data )
{
struct winbind_child_died_state * state = private_data ;
if ( child - > pid = = state - > pid ) {
state - > child = child ;
return false ;
2005-06-09 02:10:34 +04:00
}
2018-02-26 14:59:06 +03:00
return true ;
}
void winbind_child_died ( pid_t pid )
{
struct winbind_child_died_state state = { . pid = pid } ;
forall_children ( winbind_child_died_fn , & state ) ;
2005-06-09 02:10:34 +04:00
2018-02-26 14:59:06 +03:00
if ( state . 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 ;
}
2018-02-26 14:59:06 +03:00
state . child - > pid = 0 ;
2005-06-09 02:10:34 +04:00
}
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 ) ;
2013-02-25 12:31:12 +04:00
if ( domain - > alt_name ! = NULL ) {
2006-10-10 04:50:41 +04:00
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 .
*/
2018-02-26 14:55:31 +03:00
struct winbind_msg_relay_state {
struct messaging_context * msg_ctx ;
uint32_t msg_type ;
DATA_BLOB * data ;
} ;
static bool winbind_msg_relay_fn ( struct winbindd_child * child ,
void * private_data )
{
struct winbind_msg_relay_state * state = private_data ;
DBG_DEBUG ( " sending message to pid %u. \n " ,
( unsigned int ) child - > pid ) ;
messaging_send ( state - > msg_ctx , pid_to_procid ( child - > pid ) ,
state - > msg_type , state - > data ) ;
return true ;
}
2008-07-01 22:37:13 +04:00
void winbind_msg_debug ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
2018-02-26 14:55:31 +03:00
struct winbind_msg_relay_state state = {
. msg_ctx = msg_ctx , . msg_type = msg_type , . data = data
} ;
2008-07-01 22:37:13 +04:00
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 ) ;
2018-02-26 14:55:31 +03:00
forall_children ( winbind_msg_relay_fn , & state ) ;
2008-07-01 22:37:13 +04:00
}
2018-02-28 18:08:44 +03:00
void winbind_disconnect_dc_parent ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
struct winbind_msg_relay_state state = {
. msg_ctx = msg_ctx , . msg_type = msg_type , . data = data
} ;
DBG_DEBUG ( " Got disconnect_dc message \n " ) ;
forall_children ( winbind_msg_relay_fn , & state ) ;
}
2006-10-10 04:50:41 +04:00
/* Set our domains as offline and forward the offline message to our children. */
2018-02-26 15:20:25 +03:00
struct winbind_msg_on_offline_state {
struct messaging_context * msg_ctx ;
uint32_t msg_type ;
} ;
static bool winbind_msg_on_offline_fn ( struct winbindd_child * child ,
void * private_data )
{
struct winbind_msg_on_offline_state * state = private_data ;
if ( child - > domain - > internal ) {
return true ;
}
/*
* Each winbindd child should only process requests for one
* domain - make sure we only set it online / offline for that
* domain .
*/
DBG_DEBUG ( " sending message to pid %u for domain %s. \n " ,
( unsigned int ) child - > pid , child - > domain - > name ) ;
messaging_send_buf ( state - > msg_ctx ,
pid_to_procid ( child - > pid ) ,
state - > msg_type ,
( const uint8_t * ) child - > domain - > name ,
strlen ( child - > domain - > name ) + 1 ) ;
return true ;
}
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
{
2018-02-26 15:20:25 +03:00
struct winbind_msg_on_offline_state state = {
. msg_ctx = msg_ctx ,
. msg_type = MSG_WINBIND_OFFLINE ,
} ;
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 ) ;
}
2018-02-26 15:20:25 +03:00
forall_domain_children ( winbind_msg_on_offline_fn , & state ) ;
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
{
2018-02-26 15:24:50 +03:00
struct winbind_msg_on_offline_state state = {
. msg_ctx = msg_ctx ,
. msg_type = MSG_WINBIND_ONLINE ,
} ;
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 ,
2013-02-18 19:24:38 +04:00
( const uint8_t * ) domain - > name ,
2007-05-15 14:50:44 +04:00
strlen ( domain - > name ) + 1 ) ;
2007-03-01 06:16:38 +03:00
}
}
2006-10-10 04:50:41 +04:00
}
2018-02-26 15:24:50 +03:00
forall_domain_children ( winbind_msg_on_offline_fn , & state ) ;
2006-02-04 01:19:41 +03:00
}
2009-05-21 22:12:59 +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 " ,
get_global_winbindd_state_offline ( ) ?
" Offline " : " Online " ) ) = = NULL ) {
return NULL ;
}
for ( domain = domain_list ( ) ; domain ; domain = domain - > next ) {
if ( ( buf = talloc_asprintf_append_buffer ( buf , " %s:%s " ,
domain - > name ,
domain - > online ?
" Online " : " Offline " ) ) = = NULL ) {
return NULL ;
}
}
buf = talloc_asprintf_append_buffer ( buf , " \n " ) ;
DEBUG ( 5 , ( " collect_onlinestatus: %s " , buf ) ) ;
return buf ;
}
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
{
2009-05-21 22:12:59 +04:00
TALLOC_CTX * mem_ctx ;
const char * message ;
2009-12-23 17:22:09 +03:00
2009-05-21 22:12:59 +04:00
DEBUG ( 5 , ( " winbind_msg_onlinestatus received. \n " ) ) ;
mem_ctx = talloc_init ( " winbind_msg_onlinestatus " ) ;
if ( mem_ctx = = NULL ) {
return ;
2006-05-04 16:37:13 +04:00
}
2009-12-23 17:22:09 +03:00
2009-05-21 22:12:59 +04:00
message = collect_onlinestatus ( mem_ctx ) ;
if ( message = = NULL ) {
talloc_destroy ( mem_ctx ) ;
return ;
}
2018-02-13 16:05:15 +03:00
messaging_send_buf ( msg_ctx , server_id , MSG_WINBIND_ONLINESTATUS ,
2015-05-03 07:07:06 +03:00
( const uint8_t * ) message , strlen ( message ) + 1 ) ;
2009-05-21 22:12:59 +04:00
talloc_destroy ( mem_ctx ) ;
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 ;
const char * domain = NULL ;
char * s = NULL ;
NTSTATUS status ;
struct winbindd_domain * dom = NULL ;
DEBUG ( 5 , ( " winbind_msg_dump_domain_list received. \n " ) ) ;
mem_ctx = talloc_init ( " winbind_msg_dump_domain_list " ) ;
if ( ! mem_ctx ) {
return ;
}
2018-02-13 16:05:43 +03:00
if ( data - > length > 0 ) {
domain = ( const char * ) data - > data ;
2008-01-24 18:19:58 +03:00
}
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 ;
}
2018-02-13 16:05:43 +03:00
messaging_send_buf ( msg_ctx , server_id ,
2008-01-24 18:19:58 +03:00
MSG_WINBIND_DUMP_DOMAIN_LIST ,
2011-05-06 01:36:55 +04:00
( const uint8_t * ) message , strlen ( message ) + 1 ) ;
2008-01-24 18:19:58 +03:00
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 ;
}
}
2018-02-13 16:05:43 +03:00
status = messaging_send_buf ( msg_ctx , server_id ,
2008-01-24 18:19:58 +03:00
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 ) ;
}
2013-02-18 12:55:02 +04:00
static void account_lockout_policy_handler ( struct tevent_context * ctx ,
2013-02-18 13:17:40 +04:00
struct tevent_timer * 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 ;
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-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 {
2016-10-08 02:31:40 +03:00
result = wb_cache_lockout_policy ( child - > domain , mem_ctx ,
& lockout_policy ) ;
2006-12-16 04:32:57 +03:00
}
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
}
2018-08-21 21:06:16 +03:00
child - > lockout_policy_event = tevent_add_timer ( global_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 ;
2009-11-19 19:11:32 +03:00
struct timeval tv ;
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 ;
}
2009-11-19 19:11:32 +03:00
tv . tv_sec = pass_last_set_time ;
DEBUG ( 10 , ( " password last changed %s \n " ,
timeval_string ( talloc_tos ( ) , & tv , false ) ) ) ;
tv . tv_sec + = timeout ;
DEBUGADD ( 10 , ( " password valid until %s \n " ,
timeval_string ( talloc_tos ( ) , & tv , false ) ) ) ;
2008-08-21 03:20:22 +04:00
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 ) ;
2009-11-19 19:22:27 +03:00
if ( lp_clustering ( ) ) {
uint8_t randbuf ;
/*
* When having a cluster , we have several
* winbinds racing for the password change . In
* the machine_password_change_handler ( )
* function we check if someone else was
* faster when the event triggers . We add a
* 255 - second random delay here , so that we
* don ' t run to change the password at the
* exact same moment .
*/
generate_random_buffer ( & randbuf , sizeof ( randbuf ) ) ;
DEBUG ( 10 , ( " adding %d seconds randomness \n " ,
( int ) randbuf ) ) ;
t - > tv_sec + = randbuf ;
}
2008-08-21 03:20:22 +04:00
return true ;
}
DEBUG ( 10 , ( " machine password expired, needs immediate change \n " ) ) ;
* t = timeval_zero ( ) ;
return true ;
}
2013-02-18 12:55:02 +04:00
static void machine_password_change_handler ( struct tevent_context * ctx ,
2013-02-18 13:17:40 +04:00
struct tevent_timer * te ,
2009-01-05 12:22:50 +03:00
struct timeval now ,
2008-08-21 03:20:22 +04:00
void * private_data )
{
2018-08-21 21:09:16 +03:00
struct messaging_context * msg_ctx = global_messaging_context ( ) ;
2008-08-21 03:20:22 +04:00
struct winbindd_child * child =
( struct winbindd_child * ) private_data ;
struct rpc_pipe_client * netlogon_pipe = NULL ;
2018-02-02 17:24:00 +03:00
struct netlogon_creds_cli_context * netlogon_creds_ctx = NULL ;
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 ) ) {
2009-11-19 19:11:32 +03:00
DEBUG ( 10 , ( " calculate_next_machine_pwd_change failed \n " ) ) ;
2008-08-21 03:20:22 +04:00
return ;
}
2009-11-19 19:11:32 +03:00
DEBUG ( 10 , ( " calculate_next_machine_pwd_change returned %s \n " ,
timeval_string ( talloc_tos ( ) , & next_change , false ) ) ) ;
2009-11-19 19:14:40 +03:00
if ( ! timeval_expired ( & next_change ) ) {
DEBUG ( 10 , ( " Someone else has already changed the pw \n " ) ) ;
goto done ;
}
2008-08-21 03:20:22 +04:00
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 ;
}
2018-02-02 17:24:00 +03:00
result = cm_connect_netlogon_secure ( child - > domain ,
& netlogon_pipe ,
& netlogon_creds_ctx ) ;
2008-08-21 03:20:22 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " machine_password_change_handler: "
" failed to connect netlogon pipe: %s \n " ,
nt_errstr ( result ) ) ) ;
return ;
}
2018-02-02 17:24:00 +03:00
result = trust_pw_change ( netlogon_creds_ctx ,
2013-09-16 20:36:43 +04:00
msg_ctx ,
netlogon_pipe - > binding_handle ,
child - > domain - > name ,
2017-05-22 16:36:29 +03:00
child - > domain - > dcname ,
2013-09-16 20:36:43 +04:00
false ) ; /* force */
2008-08-21 03:20:22 +04:00
2009-11-19 19:11:32 +03:00
DEBUG ( 10 , ( " machine_password_change_handler: "
2013-09-16 20:36:43 +04:00
" trust_pw_change returned %s \n " ,
2009-11-19 19:11:32 +03:00
nt_errstr ( result ) ) ) ;
2009-11-19 19:20:47 +03:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_ACCESS_DENIED ) ) {
DEBUG ( 3 , ( " machine_password_change_handler: password set returned "
" ACCESS_DENIED. Maybe the trust account "
" password was changed and we didn't know it. "
" Killing connections to domain %s \n " ,
child - > domain - > name ) ) ;
2014-09-23 21:35:21 +04:00
invalidate_cm_connection ( child - > domain ) ;
2009-11-19 19:20:47 +03:00
}
if ( ! calculate_next_machine_pwd_change ( child - > domain - > name ,
& next_change ) ) {
DEBUG ( 10 , ( " calculate_next_machine_pwd_change failed \n " ) ) ;
return ;
}
DEBUG ( 10 , ( " calculate_next_machine_pwd_change returned %s \n " ,
timeval_string ( talloc_tos ( ) , & next_change , false ) ) ) ;
2008-08-21 03:20:22 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2009-11-19 19:20:47 +03:00
struct timeval tmp ;
/*
* In case of failure , give the DC a minute to recover
*/
tmp = timeval_current_ofs ( 60 , 0 ) ;
next_change = timeval_max ( & next_change , & tmp ) ;
2008-08-21 03:20:22 +04:00
}
2009-11-19 19:14:40 +03:00
done :
2018-08-21 21:06:16 +03:00
child - > machine_password_change_event = tevent_add_timer ( global_event_context ( ) , NULL ,
2008-08-21 03:20:22 +04:00
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
}
}
2018-02-26 15:45:01 +03:00
struct winbindd_reinit_after_fork_state {
const struct winbindd_child * myself ;
} ;
static bool winbindd_reinit_after_fork_fn ( struct winbindd_child * child ,
void * private_data )
{
struct winbindd_reinit_after_fork_state * state = private_data ;
if ( child = = state - > myself ) {
return true ;
}
/* Destroy all possible events in child list. */
TALLOC_FREE ( child - > lockout_policy_event ) ;
TALLOC_FREE ( child - > machine_password_change_event ) ;
/*
* Children should never be able to send each other messages ,
* all messages must go through the parent .
*/
child - > pid = ( pid_t ) 0 ;
/*
* Close service sockets to all other children
*/
if ( child - > sock ! = - 1 ) {
close ( child - > sock ) ;
child - > sock = - 1 ;
}
return true ;
}
2011-04-29 14:53:13 +04:00
NTSTATUS winbindd_reinit_after_fork ( const struct winbindd_child * myself ,
const char * logfilename )
2009-01-07 02:14:52 +03:00
{
2018-02-26 15:45:01 +03:00
struct winbindd_reinit_after_fork_state state = { . myself = myself } ;
2009-01-07 02:14:52 +03:00
struct winbindd_domain * domain ;
2010-07-04 18:28:13 +04:00
NTSTATUS status ;
2009-01-07 02:14:52 +03:00
2010-07-18 01:16:26 +04:00
status = reinit_after_fork (
2018-08-21 21:09:16 +03:00
global_messaging_context ( ) ,
2018-08-21 21:06:16 +03:00
global_event_context ( ) ,
2015-09-23 21:14:05 +03:00
true , NULL ) ;
2010-07-04 18:28:13 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-01-07 02:14:52 +03:00
DEBUG ( 0 , ( " reinit_after_fork() failed \n " ) ) ;
2011-04-29 14:53:13 +04:00
return status ;
2009-01-07 02:14:52 +03:00
}
2018-08-21 21:06:16 +03:00
initialize_password_db ( true , global_event_context ( ) ) ;
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 ) )
2011-04-29 14:53:13 +04:00
return NT_STATUS_NO_MEMORY ;
2009-01-22 16:54:21 +03:00
if ( ! winbindd_setup_sig_hup_handler ( override_logfile ? NULL :
logfilename ) )
2011-04-29 14:53:13 +04:00
return NT_STATUS_NO_MEMORY ;
2009-01-22 16:54:21 +03:00
2010-04-01 18:23:06 +04:00
/* Stop zombies in children */
CatchChild ( ) ;
2009-01-07 02:14:52 +03:00
/* Don't handle the same messages as our parent. */
2018-08-21 21:09:16 +03:00
messaging_deregister ( global_messaging_context ( ) ,
2009-01-07 02:14:52 +03:00
MSG_SMB_CONF_UPDATED , NULL ) ;
2018-08-21 21:09:16 +03:00
messaging_deregister ( global_messaging_context ( ) ,
2009-01-07 02:14:52 +03:00
MSG_SHUTDOWN , NULL ) ;
2018-08-21 21:09:16 +03:00
messaging_deregister ( global_messaging_context ( ) ,
2009-01-07 02:14:52 +03:00
MSG_WINBIND_OFFLINE , NULL ) ;
2018-08-21 21:09:16 +03:00
messaging_deregister ( global_messaging_context ( ) ,
2009-01-07 02:14:52 +03:00
MSG_WINBIND_ONLINE , NULL ) ;
2018-08-21 21:09:16 +03:00
messaging_deregister ( global_messaging_context ( ) ,
2009-01-07 02:14:52 +03:00
MSG_WINBIND_ONLINESTATUS , NULL ) ;
2018-08-21 21:09:16 +03:00
messaging_deregister ( global_messaging_context ( ) ,
2009-01-07 02:14:52 +03:00
MSG_WINBIND_DUMP_DOMAIN_LIST , NULL ) ;
2018-08-21 21:09:16 +03:00
messaging_deregister ( global_messaging_context ( ) ,
2009-01-07 02:14:52 +03:00
MSG_DEBUG , NULL ) ;
2018-08-21 21:09:16 +03:00
messaging_deregister ( global_messaging_context ( ) ,
2013-10-10 12:02:27 +04:00
MSG_WINBIND_DOMAIN_OFFLINE , NULL ) ;
2018-08-21 21:09:16 +03:00
messaging_deregister ( global_messaging_context ( ) ,
2013-10-10 12:02:27 +04:00
MSG_WINBIND_DOMAIN_ONLINE , NULL ) ;
2009-01-07 02:14:52 +03:00
/* 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 ( ) ;
2018-02-26 15:45:01 +03:00
forall_children ( winbindd_reinit_after_fork_fn , & state ) ;
2009-01-07 04:34:06 +03:00
2011-04-29 14:53:13 +04:00
return NT_STATUS_OK ;
2009-01-07 02:14:52 +03:00
}
2007-06-21 17:05:56 +04:00
2009-07-28 23:06:11 +04:00
/*
* In a child there will be only one domain , reference that here .
*/
static struct winbindd_domain * child_domain ;
struct winbindd_domain * wb_child_domain ( void )
{
return child_domain ;
}
2013-01-17 16:49:08 +04:00
struct child_handler_state {
struct winbindd_child * child ;
struct winbindd_cli_state cli ;
} ;
2013-01-17 17:34:35 +04:00
static void child_handler ( struct tevent_context * ev , struct tevent_fd * fde ,
uint16_t flags , void * private_data )
{
struct child_handler_state * state =
( struct child_handler_state * ) private_data ;
NTSTATUS status ;
/* fetch a request from the main daemon */
2014-01-16 22:00:04 +04:00
status = child_read_request ( state - > cli . sock , state - > cli . request ) ;
2013-01-17 17:34:35 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
/* we lost contact with our parent */
_exit ( 0 ) ;
}
DEBUG ( 4 , ( " child daemon request %d \n " ,
( int ) state - > cli . request - > cmd ) ) ;
ZERO_STRUCTP ( state - > cli . response ) ;
state - > cli . request - > null_term = ' \0 ' ;
state - > cli . mem_ctx = talloc_tos ( ) ;
child_process_request ( state - > child , & state - > cli ) ;
DEBUG ( 4 , ( " Finished processing child request %d \n " ,
( int ) state - > cli . request - > cmd ) ) ;
SAFE_FREE ( state - > cli . request - > extra_data . data ) ;
2014-01-16 22:00:05 +04:00
status = child_write_response ( state - > cli . sock , state - > cli . response ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2013-01-17 17:34:35 +04:00
exit ( 1 ) ;
}
}
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 ] ;
2013-01-17 16:49:08 +04:00
struct child_handler_state state ;
2009-06-14 14:58:19 +04:00
struct winbindd_request request ;
struct winbindd_response response ;
2008-06-03 02:26:37 +04:00
struct winbindd_domain * primary_domain = NULL ;
2011-04-29 14:53:13 +04:00
NTSTATUS status ;
2011-04-29 15:00:14 +04:00
ssize_t nwritten ;
2013-01-17 17:34:35 +04:00
struct tevent_fd * fde ;
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 ) ;
2013-01-17 16:49:08 +04:00
state . child = child ;
state . cli . pid = getpid ( ) ;
state . cli . request = & request ;
state . cli . response = & response ;
2006-12-13 01:41:42 +03:00
2012-03-24 23:17:08 +04:00
child - > pid = fork ( ) ;
2005-06-09 02:10:34 +04:00
if ( child - > pid = = - 1 ) {
DEBUG ( 0 , ( " Could not fork: %s \n " , strerror ( errno ) ) ) ;
2013-04-09 18:37:29 +04:00
close ( fdpair [ 0 ] ) ;
close ( fdpair [ 1 ] ) ;
2005-06-09 02:10:34 +04:00
return False ;
}
if ( child - > pid ! = 0 ) {
/* Parent */
2011-04-29 15:00:14 +04:00
ssize_t nread ;
2005-06-09 02:10:34 +04:00
close ( fdpair [ 0 ] ) ;
2011-04-29 15:00:14 +04:00
2011-08-26 13:38:21 +04:00
nread = sys_read ( fdpair [ 1 ] , & status , sizeof ( status ) ) ;
2011-04-29 15:00:14 +04:00
if ( nread ! = sizeof ( status ) ) {
DEBUG ( 1 , ( " fork_domain_child: Could not read child status: "
" nread=%d, error=%s \n " , ( int ) nread ,
strerror ( errno ) ) ) ;
close ( fdpair [ 1 ] ) ;
return false ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " fork_domain_child: Child status is %s \n " ,
nt_errstr ( status ) ) ) ;
close ( fdpair [ 1 ] ) ;
return false ;
}
2018-08-21 21:06:16 +03:00
child - > monitor_fde = tevent_add_fd ( global_event_context ( ) ,
global_event_context ( ) ,
2018-02-26 17:12:14 +03:00
fdpair [ 1 ] ,
TEVENT_FD_READ ,
child_socket_readable ,
child ) ;
if ( child - > monitor_fde = = NULL ) {
DBG_WARNING ( " tevent_add_fd failed \n " ) ;
close ( fdpair [ 1 ] ) ;
return false ;
}
2009-05-10 12:49:53 +04:00
child - > sock = fdpair [ 1 ] ;
2005-06-09 02:10:34 +04:00
return True ;
}
/* Child */
2010-03-31 22:20:26 +04:00
child_domain = child - > domain ;
2005-06-09 02:10:34 +04:00
2012-03-24 23:17:08 +04:00
DEBUG ( 10 , ( " Child process %d \n " , ( int ) getpid ( ) ) ) ;
2008-07-13 14:07:40 +04:00
2013-01-17 16:49:08 +04:00
state . cli . sock = fdpair [ 0 ] ;
2005-06-09 02:10:34 +04:00
close ( fdpair [ 1 ] ) ;
2011-04-29 14:53:13 +04:00
status = winbindd_reinit_after_fork ( child , child - > logfilename ) ;
2011-04-29 15:00:14 +04:00
2013-01-17 16:49:08 +04:00
nwritten = sys_write ( state . cli . sock , & status , sizeof ( status ) ) ;
2011-04-29 15:00:14 +04:00
if ( nwritten ! = sizeof ( status ) ) {
DEBUG ( 1 , ( " fork_domain_child: Could not write status: "
" nwritten=%d, error=%s \n " , ( int ) nwritten ,
strerror ( errno ) ) ) ;
_exit ( 0 ) ;
}
2011-04-29 14:53:13 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " winbindd_reinit_after_fork failed: %s \n " ,
nt_errstr ( status ) ) ) ;
2009-01-07 04:34:06 +03:00
_exit ( 0 ) ;
}
2017-12-20 19:42:45 +03:00
if ( child_domain ! = NULL ) {
setproctitle ( " domain child [%s] " , child_domain - > name ) ;
} else if ( child = = idmap_child ( ) ) {
setproctitle ( " idmap child " ) ;
}
2009-01-07 04:34:06 +03:00
/* Handle online/offline messages. */
2018-08-21 21:09:16 +03:00
messaging_register ( global_messaging_context ( ) , NULL ,
2009-01-07 04:34:06 +03:00
MSG_WINBIND_OFFLINE , child_msg_offline ) ;
2018-08-21 21:09:16 +03:00
messaging_register ( global_messaging_context ( ) , NULL ,
2009-01-07 04:34:06 +03:00
MSG_WINBIND_ONLINE , child_msg_online ) ;
2018-08-21 21:09:16 +03:00
messaging_register ( global_messaging_context ( ) , NULL ,
2009-01-07 04:34:06 +03:00
MSG_DEBUG , debug_message ) ;
2018-08-21 21:09:16 +03:00
messaging_register ( global_messaging_context ( ) , NULL ,
2010-09-29 14:17:05 +04:00
MSG_WINBIND_IP_DROPPED ,
winbind_msg_ip_dropped ) ;
2018-08-21 21:09:16 +03:00
messaging_register ( global_messaging_context ( ) , NULL ,
2018-02-28 18:08:44 +03:00
MSG_WINBIND_DISCONNECT_DC ,
winbind_msg_disconnect_dc ) ;
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 ;
2010-09-10 23:36:20 +04:00
child - > domain - > startup_time = time_mono ( 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 ;
2010-09-10 23:36:20 +04:00
primary_domain - > startup_time = time_mono ( NULL ) ;
2009-01-05 14:47:45 +03:00
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 ) ;
}
2013-02-18 13:57:54 +04:00
child - > lockout_policy_event = tevent_add_timer (
2018-08-21 21:06:16 +03:00
global_event_context ( ) , NULL , timeval_zero ( ) ,
2007-01-30 19:51:42 +03:00
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 ) ) {
2013-02-18 13:57:54 +04:00
child - > machine_password_change_event = tevent_add_timer (
2018-08-21 21:06:16 +03:00
global_event_context ( ) , NULL , next_change ,
2008-08-21 03:20:22 +04:00
machine_password_change_handler ,
child ) ;
}
}
2018-08-21 21:06:16 +03:00
fde = tevent_add_fd ( global_event_context ( ) , NULL , state . cli . sock ,
2013-01-17 17:34:35 +04:00
TEVENT_FD_READ , child_handler , & state ) ;
if ( fde = = NULL ) {
DEBUG ( 1 , ( " tevent_add_fd failed \n " ) ) ;
_exit ( 1 ) ;
}
2005-06-09 02:10:34 +04:00
while ( 1 ) {
2006-02-04 01:19:41 +03:00
2011-01-24 10:47:38 +03:00
int ret ;
2007-08-30 23:48:31 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2005-06-09 02:10:34 +04:00
2018-08-21 21:06:16 +03:00
ret = tevent_loop_once ( global_event_context ( ) ) ;
2013-01-17 17:34:35 +04:00
if ( ret ! = 0 ) {
DEBUG ( 1 , ( " tevent_loop_once failed: %s \n " ,
strerror ( errno ) ) ) ;
_exit ( 1 ) ;
2009-01-20 06:14:20 +03:00
}
2006-02-04 01:19:41 +03:00
2006-09-28 22:08:03 +04:00
if ( child - > domain & & child - > domain - > startup & &
2010-09-10 23:36:20 +04:00
( time_mono ( NULL ) > 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 ;
}
2007-08-30 23:48:31 +04:00
TALLOC_FREE ( frame ) ;
2005-06-09 02:10:34 +04:00
}
}
2010-09-29 14:17:05 +04:00
void winbind_msg_ip_dropped_parent ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
2018-02-26 15:37:05 +03:00
struct winbind_msg_relay_state state = {
. msg_ctx = msg_ctx ,
. msg_type = msg_type ,
. data = data ,
} ;
2010-09-29 14:17:05 +04:00
winbind_msg_ip_dropped ( msg_ctx , private_data , msg_type ,
server_id , data ) ;
2018-02-26 15:37:05 +03:00
forall_children ( winbind_msg_relay_fn , & state ) ;
2010-09-29 14:17:05 +04:00
}