74582888149a4d7e19aa964ed5349391606e4983
[obnox/samba-ctdb.git] / source / 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
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_WINBIND
35
36 extern bool override_logfile;
37 extern struct winbindd_methods cache_methods;
38
39 /* Read some data from a client connection */
40
41 static void child_read_request(struct winbindd_cli_state *state)
42 {
43         NTSTATUS status;
44
45         /* Read data */
46
47         status = read_data(state->sock, (char *)&state->request,
48                            sizeof(state->request));
49
50         if (!NT_STATUS_IS_OK(status)) {
51                 DEBUG(3, ("child_read_request: read_data failed: %s\n",
52                           nt_errstr(status)));
53                 state->finished = True;
54                 return;
55         }
56
57         if (state->request.extra_len == 0) {
58                 state->request.extra_data.data = NULL;
59                 return;
60         }
61
62         DEBUG(10, ("Need to read %d extra bytes\n", (int)state->request.extra_len));
63
64         state->request.extra_data.data =
65                 SMB_MALLOC_ARRAY(char, state->request.extra_len + 1);
66
67         if (state->request.extra_data.data == NULL) {
68                 DEBUG(0, ("malloc failed\n"));
69                 state->finished = True;
70                 return;
71         }
72
73         /* Ensure null termination */
74         state->request.extra_data.data[state->request.extra_len] = '\0';
75
76         status= read_data(state->sock, state->request.extra_data.data,
77                           state->request.extra_len);
78
79         if (!NT_STATUS_IS_OK(status)) {
80                 DEBUG(0, ("Could not read extra data: %s\n",
81                           nt_errstr(status)));
82                 state->finished = True;
83                 return;
84         }
85 }
86
87 /*
88  * Machinery for async requests sent to children. You set up a
89  * winbindd_request, select a child to query, and issue a async_request
90  * call. When the request is completed, the callback function you specified is
91  * called back with the private pointer you gave to async_request.
92  */
93
94 struct winbindd_async_request {
95         struct winbindd_async_request *next, *prev;
96         TALLOC_CTX *mem_ctx;
97         struct winbindd_child *child;
98         struct winbindd_request *request;
99         struct winbindd_response *response;
100         void (*continuation)(void *private_data, bool success);
101         struct timed_event *reply_timeout_event;
102         pid_t child_pid; /* pid of the child we're waiting on. Used to detect
103                             a restart of the child (child->pid != child_pid). */
104         void *private_data;
105 };
106
107 static void async_request_fail(struct winbindd_async_request *state);
108 static void async_main_request_sent(void *private_data, bool success);
109 static void async_request_sent(void *private_data, bool success);
110 static void async_reply_recv(void *private_data, bool success);
111 static void schedule_async_request(struct winbindd_child *child);
112
113 void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
114                    struct winbindd_request *request,
115                    struct winbindd_response *response,
116                    void (*continuation)(void *private_data, bool success),
117                    void *private_data)
118 {
119         struct winbindd_async_request *state;
120
121         SMB_ASSERT(continuation != NULL);
122
123         DEBUG(10, ("Sending request to child pid %d (domain=%s)\n",
124                    (int)child->pid,
125                    (child->domain != NULL) ? child->domain->name : "''"));
126
127         state = TALLOC_P(mem_ctx, struct winbindd_async_request);
128
129         if (state == NULL) {
130                 DEBUG(0, ("talloc failed\n"));
131                 continuation(private_data, False);
132                 return;
133         }
134
135         state->mem_ctx = mem_ctx;
136         state->child = child;
137         state->reply_timeout_event = NULL;
138         state->request = request;
139         state->response = response;
140         state->continuation = continuation;
141         state->private_data = private_data;
142
143         DLIST_ADD_END(child->requests, state, struct winbindd_async_request *);
144
145         schedule_async_request(child);
146
147         return;
148 }
149
150 static void async_main_request_sent(void *private_data, bool success)
151 {
152         struct winbindd_async_request *state =
153                 talloc_get_type_abort(private_data, struct winbindd_async_request);
154
155         if (!success) {
156                 DEBUG(5, ("Could not send async request\n"));
157                 async_request_fail(state);
158                 return;
159         }
160
161         if (state->request->extra_len == 0) {
162                 async_request_sent(private_data, True);
163                 return;
164         }
165
166         setup_async_write(&state->child->event, state->request->extra_data.data,
167                           state->request->extra_len,
168                           async_request_sent, state);
169 }
170
171 /****************************************************************
172  Handler triggered if the child winbindd doesn't respond within
173  a given timeout.
174 ****************************************************************/
175
176 static void async_request_timeout_handler(struct event_context *ctx,
177                                         struct timed_event *te,
178                                         const struct timeval *now,
179                                         void *private_data)
180 {
181         struct winbindd_async_request *state =
182                 talloc_get_type_abort(private_data, struct winbindd_async_request);
183
184         DEBUG(0,("async_request_timeout_handler: child pid %u is not responding. "
185                 "Closing connection to it.\n",
186                 state->child_pid ));
187
188         /* Deal with the reply - set to error. */
189         async_reply_recv(private_data, False);
190 }
191
192 /**************************************************************
193  Common function called on both async send and recv fail.
194  Cleans up the child and schedules the next request.
195 **************************************************************/
196
197 static void async_request_fail(struct winbindd_async_request *state)
198 {
199         DLIST_REMOVE(state->child->requests, state);
200
201         TALLOC_FREE(state->reply_timeout_event);
202
203         /* If child exists and is not already reaped,
204            send kill signal to child. */
205
206         if ((state->child->pid != (pid_t)0) &&
207                         (state->child->pid != (pid_t)-1) &&
208                         (state->child->pid == state->child_pid)) {
209                 kill(state->child_pid, SIGTERM);
210
211                 /* 
212                  * Close the socket to the child.
213                  */
214                 winbind_child_died(state->child_pid);
215         }
216
217         state->response->length = sizeof(struct winbindd_response);
218         state->response->result = WINBINDD_ERROR;
219         state->continuation(state->private_data, False);
220 }
221
222 static void async_request_sent(void *private_data_data, bool success)
223 {
224         struct winbindd_async_request *state =
225                 talloc_get_type_abort(private_data_data, struct winbindd_async_request);
226
227         if (!success) {
228                 DEBUG(5, ("Could not send async request to child pid %u\n",
229                         (unsigned int)state->child_pid ));
230                 async_request_fail(state);
231                 return;
232         }
233
234         /* Request successfully sent to the child, setup the wait for reply */
235
236         setup_async_read(&state->child->event,
237                          &state->response->result,
238                          sizeof(state->response->result),
239                          async_reply_recv, state);
240
241         /* 
242          * Set up a timeout of 300 seconds for the response.
243          * If we don't get it close the child socket and
244          * report failure.
245          */
246
247         state->reply_timeout_event = event_add_timed(winbind_event_context(),
248                                                         NULL,
249                                                         timeval_current_ofs(300,0),
250                                                         "async_request_timeout",
251                                                         async_request_timeout_handler,
252                                                         state);
253         if (!state->reply_timeout_event) {
254                 smb_panic("async_request_sent: failed to add timeout handler.\n");
255         }
256 }
257
258 static void async_reply_recv(void *private_data, bool success)
259 {
260         struct winbindd_async_request *state =
261                 talloc_get_type_abort(private_data, struct winbindd_async_request);
262         struct winbindd_child *child = state->child;
263
264         TALLOC_FREE(state->reply_timeout_event);
265
266         state->response->length = sizeof(struct winbindd_response);
267
268         if (!success) {
269                 DEBUG(5, ("Could not receive async reply from child pid %u\n",
270                         (unsigned int)state->child_pid ));
271
272                 cache_cleanup_response(state->child_pid);
273                 async_request_fail(state);
274                 return;
275         }
276
277         SMB_ASSERT(cache_retrieve_response(state->child_pid,
278                                            state->response));
279
280         cache_cleanup_response(state->child_pid);
281         
282         DLIST_REMOVE(child->requests, state);
283
284         schedule_async_request(child);
285
286         state->continuation(state->private_data, True);
287 }
288
289 static bool winbindd_child_busy(const struct winbindd_child *child)
290 {
291         return (child->event.flags != 0);
292 }
293
294 static bool fork_domain_child(struct winbindd_child *child);
295
296 static void schedule_async_request(struct winbindd_child *child)
297 {
298         struct winbindd_async_request *request = child->requests;
299
300         if (request == NULL) {
301                 return;
302         }
303
304         if (winbindd_child_busy(child)) {
305                 return;         /* Busy */
306         }
307
308         /*
309          * This may be a reschedule, so we might
310          * have an existing timeout event pending on
311          * the first entry in the child->requests list
312          * (we only send one request at a time).
313          * Ensure we free it before we reschedule.
314          * Bug #5814, from hargagan <shargagan@novell.com>.
315          * JRA.
316          */
317
318         TALLOC_FREE(request->reply_timeout_event);
319
320         if ((child->pid == 0) && (!fork_domain_child(child))) {
321                 /* fork_domain_child failed.
322                    Cancel all outstanding requests */
323
324                 while (request != NULL) {
325                         /* request might be free'd in the continuation */
326                         struct winbindd_async_request *next = request->next;
327
328                         async_request_fail(request);
329                         request = next;
330                 }
331                 return;
332         }
333
334         /* Now we know who we're sending to - remember the pid. */
335         request->child_pid = child->pid;
336
337         setup_async_write(&child->event, request->request,
338                           sizeof(*request->request),
339                           async_main_request_sent, request);
340
341         return;
342 }
343
344 struct domain_request_state {
345         TALLOC_CTX *mem_ctx;
346         struct winbindd_domain *domain;
347         struct winbindd_request *request;
348         struct winbindd_response *response;
349         void (*continuation)(void *private_data_data, bool success);
350         void *private_data_data;
351 };
352
353 static void domain_init_recv(void *private_data_data, bool success);
354
355 void async_domain_request(TALLOC_CTX *mem_ctx,
356                           struct winbindd_domain *domain,
357                           struct winbindd_request *request,
358                           struct winbindd_response *response,
359                           void (*continuation)(void *private_data_data, bool success),
360                           void *private_data_data)
361 {
362         struct domain_request_state *state;
363
364         if (domain->initialized) {
365                 async_request(mem_ctx, &domain->child, request, response,
366                               continuation, private_data_data);
367                 return;
368         }
369
370         state = TALLOC_P(mem_ctx, struct domain_request_state);
371         if (state == NULL) {
372                 DEBUG(0, ("talloc failed\n"));
373                 continuation(private_data_data, False);
374                 return;
375         }
376
377         state->mem_ctx = mem_ctx;
378         state->domain = domain;
379         state->request = request;
380         state->response = response;
381         state->continuation = continuation;
382         state->private_data_data = private_data_data;
383
384         init_child_connection(domain, domain_init_recv, state);
385 }
386
387 static void domain_init_recv(void *private_data_data, bool success)
388 {
389         struct domain_request_state *state =
390                 talloc_get_type_abort(private_data_data, struct domain_request_state);
391
392         if (!success) {
393                 DEBUG(5, ("Domain init returned an error\n"));
394                 state->continuation(state->private_data_data, False);
395                 return;
396         }
397
398         async_request(state->mem_ctx, &state->domain->child,
399                       state->request, state->response,
400                       state->continuation, state->private_data_data);
401 }
402
403 static void recvfrom_child(void *private_data_data, bool success)
404 {
405         struct winbindd_cli_state *state =
406                 talloc_get_type_abort(private_data_data, struct winbindd_cli_state);
407         enum winbindd_result result = state->response.result;
408
409         /* This is an optimization: The child has written directly to the
410          * response buffer. The request itself is still in pending state,
411          * state that in the result code. */
412
413         state->response.result = WINBINDD_PENDING;
414
415         if ((!success) || (result != WINBINDD_OK)) {
416                 request_error(state);
417                 return;
418         }
419
420         request_ok(state);
421 }
422
423 void sendto_child(struct winbindd_cli_state *state,
424                   struct winbindd_child *child)
425 {
426         async_request(state->mem_ctx, child, &state->request,
427                       &state->response, recvfrom_child, state);
428 }
429
430 void sendto_domain(struct winbindd_cli_state *state,
431                    struct winbindd_domain *domain)
432 {
433         async_domain_request(state->mem_ctx, domain,
434                              &state->request, &state->response,
435                              recvfrom_child, state);
436 }
437
438 static void child_process_request(struct winbindd_child *child,
439                                   struct winbindd_cli_state *state)
440 {
441         struct winbindd_domain *domain = child->domain;
442         const struct winbindd_child_dispatch_table *table = child->table;
443
444         /* Free response data - we may be interrupted and receive another
445            command before being able to send this data off. */
446
447         state->response.result = WINBINDD_ERROR;
448         state->response.length = sizeof(struct winbindd_response);
449
450         /* as all requests in the child are sync, we can use talloc_tos() */
451         state->mem_ctx = talloc_tos();
452
453         /* Process command */
454
455         for (; table->name; table++) {
456                 if (state->request.cmd == table->struct_cmd) {
457                         DEBUG(10,("child_process_request: request fn %s\n",
458                                   table->name));
459                         state->response.result = table->struct_fn(domain, state);
460                         return;
461                 }
462         }
463
464         DEBUG(1 ,("child_process_request: unknown request fn number %d\n",
465                   (int)state->request.cmd));
466         state->response.result = WINBINDD_ERROR;
467 }
468
469 void setup_child(struct winbindd_child *child,
470                  const struct winbindd_child_dispatch_table *table,
471                  const char *logprefix,
472                  const char *logname)
473 {
474         if (logprefix && logname) {
475                 if (asprintf(&child->logfilename, "%s/%s-%s",
476                              get_dyn_LOGFILEBASE(), logprefix, logname) < 0) {
477                         smb_panic("Internal error: asprintf failed");
478                 }
479         } else {
480                 smb_panic("Internal error: logprefix == NULL && "
481                           "logname == NULL");
482         }
483
484         child->domain = NULL;
485         child->table = table;
486 }
487
488 struct winbindd_child *children = NULL;
489
490 void winbind_child_died(pid_t pid)
491 {
492         struct winbindd_child *child;
493
494         for (child = children; child != NULL; child = child->next) {
495                 if (child->pid == pid) {
496                         break;
497                 }
498         }
499
500         if (child == NULL) {
501                 DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
502                 return;
503         }
504
505         /* This will be re-added in fork_domain_child() */
506
507         DLIST_REMOVE(children, child);
508         
509         remove_fd_event(&child->event);
510         close(child->event.fd);
511         child->event.fd = 0;
512         child->event.flags = 0;
513         child->pid = 0;
514
515         if (child->requests) {
516                 /*
517                  * schedule_async_request() will also
518                  * clear this event but the call is
519                  * idempotent so it doesn't hurt to
520                  * cover all possible future code
521                  * paths. JRA.
522                  */
523                 TALLOC_FREE(child->requests->reply_timeout_event);
524         }
525
526         schedule_async_request(child);
527 }
528
529 /* Ensure any negative cache entries with the netbios or realm names are removed. */
530
531 void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
532 {
533         flush_negative_conn_cache_for_domain(domain->name);
534         if (*domain->alt_name) {
535                 flush_negative_conn_cache_for_domain(domain->alt_name);
536         }
537 }
538
539 /* 
540  * Parent winbindd process sets its own debug level first and then
541  * sends a message to all the winbindd children to adjust their debug
542  * level to that of parents.
543  */
544
545 void winbind_msg_debug(struct messaging_context *msg_ctx,
546                          void *private_data,
547                          uint32_t msg_type,
548                          struct server_id server_id,
549                          DATA_BLOB *data)
550 {
551         struct winbindd_child *child;
552
553         DEBUG(10,("winbind_msg_debug: got debug message.\n"));
554         
555         debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data);
556
557         for (child = children; child != NULL; child = child->next) {
558
559                 DEBUG(10,("winbind_msg_debug: sending message to pid %u.\n",
560                         (unsigned int)child->pid));
561
562                 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
563                            MSG_DEBUG,
564                            data->data,
565                            strlen((char *) data->data) + 1);
566         }
567 }
568
569 /* Set our domains as offline and forward the offline message to our children. */
570
571 void winbind_msg_offline(struct messaging_context *msg_ctx,
572                          void *private_data,
573                          uint32_t msg_type,
574                          struct server_id server_id,
575                          DATA_BLOB *data)
576 {
577         struct winbindd_child *child;
578         struct winbindd_domain *domain;
579
580         DEBUG(10,("winbind_msg_offline: got offline message.\n"));
581
582         if (!lp_winbind_offline_logon()) {
583                 DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
584                 return;
585         }
586
587         /* Set our global state as offline. */
588         if (!set_global_winbindd_state_offline()) {
589                 DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
590                 return;
591         }
592
593         /* Set all our domains as offline. */
594         for (domain = domain_list(); domain; domain = domain->next) {
595                 if (domain->internal) {
596                         continue;
597                 }
598                 DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
599                 set_domain_offline(domain);
600         }
601
602         for (child = children; child != NULL; child = child->next) {
603                 /* Don't send message to internal childs.  We've already
604                    done so above. */
605                 if (!child->domain || winbindd_internal_child(child)) {
606                         continue;
607                 }
608
609                 /* Or internal domains (this should not be possible....) */
610                 if (child->domain->internal) {
611                         continue;
612                 }
613
614                 /* Each winbindd child should only process requests for one domain - make sure
615                    we only set it online / offline for that domain. */
616
617                 DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
618                         (unsigned int)child->pid, domain->name ));
619
620                 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
621                                    MSG_WINBIND_OFFLINE,
622                                    (uint8 *)child->domain->name,
623                                    strlen(child->domain->name)+1);
624         }
625 }
626
627 /* Set our domains as online and forward the online message to our children. */
628
629 void winbind_msg_online(struct messaging_context *msg_ctx,
630                         void *private_data,
631                         uint32_t msg_type,
632                         struct server_id server_id,
633                         DATA_BLOB *data)
634 {
635         struct winbindd_child *child;
636         struct winbindd_domain *domain;
637
638         DEBUG(10,("winbind_msg_online: got online message.\n"));
639
640         if (!lp_winbind_offline_logon()) {
641                 DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
642                 return;
643         }
644
645         /* Set our global state as online. */
646         set_global_winbindd_state_online();
647
648         smb_nscd_flush_user_cache();
649         smb_nscd_flush_group_cache();
650
651         /* Set all our domains as online. */
652         for (domain = domain_list(); domain; domain = domain->next) {
653                 if (domain->internal) {
654                         continue;
655                 }
656                 DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain->name));
657
658                 winbindd_flush_negative_conn_cache(domain);
659                 set_domain_online_request(domain);
660
661                 /* Send an online message to the idmap child when our
662                    primary domain comes back online */
663
664                 if ( domain->primary ) {
665                         struct winbindd_child *idmap = idmap_child();
666                         
667                         if ( idmap->pid != 0 ) {
668                                 messaging_send_buf(msg_ctx,
669                                                    pid_to_procid(idmap->pid), 
670                                                    MSG_WINBIND_ONLINE,
671                                                    (uint8 *)domain->name,
672                                                    strlen(domain->name)+1);
673                         }
674                         
675                 }
676         }
677
678         for (child = children; child != NULL; child = child->next) {
679                 /* Don't send message to internal childs. */
680                 if (!child->domain || winbindd_internal_child(child)) {
681                         continue;
682                 }
683
684                 /* Or internal domains (this should not be possible....) */
685                 if (child->domain->internal) {
686                         continue;
687                 }
688
689                 /* Each winbindd child should only process requests for one domain - make sure
690                    we only set it online / offline for that domain. */
691
692                 DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n",
693                         (unsigned int)child->pid, child->domain->name ));
694
695                 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
696                                    MSG_WINBIND_ONLINE,
697                                    (uint8 *)child->domain->name,
698                                    strlen(child->domain->name)+1);
699         }
700 }
701
702 /* Forward the online/offline messages to our children. */
703 void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
704                               void *private_data,
705                               uint32_t msg_type,
706                               struct server_id server_id,
707                               DATA_BLOB *data)
708 {
709         struct winbindd_child *child;
710
711         DEBUG(10,("winbind_msg_onlinestatus: got onlinestatus message.\n"));
712
713         for (child = children; child != NULL; child = child->next) {
714                 if (child->domain && child->domain->primary) {
715                         DEBUG(10,("winbind_msg_onlinestatus: "
716                                   "sending message to pid %u of primary domain.\n",
717                                   (unsigned int)child->pid));
718                         messaging_send_buf(msg_ctx, pid_to_procid(child->pid), 
719                                            MSG_WINBIND_ONLINESTATUS,
720                                            (uint8 *)data->data,
721                                            data->length);
722                         break;
723                 }
724         }
725 }
726
727 void winbind_msg_dump_event_list(struct messaging_context *msg_ctx,
728                                  void *private_data,
729                                  uint32_t msg_type,
730                                  struct server_id server_id,
731                                  DATA_BLOB *data)
732 {
733         struct winbindd_child *child;
734
735         DEBUG(10,("winbind_msg_dump_event_list received\n"));
736
737         dump_event_list(winbind_event_context());
738
739         for (child = children; child != NULL; child = child->next) {
740
741                 DEBUG(10,("winbind_msg_dump_event_list: sending message to pid %u\n",
742                         (unsigned int)child->pid));
743
744                 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
745                                    MSG_DUMP_EVENT_LIST,
746                                    NULL, 0);
747         }
748
749 }
750
751 void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
752                                   void *private_data,
753                                   uint32_t msg_type,
754                                   struct server_id server_id,
755                                   DATA_BLOB *data)
756 {
757         TALLOC_CTX *mem_ctx;
758         const char *message = NULL;
759         struct server_id *sender = NULL;
760         const char *domain = NULL;
761         char *s = NULL;
762         NTSTATUS status;
763         struct winbindd_domain *dom = NULL;
764
765         DEBUG(5,("winbind_msg_dump_domain_list received.\n"));
766
767         if (!data || !data->data) {
768                 return;
769         }
770
771         if (data->length < sizeof(struct server_id)) {
772                 return;
773         }
774
775         mem_ctx = talloc_init("winbind_msg_dump_domain_list");
776         if (!mem_ctx) {
777                 return;
778         }
779
780         sender = (struct server_id *)data->data;
781         if (data->length > sizeof(struct server_id)) {
782                 domain = (const char *)data->data+sizeof(struct server_id);
783         }
784
785         if (domain) {
786
787                 DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n",
788                         domain));
789
790                 message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain,
791                                                   find_domain_from_name_noinit(domain));
792                 if (!message) {
793                         talloc_destroy(mem_ctx);
794                         return;
795                 }
796
797                 messaging_send_buf(msg_ctx, *sender,
798                                    MSG_WINBIND_DUMP_DOMAIN_LIST,
799                                    (uint8_t *)message, strlen(message) + 1);
800
801                 talloc_destroy(mem_ctx);
802
803                 return;
804         }
805
806         DEBUG(5,("winbind_msg_dump_domain_list all domains\n"));
807
808         for (dom = domain_list(); dom; dom=dom->next) {
809                 message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, dom);
810                 if (!message) {
811                         talloc_destroy(mem_ctx);
812                         return;
813                 }
814
815                 s = talloc_asprintf_append(s, "%s\n", message);
816                 if (!s) {
817                         talloc_destroy(mem_ctx);
818                         return;
819                 }
820         }
821
822         status = messaging_send_buf(msg_ctx, *sender,
823                                     MSG_WINBIND_DUMP_DOMAIN_LIST,
824                                     (uint8_t *)s, strlen(s) + 1);
825         if (!NT_STATUS_IS_OK(status)) {
826                 DEBUG(0,("failed to send message: %s\n",
827                 nt_errstr(status)));
828         }
829
830         talloc_destroy(mem_ctx);
831 }
832
833 static void account_lockout_policy_handler(struct event_context *ctx,
834                                            struct timed_event *te,
835                                            const struct timeval *now,
836                                            void *private_data)
837 {
838         struct winbindd_child *child =
839                 (struct winbindd_child *)private_data;
840         TALLOC_CTX *mem_ctx = NULL;
841         struct winbindd_methods *methods;
842         struct samr_DomInfo12 lockout_policy;
843         NTSTATUS result;
844
845         DEBUG(10,("account_lockout_policy_handler called\n"));
846
847         TALLOC_FREE(child->lockout_policy_event);
848
849         if ( !winbindd_can_contact_domain( child->domain ) ) {
850                 DEBUG(10,("account_lockout_policy_handler: Removing myself since I "
851                           "do not have an incoming trust to domain %s\n", 
852                           child->domain->name));
853
854                 return;         
855         }
856
857         methods = child->domain->methods;
858
859         mem_ctx = talloc_init("account_lockout_policy_handler ctx");
860         if (!mem_ctx) {
861                 result = NT_STATUS_NO_MEMORY;
862         } else {
863                 result = methods->lockout_policy(child->domain, mem_ctx, &lockout_policy);
864         }
865         TALLOC_FREE(mem_ctx);
866
867         if (!NT_STATUS_IS_OK(result)) {
868                 DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
869                          nt_errstr(result)));
870         }
871
872         child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL,
873                                                       timeval_current_ofs(3600, 0),
874                                                       "account_lockout_policy_handler",
875                                                       account_lockout_policy_handler,
876                                                       child);
877 }
878
879 /* Deal with a request to go offline. */
880
881 static void child_msg_offline(struct messaging_context *msg,
882                               void *private_data,
883                               uint32_t msg_type,
884                               struct server_id server_id,
885                               DATA_BLOB *data)
886 {
887         struct winbindd_domain *domain;
888         struct winbindd_domain *primary_domain = NULL;
889         const char *domainname = (const char *)data->data;
890
891         if (data->data == NULL || data->length == 0) {
892                 return;
893         }
894
895         DEBUG(5,("child_msg_offline received for domain %s.\n", domainname));
896
897         if (!lp_winbind_offline_logon()) {
898                 DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
899                 return;
900         }
901
902         primary_domain = find_our_domain();
903
904         /* Mark the requested domain offline. */
905
906         for (domain = domain_list(); domain; domain = domain->next) {
907                 if (domain->internal) {
908                         continue;
909                 }
910                 if (strequal(domain->name, domainname)) {
911                         DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name));
912                         set_domain_offline(domain);
913                         /* we are in the trusted domain, set the primary domain 
914                          * offline too */
915                         if (domain != primary_domain) {
916                                 set_domain_offline(primary_domain);
917                         }
918                 }
919         }
920 }
921
922 /* Deal with a request to go online. */
923
924 static void child_msg_online(struct messaging_context *msg,
925                              void *private_data,
926                              uint32_t msg_type,
927                              struct server_id server_id,
928                              DATA_BLOB *data)
929 {
930         struct winbindd_domain *domain;
931         struct winbindd_domain *primary_domain = NULL;
932         const char *domainname = (const char *)data->data;
933
934         if (data->data == NULL || data->length == 0) {
935                 return;
936         }
937
938         DEBUG(5,("child_msg_online received for domain %s.\n", domainname));
939
940         if (!lp_winbind_offline_logon()) {
941                 DEBUG(10,("child_msg_online: rejecting online message.\n"));
942                 return;
943         }
944
945         primary_domain = find_our_domain();
946
947         /* Set our global state as online. */
948         set_global_winbindd_state_online();
949
950         /* Try and mark everything online - delete any negative cache entries
951            to force a reconnect now. */
952
953         for (domain = domain_list(); domain; domain = domain->next) {
954                 if (domain->internal) {
955                         continue;
956                 }
957                 if (strequal(domain->name, domainname)) {
958                         DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name));
959                         winbindd_flush_negative_conn_cache(domain);
960                         set_domain_online_request(domain);
961
962                         /* we can be in trusted domain, which will contact primary domain
963                          * we have to bring primary domain online in trusted domain process
964                          * see, winbindd_dual_pam_auth() --> winbindd_dual_pam_auth_samlogon()
965                          * --> contact_domain = find_our_domain()
966                          * */
967                         if (domain != primary_domain) {
968                                 winbindd_flush_negative_conn_cache(primary_domain);
969                                 set_domain_online_request(primary_domain);
970                         }
971                 }
972         }
973 }
974
975 static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
976 {
977         struct winbindd_domain *domain;
978         char *buf = NULL;
979
980         if ((buf = talloc_asprintf(mem_ctx, "global:%s ", 
981                                    get_global_winbindd_state_offline() ? 
982                                    "Offline":"Online")) == NULL) {
983                 return NULL;
984         }
985
986         for (domain = domain_list(); domain; domain = domain->next) {
987                 if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ", 
988                                                   domain->name, 
989                                                   domain->online ?
990                                                   "Online":"Offline")) == NULL) {
991                         return NULL;
992                 }
993         }
994
995         buf = talloc_asprintf_append_buffer(buf, "\n");
996
997         DEBUG(5,("collect_onlinestatus: %s", buf));
998
999         return buf;
1000 }
1001
1002 static void child_msg_onlinestatus(struct messaging_context *msg_ctx,
1003                                    void *private_data,
1004                                    uint32_t msg_type,
1005                                    struct server_id server_id,
1006                                    DATA_BLOB *data)
1007 {
1008         TALLOC_CTX *mem_ctx;
1009         const char *message;
1010         struct server_id *sender;
1011         
1012         DEBUG(5,("winbind_msg_onlinestatus received.\n"));
1013
1014         if (!data->data) {
1015                 return;
1016         }
1017
1018         sender = (struct server_id *)data->data;
1019
1020         mem_ctx = talloc_init("winbind_msg_onlinestatus");
1021         if (mem_ctx == NULL) {
1022                 return;
1023         }
1024         
1025         message = collect_onlinestatus(mem_ctx);
1026         if (message == NULL) {
1027                 talloc_destroy(mem_ctx);
1028                 return;
1029         }
1030
1031         messaging_send_buf(msg_ctx, *sender, MSG_WINBIND_ONLINESTATUS, 
1032                            (uint8 *)message, strlen(message) + 1);
1033
1034         talloc_destroy(mem_ctx);
1035 }
1036
1037 static void child_msg_dump_event_list(struct messaging_context *msg,
1038                                       void *private_data,
1039                                       uint32_t msg_type,
1040                                       struct server_id server_id,
1041                                       DATA_BLOB *data)
1042 {
1043         DEBUG(5,("child_msg_dump_event_list received\n"));
1044
1045         dump_event_list(winbind_event_context());
1046 }
1047
1048 void ccache_remove_all_after_fork(void);
1049
1050 bool winbindd_reinit_after_fork(const char *logfilename)
1051 {
1052         struct winbindd_domain *domain;
1053         struct winbindd_child *cl;
1054
1055         if (!reinit_after_fork(winbind_messaging_context(),
1056                                winbind_event_context(), true)) {
1057                 DEBUG(0,("reinit_after_fork() failed\n"));
1058                 return false;
1059         }
1060
1061         close_conns_after_fork();
1062
1063         if (!override_logfile && logfilename) {
1064                 lp_set_logfile(logfilename);
1065                 reopen_logs();
1066         }
1067
1068         /* Don't handle the same messages as our parent. */
1069         messaging_deregister(winbind_messaging_context(),
1070                              MSG_SMB_CONF_UPDATED, NULL);
1071         messaging_deregister(winbind_messaging_context(),
1072                              MSG_SHUTDOWN, NULL);
1073         messaging_deregister(winbind_messaging_context(),
1074                              MSG_WINBIND_OFFLINE, NULL);
1075         messaging_deregister(winbind_messaging_context(),
1076                              MSG_WINBIND_ONLINE, NULL);
1077         messaging_deregister(winbind_messaging_context(),
1078                              MSG_WINBIND_ONLINESTATUS, NULL);
1079         messaging_deregister(winbind_messaging_context(),
1080                              MSG_DUMP_EVENT_LIST, NULL);
1081         messaging_deregister(winbind_messaging_context(),
1082                              MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1083         messaging_deregister(winbind_messaging_context(),
1084                              MSG_DEBUG, NULL);
1085
1086         /* We have destroyed all events in the winbindd_event_context
1087          * in reinit_after_fork(), so clean out all possible pending
1088          * event pointers. */
1089
1090         /* Deal with check_online_events. */
1091
1092         for (domain = domain_list(); domain; domain = domain->next) {
1093                 TALLOC_FREE(domain->check_online_event);
1094         }
1095
1096         /* Ensure we're not handling a credential cache event inherited
1097          * from our parent. */
1098
1099         ccache_remove_all_after_fork();
1100
1101         /* Destroy all possible events in child list. */
1102         for (cl = children; cl != NULL; cl = cl->next) {
1103                 struct winbindd_async_request *request;
1104
1105                 for (request = cl->requests; request; request = request->next) {
1106                         TALLOC_FREE(request->reply_timeout_event);
1107                 }
1108                 TALLOC_FREE(cl->lockout_policy_event);
1109
1110                 /* Children should never be able to send
1111                  * each other messages, all messages must
1112                  * go through the parent.
1113                  */
1114                 cl->pid = (pid_t)0;
1115         }
1116         /*
1117          * This is a little tricky, children must not
1118          * send an MSG_WINBIND_ONLINE message to idmap_child().
1119          * If we are in a child of our primary domain or
1120          * in the process created by fork_child_dc_connect(),
1121          * and the primary domain cannot go online,
1122          * fork_child_dc_connection() sends MSG_WINBIND_ONLINE
1123          * periodically to idmap_child().
1124          *
1125          * The sequence is, fork_child_dc_connect() ---> getdcs() --->
1126          * get_dc_name_via_netlogon() ---> cm_connect_netlogon()
1127          * ---> init_dc_connection() ---> cm_open_connection --->
1128          * set_domain_online(), sends MSG_WINBIND_ONLINE to
1129          * idmap_child(). Disallow children sending messages
1130          * to each other, all messages must go through the parent.
1131          */
1132         cl = idmap_child();
1133         cl->pid = (pid_t)0;
1134
1135         return true;
1136 }
1137
1138 static bool fork_domain_child(struct winbindd_child *child)
1139 {
1140         int fdpair[2];
1141         struct winbindd_cli_state state;
1142         struct winbindd_domain *primary_domain = NULL;
1143
1144         if (child->domain) {
1145                 DEBUG(10, ("fork_domain_child called for domain '%s'\n",
1146                            child->domain->name));
1147         } else {
1148                 DEBUG(10, ("fork_domain_child called without domain.\n"));
1149         }
1150
1151         if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) {
1152                 DEBUG(0, ("Could not open child pipe: %s\n",
1153                           strerror(errno)));
1154                 return False;
1155         }
1156
1157         ZERO_STRUCT(state);
1158         state.pid = sys_getpid();
1159
1160         child->pid = sys_fork();
1161
1162         if (child->pid == -1) {
1163                 DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
1164                 return False;
1165         }
1166
1167         if (child->pid != 0) {
1168                 /* Parent */
1169                 close(fdpair[0]);
1170                 child->next = child->prev = NULL;
1171                 DLIST_ADD(children, child);
1172                 child->event.fd = fdpair[1];
1173                 child->event.flags = 0;
1174                 add_fd_event(&child->event);
1175                 return True;
1176         }
1177
1178         /* Child */
1179
1180         DEBUG(10, ("Child process %d\n", (int)sys_getpid()));
1181
1182         /* Stop zombies in children */
1183         CatchChild();
1184
1185         state.sock = fdpair[0];
1186         close(fdpair[1]);
1187
1188         if (!winbindd_reinit_after_fork(child->logfilename)) {
1189                 DEBUG(0, ("winbindd_reinit_after_fork failed.\n"));
1190                 _exit(0);
1191         }
1192  
1193         /* Handle online/offline messages. */
1194         messaging_register(winbind_messaging_context(), NULL,
1195                            MSG_WINBIND_OFFLINE, child_msg_offline);
1196         messaging_register(winbind_messaging_context(), NULL,
1197                            MSG_WINBIND_ONLINE, child_msg_online);
1198         messaging_register(winbind_messaging_context(), NULL,
1199                            MSG_WINBIND_ONLINESTATUS, child_msg_onlinestatus);
1200         messaging_register(winbind_messaging_context(), NULL,
1201                            MSG_DUMP_EVENT_LIST, child_msg_dump_event_list);
1202         messaging_register(winbind_messaging_context(), NULL,
1203                            MSG_DEBUG, debug_message);
1204         
1205         primary_domain = find_our_domain();
1206
1207         if (primary_domain == NULL) {
1208                 smb_panic("no primary domain found");
1209         }
1210
1211         /* It doesn't matter if we allow cache login,
1212          * try to bring domain online after fork. */
1213         if ( child->domain ) {
1214                 child->domain->startup = True;
1215                 child->domain->startup_time = time(NULL);
1216                 /* we can be in primary domain or in trusted domain
1217                  * If we are in trusted domain, set the primary domain
1218                  * in start-up mode */
1219                 if (!(child->domain->internal)) {
1220                         set_domain_online_request(child->domain);
1221                         if (!(child->domain->primary)) {
1222                                 primary_domain->startup = True;
1223                                 primary_domain->startup_time = time(NULL);
1224                                 set_domain_online_request(primary_domain);
1225                         }
1226                 }
1227         }
1228         
1229         /*
1230          * We are in idmap child, make sure that we set the
1231          * check_online_event to bring primary domain online.
1232          */
1233         if (child == idmap_child()) {
1234                 set_domain_online_request(primary_domain);
1235         }
1236
1237         /* We might be in the idmap child...*/
1238         if (child->domain && !(child->domain->internal) &&
1239             lp_winbind_offline_logon()) {
1240
1241                 set_domain_online_request(child->domain);
1242
1243                 if (primary_domain && (primary_domain != child->domain)) {
1244                         /* We need to talk to the primary
1245                          * domain as well as the trusted
1246                          * domain inside a trusted domain
1247                          * child.
1248                          * See the code in :
1249                          * set_dc_type_and_flags_trustinfo()
1250                          * for details.
1251                          */
1252                         set_domain_online_request(primary_domain);
1253                 }
1254
1255                 child->lockout_policy_event = event_add_timed(
1256                         winbind_event_context(), NULL, timeval_zero(),
1257                         "account_lockout_policy_handler",
1258                         account_lockout_policy_handler,
1259                         child);
1260         }
1261
1262         while (1) {
1263
1264                 int ret;
1265                 fd_set read_fds;
1266                 struct timeval t;
1267                 struct timeval *tp;
1268                 struct timeval now;
1269                 TALLOC_CTX *frame = talloc_stackframe();
1270
1271                 /* check for signals */
1272                 winbind_check_sigterm(false);
1273                 winbind_check_sighup(override_logfile ? NULL :
1274                                 child->logfilename);
1275
1276                 run_events(winbind_event_context(), 0, NULL, NULL);
1277
1278                 GetTimeOfDay(&now);
1279
1280                 if (child->domain && child->domain->startup &&
1281                                 (now.tv_sec > child->domain->startup_time + 30)) {
1282                         /* No longer in "startup" mode. */
1283                         DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
1284                                 child->domain->name ));
1285                         child->domain->startup = False;
1286                 }
1287
1288                 tp = get_timed_events_timeout(winbind_event_context(), &t);
1289                 if (tp) {
1290                         DEBUG(11,("select will use timeout of %u.%u seconds\n",
1291                                 (unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec ));
1292                 }
1293
1294                 /* Handle messages */
1295
1296                 message_dispatch(winbind_messaging_context());
1297
1298                 FD_ZERO(&read_fds);
1299                 FD_SET(state.sock, &read_fds);
1300
1301                 ret = sys_select(state.sock + 1, &read_fds, NULL, NULL, tp);
1302
1303                 if (ret == 0) {
1304                         DEBUG(11,("nothing is ready yet, continue\n"));
1305                         TALLOC_FREE(frame);
1306                         continue;
1307                 }
1308
1309                 if (ret == -1 && errno == EINTR) {
1310                         /* We got a signal - continue. */
1311                         TALLOC_FREE(frame);
1312                         continue;
1313                 }
1314
1315                 if (ret == -1 && errno != EINTR) {
1316                         DEBUG(0,("select error occured\n"));
1317                         TALLOC_FREE(frame);
1318                         perror("select");
1319                         _exit(1);
1320                 }
1321
1322                 /* fetch a request from the main daemon */
1323                 child_read_request(&state);
1324
1325                 if (state.finished) {
1326                         /* we lost contact with our parent */
1327                         _exit(0);
1328                 }
1329
1330                 DEBUG(4,("child daemon request %d\n", (int)state.request.cmd));
1331
1332                 ZERO_STRUCT(state.response);
1333                 state.request.null_term = '\0';
1334                 child_process_request(child, &state);
1335
1336                 SAFE_FREE(state.request.extra_data.data);
1337
1338                 cache_store_response(sys_getpid(), &state.response);
1339
1340                 SAFE_FREE(state.response.extra_data.data);
1341
1342                 /* We just send the result code back, the result
1343                  * structure needs to be fetched via the
1344                  * winbindd_cache. Hmm. That needs fixing... */
1345
1346                 if (write_data(state.sock,
1347                                (const char *)&state.response.result,
1348                                sizeof(state.response.result)) !=
1349                     sizeof(state.response.result)) {
1350                         DEBUG(0, ("Could not write result\n"));
1351                         exit(1);
1352                 }
1353                 TALLOC_FREE(frame);
1354         }
1355 }