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