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