2 Unix SMB/CIFS implementation.
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.
32 #include "nsswitch/wb_reqtrans.h"
34 #include "../lib/util/select.h"
35 #include "../libcli/security/security.h"
36 #include "system/select.h"
39 #include "../lib/util/tevent_unix.h"
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)
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",
64 if (state->request->extra_len == 0) {
65 state->request->extra_data.data = NULL;
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",
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,
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);
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);
137 static void wb_child_request_trigger(struct tevent_req *req,
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);
149 subreq = wb_simple_trans_send(state, winbind_event_context(), NULL,
150 state->child->sock, state->request);
151 if (tevent_req_nomem(subreq, req)) {
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);
166 ret = wb_simple_trans_recv(subreq, state, &state->response, &err);
170 * The basic parent/child communication broke, close
173 close(state->child->sock);
174 state->child->sock = -1;
175 tevent_req_error(req, err);
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)) {
190 *presponse = talloc_move(mem_ctx, &state->response);
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)
203 for (i=0; i<lp_winbind_max_domain_connections(); i++) {
204 if (!winbindd_child_busy(&domain->children[i])) {
205 return &domain->children[i];
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) {
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);
258 state->child = choose_domain_child(domain);
260 if (domain->initialized) {
261 subreq = wb_child_request_send(state, ev, state->child,
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);
270 state->domain = domain;
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,
288 if (tevent_req_nomem(subreq, req)) {
289 return tevent_req_post(req, ev);
291 tevent_req_set_callback(subreq, wb_domain_request_initialized,
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
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);
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;
324 ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
327 tevent_req_error(req, err);
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,
340 if (tevent_req_nomem(subreq, req)) {
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;
355 ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
358 tevent_req_error(req, err);
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);
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,
380 if (tevent_req_nomem(subreq, req)) {
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);
394 ret = wb_child_request_recv(subreq, talloc_tos(), &state->response,
398 tevent_req_error(req, err);
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)) {
413 *presponse = talloc_move(mem_ctx, &state->response);
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",
438 state->response->result = table->struct_fn(domain, state);
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,
453 if (logprefix && logname) {
454 char *logbase = NULL;
459 if (asprintf(&logbase, "%s", lp_logfile()) < 0) {
460 smb_panic("Internal error: asprintf failed");
463 if ((end = strrchr_m(logbase, '/'))) {
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) {
475 smb_panic("Internal error: asprintf failed");
480 smb_panic("Internal error: logprefix == NULL && "
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) {
506 DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
510 /* This will be re-added in fork_domain_child() */
512 DLIST_REMOVE(winbindd_children, child);
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,
535 struct server_id server_id,
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),
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,
561 struct server_id server_id,
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"));
574 /* Set our global state as offline. */
575 if (!set_global_winbindd_state_offline()) {
576 DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
580 /* Set all our domains as offline. */
581 for (domain = domain_list(); domain; domain = domain->next) {
582 if (domain->internal) {
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
592 if (!child->domain || winbindd_internal_child(child)) {
596 /* Or internal domains (this should not be possible....) */
597 if (child->domain->internal) {
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),
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,
619 struct server_id server_id,
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"));
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) {
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),
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)) {
670 /* Or internal domains (this should not be possible....) */
671 if (child->domain->internal) {
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),
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;
693 if ((buf = talloc_asprintf(mem_ctx, "global:%s ",
694 get_global_winbindd_state_offline() ?
695 "Offline":"Online")) == NULL) {
699 for (domain = domain_list(); domain; domain = domain->next) {
700 if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ",
703 "Online":"Offline")) == NULL) {
708 buf = talloc_asprintf_append_buffer(buf, "\n");
710 DEBUG(5,("collect_onlinestatus: %s", buf));
715 void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
718 struct server_id server_id,
723 struct server_id *sender;
725 DEBUG(5,("winbind_msg_onlinestatus received.\n"));
731 sender = (struct server_id *)data->data;
733 mem_ctx = talloc_init("winbind_msg_onlinestatus");
734 if (mem_ctx == NULL) {
738 message = collect_onlinestatus(mem_ctx);
739 if (message == NULL) {
740 talloc_destroy(mem_ctx);
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,
753 struct server_id server_id,
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),
774 void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
777 struct server_id server_id,
781 const char *message = NULL;
782 struct server_id *sender = NULL;
783 const char *domain = NULL;
786 struct winbindd_domain *dom = NULL;
788 DEBUG(5,("winbind_msg_dump_domain_list received.\n"));
790 if (!data || !data->data) {
794 if (data->length < sizeof(struct server_id)) {
798 mem_ctx = talloc_init("winbind_msg_dump_domain_list");
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);
810 DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n",
813 message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain,
814 find_domain_from_name_noinit(domain));
816 talloc_destroy(mem_ctx);
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);
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);
834 talloc_destroy(mem_ctx);
838 s = talloc_asprintf_append(s, "%s\n", message);
840 talloc_destroy(mem_ctx);
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",
853 talloc_destroy(mem_ctx);
856 static void account_lockout_policy_handler(struct event_context *ctx,
857 struct timed_event *te,
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;
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));
880 methods = child->domain->methods;
882 mem_ctx = talloc_init("account_lockout_policy_handler ctx");
884 result = NT_STATUS_NO_MEMORY;
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",
895 child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL,
896 timeval_current_ofs(3600, 0),
897 account_lockout_policy_handler,
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,
910 time_t pass_last_set_time;
916 pw = secrets_fetch_machine_password(domain,
921 DEBUG(0,("cannot fetch own machine password ????"));
927 timeout = get_machine_password_timeout();
929 DEBUG(10,("machine password never expires\n"));
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()) {
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
958 generate_random_buffer(&randbuf, sizeof(randbuf));
959 DEBUG(10, ("adding %d seconds randomness\n",
961 t->tv_sec += randbuf;
966 DEBUG(10,("machine password expired, needs immediate change\n"));
973 static void machine_password_change_handler(struct event_context *ctx,
974 struct timed_event *te,
978 struct winbindd_child *child =
979 (struct winbindd_child *)private_data;
980 struct rpc_pipe_client *netlogon_pipe = NULL;
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,
991 DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
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"));
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));
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)));
1018 frame = talloc_stackframe();
1020 result = trust_pw_find_change_and_store_it(netlogon_pipe,
1022 child->domain->name);
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,
1040 DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
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)) {
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);
1057 child->machine_password_change_event = event_add_timed(winbind_event_context(), NULL,
1059 machine_password_change_handler,
1063 /* Deal with a request to go offline. */
1065 static void child_msg_offline(struct messaging_context *msg,
1068 struct server_id server_id,
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) {
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"));
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) {
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
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,
1111 struct server_id server_id,
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) {
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"));
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) {
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()
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,
1162 struct server_id server_id,
1165 DEBUG(5,("child_msg_dump_event_list received\n"));
1167 dump_event_list(winbind_event_context());
1170 bool winbindd_reinit_after_fork(const struct winbindd_child *myself,
1171 const char *logfilename)
1173 struct winbindd_domain *domain;
1174 struct winbindd_child *cl;
1177 status = reinit_after_fork(
1178 winbind_messaging_context(),
1179 winbind_event_context(),
1182 if (!NT_STATUS_IS_OK(status)) {
1183 DEBUG(0,("reinit_after_fork() failed\n"));
1187 close_conns_after_fork();
1189 if (!override_logfile && logfilename) {
1190 lp_set_logfile(logfilename);
1194 if (!winbindd_setup_sig_term_handler(false))
1196 if (!winbindd_setup_sig_hup_handler(override_logfile ? NULL :
1200 /* Stop zombies in children */
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(),
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.
1248 * Close service sockets to all other children
1250 if ((cl != myself) && (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.
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)
1290 struct winbindd_cli_state state;
1291 struct winbindd_request request;
1292 struct winbindd_response response;
1293 struct winbindd_domain *primary_domain = NULL;
1295 if (child->domain) {
1296 DEBUG(10, ("fork_domain_child called for domain '%s'\n",
1297 child->domain->name));
1299 DEBUG(10, ("fork_domain_child called without domain.\n"));
1302 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) {
1303 DEBUG(0, ("Could not open child pipe: %s\n",
1309 state.pid = sys_getpid();
1310 state.request = &request;
1311 state.response = &response;
1313 child->pid = sys_fork();
1315 if (child->pid == -1) {
1316 DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
1320 if (child->pid != 0) {
1323 child->next = child->prev = NULL;
1324 DLIST_ADD(winbindd_children, child);
1325 child->sock = fdpair[1];
1330 child_domain = child->domain;
1332 DEBUG(10, ("Child process %d\n", (int)sys_getpid()));
1334 state.sock = fdpair[0];
1337 if (!winbindd_reinit_after_fork(child, child->logfilename)) {
1341 /* Handle online/offline messages. */
1342 messaging_register(winbind_messaging_context(), NULL,
1343 MSG_WINBIND_OFFLINE, child_msg_offline);
1344 messaging_register(winbind_messaging_context(), NULL,
1345 MSG_WINBIND_ONLINE, child_msg_online);
1346 messaging_register(winbind_messaging_context(), NULL,
1347 MSG_DUMP_EVENT_LIST, child_msg_dump_event_list);
1348 messaging_register(winbind_messaging_context(), NULL,
1349 MSG_DEBUG, debug_message);
1350 messaging_register(winbind_messaging_context(), NULL,
1351 MSG_WINBIND_IP_DROPPED,
1352 winbind_msg_ip_dropped);
1355 primary_domain = find_our_domain();
1357 if (primary_domain == NULL) {
1358 smb_panic("no primary domain found");
1361 /* It doesn't matter if we allow cache login,
1362 * try to bring domain online after fork. */
1363 if ( child->domain ) {
1364 child->domain->startup = True;
1365 child->domain->startup_time = time_mono(NULL);
1366 /* we can be in primary domain or in trusted domain
1367 * If we are in trusted domain, set the primary domain
1368 * in start-up mode */
1369 if (!(child->domain->internal)) {
1370 set_domain_online_request(child->domain);
1371 if (!(child->domain->primary)) {
1372 primary_domain->startup = True;
1373 primary_domain->startup_time = time_mono(NULL);
1374 set_domain_online_request(primary_domain);
1380 * We are in idmap child, make sure that we set the
1381 * check_online_event to bring primary domain online.
1383 if (child == idmap_child()) {
1384 set_domain_online_request(primary_domain);
1387 /* We might be in the idmap child...*/
1388 if (child->domain && !(child->domain->internal) &&
1389 lp_winbind_offline_logon()) {
1391 set_domain_online_request(child->domain);
1393 if (primary_domain && (primary_domain != child->domain)) {
1394 /* We need to talk to the primary
1395 * domain as well as the trusted
1396 * domain inside a trusted domain
1399 * set_dc_type_and_flags_trustinfo()
1402 set_domain_online_request(primary_domain);
1405 child->lockout_policy_event = event_add_timed(
1406 winbind_event_context(), NULL, timeval_zero(),
1407 account_lockout_policy_handler,
1411 if (child->domain && child->domain->primary &&
1412 !USE_KERBEROS_KEYTAB &&
1413 lp_server_role() == ROLE_DOMAIN_MEMBER) {
1415 struct timeval next_change;
1417 if (calculate_next_machine_pwd_change(child->domain->name,
1419 child->machine_password_change_event = event_add_timed(
1420 winbind_event_context(), NULL, next_change,
1421 machine_password_change_handler,
1429 struct pollfd *pfds;
1434 TALLOC_CTX *frame = talloc_stackframe();
1435 struct iovec iov[2];
1439 if (run_events_poll(winbind_event_context(), 0, NULL, 0)) {
1444 if (child->domain && child->domain->startup &&
1445 (time_mono(NULL) > child->domain->startup_time + 30)) {
1446 /* No longer in "startup" mode. */
1447 DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
1448 child->domain->name ));
1449 child->domain->startup = False;
1452 pfds = TALLOC_ZERO_P(talloc_tos(), struct pollfd);
1454 DEBUG(1, ("talloc failed\n"));
1458 pfds->fd = state.sock;
1459 pfds->events = POLLIN|POLLHUP;
1464 if (!event_add_to_poll_args(
1465 winbind_event_context(), talloc_tos(),
1466 &pfds, &num_pfds, &timeout)) {
1467 DEBUG(1, ("event_add_to_poll_args failed\n"));
1470 tp = get_timed_events_timeout(winbind_event_context(), &t);
1472 DEBUG(11,("select will use timeout of %u.%u seconds\n",
1473 (unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec ));
1476 ret = sys_poll(pfds, num_pfds, timeout);
1478 if (run_events_poll(winbind_event_context(), ret,
1480 /* We got a signal - continue. */
1488 DEBUG(11,("nothing is ready yet, continue\n"));
1493 if (ret == -1 && errno == EINTR) {
1494 /* We got a signal - continue. */
1499 if (ret == -1 && errno != EINTR) {
1500 DEBUG(0,("poll error occured\n"));
1506 /* fetch a request from the main daemon */
1507 status = child_read_request(&state);
1509 if (!NT_STATUS_IS_OK(status)) {
1510 /* we lost contact with our parent */
1514 DEBUG(4,("child daemon request %d\n", (int)state.request->cmd));
1516 ZERO_STRUCTP(state.response);
1517 state.request->null_term = '\0';
1518 state.mem_ctx = frame;
1519 child_process_request(child, &state);
1521 DEBUG(4, ("Finished processing child request %d\n",
1522 (int)state.request->cmd));
1524 SAFE_FREE(state.request->extra_data.data);
1526 iov[0].iov_base = (void *)state.response;
1527 iov[0].iov_len = sizeof(struct winbindd_response);
1530 if (state.response->length > sizeof(struct winbindd_response)) {
1532 (void *)state.response->extra_data.data;
1533 iov[1].iov_len = state.response->length-iov[0].iov_len;
1537 DEBUG(10, ("Writing %d bytes to parent\n",
1538 (int)state.response->length));
1540 if (write_data_iov(state.sock, iov, iov_count) !=
1541 state.response->length) {
1542 DEBUG(0, ("Could not write result\n"));
1549 void winbind_msg_ip_dropped_parent(struct messaging_context *msg_ctx,
1552 struct server_id server_id,
1555 struct winbindd_child *child;
1557 winbind_msg_ip_dropped(msg_ctx, private_data, msg_type,
1561 for (child = winbindd_children; child != NULL; child = child->next) {
1562 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
1563 msg_type, data->data, data->length);