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