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