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