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