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