s3: Make winbindd_reinit_after_fork return NTSTATUS
[Samba.git] / source3 / winbindd / winbindd_dual.c
blob8df6708778bf62346e7710d425c9824685fb628a
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind child daemons
6 Copyright (C) Andrew Tridgell 2002
7 Copyright (C) Volker Lendecke 2004,2005
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.
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.
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/>.
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.
30 #include "includes.h"
31 #include "winbindd.h"
32 #include "nsswitch/wb_reqtrans.h"
33 #include "secrets.h"
34 #include "../lib/util/select.h"
35 #include "../libcli/security/security.h"
36 #include "system/select.h"
37 #include "messages.h"
38 #include "ntdomain.h"
39 #include "../lib/util/tevent_unix.h"
41 #undef DBGC_CLASS
42 #define DBGC_CLASS DBGC_WINBIND
44 extern bool override_logfile;
45 extern struct winbindd_methods cache_methods;
47 /* Read some data from a client connection */
49 static NTSTATUS child_read_request(struct winbindd_cli_state *state)
51 NTSTATUS status;
53 /* Read data */
55 status = read_data(state->sock, (char *)state->request,
56 sizeof(*state->request));
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;
64 if (state->request->extra_len == 0) {
65 state->request->extra_data.data = NULL;
66 return NT_STATUS_OK;
69 DEBUG(10, ("Need to read %d extra bytes\n", (int)state->request->extra_len));
71 state->request->extra_data.data =
72 SMB_MALLOC_ARRAY(char, state->request->extra_len + 1);
74 if (state->request->extra_data.data == NULL) {
75 DEBUG(0, ("malloc failed\n"));
76 return NT_STATUS_NO_MEMORY;
79 /* Ensure null termination */
80 state->request->extra_data.data[state->request->extra_len] = '\0';
82 status= read_data(state->sock, state->request->extra_data.data,
83 state->request->extra_len);
85 if (!NT_STATUS_IS_OK(status)) {
86 DEBUG(0, ("Could not read extra data: %s\n",
87 nt_errstr(status)));
89 return status;
93 * Do winbind child async request. This is not simply wb_simple_trans. We have
94 * to do the queueing ourselves because while a request is queued, the child
95 * might have crashed, and we have to re-fork it in the _trigger function.
98 struct wb_child_request_state {
99 struct tevent_context *ev;
100 struct winbindd_child *child;
101 struct winbindd_request *request;
102 struct winbindd_response *response;
105 static bool fork_domain_child(struct winbindd_child *child);
107 static void wb_child_request_trigger(struct tevent_req *req,
108 void *private_data);
109 static void wb_child_request_done(struct tevent_req *subreq);
111 struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx,
112 struct tevent_context *ev,
113 struct winbindd_child *child,
114 struct winbindd_request *request)
116 struct tevent_req *req;
117 struct wb_child_request_state *state;
119 req = tevent_req_create(mem_ctx, &state,
120 struct wb_child_request_state);
121 if (req == NULL) {
122 return NULL;
125 state->ev = ev;
126 state->child = child;
127 state->request = request;
129 if (!tevent_queue_add(child->queue, ev, req,
130 wb_child_request_trigger, NULL)) {
131 tevent_req_nomem(NULL, req);
132 return tevent_req_post(req, ev);
134 return req;
137 static void wb_child_request_trigger(struct tevent_req *req,
138 void *private_data)
140 struct wb_child_request_state *state = tevent_req_data(
141 req, struct wb_child_request_state);
142 struct tevent_req *subreq;
144 if ((state->child->sock == -1) && (!fork_domain_child(state->child))) {
145 tevent_req_error(req, errno);
146 return;
149 subreq = wb_simple_trans_send(state, winbind_event_context(), NULL,
150 state->child->sock, state->request);
151 if (tevent_req_nomem(subreq, req)) {
152 return;
154 tevent_req_set_callback(subreq, wb_child_request_done, req);
155 tevent_req_set_endtime(req, state->ev, timeval_current_ofs(300, 0));
158 static void wb_child_request_done(struct tevent_req *subreq)
160 struct tevent_req *req = tevent_req_callback_data(
161 subreq, struct tevent_req);
162 struct wb_child_request_state *state = tevent_req_data(
163 req, struct wb_child_request_state);
164 int ret, err;
166 ret = wb_simple_trans_recv(subreq, state, &state->response, &err);
167 TALLOC_FREE(subreq);
168 if (ret == -1) {
170 * The basic parent/child communication broke, close
171 * our socket
173 close(state->child->sock);
174 state->child->sock = -1;
175 tevent_req_error(req, err);
176 return;
178 tevent_req_done(req);
181 int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
182 struct winbindd_response **presponse, int *err)
184 struct wb_child_request_state *state = tevent_req_data(
185 req, struct wb_child_request_state);
187 if (tevent_req_is_unix_error(req, err)) {
188 return -1;
190 *presponse = talloc_move(mem_ctx, &state->response);
191 return 0;
194 static bool winbindd_child_busy(struct winbindd_child *child)
196 return tevent_queue_length(child->queue) > 0;
199 static struct winbindd_child *find_idle_child(struct winbindd_domain *domain)
201 int i;
203 for (i=0; i<lp_winbind_max_domain_connections(); i++) {
204 if (!winbindd_child_busy(&domain->children[i])) {
205 return &domain->children[i];
209 return NULL;
212 struct winbindd_child *choose_domain_child(struct winbindd_domain *domain)
214 struct winbindd_child *result;
216 result = find_idle_child(domain);
217 if (result != NULL) {
218 return result;
220 return &domain->children[rand() % lp_winbind_max_domain_connections()];
223 struct dcerpc_binding_handle *dom_child_handle(struct winbindd_domain *domain)
225 struct winbindd_child *child;
227 child = choose_domain_child(domain);
228 return child->binding_handle;
231 struct wb_domain_request_state {
232 struct tevent_context *ev;
233 struct winbindd_domain *domain;
234 struct winbindd_child *child;
235 struct winbindd_request *request;
236 struct winbindd_request *init_req;
237 struct winbindd_response *response;
240 static void wb_domain_request_gotdc(struct tevent_req *subreq);
241 static void wb_domain_request_initialized(struct tevent_req *subreq);
242 static void wb_domain_request_done(struct tevent_req *subreq);
244 struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
245 struct tevent_context *ev,
246 struct winbindd_domain *domain,
247 struct winbindd_request *request)
249 struct tevent_req *req, *subreq;
250 struct wb_domain_request_state *state;
252 req = tevent_req_create(mem_ctx, &state,
253 struct wb_domain_request_state);
254 if (req == NULL) {
255 return NULL;
258 state->child = choose_domain_child(domain);
260 if (domain->initialized) {
261 subreq = wb_child_request_send(state, ev, state->child,
262 request);
263 if (tevent_req_nomem(subreq, req)) {
264 return tevent_req_post(req, ev);
266 tevent_req_set_callback(subreq, wb_domain_request_done, req);
267 return req;
270 state->domain = domain;
271 state->ev = ev;
272 state->request = request;
274 state->init_req = talloc_zero(state, struct winbindd_request);
275 if (tevent_req_nomem(state->init_req, req)) {
276 return tevent_req_post(req, ev);
279 if (IS_DC || domain->primary || domain->internal) {
280 /* The primary domain has to find the DC name itself */
281 state->init_req->cmd = WINBINDD_INIT_CONNECTION;
282 fstrcpy(state->init_req->domain_name, domain->name);
283 state->init_req->data.init_conn.is_primary = domain->primary;
284 fstrcpy(state->init_req->data.init_conn.dcname, "");
286 subreq = wb_child_request_send(state, ev, state->child,
287 state->init_req);
288 if (tevent_req_nomem(subreq, req)) {
289 return tevent_req_post(req, ev);
291 tevent_req_set_callback(subreq, wb_domain_request_initialized,
292 req);
293 return req;
297 * Ask our DC for a DC name
299 domain = find_our_domain();
301 /* This is *not* the primary domain, let's ask our DC about a DC
302 * name */
304 state->init_req->cmd = WINBINDD_GETDCNAME;
305 fstrcpy(state->init_req->domain_name, domain->name);
307 subreq = wb_child_request_send(state, ev, state->child, request);
308 if (tevent_req_nomem(subreq, req)) {
309 return tevent_req_post(req, ev);
311 tevent_req_set_callback(subreq, wb_domain_request_gotdc, req);
312 return req;
315 static void wb_domain_request_gotdc(struct tevent_req *subreq)
317 struct tevent_req *req = tevent_req_callback_data(
318 subreq, struct tevent_req);
319 struct wb_domain_request_state *state = tevent_req_data(
320 req, struct wb_domain_request_state);
321 struct winbindd_response *response;
322 int ret, err;
324 ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
325 TALLOC_FREE(subreq);
326 if (ret == -1) {
327 tevent_req_error(req, err);
328 return;
330 state->init_req->cmd = WINBINDD_INIT_CONNECTION;
331 fstrcpy(state->init_req->domain_name, state->domain->name);
332 state->init_req->data.init_conn.is_primary = False;
333 fstrcpy(state->init_req->data.init_conn.dcname,
334 response->data.dc_name);
336 TALLOC_FREE(response);
338 subreq = wb_child_request_send(state, state->ev, state->child,
339 state->init_req);
340 if (tevent_req_nomem(subreq, req)) {
341 return;
343 tevent_req_set_callback(subreq, wb_domain_request_initialized, req);
346 static void wb_domain_request_initialized(struct tevent_req *subreq)
348 struct tevent_req *req = tevent_req_callback_data(
349 subreq, struct tevent_req);
350 struct wb_domain_request_state *state = tevent_req_data(
351 req, struct wb_domain_request_state);
352 struct winbindd_response *response;
353 int ret, err;
355 ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
356 TALLOC_FREE(subreq);
357 if (ret == -1) {
358 tevent_req_error(req, err);
359 return;
362 if (!string_to_sid(&state->domain->sid,
363 response->data.domain_info.sid)) {
364 DEBUG(1,("init_child_recv: Could not convert sid %s "
365 "from string\n", response->data.domain_info.sid));
366 tevent_req_error(req, EINVAL);
367 return;
369 fstrcpy(state->domain->name, response->data.domain_info.name);
370 fstrcpy(state->domain->alt_name, response->data.domain_info.alt_name);
371 state->domain->native_mode = response->data.domain_info.native_mode;
372 state->domain->active_directory =
373 response->data.domain_info.active_directory;
374 state->domain->initialized = true;
376 TALLOC_FREE(response);
378 subreq = wb_child_request_send(state, state->ev, state->child,
379 state->request);
380 if (tevent_req_nomem(subreq, req)) {
381 return;
383 tevent_req_set_callback(subreq, wb_domain_request_done, req);
386 static void wb_domain_request_done(struct tevent_req *subreq)
388 struct tevent_req *req = tevent_req_callback_data(
389 subreq, struct tevent_req);
390 struct wb_domain_request_state *state = tevent_req_data(
391 req, struct wb_domain_request_state);
392 int ret, err;
394 ret = wb_child_request_recv(subreq, talloc_tos(), &state->response,
395 &err);
396 TALLOC_FREE(subreq);
397 if (ret == -1) {
398 tevent_req_error(req, err);
399 return;
401 tevent_req_done(req);
404 int wb_domain_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
405 struct winbindd_response **presponse, int *err)
407 struct wb_domain_request_state *state = tevent_req_data(
408 req, struct wb_domain_request_state);
410 if (tevent_req_is_unix_error(req, err)) {
411 return -1;
413 *presponse = talloc_move(mem_ctx, &state->response);
414 return 0;
417 static void child_process_request(struct winbindd_child *child,
418 struct winbindd_cli_state *state)
420 struct winbindd_domain *domain = child->domain;
421 const struct winbindd_child_dispatch_table *table = child->table;
423 /* Free response data - we may be interrupted and receive another
424 command before being able to send this data off. */
426 state->response->result = WINBINDD_ERROR;
427 state->response->length = sizeof(struct winbindd_response);
429 /* as all requests in the child are sync, we can use talloc_tos() */
430 state->mem_ctx = talloc_tos();
432 /* Process command */
434 for (; table->name; table++) {
435 if (state->request->cmd == table->struct_cmd) {
436 DEBUG(10,("child_process_request: request fn %s\n",
437 table->name));
438 state->response->result = table->struct_fn(domain, state);
439 return;
443 DEBUG(1, ("child_process_request: unknown request fn number %d\n",
444 (int)state->request->cmd));
445 state->response->result = WINBINDD_ERROR;
448 void setup_child(struct winbindd_domain *domain, struct winbindd_child *child,
449 const struct winbindd_child_dispatch_table *table,
450 const char *logprefix,
451 const char *logname)
453 if (logprefix && logname) {
454 char *logbase = NULL;
456 if (*lp_logfile()) {
457 char *end = NULL;
459 if (asprintf(&logbase, "%s", lp_logfile()) < 0) {
460 smb_panic("Internal error: asprintf failed");
463 if ((end = strrchr_m(logbase, '/'))) {
464 *end = '\0';
466 } else {
467 if (asprintf(&logbase, "%s", get_dyn_LOGFILEBASE()) < 0) {
468 smb_panic("Internal error: asprintf failed");
472 if (asprintf(&child->logfilename, "%s/%s-%s",
473 logbase, logprefix, logname) < 0) {
474 SAFE_FREE(logbase);
475 smb_panic("Internal error: asprintf failed");
478 SAFE_FREE(logbase);
479 } else {
480 smb_panic("Internal error: logprefix == NULL && "
481 "logname == NULL");
484 child->sock = -1;
485 child->domain = domain;
486 child->table = table;
487 child->queue = tevent_queue_create(NULL, "winbind_child");
488 SMB_ASSERT(child->queue != NULL);
489 child->binding_handle = wbint_binding_handle(NULL, domain, child);
490 SMB_ASSERT(child->binding_handle != NULL);
493 static struct winbindd_child *winbindd_children = NULL;
495 void winbind_child_died(pid_t pid)
497 struct winbindd_child *child;
499 for (child = winbindd_children; child != NULL; child = child->next) {
500 if (child->pid == pid) {
501 break;
505 if (child == NULL) {
506 DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
507 return;
510 /* This will be re-added in fork_domain_child() */
512 DLIST_REMOVE(winbindd_children, child);
513 child->pid = 0;
516 /* Ensure any negative cache entries with the netbios or realm names are removed. */
518 void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
520 flush_negative_conn_cache_for_domain(domain->name);
521 if (*domain->alt_name) {
522 flush_negative_conn_cache_for_domain(domain->alt_name);
527 * Parent winbindd process sets its own debug level first and then
528 * sends a message to all the winbindd children to adjust their debug
529 * level to that of parents.
532 void winbind_msg_debug(struct messaging_context *msg_ctx,
533 void *private_data,
534 uint32_t msg_type,
535 struct server_id server_id,
536 DATA_BLOB *data)
538 struct winbindd_child *child;
540 DEBUG(10,("winbind_msg_debug: got debug message.\n"));
542 debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data);
544 for (child = winbindd_children; child != NULL; child = child->next) {
546 DEBUG(10,("winbind_msg_debug: sending message to pid %u.\n",
547 (unsigned int)child->pid));
549 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
550 MSG_DEBUG,
551 data->data,
552 strlen((char *) data->data) + 1);
556 /* Set our domains as offline and forward the offline message to our children. */
558 void winbind_msg_offline(struct messaging_context *msg_ctx,
559 void *private_data,
560 uint32_t msg_type,
561 struct server_id server_id,
562 DATA_BLOB *data)
564 struct winbindd_child *child;
565 struct winbindd_domain *domain;
567 DEBUG(10,("winbind_msg_offline: got offline message.\n"));
569 if (!lp_winbind_offline_logon()) {
570 DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
571 return;
574 /* Set our global state as offline. */
575 if (!set_global_winbindd_state_offline()) {
576 DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
577 return;
580 /* Set all our domains as offline. */
581 for (domain = domain_list(); domain; domain = domain->next) {
582 if (domain->internal) {
583 continue;
585 DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
586 set_domain_offline(domain);
589 for (child = winbindd_children; child != NULL; child = child->next) {
590 /* Don't send message to internal children. We've already
591 done so above. */
592 if (!child->domain || winbindd_internal_child(child)) {
593 continue;
596 /* Or internal domains (this should not be possible....) */
597 if (child->domain->internal) {
598 continue;
601 /* Each winbindd child should only process requests for one domain - make sure
602 we only set it online / offline for that domain. */
604 DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
605 (unsigned int)child->pid, domain->name ));
607 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
608 MSG_WINBIND_OFFLINE,
609 (uint8 *)child->domain->name,
610 strlen(child->domain->name)+1);
614 /* Set our domains as online and forward the online message to our children. */
616 void winbind_msg_online(struct messaging_context *msg_ctx,
617 void *private_data,
618 uint32_t msg_type,
619 struct server_id server_id,
620 DATA_BLOB *data)
622 struct winbindd_child *child;
623 struct winbindd_domain *domain;
625 DEBUG(10,("winbind_msg_online: got online message.\n"));
627 if (!lp_winbind_offline_logon()) {
628 DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
629 return;
632 /* Set our global state as online. */
633 set_global_winbindd_state_online();
635 smb_nscd_flush_user_cache();
636 smb_nscd_flush_group_cache();
638 /* Set all our domains as online. */
639 for (domain = domain_list(); domain; domain = domain->next) {
640 if (domain->internal) {
641 continue;
643 DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain->name));
645 winbindd_flush_negative_conn_cache(domain);
646 set_domain_online_request(domain);
648 /* Send an online message to the idmap child when our
649 primary domain comes back online */
651 if ( domain->primary ) {
652 struct winbindd_child *idmap = idmap_child();
654 if ( idmap->pid != 0 ) {
655 messaging_send_buf(msg_ctx,
656 pid_to_procid(idmap->pid),
657 MSG_WINBIND_ONLINE,
658 (uint8 *)domain->name,
659 strlen(domain->name)+1);
664 for (child = winbindd_children; child != NULL; child = child->next) {
665 /* Don't send message to internal childs. */
666 if (!child->domain || winbindd_internal_child(child)) {
667 continue;
670 /* Or internal domains (this should not be possible....) */
671 if (child->domain->internal) {
672 continue;
675 /* Each winbindd child should only process requests for one domain - make sure
676 we only set it online / offline for that domain. */
678 DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n",
679 (unsigned int)child->pid, child->domain->name ));
681 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
682 MSG_WINBIND_ONLINE,
683 (uint8 *)child->domain->name,
684 strlen(child->domain->name)+1);
688 static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
690 struct winbindd_domain *domain;
691 char *buf = NULL;
693 if ((buf = talloc_asprintf(mem_ctx, "global:%s ",
694 get_global_winbindd_state_offline() ?
695 "Offline":"Online")) == NULL) {
696 return NULL;
699 for (domain = domain_list(); domain; domain = domain->next) {
700 if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ",
701 domain->name,
702 domain->online ?
703 "Online":"Offline")) == NULL) {
704 return NULL;
708 buf = talloc_asprintf_append_buffer(buf, "\n");
710 DEBUG(5,("collect_onlinestatus: %s", buf));
712 return buf;
715 void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
716 void *private_data,
717 uint32_t msg_type,
718 struct server_id server_id,
719 DATA_BLOB *data)
721 TALLOC_CTX *mem_ctx;
722 const char *message;
723 struct server_id *sender;
725 DEBUG(5,("winbind_msg_onlinestatus received.\n"));
727 if (!data->data) {
728 return;
731 sender = (struct server_id *)data->data;
733 mem_ctx = talloc_init("winbind_msg_onlinestatus");
734 if (mem_ctx == NULL) {
735 return;
738 message = collect_onlinestatus(mem_ctx);
739 if (message == NULL) {
740 talloc_destroy(mem_ctx);
741 return;
744 messaging_send_buf(msg_ctx, *sender, MSG_WINBIND_ONLINESTATUS,
745 (uint8 *)message, strlen(message) + 1);
747 talloc_destroy(mem_ctx);
750 void winbind_msg_dump_event_list(struct messaging_context *msg_ctx,
751 void *private_data,
752 uint32_t msg_type,
753 struct server_id server_id,
754 DATA_BLOB *data)
756 struct winbindd_child *child;
758 DEBUG(10,("winbind_msg_dump_event_list received\n"));
760 dump_event_list(winbind_event_context());
762 for (child = winbindd_children; child != NULL; child = child->next) {
764 DEBUG(10,("winbind_msg_dump_event_list: sending message to pid %u\n",
765 (unsigned int)child->pid));
767 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
768 MSG_DUMP_EVENT_LIST,
769 NULL, 0);
774 void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
775 void *private_data,
776 uint32_t msg_type,
777 struct server_id server_id,
778 DATA_BLOB *data)
780 TALLOC_CTX *mem_ctx;
781 const char *message = NULL;
782 struct server_id *sender = NULL;
783 const char *domain = NULL;
784 char *s = NULL;
785 NTSTATUS status;
786 struct winbindd_domain *dom = NULL;
788 DEBUG(5,("winbind_msg_dump_domain_list received.\n"));
790 if (!data || !data->data) {
791 return;
794 if (data->length < sizeof(struct server_id)) {
795 return;
798 mem_ctx = talloc_init("winbind_msg_dump_domain_list");
799 if (!mem_ctx) {
800 return;
803 sender = (struct server_id *)data->data;
804 if (data->length > sizeof(struct server_id)) {
805 domain = (const char *)data->data+sizeof(struct server_id);
808 if (domain) {
810 DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n",
811 domain));
813 message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain,
814 find_domain_from_name_noinit(domain));
815 if (!message) {
816 talloc_destroy(mem_ctx);
817 return;
820 messaging_send_buf(msg_ctx, *sender,
821 MSG_WINBIND_DUMP_DOMAIN_LIST,
822 (uint8_t *)message, strlen(message) + 1);
824 talloc_destroy(mem_ctx);
826 return;
829 DEBUG(5,("winbind_msg_dump_domain_list all domains\n"));
831 for (dom = domain_list(); dom; dom=dom->next) {
832 message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, dom);
833 if (!message) {
834 talloc_destroy(mem_ctx);
835 return;
838 s = talloc_asprintf_append(s, "%s\n", message);
839 if (!s) {
840 talloc_destroy(mem_ctx);
841 return;
845 status = messaging_send_buf(msg_ctx, *sender,
846 MSG_WINBIND_DUMP_DOMAIN_LIST,
847 (uint8_t *)s, strlen(s) + 1);
848 if (!NT_STATUS_IS_OK(status)) {
849 DEBUG(0,("failed to send message: %s\n",
850 nt_errstr(status)));
853 talloc_destroy(mem_ctx);
856 static void account_lockout_policy_handler(struct event_context *ctx,
857 struct timed_event *te,
858 struct timeval now,
859 void *private_data)
861 struct winbindd_child *child =
862 (struct winbindd_child *)private_data;
863 TALLOC_CTX *mem_ctx = NULL;
864 struct winbindd_methods *methods;
865 struct samr_DomInfo12 lockout_policy;
866 NTSTATUS result;
868 DEBUG(10,("account_lockout_policy_handler called\n"));
870 TALLOC_FREE(child->lockout_policy_event);
872 if ( !winbindd_can_contact_domain( child->domain ) ) {
873 DEBUG(10,("account_lockout_policy_handler: Removing myself since I "
874 "do not have an incoming trust to domain %s\n",
875 child->domain->name));
877 return;
880 methods = child->domain->methods;
882 mem_ctx = talloc_init("account_lockout_policy_handler ctx");
883 if (!mem_ctx) {
884 result = NT_STATUS_NO_MEMORY;
885 } else {
886 result = methods->lockout_policy(child->domain, mem_ctx, &lockout_policy);
888 TALLOC_FREE(mem_ctx);
890 if (!NT_STATUS_IS_OK(result)) {
891 DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
892 nt_errstr(result)));
895 child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL,
896 timeval_current_ofs(3600, 0),
897 account_lockout_policy_handler,
898 child);
901 static time_t get_machine_password_timeout(void)
903 /* until we have gpo support use lp setting */
904 return lp_machine_password_timeout();
907 static bool calculate_next_machine_pwd_change(const char *domain,
908 struct timeval *t)
910 time_t pass_last_set_time;
911 time_t timeout;
912 time_t next_change;
913 struct timeval tv;
914 char *pw;
916 pw = secrets_fetch_machine_password(domain,
917 &pass_last_set_time,
918 NULL);
920 if (pw == NULL) {
921 DEBUG(0,("cannot fetch own machine password ????"));
922 return false;
925 SAFE_FREE(pw);
927 timeout = get_machine_password_timeout();
928 if (timeout == 0) {
929 DEBUG(10,("machine password never expires\n"));
930 return false;
933 tv.tv_sec = pass_last_set_time;
934 DEBUG(10, ("password last changed %s\n",
935 timeval_string(talloc_tos(), &tv, false)));
936 tv.tv_sec += timeout;
937 DEBUGADD(10, ("password valid until %s\n",
938 timeval_string(talloc_tos(), &tv, false)));
940 if (time(NULL) < (pass_last_set_time + timeout)) {
941 next_change = pass_last_set_time + timeout;
942 DEBUG(10,("machine password still valid until: %s\n",
943 http_timestring(talloc_tos(), next_change)));
944 *t = timeval_set(next_change, 0);
946 if (lp_clustering()) {
947 uint8_t randbuf;
949 * When having a cluster, we have several
950 * winbinds racing for the password change. In
951 * the machine_password_change_handler()
952 * function we check if someone else was
953 * faster when the event triggers. We add a
954 * 255-second random delay here, so that we
955 * don't run to change the password at the
956 * exact same moment.
958 generate_random_buffer(&randbuf, sizeof(randbuf));
959 DEBUG(10, ("adding %d seconds randomness\n",
960 (int)randbuf));
961 t->tv_sec += randbuf;
963 return true;
966 DEBUG(10,("machine password expired, needs immediate change\n"));
968 *t = timeval_zero();
970 return true;
973 static void machine_password_change_handler(struct event_context *ctx,
974 struct timed_event *te,
975 struct timeval now,
976 void *private_data)
978 struct winbindd_child *child =
979 (struct winbindd_child *)private_data;
980 struct rpc_pipe_client *netlogon_pipe = NULL;
981 TALLOC_CTX *frame;
982 NTSTATUS result;
983 struct timeval next_change;
985 DEBUG(10,("machine_password_change_handler called\n"));
987 TALLOC_FREE(child->machine_password_change_event);
989 if (!calculate_next_machine_pwd_change(child->domain->name,
990 &next_change)) {
991 DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
992 return;
995 DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
996 timeval_string(talloc_tos(), &next_change, false)));
998 if (!timeval_expired(&next_change)) {
999 DEBUG(10, ("Someone else has already changed the pw\n"));
1000 goto done;
1003 if (!winbindd_can_contact_domain(child->domain)) {
1004 DEBUG(10,("machine_password_change_handler: Removing myself since I "
1005 "do not have an incoming trust to domain %s\n",
1006 child->domain->name));
1007 return;
1010 result = cm_connect_netlogon(child->domain, &netlogon_pipe);
1011 if (!NT_STATUS_IS_OK(result)) {
1012 DEBUG(10,("machine_password_change_handler: "
1013 "failed to connect netlogon pipe: %s\n",
1014 nt_errstr(result)));
1015 return;
1018 frame = talloc_stackframe();
1020 result = trust_pw_find_change_and_store_it(netlogon_pipe,
1021 frame,
1022 child->domain->name);
1023 TALLOC_FREE(frame);
1025 DEBUG(10, ("machine_password_change_handler: "
1026 "trust_pw_find_change_and_store_it returned %s\n",
1027 nt_errstr(result)));
1029 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1030 DEBUG(3,("machine_password_change_handler: password set returned "
1031 "ACCESS_DENIED. Maybe the trust account "
1032 "password was changed and we didn't know it. "
1033 "Killing connections to domain %s\n",
1034 child->domain->name));
1035 TALLOC_FREE(child->domain->conn.netlogon_pipe);
1038 if (!calculate_next_machine_pwd_change(child->domain->name,
1039 &next_change)) {
1040 DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
1041 return;
1044 DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
1045 timeval_string(talloc_tos(), &next_change, false)));
1047 if (!NT_STATUS_IS_OK(result)) {
1048 struct timeval tmp;
1050 * In case of failure, give the DC a minute to recover
1052 tmp = timeval_current_ofs(60, 0);
1053 next_change = timeval_max(&next_change, &tmp);
1056 done:
1057 child->machine_password_change_event = event_add_timed(winbind_event_context(), NULL,
1058 next_change,
1059 machine_password_change_handler,
1060 child);
1063 /* Deal with a request to go offline. */
1065 static void child_msg_offline(struct messaging_context *msg,
1066 void *private_data,
1067 uint32_t msg_type,
1068 struct server_id server_id,
1069 DATA_BLOB *data)
1071 struct winbindd_domain *domain;
1072 struct winbindd_domain *primary_domain = NULL;
1073 const char *domainname = (const char *)data->data;
1075 if (data->data == NULL || data->length == 0) {
1076 return;
1079 DEBUG(5,("child_msg_offline received for domain %s.\n", domainname));
1081 if (!lp_winbind_offline_logon()) {
1082 DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
1083 return;
1086 primary_domain = find_our_domain();
1088 /* Mark the requested domain offline. */
1090 for (domain = domain_list(); domain; domain = domain->next) {
1091 if (domain->internal) {
1092 continue;
1094 if (strequal(domain->name, domainname)) {
1095 DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name));
1096 set_domain_offline(domain);
1097 /* we are in the trusted domain, set the primary domain
1098 * offline too */
1099 if (domain != primary_domain) {
1100 set_domain_offline(primary_domain);
1106 /* Deal with a request to go online. */
1108 static void child_msg_online(struct messaging_context *msg,
1109 void *private_data,
1110 uint32_t msg_type,
1111 struct server_id server_id,
1112 DATA_BLOB *data)
1114 struct winbindd_domain *domain;
1115 struct winbindd_domain *primary_domain = NULL;
1116 const char *domainname = (const char *)data->data;
1118 if (data->data == NULL || data->length == 0) {
1119 return;
1122 DEBUG(5,("child_msg_online received for domain %s.\n", domainname));
1124 if (!lp_winbind_offline_logon()) {
1125 DEBUG(10,("child_msg_online: rejecting online message.\n"));
1126 return;
1129 primary_domain = find_our_domain();
1131 /* Set our global state as online. */
1132 set_global_winbindd_state_online();
1134 /* Try and mark everything online - delete any negative cache entries
1135 to force a reconnect now. */
1137 for (domain = domain_list(); domain; domain = domain->next) {
1138 if (domain->internal) {
1139 continue;
1141 if (strequal(domain->name, domainname)) {
1142 DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name));
1143 winbindd_flush_negative_conn_cache(domain);
1144 set_domain_online_request(domain);
1146 /* we can be in trusted domain, which will contact primary domain
1147 * we have to bring primary domain online in trusted domain process
1148 * see, winbindd_dual_pam_auth() --> winbindd_dual_pam_auth_samlogon()
1149 * --> contact_domain = find_our_domain()
1150 * */
1151 if (domain != primary_domain) {
1152 winbindd_flush_negative_conn_cache(primary_domain);
1153 set_domain_online_request(primary_domain);
1159 static void child_msg_dump_event_list(struct messaging_context *msg,
1160 void *private_data,
1161 uint32_t msg_type,
1162 struct server_id server_id,
1163 DATA_BLOB *data)
1165 DEBUG(5,("child_msg_dump_event_list received\n"));
1167 dump_event_list(winbind_event_context());
1170 NTSTATUS winbindd_reinit_after_fork(const struct winbindd_child *myself,
1171 const char *logfilename)
1173 struct winbindd_domain *domain;
1174 struct winbindd_child *cl;
1175 NTSTATUS status;
1177 status = reinit_after_fork(
1178 winbind_messaging_context(),
1179 winbind_event_context(),
1180 procid_self(),
1181 true);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 DEBUG(0,("reinit_after_fork() failed\n"));
1184 return status;
1187 close_conns_after_fork();
1189 if (!override_logfile && logfilename) {
1190 lp_set_logfile(logfilename);
1191 reopen_logs();
1194 if (!winbindd_setup_sig_term_handler(false))
1195 return NT_STATUS_NO_MEMORY;
1196 if (!winbindd_setup_sig_hup_handler(override_logfile ? NULL :
1197 logfilename))
1198 return NT_STATUS_NO_MEMORY;
1200 /* Stop zombies in children */
1201 CatchChild();
1203 /* Don't handle the same messages as our parent. */
1204 messaging_deregister(winbind_messaging_context(),
1205 MSG_SMB_CONF_UPDATED, NULL);
1206 messaging_deregister(winbind_messaging_context(),
1207 MSG_SHUTDOWN, NULL);
1208 messaging_deregister(winbind_messaging_context(),
1209 MSG_WINBIND_OFFLINE, NULL);
1210 messaging_deregister(winbind_messaging_context(),
1211 MSG_WINBIND_ONLINE, NULL);
1212 messaging_deregister(winbind_messaging_context(),
1213 MSG_WINBIND_ONLINESTATUS, NULL);
1214 messaging_deregister(winbind_messaging_context(),
1215 MSG_DUMP_EVENT_LIST, NULL);
1216 messaging_deregister(winbind_messaging_context(),
1217 MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1218 messaging_deregister(winbind_messaging_context(),
1219 MSG_DEBUG, NULL);
1221 /* We have destroyed all events in the winbindd_event_context
1222 * in reinit_after_fork(), so clean out all possible pending
1223 * event pointers. */
1225 /* Deal with check_online_events. */
1227 for (domain = domain_list(); domain; domain = domain->next) {
1228 TALLOC_FREE(domain->check_online_event);
1231 /* Ensure we're not handling a credential cache event inherited
1232 * from our parent. */
1234 ccache_remove_all_after_fork();
1236 /* Destroy all possible events in child list. */
1237 for (cl = winbindd_children; cl != NULL; cl = cl->next) {
1238 TALLOC_FREE(cl->lockout_policy_event);
1239 TALLOC_FREE(cl->machine_password_change_event);
1241 /* Children should never be able to send
1242 * each other messages, all messages must
1243 * go through the parent.
1245 cl->pid = (pid_t)0;
1248 * Close service sockets to all other children
1250 if ((cl != myself) && (cl->sock != -1)) {
1251 close(cl->sock);
1252 cl->sock = -1;
1256 * This is a little tricky, children must not
1257 * send an MSG_WINBIND_ONLINE message to idmap_child().
1258 * If we are in a child of our primary domain or
1259 * in the process created by fork_child_dc_connect(),
1260 * and the primary domain cannot go online,
1261 * fork_child_dc_connection() sends MSG_WINBIND_ONLINE
1262 * periodically to idmap_child().
1264 * The sequence is, fork_child_dc_connect() ---> getdcs() --->
1265 * get_dc_name_via_netlogon() ---> cm_connect_netlogon()
1266 * ---> init_dc_connection() ---> cm_open_connection --->
1267 * set_domain_online(), sends MSG_WINBIND_ONLINE to
1268 * idmap_child(). Disallow children sending messages
1269 * to each other, all messages must go through the parent.
1271 cl = idmap_child();
1272 cl->pid = (pid_t)0;
1274 return NT_STATUS_OK;
1278 * In a child there will be only one domain, reference that here.
1280 static struct winbindd_domain *child_domain;
1282 struct winbindd_domain *wb_child_domain(void)
1284 return child_domain;
1287 static bool fork_domain_child(struct winbindd_child *child)
1289 int fdpair[2];
1290 struct winbindd_cli_state state;
1291 struct winbindd_request request;
1292 struct winbindd_response response;
1293 struct winbindd_domain *primary_domain = NULL;
1294 NTSTATUS status;
1296 if (child->domain) {
1297 DEBUG(10, ("fork_domain_child called for domain '%s'\n",
1298 child->domain->name));
1299 } else {
1300 DEBUG(10, ("fork_domain_child called without domain.\n"));
1303 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) {
1304 DEBUG(0, ("Could not open child pipe: %s\n",
1305 strerror(errno)));
1306 return False;
1309 ZERO_STRUCT(state);
1310 state.pid = sys_getpid();
1311 state.request = &request;
1312 state.response = &response;
1314 child->pid = sys_fork();
1316 if (child->pid == -1) {
1317 DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
1318 return False;
1321 if (child->pid != 0) {
1322 /* Parent */
1323 close(fdpair[0]);
1324 child->next = child->prev = NULL;
1325 DLIST_ADD(winbindd_children, child);
1326 child->sock = fdpair[1];
1327 return True;
1330 /* Child */
1331 child_domain = child->domain;
1333 DEBUG(10, ("Child process %d\n", (int)sys_getpid()));
1335 state.sock = fdpair[0];
1336 close(fdpair[1]);
1338 status = winbindd_reinit_after_fork(child, child->logfilename);
1339 if (!NT_STATUS_IS_OK(status)) {
1340 DEBUG(1, ("winbindd_reinit_after_fork failed: %s\n",
1341 nt_errstr(status)));
1342 _exit(0);
1345 /* Handle online/offline messages. */
1346 messaging_register(winbind_messaging_context(), NULL,
1347 MSG_WINBIND_OFFLINE, child_msg_offline);
1348 messaging_register(winbind_messaging_context(), NULL,
1349 MSG_WINBIND_ONLINE, child_msg_online);
1350 messaging_register(winbind_messaging_context(), NULL,
1351 MSG_DUMP_EVENT_LIST, child_msg_dump_event_list);
1352 messaging_register(winbind_messaging_context(), NULL,
1353 MSG_DEBUG, debug_message);
1354 messaging_register(winbind_messaging_context(), NULL,
1355 MSG_WINBIND_IP_DROPPED,
1356 winbind_msg_ip_dropped);
1359 primary_domain = find_our_domain();
1361 if (primary_domain == NULL) {
1362 smb_panic("no primary domain found");
1365 /* It doesn't matter if we allow cache login,
1366 * try to bring domain online after fork. */
1367 if ( child->domain ) {
1368 child->domain->startup = True;
1369 child->domain->startup_time = time_mono(NULL);
1370 /* we can be in primary domain or in trusted domain
1371 * If we are in trusted domain, set the primary domain
1372 * in start-up mode */
1373 if (!(child->domain->internal)) {
1374 set_domain_online_request(child->domain);
1375 if (!(child->domain->primary)) {
1376 primary_domain->startup = True;
1377 primary_domain->startup_time = time_mono(NULL);
1378 set_domain_online_request(primary_domain);
1384 * We are in idmap child, make sure that we set the
1385 * check_online_event to bring primary domain online.
1387 if (child == idmap_child()) {
1388 set_domain_online_request(primary_domain);
1391 /* We might be in the idmap child...*/
1392 if (child->domain && !(child->domain->internal) &&
1393 lp_winbind_offline_logon()) {
1395 set_domain_online_request(child->domain);
1397 if (primary_domain && (primary_domain != child->domain)) {
1398 /* We need to talk to the primary
1399 * domain as well as the trusted
1400 * domain inside a trusted domain
1401 * child.
1402 * See the code in :
1403 * set_dc_type_and_flags_trustinfo()
1404 * for details.
1406 set_domain_online_request(primary_domain);
1409 child->lockout_policy_event = event_add_timed(
1410 winbind_event_context(), NULL, timeval_zero(),
1411 account_lockout_policy_handler,
1412 child);
1415 if (child->domain && child->domain->primary &&
1416 !USE_KERBEROS_KEYTAB &&
1417 lp_server_role() == ROLE_DOMAIN_MEMBER) {
1419 struct timeval next_change;
1421 if (calculate_next_machine_pwd_change(child->domain->name,
1422 &next_change)) {
1423 child->machine_password_change_event = event_add_timed(
1424 winbind_event_context(), NULL, next_change,
1425 machine_password_change_handler,
1426 child);
1430 while (1) {
1432 int ret;
1433 struct pollfd *pfds;
1434 int num_pfds;
1435 int timeout;
1436 struct timeval t;
1437 struct timeval *tp;
1438 TALLOC_CTX *frame = talloc_stackframe();
1439 struct iovec iov[2];
1440 int iov_count;
1442 if (run_events_poll(winbind_event_context(), 0, NULL, 0)) {
1443 TALLOC_FREE(frame);
1444 continue;
1447 if (child->domain && child->domain->startup &&
1448 (time_mono(NULL) > child->domain->startup_time + 30)) {
1449 /* No longer in "startup" mode. */
1450 DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
1451 child->domain->name ));
1452 child->domain->startup = False;
1455 pfds = TALLOC_ZERO_P(talloc_tos(), struct pollfd);
1456 if (pfds == NULL) {
1457 DEBUG(1, ("talloc failed\n"));
1458 _exit(1);
1461 pfds->fd = state.sock;
1462 pfds->events = POLLIN|POLLHUP;
1463 num_pfds = 1;
1465 timeout = INT_MAX;
1467 if (!event_add_to_poll_args(
1468 winbind_event_context(), talloc_tos(),
1469 &pfds, &num_pfds, &timeout)) {
1470 DEBUG(1, ("event_add_to_poll_args failed\n"));
1471 _exit(1);
1473 tp = get_timed_events_timeout(winbind_event_context(), &t);
1474 if (tp) {
1475 DEBUG(11,("select will use timeout of %u.%u seconds\n",
1476 (unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec ));
1479 ret = sys_poll(pfds, num_pfds, timeout);
1481 if (run_events_poll(winbind_event_context(), ret,
1482 pfds, num_pfds)) {
1483 /* We got a signal - continue. */
1484 TALLOC_FREE(frame);
1485 continue;
1488 TALLOC_FREE(pfds);
1490 if (ret == 0) {
1491 DEBUG(11,("nothing is ready yet, continue\n"));
1492 TALLOC_FREE(frame);
1493 continue;
1496 if (ret == -1 && errno == EINTR) {
1497 /* We got a signal - continue. */
1498 TALLOC_FREE(frame);
1499 continue;
1502 if (ret == -1 && errno != EINTR) {
1503 DEBUG(0,("poll error occured\n"));
1504 TALLOC_FREE(frame);
1505 perror("poll");
1506 _exit(1);
1509 /* fetch a request from the main daemon */
1510 status = child_read_request(&state);
1512 if (!NT_STATUS_IS_OK(status)) {
1513 /* we lost contact with our parent */
1514 _exit(0);
1517 DEBUG(4,("child daemon request %d\n", (int)state.request->cmd));
1519 ZERO_STRUCTP(state.response);
1520 state.request->null_term = '\0';
1521 state.mem_ctx = frame;
1522 child_process_request(child, &state);
1524 DEBUG(4, ("Finished processing child request %d\n",
1525 (int)state.request->cmd));
1527 SAFE_FREE(state.request->extra_data.data);
1529 iov[0].iov_base = (void *)state.response;
1530 iov[0].iov_len = sizeof(struct winbindd_response);
1531 iov_count = 1;
1533 if (state.response->length > sizeof(struct winbindd_response)) {
1534 iov[1].iov_base =
1535 (void *)state.response->extra_data.data;
1536 iov[1].iov_len = state.response->length-iov[0].iov_len;
1537 iov_count = 2;
1540 DEBUG(10, ("Writing %d bytes to parent\n",
1541 (int)state.response->length));
1543 if (write_data_iov(state.sock, iov, iov_count) !=
1544 state.response->length) {
1545 DEBUG(0, ("Could not write result\n"));
1546 exit(1);
1548 TALLOC_FREE(frame);
1552 void winbind_msg_ip_dropped_parent(struct messaging_context *msg_ctx,
1553 void *private_data,
1554 uint32_t msg_type,
1555 struct server_id server_id,
1556 DATA_BLOB *data)
1558 struct winbindd_child *child;
1560 winbind_msg_ip_dropped(msg_ctx, private_data, msg_type,
1561 server_id, data);
1564 for (child = winbindd_children; child != NULL; child = child->next) {
1565 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
1566 msg_type, data->data, data->length);