• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source3/winbindd/
1/*
2   Unix SMB/CIFS implementation.
3
4   Winbind child daemons
5
6   Copyright (C) Andrew Tridgell 2002
7   Copyright (C) Volker Lendecke 2004,2005
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 3 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21*/
22
23/*
24 * We fork a child per domain to be able to act non-blocking in the main
25 * winbind daemon. A domain controller thousands of miles away being being
26 * slow replying with a 10.000 user list should not hold up netlogon calls
27 * that can be handled locally.
28 */
29
30#include "includes.h"
31#include "winbindd.h"
32#include "../../nsswitch/libwbclient/wbc_async.h"
33
34#undef DBGC_CLASS
35#define DBGC_CLASS DBGC_WINBIND
36
37extern bool override_logfile;
38extern struct winbindd_methods cache_methods;
39
40/* Read some data from a client connection */
41
42static NTSTATUS child_read_request(struct winbindd_cli_state *state)
43{
44	NTSTATUS status;
45
46	/* Read data */
47
48	status = read_data(state->sock, (char *)state->request,
49			   sizeof(*state->request));
50
51	if (!NT_STATUS_IS_OK(status)) {
52		DEBUG(3, ("child_read_request: read_data failed: %s\n",
53			  nt_errstr(status)));
54		return status;
55	}
56
57	if (state->request->extra_len == 0) {
58		state->request->extra_data.data = NULL;
59		return NT_STATUS_OK;
60	}
61
62	DEBUG(10, ("Need to read %d extra bytes\n", (int)state->request->extra_len));
63
64	state->request->extra_data.data =
65		SMB_MALLOC_ARRAY(char, state->request->extra_len + 1);
66
67	if (state->request->extra_data.data == NULL) {
68		DEBUG(0, ("malloc failed\n"));
69		return NT_STATUS_NO_MEMORY;
70	}
71
72	/* Ensure null termination */
73	state->request->extra_data.data[state->request->extra_len] = '\0';
74
75	status= read_data(state->sock, state->request->extra_data.data,
76			  state->request->extra_len);
77
78	if (!NT_STATUS_IS_OK(status)) {
79		DEBUG(0, ("Could not read extra data: %s\n",
80			  nt_errstr(status)));
81	}
82	return status;
83}
84
85/*
86 * Do winbind child async request. This is not simply wb_simple_trans. We have
87 * to do the queueing ourselves because while a request is queued, the child
88 * might have crashed, and we have to re-fork it in the _trigger function.
89 */
90
91struct wb_child_request_state {
92	struct tevent_context *ev;
93	struct winbindd_child *child;
94	struct winbindd_request *request;
95	struct winbindd_response *response;
96};
97
98static bool fork_domain_child(struct winbindd_child *child);
99
100static void wb_child_request_trigger(struct tevent_req *req,
101					    void *private_data);
102static void wb_child_request_done(struct tevent_req *subreq);
103
104struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx,
105					 struct tevent_context *ev,
106					 struct winbindd_child *child,
107					 struct winbindd_request *request)
108{
109	struct tevent_req *req;
110	struct wb_child_request_state *state;
111
112	req = tevent_req_create(mem_ctx, &state,
113				struct wb_child_request_state);
114	if (req == NULL) {
115		return NULL;
116	}
117
118	state->ev = ev;
119	state->child = child;
120	state->request = request;
121
122	if (!tevent_queue_add(child->queue, ev, req,
123			      wb_child_request_trigger, NULL)) {
124		tevent_req_nomem(NULL, req);
125		return tevent_req_post(req, ev);
126	}
127	return req;
128}
129
130static void wb_child_request_trigger(struct tevent_req *req,
131				     void *private_data)
132{
133	struct wb_child_request_state *state = tevent_req_data(
134		req, struct wb_child_request_state);
135	struct tevent_req *subreq;
136
137	if ((state->child->pid == 0) && (!fork_domain_child(state->child))) {
138		tevent_req_error(req, errno);
139		return;
140	}
141
142	subreq = wb_simple_trans_send(state, winbind_event_context(), NULL,
143				      state->child->sock, state->request);
144	if (tevent_req_nomem(subreq, req)) {
145		return;
146	}
147	tevent_req_set_callback(subreq, wb_child_request_done, req);
148
149	if (!tevent_req_set_endtime(req, state->ev,
150				    timeval_current_ofs(300, 0))) {
151		tevent_req_nomem(NULL, req);
152                return;
153        }
154}
155
156static void wb_child_request_done(struct tevent_req *subreq)
157{
158	struct tevent_req *req = tevent_req_callback_data(
159		subreq, struct tevent_req);
160	struct wb_child_request_state *state = tevent_req_data(
161		req, struct wb_child_request_state);
162	int ret, err;
163
164	ret = wb_simple_trans_recv(subreq, state, &state->response, &err);
165	TALLOC_FREE(subreq);
166	if (ret == -1) {
167		tevent_req_error(req, err);
168		return;
169	}
170	tevent_req_done(req);
171}
172
173int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
174			  struct winbindd_response **presponse, int *err)
175{
176	struct wb_child_request_state *state = tevent_req_data(
177		req, struct wb_child_request_state);
178
179	if (tevent_req_is_unix_error(req, err)) {
180		return -1;
181	}
182	*presponse = talloc_move(mem_ctx, &state->response);
183	return 0;
184}
185
186struct wb_domain_request_state {
187	struct tevent_context *ev;
188	struct winbindd_domain *domain;
189	struct winbindd_request *request;
190	struct winbindd_request *init_req;
191	struct winbindd_response *response;
192};
193
194static void wb_domain_request_gotdc(struct tevent_req *subreq);
195static void wb_domain_request_initialized(struct tevent_req *subreq);
196static void wb_domain_request_done(struct tevent_req *subreq);
197
198struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
199					  struct tevent_context *ev,
200					  struct winbindd_domain *domain,
201					  struct winbindd_request *request)
202{
203	struct tevent_req *req, *subreq;
204	struct wb_domain_request_state *state;
205
206	req = tevent_req_create(mem_ctx, &state,
207				struct wb_domain_request_state);
208	if (req == NULL) {
209		return NULL;
210	}
211
212	if (domain->initialized) {
213		subreq = wb_child_request_send(state, ev, &domain->child,
214					       request);
215		if (tevent_req_nomem(subreq, req)) {
216			return tevent_req_post(req, ev);
217		}
218		tevent_req_set_callback(subreq, wb_domain_request_done, req);
219		return req;
220	}
221
222	state->domain = domain;
223	state->ev = ev;
224	state->request = request;
225
226	state->init_req = talloc_zero(state, struct winbindd_request);
227	if (tevent_req_nomem(state->init_req, req)) {
228		return tevent_req_post(req, ev);
229	}
230
231	if (IS_DC || domain->primary || domain->internal) {
232		/* The primary domain has to find the DC name itself */
233		state->init_req->cmd = WINBINDD_INIT_CONNECTION;
234		fstrcpy(state->init_req->domain_name, domain->name);
235		state->init_req->data.init_conn.is_primary =
236			domain->primary ? true : false;
237		fstrcpy(state->init_req->data.init_conn.dcname, "");
238
239		subreq = wb_child_request_send(state, ev, &domain->child,
240					       state->init_req);
241		if (tevent_req_nomem(subreq, req)) {
242			return tevent_req_post(req, ev);
243		}
244		tevent_req_set_callback(subreq, wb_domain_request_initialized,
245					req);
246		return req;
247	}
248
249	/*
250	 * Ask our DC for a DC name
251	 */
252	domain = find_our_domain();
253
254	/* This is *not* the primary domain, let's ask our DC about a DC
255	 * name */
256
257	state->init_req->cmd = WINBINDD_GETDCNAME;
258	fstrcpy(state->init_req->domain_name, domain->name);
259
260	subreq = wb_child_request_send(state, ev, &domain->child, request);
261	if (tevent_req_nomem(subreq, req)) {
262		return tevent_req_post(req, ev);
263	}
264	tevent_req_set_callback(subreq, wb_domain_request_gotdc, req);
265	return req;
266}
267
268static void wb_domain_request_gotdc(struct tevent_req *subreq)
269{
270	struct tevent_req *req = tevent_req_callback_data(
271		subreq, struct tevent_req);
272	struct wb_domain_request_state *state = tevent_req_data(
273		req, struct wb_domain_request_state);
274	struct winbindd_response *response;
275	int ret, err;
276
277	ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
278	TALLOC_FREE(subreq);
279	if (ret == -1) {
280		tevent_req_error(req, err);
281		return;
282	}
283	state->init_req->cmd = WINBINDD_INIT_CONNECTION;
284	fstrcpy(state->init_req->domain_name, state->domain->name);
285	state->init_req->data.init_conn.is_primary = False;
286	fstrcpy(state->init_req->data.init_conn.dcname,
287		response->data.dc_name);
288
289	TALLOC_FREE(response);
290
291	subreq = wb_child_request_send(state, state->ev, &state->domain->child,
292				       state->init_req);
293	if (tevent_req_nomem(subreq, req)) {
294		return;
295	}
296	tevent_req_set_callback(subreq, wb_domain_request_initialized, req);
297}
298
299static void wb_domain_request_initialized(struct tevent_req *subreq)
300{
301	struct tevent_req *req = tevent_req_callback_data(
302		subreq, struct tevent_req);
303	struct wb_domain_request_state *state = tevent_req_data(
304		req, struct wb_domain_request_state);
305	struct winbindd_response *response;
306	int ret, err;
307
308	ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
309	TALLOC_FREE(subreq);
310	if (ret == -1) {
311		tevent_req_error(req, err);
312		return;
313	}
314
315	if (!string_to_sid(&state->domain->sid,
316			   response->data.domain_info.sid)) {
317		DEBUG(1,("init_child_recv: Could not convert sid %s "
318			"from string\n", response->data.domain_info.sid));
319		tevent_req_error(req, EINVAL);
320		return;
321	}
322	fstrcpy(state->domain->name, response->data.domain_info.name);
323	fstrcpy(state->domain->alt_name, response->data.domain_info.alt_name);
324	state->domain->native_mode = response->data.domain_info.native_mode;
325	state->domain->active_directory =
326		response->data.domain_info.active_directory;
327	state->domain->initialized = true;
328
329	TALLOC_FREE(response);
330
331	subreq = wb_child_request_send(state, state->ev, &state->domain->child,
332				       state->request);
333	if (tevent_req_nomem(subreq, req)) {
334		return;
335	}
336	tevent_req_set_callback(subreq, wb_domain_request_done, req);
337}
338
339static void wb_domain_request_done(struct tevent_req *subreq)
340{
341	struct tevent_req *req = tevent_req_callback_data(
342		subreq, struct tevent_req);
343	struct wb_domain_request_state *state = tevent_req_data(
344		req, struct wb_domain_request_state);
345	int ret, err;
346
347	ret = wb_child_request_recv(subreq, talloc_tos(), &state->response,
348				    &err);
349	TALLOC_FREE(subreq);
350	if (ret == -1) {
351		tevent_req_error(req, err);
352		return;
353	}
354	tevent_req_done(req);
355}
356
357int wb_domain_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
358			   struct winbindd_response **presponse, int *err)
359{
360	struct wb_domain_request_state *state = tevent_req_data(
361		req, struct wb_domain_request_state);
362
363	if (tevent_req_is_unix_error(req, err)) {
364		return -1;
365	}
366	*presponse = talloc_move(mem_ctx, &state->response);
367	return 0;
368}
369
370struct domain_request_state {
371	struct winbindd_domain *domain;
372	struct winbindd_request *request;
373	struct winbindd_response *response;
374	void (*continuation)(void *private_data_data, bool success);
375	void *private_data_data;
376};
377
378static void async_domain_request_done(struct tevent_req *req);
379
380void async_domain_request(TALLOC_CTX *mem_ctx,
381			  struct winbindd_domain *domain,
382			  struct winbindd_request *request,
383			  struct winbindd_response *response,
384			  void (*continuation)(void *private_data_data, bool success),
385			  void *private_data_data)
386{
387	struct tevent_req *subreq;
388	struct domain_request_state *state;
389
390	state = TALLOC_P(mem_ctx, struct domain_request_state);
391	if (state == NULL) {
392		DEBUG(0, ("talloc failed\n"));
393		continuation(private_data_data, False);
394		return;
395	}
396
397	state->domain = domain;
398	state->request = request;
399	state->response = response;
400	state->continuation = continuation;
401	state->private_data_data = private_data_data;
402
403	subreq = wb_domain_request_send(state, winbind_event_context(),
404					domain, request);
405	if (subreq == NULL) {
406		DEBUG(5, ("wb_domain_request_send failed\n"));
407		continuation(private_data_data, false);
408		return;
409	}
410	tevent_req_set_callback(subreq, async_domain_request_done, state);
411}
412
413static void async_domain_request_done(struct tevent_req *req)
414{
415	struct domain_request_state *state = tevent_req_callback_data(
416		req, struct domain_request_state);
417	struct winbindd_response *response;
418	int ret, err;
419
420	ret = wb_domain_request_recv(req, state, &response, &err);
421	TALLOC_FREE(req);
422	if (ret == -1) {
423		DEBUG(5, ("wb_domain_request returned %s\n", strerror(err)));
424		state->continuation(state->private_data_data, false);
425		return;
426	}
427	*(state->response) = *response;
428	state->continuation(state->private_data_data, true);
429}
430
431static void recvfrom_child(void *private_data_data, bool success)
432{
433	struct winbindd_cli_state *state =
434		talloc_get_type_abort(private_data_data, struct winbindd_cli_state);
435	enum winbindd_result result = state->response->result;
436
437	/* This is an optimization: The child has written directly to the
438	 * response buffer. The request itself is still in pending state,
439	 * state that in the result code. */
440
441	state->response->result = WINBINDD_PENDING;
442
443	if ((!success) || (result != WINBINDD_OK)) {
444		request_error(state);
445		return;
446	}
447
448	request_ok(state);
449}
450
451void sendto_domain(struct winbindd_cli_state *state,
452		   struct winbindd_domain *domain)
453{
454	async_domain_request(state->mem_ctx, domain,
455			     state->request, state->response,
456			     recvfrom_child, state);
457}
458
459static void child_process_request(struct winbindd_child *child,
460				  struct winbindd_cli_state *state)
461{
462	struct winbindd_domain *domain = child->domain;
463	const struct winbindd_child_dispatch_table *table = child->table;
464
465	/* Free response data - we may be interrupted and receive another
466	   command before being able to send this data off. */
467
468	state->response->result = WINBINDD_ERROR;
469	state->response->length = sizeof(struct winbindd_response);
470
471	/* as all requests in the child are sync, we can use talloc_tos() */
472	state->mem_ctx = talloc_tos();
473
474	/* Process command */
475
476	for (; table->name; table++) {
477		if (state->request->cmd == table->struct_cmd) {
478			DEBUG(10,("child_process_request: request fn %s\n",
479				  table->name));
480			state->response->result = table->struct_fn(domain, state);
481			return;
482		}
483	}
484
485	DEBUG(1 ,("child_process_request: unknown request fn number %d\n",
486		  (int)state->request->cmd));
487	state->response->result = WINBINDD_ERROR;
488}
489
490void setup_child(struct winbindd_domain *domain, struct winbindd_child *child,
491		 const struct winbindd_child_dispatch_table *table,
492		 const char *logprefix,
493		 const char *logname)
494{
495	if (logprefix && logname) {
496		if (asprintf(&child->logfilename, "%s/%s-%s",
497			     get_dyn_LOGFILEBASE(), logprefix, logname) < 0) {
498			smb_panic("Internal error: asprintf failed");
499		}
500	} else {
501		smb_panic("Internal error: logprefix == NULL && "
502			  "logname == NULL");
503	}
504
505	child->domain = domain;
506	child->table = table;
507	child->queue = tevent_queue_create(NULL, "winbind_child");
508	SMB_ASSERT(child->queue != NULL);
509	child->rpccli = wbint_rpccli_create(NULL, domain, child);
510	SMB_ASSERT(child->rpccli != NULL);
511}
512
513struct winbindd_child *children = NULL;
514
515void winbind_child_died(pid_t pid)
516{
517	struct winbindd_child *child;
518
519	for (child = children; child != NULL; child = child->next) {
520		if (child->pid == pid) {
521			break;
522		}
523	}
524
525	if (child == NULL) {
526		DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
527		return;
528	}
529
530	/* This will be re-added in fork_domain_child() */
531
532	DLIST_REMOVE(children, child);
533
534	close(child->sock);
535	child->sock = -1;
536	child->pid = 0;
537}
538
539/* Ensure any negative cache entries with the netbios or realm names are removed. */
540
541void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
542{
543	flush_negative_conn_cache_for_domain(domain->name);
544	if (*domain->alt_name) {
545		flush_negative_conn_cache_for_domain(domain->alt_name);
546	}
547}
548
549/*
550 * Parent winbindd process sets its own debug level first and then
551 * sends a message to all the winbindd children to adjust their debug
552 * level to that of parents.
553 */
554
555void winbind_msg_debug(struct messaging_context *msg_ctx,
556 			 void *private_data,
557			 uint32_t msg_type,
558			 struct server_id server_id,
559			 DATA_BLOB *data)
560{
561	struct winbindd_child *child;
562
563	DEBUG(10,("winbind_msg_debug: got debug message.\n"));
564
565	debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data);
566
567	for (child = children; child != NULL; child = child->next) {
568
569		DEBUG(10,("winbind_msg_debug: sending message to pid %u.\n",
570			(unsigned int)child->pid));
571
572		messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
573			   MSG_DEBUG,
574			   data->data,
575			   strlen((char *) data->data) + 1);
576	}
577}
578
579/* Set our domains as offline and forward the offline message to our children. */
580
581void winbind_msg_offline(struct messaging_context *msg_ctx,
582			 void *private_data,
583			 uint32_t msg_type,
584			 struct server_id server_id,
585			 DATA_BLOB *data)
586{
587	struct winbindd_child *child;
588	struct winbindd_domain *domain;
589
590	DEBUG(10,("winbind_msg_offline: got offline message.\n"));
591
592	if (!lp_winbind_offline_logon()) {
593		DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
594		return;
595	}
596
597	/* Set our global state as offline. */
598	if (!set_global_winbindd_state_offline()) {
599		DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
600		return;
601	}
602
603	/* Set all our domains as offline. */
604	for (domain = domain_list(); domain; domain = domain->next) {
605		if (domain->internal) {
606			continue;
607		}
608		DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
609		set_domain_offline(domain);
610	}
611
612	for (child = children; child != NULL; child = child->next) {
613		/* Don't send message to internal childs.  We've already
614		   done so above. */
615		if (!child->domain || winbindd_internal_child(child)) {
616			continue;
617		}
618
619		/* Or internal domains (this should not be possible....) */
620		if (child->domain->internal) {
621			continue;
622		}
623
624		/* Each winbindd child should only process requests for one domain - make sure
625		   we only set it online / offline for that domain. */
626
627		DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
628			(unsigned int)child->pid, domain->name ));
629
630		messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
631				   MSG_WINBIND_OFFLINE,
632				   (uint8 *)child->domain->name,
633				   strlen(child->domain->name)+1);
634	}
635}
636
637/* Set our domains as online and forward the online message to our children. */
638
639void winbind_msg_online(struct messaging_context *msg_ctx,
640			void *private_data,
641			uint32_t msg_type,
642			struct server_id server_id,
643			DATA_BLOB *data)
644{
645	struct winbindd_child *child;
646	struct winbindd_domain *domain;
647
648	DEBUG(10,("winbind_msg_online: got online message.\n"));
649
650	if (!lp_winbind_offline_logon()) {
651		DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
652		return;
653	}
654
655	/* Set our global state as online. */
656	set_global_winbindd_state_online();
657
658	smb_nscd_flush_user_cache();
659	smb_nscd_flush_group_cache();
660
661	/* Set all our domains as online. */
662	for (domain = domain_list(); domain; domain = domain->next) {
663		if (domain->internal) {
664			continue;
665		}
666		DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain->name));
667
668		winbindd_flush_negative_conn_cache(domain);
669		set_domain_online_request(domain);
670
671		/* Send an online message to the idmap child when our
672		   primary domain comes back online */
673
674		if ( domain->primary ) {
675			struct winbindd_child *idmap = idmap_child();
676
677			if ( idmap->pid != 0 ) {
678				messaging_send_buf(msg_ctx,
679						   pid_to_procid(idmap->pid),
680						   MSG_WINBIND_ONLINE,
681						   (uint8 *)domain->name,
682						   strlen(domain->name)+1);
683			}
684		}
685	}
686
687	for (child = children; child != NULL; child = child->next) {
688		/* Don't send message to internal childs. */
689		if (!child->domain || winbindd_internal_child(child)) {
690			continue;
691		}
692
693		/* Or internal domains (this should not be possible....) */
694		if (child->domain->internal) {
695			continue;
696		}
697
698		/* Each winbindd child should only process requests for one domain - make sure
699		   we only set it online / offline for that domain. */
700
701		DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n",
702			(unsigned int)child->pid, child->domain->name ));
703
704		messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
705				   MSG_WINBIND_ONLINE,
706				   (uint8 *)child->domain->name,
707				   strlen(child->domain->name)+1);
708	}
709}
710
711static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
712{
713	struct winbindd_domain *domain;
714	char *buf = NULL;
715
716	if ((buf = talloc_asprintf(mem_ctx, "global:%s ",
717				   get_global_winbindd_state_offline() ?
718				   "Offline":"Online")) == NULL) {
719		return NULL;
720	}
721
722	for (domain = domain_list(); domain; domain = domain->next) {
723		if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ",
724						  domain->name,
725						  domain->online ?
726						  "Online":"Offline")) == NULL) {
727			return NULL;
728		}
729	}
730
731	buf = talloc_asprintf_append_buffer(buf, "\n");
732
733	DEBUG(5,("collect_onlinestatus: %s", buf));
734
735	return buf;
736}
737
738void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
739			      void *private_data,
740			      uint32_t msg_type,
741			      struct server_id server_id,
742			      DATA_BLOB *data)
743{
744	TALLOC_CTX *mem_ctx;
745	const char *message;
746	struct server_id *sender;
747
748	DEBUG(5,("winbind_msg_onlinestatus received.\n"));
749
750	if (!data->data) {
751		return;
752	}
753
754	sender = (struct server_id *)data->data;
755
756	mem_ctx = talloc_init("winbind_msg_onlinestatus");
757	if (mem_ctx == NULL) {
758		return;
759	}
760
761	message = collect_onlinestatus(mem_ctx);
762	if (message == NULL) {
763		talloc_destroy(mem_ctx);
764		return;
765	}
766
767	messaging_send_buf(msg_ctx, *sender, MSG_WINBIND_ONLINESTATUS,
768			   (uint8 *)message, strlen(message) + 1);
769
770	talloc_destroy(mem_ctx);
771}
772
773void winbind_msg_dump_event_list(struct messaging_context *msg_ctx,
774				 void *private_data,
775				 uint32_t msg_type,
776				 struct server_id server_id,
777				 DATA_BLOB *data)
778{
779	struct winbindd_child *child;
780
781	DEBUG(10,("winbind_msg_dump_event_list received\n"));
782
783	dump_event_list(winbind_event_context());
784
785	for (child = children; child != NULL; child = child->next) {
786
787		DEBUG(10,("winbind_msg_dump_event_list: sending message to pid %u\n",
788			(unsigned int)child->pid));
789
790		messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
791				   MSG_DUMP_EVENT_LIST,
792				   NULL, 0);
793	}
794
795}
796
797void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
798				  void *private_data,
799				  uint32_t msg_type,
800				  struct server_id server_id,
801				  DATA_BLOB *data)
802{
803	TALLOC_CTX *mem_ctx;
804	const char *message = NULL;
805	struct server_id *sender = NULL;
806	const char *domain = NULL;
807	char *s = NULL;
808	NTSTATUS status;
809	struct winbindd_domain *dom = NULL;
810
811	DEBUG(5,("winbind_msg_dump_domain_list received.\n"));
812
813	if (!data || !data->data) {
814		return;
815	}
816
817	if (data->length < sizeof(struct server_id)) {
818		return;
819	}
820
821	mem_ctx = talloc_init("winbind_msg_dump_domain_list");
822	if (!mem_ctx) {
823		return;
824	}
825
826	sender = (struct server_id *)data->data;
827	if (data->length > sizeof(struct server_id)) {
828		domain = (const char *)data->data+sizeof(struct server_id);
829	}
830
831	if (domain) {
832
833		DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n",
834			domain));
835
836		message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain,
837						  find_domain_from_name_noinit(domain));
838		if (!message) {
839			talloc_destroy(mem_ctx);
840			return;
841		}
842
843		messaging_send_buf(msg_ctx, *sender,
844				   MSG_WINBIND_DUMP_DOMAIN_LIST,
845				   (uint8_t *)message, strlen(message) + 1);
846
847		talloc_destroy(mem_ctx);
848
849		return;
850	}
851
852	DEBUG(5,("winbind_msg_dump_domain_list all domains\n"));
853
854	for (dom = domain_list(); dom; dom=dom->next) {
855		message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, dom);
856		if (!message) {
857			talloc_destroy(mem_ctx);
858			return;
859		}
860
861		s = talloc_asprintf_append(s, "%s\n", message);
862		if (!s) {
863			talloc_destroy(mem_ctx);
864			return;
865		}
866	}
867
868	status = messaging_send_buf(msg_ctx, *sender,
869				    MSG_WINBIND_DUMP_DOMAIN_LIST,
870				    (uint8_t *)s, strlen(s) + 1);
871	if (!NT_STATUS_IS_OK(status)) {
872		DEBUG(0,("failed to send message: %s\n",
873		nt_errstr(status)));
874	}
875
876	talloc_destroy(mem_ctx);
877}
878
879static void account_lockout_policy_handler(struct event_context *ctx,
880					   struct timed_event *te,
881					   struct timeval now,
882					   void *private_data)
883{
884	struct winbindd_child *child =
885		(struct winbindd_child *)private_data;
886	TALLOC_CTX *mem_ctx = NULL;
887	struct winbindd_methods *methods;
888	struct samr_DomInfo12 lockout_policy;
889	NTSTATUS result;
890
891	DEBUG(10,("account_lockout_policy_handler called\n"));
892
893	TALLOC_FREE(child->lockout_policy_event);
894
895	if ( !winbindd_can_contact_domain( child->domain ) ) {
896		DEBUG(10,("account_lockout_policy_handler: Removing myself since I "
897			  "do not have an incoming trust to domain %s\n",
898			  child->domain->name));
899
900		return;
901	}
902
903	methods = child->domain->methods;
904
905	mem_ctx = talloc_init("account_lockout_policy_handler ctx");
906	if (!mem_ctx) {
907		result = NT_STATUS_NO_MEMORY;
908	} else {
909		result = methods->lockout_policy(child->domain, mem_ctx, &lockout_policy);
910	}
911	TALLOC_FREE(mem_ctx);
912
913	if (!NT_STATUS_IS_OK(result)) {
914		DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
915			 nt_errstr(result)));
916	}
917
918	child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL,
919						      timeval_current_ofs(3600, 0),
920						      account_lockout_policy_handler,
921						      child);
922}
923
924static time_t get_machine_password_timeout(void)
925{
926	/* until we have gpo support use lp setting */
927	return lp_machine_password_timeout();
928}
929
930static bool calculate_next_machine_pwd_change(const char *domain,
931					      struct timeval *t)
932{
933	time_t pass_last_set_time;
934	time_t timeout;
935	time_t next_change;
936	struct timeval tv;
937	char *pw;
938
939	pw = secrets_fetch_machine_password(domain,
940					    &pass_last_set_time,
941					    NULL);
942
943	if (pw == NULL) {
944		DEBUG(0,("cannot fetch own machine password ????"));
945		return false;
946	}
947
948	SAFE_FREE(pw);
949
950	timeout = get_machine_password_timeout();
951	if (timeout == 0) {
952		DEBUG(10,("machine password never expires\n"));
953		return false;
954	}
955
956	tv.tv_sec = pass_last_set_time;
957	DEBUG(10, ("password last changed %s\n",
958		   timeval_string(talloc_tos(), &tv, false)));
959	tv.tv_sec += timeout;
960	DEBUGADD(10, ("password valid until %s\n",
961		      timeval_string(talloc_tos(), &tv, false)));
962
963	if (time(NULL) < (pass_last_set_time + timeout)) {
964		next_change = pass_last_set_time + timeout;
965		DEBUG(10,("machine password still valid until: %s\n",
966			http_timestring(talloc_tos(), next_change)));
967		*t = timeval_set(next_change, 0);
968
969		if (lp_clustering()) {
970			uint8_t randbuf;
971			/*
972			 * When having a cluster, we have several
973			 * winbinds racing for the password change. In
974			 * the machine_password_change_handler()
975			 * function we check if someone else was
976			 * faster when the event triggers. We add a
977			 * 255-second random delay here, so that we
978			 * don't run to change the password at the
979			 * exact same moment.
980			 */
981			generate_random_buffer(&randbuf, sizeof(randbuf));
982			DEBUG(10, ("adding %d seconds randomness\n",
983				   (int)randbuf));
984			t->tv_sec += randbuf;
985		}
986		return true;
987	}
988
989	DEBUG(10,("machine password expired, needs immediate change\n"));
990
991	*t = timeval_zero();
992
993	return true;
994}
995
996static void machine_password_change_handler(struct event_context *ctx,
997					    struct timed_event *te,
998					    struct timeval now,
999					    void *private_data)
1000{
1001	struct winbindd_child *child =
1002		(struct winbindd_child *)private_data;
1003	struct rpc_pipe_client *netlogon_pipe = NULL;
1004	TALLOC_CTX *frame;
1005	NTSTATUS result;
1006	struct timeval next_change;
1007
1008	DEBUG(10,("machine_password_change_handler called\n"));
1009
1010	TALLOC_FREE(child->machine_password_change_event);
1011
1012	if (!calculate_next_machine_pwd_change(child->domain->name,
1013					       &next_change)) {
1014		DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
1015		return;
1016	}
1017
1018	DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
1019		   timeval_string(talloc_tos(), &next_change, false)));
1020
1021	if (!timeval_expired(&next_change)) {
1022		DEBUG(10, ("Someone else has already changed the pw\n"));
1023		goto done;
1024	}
1025
1026	if (!winbindd_can_contact_domain(child->domain)) {
1027		DEBUG(10,("machine_password_change_handler: Removing myself since I "
1028			  "do not have an incoming trust to domain %s\n",
1029			  child->domain->name));
1030		return;
1031	}
1032
1033	result = cm_connect_netlogon(child->domain, &netlogon_pipe);
1034	if (!NT_STATUS_IS_OK(result)) {
1035		DEBUG(10,("machine_password_change_handler: "
1036			"failed to connect netlogon pipe: %s\n",
1037			 nt_errstr(result)));
1038		return;
1039	}
1040
1041	frame = talloc_stackframe();
1042
1043	result = trust_pw_find_change_and_store_it(netlogon_pipe,
1044						   frame,
1045						   child->domain->name);
1046	TALLOC_FREE(frame);
1047
1048	DEBUG(10, ("machine_password_change_handler: "
1049		   "trust_pw_find_change_and_store_it returned %s\n",
1050		   nt_errstr(result)));
1051
1052	if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1053		DEBUG(3,("machine_password_change_handler: password set returned "
1054			 "ACCESS_DENIED.  Maybe the trust account "
1055			 "password was changed and we didn't know it. "
1056			 "Killing connections to domain %s\n",
1057			 child->domain->name));
1058		TALLOC_FREE(child->domain->conn.netlogon_pipe);
1059	}
1060
1061	if (!calculate_next_machine_pwd_change(child->domain->name,
1062					       &next_change)) {
1063		DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
1064		return;
1065	}
1066
1067	DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
1068		   timeval_string(talloc_tos(), &next_change, false)));
1069
1070	if (!NT_STATUS_IS_OK(result)) {
1071		struct timeval tmp;
1072		/*
1073		 * In case of failure, give the DC a minute to recover
1074		 */
1075		tmp = timeval_current_ofs(60, 0);
1076		next_change = timeval_max(&next_change, &tmp);
1077	}
1078
1079done:
1080	child->machine_password_change_event = event_add_timed(winbind_event_context(), NULL,
1081							      next_change,
1082							      machine_password_change_handler,
1083							      child);
1084}
1085
1086/* Deal with a request to go offline. */
1087
1088static void child_msg_offline(struct messaging_context *msg,
1089			      void *private_data,
1090			      uint32_t msg_type,
1091			      struct server_id server_id,
1092			      DATA_BLOB *data)
1093{
1094	struct winbindd_domain *domain;
1095	struct winbindd_domain *primary_domain = NULL;
1096	const char *domainname = (const char *)data->data;
1097
1098	if (data->data == NULL || data->length == 0) {
1099		return;
1100	}
1101
1102	DEBUG(5,("child_msg_offline received for domain %s.\n", domainname));
1103
1104	if (!lp_winbind_offline_logon()) {
1105		DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
1106		return;
1107	}
1108
1109	primary_domain = find_our_domain();
1110
1111	/* Mark the requested domain offline. */
1112
1113	for (domain = domain_list(); domain; domain = domain->next) {
1114		if (domain->internal) {
1115			continue;
1116		}
1117		if (strequal(domain->name, domainname)) {
1118			DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name));
1119			set_domain_offline(domain);
1120			/* we are in the trusted domain, set the primary domain
1121			 * offline too */
1122			if (domain != primary_domain) {
1123				set_domain_offline(primary_domain);
1124			}
1125		}
1126	}
1127}
1128
1129/* Deal with a request to go online. */
1130
1131static void child_msg_online(struct messaging_context *msg,
1132			     void *private_data,
1133			     uint32_t msg_type,
1134			     struct server_id server_id,
1135			     DATA_BLOB *data)
1136{
1137	struct winbindd_domain *domain;
1138	struct winbindd_domain *primary_domain = NULL;
1139	const char *domainname = (const char *)data->data;
1140
1141	if (data->data == NULL || data->length == 0) {
1142		return;
1143	}
1144
1145	DEBUG(5,("child_msg_online received for domain %s.\n", domainname));
1146
1147	if (!lp_winbind_offline_logon()) {
1148		DEBUG(10,("child_msg_online: rejecting online message.\n"));
1149		return;
1150	}
1151
1152	primary_domain = find_our_domain();
1153
1154	/* Set our global state as online. */
1155	set_global_winbindd_state_online();
1156
1157	/* Try and mark everything online - delete any negative cache entries
1158	   to force a reconnect now. */
1159
1160	for (domain = domain_list(); domain; domain = domain->next) {
1161		if (domain->internal) {
1162			continue;
1163		}
1164		if (strequal(domain->name, domainname)) {
1165			DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name));
1166			winbindd_flush_negative_conn_cache(domain);
1167			set_domain_online_request(domain);
1168
1169			/* we can be in trusted domain, which will contact primary domain
1170			 * we have to bring primary domain online in trusted domain process
1171			 * see, winbindd_dual_pam_auth() --> winbindd_dual_pam_auth_samlogon()
1172			 * --> contact_domain = find_our_domain()
1173			 * */
1174			if (domain != primary_domain) {
1175				winbindd_flush_negative_conn_cache(primary_domain);
1176				set_domain_online_request(primary_domain);
1177			}
1178		}
1179	}
1180}
1181
1182static void child_msg_dump_event_list(struct messaging_context *msg,
1183				      void *private_data,
1184				      uint32_t msg_type,
1185				      struct server_id server_id,
1186				      DATA_BLOB *data)
1187{
1188	DEBUG(5,("child_msg_dump_event_list received\n"));
1189
1190	dump_event_list(winbind_event_context());
1191}
1192
1193bool winbindd_reinit_after_fork(const char *logfilename)
1194{
1195	struct winbindd_domain *domain;
1196	struct winbindd_child *cl;
1197
1198	if (!NT_STATUS_IS_OK(reinit_after_fork(winbind_messaging_context(),
1199					       winbind_event_context(),
1200					       true))) {
1201		DEBUG(0,("reinit_after_fork() failed\n"));
1202		return false;
1203	}
1204
1205	close_conns_after_fork();
1206
1207	if (!override_logfile && logfilename) {
1208		lp_set_logfile(logfilename);
1209		reopen_logs();
1210	}
1211
1212	if (!winbindd_setup_sig_term_handler(false))
1213		return false;
1214	if (!winbindd_setup_sig_hup_handler(override_logfile ? NULL :
1215					    logfilename))
1216		return false;
1217
1218	/* Stop zombies in children */
1219	CatchChild();
1220
1221	/* Don't handle the same messages as our parent. */
1222	messaging_deregister(winbind_messaging_context(),
1223			     MSG_SMB_CONF_UPDATED, NULL);
1224	messaging_deregister(winbind_messaging_context(),
1225			     MSG_SHUTDOWN, NULL);
1226	messaging_deregister(winbind_messaging_context(),
1227			     MSG_WINBIND_OFFLINE, NULL);
1228	messaging_deregister(winbind_messaging_context(),
1229			     MSG_WINBIND_ONLINE, NULL);
1230	messaging_deregister(winbind_messaging_context(),
1231			     MSG_WINBIND_ONLINESTATUS, NULL);
1232	messaging_deregister(winbind_messaging_context(),
1233			     MSG_DUMP_EVENT_LIST, NULL);
1234	messaging_deregister(winbind_messaging_context(),
1235			     MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1236	messaging_deregister(winbind_messaging_context(),
1237			     MSG_DEBUG, NULL);
1238
1239	/* We have destroyed all events in the winbindd_event_context
1240	 * in reinit_after_fork(), so clean out all possible pending
1241	 * event pointers. */
1242
1243	/* Deal with check_online_events. */
1244
1245	for (domain = domain_list(); domain; domain = domain->next) {
1246		TALLOC_FREE(domain->check_online_event);
1247	}
1248
1249	/* Ensure we're not handling a credential cache event inherited
1250	 * from our parent. */
1251
1252	ccache_remove_all_after_fork();
1253
1254	/* Destroy all possible events in child list. */
1255	for (cl = children; cl != NULL; cl = cl->next) {
1256		TALLOC_FREE(cl->lockout_policy_event);
1257		TALLOC_FREE(cl->machine_password_change_event);
1258
1259		/* Children should never be able to send
1260		 * each other messages, all messages must
1261		 * go through the parent.
1262		 */
1263		cl->pid = (pid_t)0;
1264        }
1265	/*
1266	 * This is a little tricky, children must not
1267	 * send an MSG_WINBIND_ONLINE message to idmap_child().
1268	 * If we are in a child of our primary domain or
1269	 * in the process created by fork_child_dc_connect(),
1270	 * and the primary domain cannot go online,
1271	 * fork_child_dc_connection() sends MSG_WINBIND_ONLINE
1272	 * periodically to idmap_child().
1273	 *
1274	 * The sequence is, fork_child_dc_connect() ---> getdcs() --->
1275	 * get_dc_name_via_netlogon() ---> cm_connect_netlogon()
1276	 * ---> init_dc_connection() ---> cm_open_connection --->
1277	 * set_domain_online(), sends MSG_WINBIND_ONLINE to
1278	 * idmap_child(). Disallow children sending messages
1279	 * to each other, all messages must go through the parent.
1280	 */
1281	cl = idmap_child();
1282	cl->pid = (pid_t)0;
1283
1284	return true;
1285}
1286
1287/*
1288 * In a child there will be only one domain, reference that here.
1289 */
1290static struct winbindd_domain *child_domain;
1291
1292struct winbindd_domain *wb_child_domain(void)
1293{
1294	return child_domain;
1295}
1296
1297static bool fork_domain_child(struct winbindd_child *child)
1298{
1299	int fdpair[2];
1300	struct winbindd_cli_state state;
1301	struct winbindd_request request;
1302	struct winbindd_response response;
1303	struct winbindd_domain *primary_domain = NULL;
1304
1305	if (child->domain) {
1306		DEBUG(10, ("fork_domain_child called for domain '%s'\n",
1307			   child->domain->name));
1308	} else {
1309		DEBUG(10, ("fork_domain_child called without domain.\n"));
1310	}
1311	child_domain = child->domain;
1312
1313	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) {
1314		DEBUG(0, ("Could not open child pipe: %s\n",
1315			  strerror(errno)));
1316		return False;
1317	}
1318
1319	ZERO_STRUCT(state);
1320	state.pid = sys_getpid();
1321	state.request = &request;
1322	state.response = &response;
1323
1324	child->pid = sys_fork();
1325
1326	if (child->pid == -1) {
1327		DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
1328		return False;
1329	}
1330
1331	if (child->pid != 0) {
1332		/* Parent */
1333		close(fdpair[0]);
1334		child->next = child->prev = NULL;
1335		DLIST_ADD(children, child);
1336		child->sock = fdpair[1];
1337		return True;
1338	}
1339
1340	/* Child */
1341
1342	DEBUG(10, ("Child process %d\n", (int)sys_getpid()));
1343
1344	state.sock = fdpair[0];
1345	close(fdpair[1]);
1346
1347	if (!winbindd_reinit_after_fork(child->logfilename)) {
1348		_exit(0);
1349	}
1350
1351	/* Handle online/offline messages. */
1352	messaging_register(winbind_messaging_context(), NULL,
1353			   MSG_WINBIND_OFFLINE, child_msg_offline);
1354	messaging_register(winbind_messaging_context(), NULL,
1355			   MSG_WINBIND_ONLINE, child_msg_online);
1356	messaging_register(winbind_messaging_context(), NULL,
1357			   MSG_DUMP_EVENT_LIST, child_msg_dump_event_list);
1358	messaging_register(winbind_messaging_context(), NULL,
1359			   MSG_DEBUG, debug_message);
1360
1361	primary_domain = find_our_domain();
1362
1363	if (primary_domain == NULL) {
1364		smb_panic("no primary domain found");
1365	}
1366
1367	/* It doesn't matter if we allow cache login,
1368	 * try to bring domain online after fork. */
1369	if ( child->domain ) {
1370		child->domain->startup = True;
1371		child->domain->startup_time = time(NULL);
1372		/* we can be in primary domain or in trusted domain
1373		 * If we are in trusted domain, set the primary domain
1374		 * in start-up mode */
1375		if (!(child->domain->internal)) {
1376			set_domain_online_request(child->domain);
1377			if (!(child->domain->primary)) {
1378				primary_domain->startup = True;
1379				primary_domain->startup_time = time(NULL);
1380				set_domain_online_request(primary_domain);
1381			}
1382		}
1383	}
1384
1385	/*
1386	 * We are in idmap child, make sure that we set the
1387	 * check_online_event to bring primary domain online.
1388	 */
1389	if (child == idmap_child()) {
1390		set_domain_online_request(primary_domain);
1391	}
1392
1393	/* We might be in the idmap child...*/
1394	if (child->domain && !(child->domain->internal) &&
1395	    lp_winbind_offline_logon()) {
1396
1397		set_domain_online_request(child->domain);
1398
1399		if (primary_domain && (primary_domain != child->domain)) {
1400			/* We need to talk to the primary
1401			 * domain as well as the trusted
1402			 * domain inside a trusted domain
1403			 * child.
1404			 * See the code in :
1405			 * set_dc_type_and_flags_trustinfo()
1406			 * for details.
1407			 */
1408			set_domain_online_request(primary_domain);
1409		}
1410
1411		child->lockout_policy_event = event_add_timed(
1412			winbind_event_context(), NULL, timeval_zero(),
1413			account_lockout_policy_handler,
1414			child);
1415	}
1416
1417	if (child->domain && child->domain->primary &&
1418	    !USE_KERBEROS_KEYTAB &&
1419	    lp_server_role() == ROLE_DOMAIN_MEMBER) {
1420
1421		struct timeval next_change;
1422
1423		if (calculate_next_machine_pwd_change(child->domain->name,
1424						       &next_change)) {
1425			child->machine_password_change_event = event_add_timed(
1426				winbind_event_context(), NULL, next_change,
1427				machine_password_change_handler,
1428				child);
1429		}
1430	}
1431
1432	while (1) {
1433
1434		int ret;
1435		fd_set r_fds;
1436		fd_set w_fds;
1437		int maxfd;
1438		struct timeval t;
1439		struct timeval *tp;
1440		struct timeval now;
1441		TALLOC_CTX *frame = talloc_stackframe();
1442		struct iovec iov[2];
1443		int iov_count;
1444		NTSTATUS status;
1445
1446		if (run_events(winbind_event_context(), 0, NULL, NULL)) {
1447			TALLOC_FREE(frame);
1448			continue;
1449		}
1450
1451		GetTimeOfDay(&now);
1452
1453		if (child->domain && child->domain->startup &&
1454				(now.tv_sec > child->domain->startup_time + 30)) {
1455			/* No longer in "startup" mode. */
1456			DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
1457				child->domain->name ));
1458			child->domain->startup = False;
1459		}
1460
1461		FD_ZERO(&r_fds);
1462		FD_ZERO(&w_fds);
1463
1464		if (state.sock < 0 || state.sock >= FD_SETSIZE) {
1465			TALLOC_FREE(frame);
1466			perror("EBADF");
1467			_exit(1);
1468		}
1469
1470		FD_SET(state.sock, &r_fds);
1471		maxfd = state.sock;
1472
1473		/*
1474		 * Initialize this high as event_add_to_select_args()
1475		 * uses a timeval_min() on this and next_event. Fix
1476		 * from Roel van Meer <rolek@alt001.com>.
1477		 */
1478		t.tv_sec = 999999;
1479		t.tv_usec = 0;
1480
1481		event_add_to_select_args(winbind_event_context(), &now,
1482					 &r_fds, &w_fds, &t, &maxfd);
1483		tp = get_timed_events_timeout(winbind_event_context(), &t);
1484		if (tp) {
1485			DEBUG(11,("select will use timeout of %u.%u seconds\n",
1486				(unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec ));
1487		}
1488
1489		ret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, tp);
1490
1491		if (run_events(winbind_event_context(), ret, &r_fds, &w_fds)) {
1492			/* We got a signal - continue. */
1493			TALLOC_FREE(frame);
1494			continue;
1495		}
1496
1497		if (ret == 0) {
1498			DEBUG(11,("nothing is ready yet, continue\n"));
1499			TALLOC_FREE(frame);
1500			continue;
1501		}
1502
1503		if (ret == -1 && errno == EINTR) {
1504			/* We got a signal - continue. */
1505			TALLOC_FREE(frame);
1506			continue;
1507		}
1508
1509		if (ret == -1 && errno != EINTR) {
1510			DEBUG(0,("select error occured\n"));
1511			TALLOC_FREE(frame);
1512			perror("select");
1513			_exit(1);
1514		}
1515
1516		/* fetch a request from the main daemon */
1517		status = child_read_request(&state);
1518
1519		if (!NT_STATUS_IS_OK(status)) {
1520			/* we lost contact with our parent */
1521			_exit(0);
1522		}
1523
1524		DEBUG(4,("child daemon request %d\n", (int)state.request->cmd));
1525
1526		ZERO_STRUCTP(state.response);
1527		state.request->null_term = '\0';
1528		state.mem_ctx = frame;
1529		child_process_request(child, &state);
1530
1531		DEBUG(4, ("Finished processing child request %d\n",
1532			  (int)state.request->cmd));
1533
1534		SAFE_FREE(state.request->extra_data.data);
1535
1536		iov[0].iov_base = (void *)state.response;
1537		iov[0].iov_len = sizeof(struct winbindd_response);
1538		iov_count = 1;
1539
1540		if (state.response->length > sizeof(struct winbindd_response)) {
1541			iov[1].iov_base =
1542				(void *)state.response->extra_data.data;
1543			iov[1].iov_len = state.response->length-iov[0].iov_len;
1544			iov_count = 2;
1545		}
1546
1547		DEBUG(10, ("Writing %d bytes to parent\n",
1548			   (int)state.response->length));
1549
1550		if (write_data_iov(state.sock, iov, iov_count) !=
1551		    state.response->length) {
1552			DEBUG(0, ("Could not write result\n"));
1553			exit(1);
1554		}
1555		TALLOC_FREE(frame);
1556	}
1557}
1558