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.
34 #define DBGC_CLASS DBGC_WINBIND
36 extern BOOL override_logfile;
38 /* Read some data from a client connection */
40 static void child_read_struct_request(struct winbindd_cli_state *state)
46 memcpy(&state->request,
48 sizeof(state->c.autodetect));
50 len = read_data(state->sock,
51 (char *)&state->request + sizeof(state->c.autodetect),
52 sizeof(state->request) - sizeof(state->c.autodetect));
54 len += sizeof(state->c.autodetect);
56 if (len != sizeof(state->request)) {
57 DEBUG(len > 0 ? 0 : 3, ("Got invalid request length: %d\n", (int)len));
58 state->finished = True;
62 if (state->request.extra_len == 0) {
63 state->request.extra_data.data = NULL;
67 DEBUG(10, ("Need to read %d extra bytes\n", (int)state->request.extra_len));
69 state->request.extra_data.data =
70 SMB_MALLOC_ARRAY(char, state->request.extra_len + 1);
72 if (state->request.extra_data.data == NULL) {
73 DEBUG(0, ("malloc failed\n"));
74 state->finished = True;
78 /* Ensure null termination */
79 state->request.extra_data.data[state->request.extra_len] = '\0';
81 len = read_data(state->sock, state->request.extra_data.data,
82 state->request.extra_len);
84 if (len != state->request.extra_len) {
85 DEBUG(0, ("Could not read extra data\n"));
86 state->finished = True;
91 static void child_read_ndr_request(struct winbindd_cli_state *state)
93 size_t autodetect_len = sizeof(state->c.autodetect);
97 status = winbindd_ndr_parse_autodetect(state->mem_ctx,
99 WINBIND_MAX_LENGTH_PRIVILEGED,
101 if (!NT_STATUS_IS_OK(status)) {
102 state->finished = True;
106 len = read_data(state->sock,
107 (char *)state->c.in.packet.data + autodetect_len,
108 state->c.in.packet.length - autodetect_len);
110 if (len != state->c.in.packet.length - autodetect_len) {
111 DEBUG(0, ("Could not read the whole packet\n"));
112 state->finished = True;
117 static void child_read_request(struct winbindd_cli_state *state)
123 len = read_data(state->sock, (char *)state->c.autodetect,
124 sizeof(state->c.autodetect));
126 if (len != sizeof(state->c.autodetect)) {
127 DEBUG(len > 0 ? 0 : 3, ("Got invalid request length: %d\n", (int)len));
128 state->finished = True;
132 /* as all requests in the child are sync, we can use talloc_tos() */
133 state->mem_ctx = talloc_tos();
135 if (strncmp("WBPT", (const char *)&state->c.autodetect[4], 4) == 0) {
136 state->is_ndr = true;
137 child_read_ndr_request(state);
141 state->is_ndr = false;
142 child_read_struct_request(state);
146 * Machinery for async requests sent to children. You set up a
147 * winbindd_request, select a child to query, and issue a async_request
148 * call. When the request is completed, the callback function you specified is
149 * called back with the private pointer you gave to async_request.
152 struct winbindd_async_request {
153 struct winbindd_async_request *next, *prev;
155 struct winbindd_child *child;
158 struct winbindd_request *request;
159 struct winbindd_response *response;
161 struct winbindd_ndr_call *call;
162 void (*continuation)(void *private_data, BOOL success);
163 struct timed_event *reply_timeout_event;
164 pid_t child_pid; /* pid of the child we're waiting on. Used to detect
165 a restart of the child (child->pid != child_pid). */
169 static void async_old_main_request_sent(void *private_data, BOOL success);
170 static void async_request_sent(void *private_data, BOOL success);
171 static void async_reply_recv(void *private_data, BOOL success);
172 static void schedule_async_request(struct winbindd_child *child);
174 void async_request(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
175 struct winbindd_request *request,
176 struct winbindd_response *response,
177 void (*continuation)(void *private_data, BOOL success),
180 struct winbindd_async_request *state;
182 SMB_ASSERT(continuation != NULL);
184 state = TALLOC_P(mem_ctx, struct winbindd_async_request);
187 DEBUG(0, ("talloc failed\n"));
188 continuation(private_data, False);
192 state->mem_ctx = mem_ctx;
193 state->child = child;
194 state->continuation = continuation;
195 state->private_data = private_data;
196 state->is_ndr = false;
197 state->old.request = request;
198 state->old.response = response;
200 DLIST_ADD_END(child->requests, state, struct winbindd_async_request *);
202 schedule_async_request(child);
207 void async_ndr_call(TALLOC_CTX *mem_ctx, struct winbindd_child *child,
208 struct winbindd_ndr_call *call,
209 void (*continuation)(void *private_data, BOOL success),
212 struct winbindd_async_request *state;
215 SMB_ASSERT(continuation != NULL);
217 state = TALLOC_P(mem_ctx, struct winbindd_async_request);
220 DEBUG(0, ("talloc failed\n"));
221 continuation(private_data, False);
225 state->mem_ctx = mem_ctx;
226 state->child = child;
227 state->continuation = continuation;
228 state->private_data = private_data;
229 state->is_ndr = true;
232 status = winbindd_push_ndr_request(state->mem_ctx,
234 if (!NT_STATUS_IS_OK(status)) {
235 DEBUG(0, ("failed to push request: %s\n",
237 continuation(private_data, False);
241 DLIST_ADD_END(child->requests, state, struct winbindd_async_request *);
243 schedule_async_request(child);
248 static void async_old_main_request_sent(void *private_data, BOOL success)
250 struct winbindd_async_request *state =
251 talloc_get_type_abort(private_data, struct winbindd_async_request);
254 DEBUG(5, ("Could not send async request\n"));
256 state->old.response->length = sizeof(struct winbindd_response);
257 state->old.response->result = WINBINDD_ERROR;
258 state->continuation(state->private_data, False);
262 if (state->old.request->extra_len == 0) {
263 async_request_sent(private_data, True);
267 setup_async_write(&state->child->event,
268 state->old.request->extra_data.data,
269 state->old.request->extra_len,
270 async_request_sent, state);
273 /****************************************************************
274 Handler triggered if the child winbindd doesn't respond within
276 ****************************************************************/
278 static void async_request_timeout_handler(struct event_context *ctx,
279 struct timed_event *te,
280 const struct timeval *now,
283 struct winbindd_async_request *state =
284 talloc_get_type_abort(private_data, struct winbindd_async_request);
286 DEBUG(0,("async_request_timeout_handler: child pid %u is not responding. "
287 "Closing connection to it.\n",
290 /* Deal with the reply - set to error. */
291 async_reply_recv(private_data, False);
294 /**************************************************************
295 Common function called on both async send and recv fail.
296 Cleans up the child and schedules the next request.
297 **************************************************************/
299 static void async_request_fail(struct winbindd_async_request *state)
301 DLIST_REMOVE(state->child->requests, state);
303 TALLOC_FREE(state->reply_timeout_event);
305 SMB_ASSERT(state->child_pid != (pid_t)0);
307 /* If not already reaped, send kill signal to child. */
308 if (state->child->pid == state->child_pid) {
309 kill(state->child_pid, SIGTERM);
312 * Close the socket to the child.
314 winbind_child_died(state->child_pid);
318 state->call->out.header = state->call->in.header;
319 state->call->out.header.flags = 0;
320 state->call->out.header.flags |= WINBIND_HEADER_FLAGS_RESPONSE;
321 state->call->out.header.flags |= WINBIND_HEADER_FLAGS_ERROR;
322 state->call->ndr.result = WINBIND_STATUS_UNKNOWN_ERROR;
324 cache_cleanup_response(state->child_pid);
325 state->old.response->length = sizeof(struct winbindd_response);
326 state->old.response->result = WINBINDD_ERROR;
329 state->continuation(state->private_data, False);
332 static void async_old_request_sent(struct winbindd_async_request *state)
334 /* Request successfully sent to the child, setup the wait for reply */
336 setup_async_read(&state->child->event,
337 &state->old.response->result,
338 sizeof(state->old.response->result),
339 async_reply_recv, state);
342 static void async_ndr_reply_recv_auto(void *private_data_data, BOOL success)
344 struct winbindd_async_request *state =
345 talloc_get_type_abort(private_data_data, struct winbindd_async_request);
346 size_t autodetect_len = sizeof(state->call->autodetect);
350 DEBUG(5, ("Could not recv async response from child pid %u\n",
351 (unsigned int)state->child_pid ));
352 async_request_fail(state);
356 status = winbindd_ndr_parse_autodetect(state->mem_ctx,
358 WINBIND_MAX_LENGTH_PRIVILEGED,
360 if (!NT_STATUS_IS_OK(status)) {
361 async_request_fail(state);
365 setup_async_read(&state->child->event,
366 state->call->out.packet.data + autodetect_len,
367 state->call->out.packet.length - autodetect_len,
368 async_reply_recv, state);
371 static void async_ndr_request_sent(struct winbindd_async_request *state)
374 * Request successfully sent to the child,
375 * setup the wait for first bytes of the reply
378 setup_async_read(&state->child->event,
379 state->call->autodetect,
380 sizeof(state->call->autodetect),
381 async_ndr_reply_recv_auto, state);
384 static void async_request_sent(void *private_data_data, BOOL success)
386 struct winbindd_async_request *state =
387 talloc_get_type_abort(private_data_data, struct winbindd_async_request);
390 DEBUG(5, ("Could not send async request to child pid %u\n",
391 (unsigned int)state->child_pid ));
392 async_request_fail(state);
396 /* Request successfully sent to the child, setup the wait for reply */
399 async_ndr_request_sent(state);
401 async_old_request_sent(state);
405 * Set up a timeout of 300 seconds for the response.
406 * If we don't get it close the child socket and
410 state->reply_timeout_event = event_add_timed(winbind_event_context(),
412 timeval_current_ofs(300,0),
413 "async_request_timeout",
414 async_request_timeout_handler,
416 if (!state->reply_timeout_event) {
417 smb_panic("async_request_sent: failed to add timeout handler.\n");
421 static BOOL async_old_reply_recv(struct winbindd_async_request *state)
423 state->old.response->length = sizeof(struct winbindd_response);
425 SMB_ASSERT(cache_retrieve_response(state->child_pid,
426 state->old.response));
428 cache_cleanup_response(state->child_pid);
433 static BOOL async_ndr_reply_recv(struct winbindd_async_request *state)
437 status = winbindd_pull_ndr_response(state->mem_ctx,
439 if (!NT_STATUS_IS_OK(status)) {
443 if (state->call->ndr.result != WINBIND_STATUS_OK) {
450 static void async_reply_recv(void *private_data, BOOL success)
452 struct winbindd_async_request *state =
453 talloc_get_type_abort(private_data, struct winbindd_async_request);
456 DEBUG(5, ("Could not receive async reply from child pid %u\n",
457 (unsigned int)state->child_pid ));
459 async_request_fail(state);
463 TALLOC_FREE(state->reply_timeout_event);
464 DLIST_REMOVE(state->child->requests, state);
467 success = async_ndr_reply_recv(state);
469 success = async_old_reply_recv(state);
472 schedule_async_request(state->child);
474 state->continuation(state->private_data, success);
477 static BOOL fork_domain_child(struct winbindd_child *child);
479 static void schedule_async_request(struct winbindd_child *child)
481 struct winbindd_async_request *request = child->requests;
483 if (request == NULL) {
487 if (child->event.flags != 0) {
491 if ((child->pid == 0) && (!fork_domain_child(child))) {
492 /* Cancel all outstanding requests */
494 while (request != NULL) {
495 /* request might be free'd in the continuation */
496 struct winbindd_async_request *next = request->next;
497 request->continuation(request->private_data, False);
503 /* Now we know who we're sending to - remember the pid. */
504 request->child_pid = child->pid;
506 if (request->is_ndr) {
507 setup_async_write(&child->event, request->call->in.packet.data,
508 request->call->in.packet.length,
509 async_request_sent, request);
511 setup_async_write(&child->event, request->old.request,
512 sizeof(*request->old.request),
513 async_old_main_request_sent, request);
519 struct domain_request_state {
521 struct winbindd_domain *domain;
522 struct winbindd_request *request;
523 struct winbindd_response *response;
524 void (*continuation)(void *private_data_data, BOOL success);
525 void *private_data_data;
528 static void domain_init_recv(void *private_data_data, BOOL success);
530 void async_domain_request(TALLOC_CTX *mem_ctx,
531 struct winbindd_domain *domain,
532 struct winbindd_request *request,
533 struct winbindd_response *response,
534 void (*continuation)(void *private_data_data, BOOL success),
535 void *private_data_data)
537 struct domain_request_state *state;
539 if (domain->initialized) {
540 async_request(mem_ctx, &domain->child, request, response,
541 continuation, private_data_data);
545 state = TALLOC_P(mem_ctx, struct domain_request_state);
547 DEBUG(0, ("talloc failed\n"));
548 continuation(private_data_data, False);
552 state->mem_ctx = mem_ctx;
553 state->domain = domain;
554 state->request = request;
555 state->response = response;
556 state->continuation = continuation;
557 state->private_data_data = private_data_data;
559 init_child_connection(domain, domain_init_recv, state);
562 static void domain_init_recv(void *private_data_data, BOOL success)
564 struct domain_request_state *state =
565 talloc_get_type_abort(private_data_data, struct domain_request_state);
568 DEBUG(5, ("Domain init returned an error\n"));
569 state->continuation(state->private_data_data, False);
573 async_request(state->mem_ctx, &state->domain->child,
574 state->request, state->response,
575 state->continuation, state->private_data_data);
578 struct domain_ndr_call_state {
580 struct winbindd_domain *domain;
581 struct winbindd_ndr_call *call;
582 void (*continuation)(void *private_data_data, BOOL success);
583 void *private_data_data;
586 static void domain_ndr_init_recv(void *private_data_data, BOOL success);
588 void async_ndr_domain_call(TALLOC_CTX *mem_ctx,
589 struct winbindd_domain *domain,
590 struct winbindd_ndr_call *call,
591 void (*continuation)(void *private_data_data, BOOL success),
592 void *private_data_data)
594 struct domain_ndr_call_state *state;
596 if (domain->initialized) {
597 async_ndr_call(mem_ctx, &domain->child, call,
598 continuation, private_data_data);
602 state = TALLOC_P(mem_ctx, struct domain_ndr_call_state);
604 DEBUG(0, ("talloc failed\n"));
605 continuation(private_data_data, False);
609 state->mem_ctx = mem_ctx;
610 state->domain = domain;
612 state->continuation = continuation;
613 state->private_data_data = private_data_data;
615 init_child_connection(domain, domain_ndr_init_recv, state);
618 static void domain_ndr_init_recv(void *private_data_data, BOOL success)
620 struct domain_ndr_call_state *state =
621 talloc_get_type_abort(private_data_data, struct domain_ndr_call_state);
624 DEBUG(5, ("Domain init returned an error\n"));
625 state->continuation(state->private_data_data, False);
629 async_ndr_call(state->mem_ctx, &state->domain->child,
631 state->continuation, state->private_data_data);
634 static void recvfrom_child_old(void *private_data_data, BOOL success)
636 struct winbindd_cli_state *state =
637 talloc_get_type_abort(private_data_data, struct winbindd_cli_state);
638 enum winbindd_result result = state->response.result;
640 /* This is an optimization: The child has written directly to the
641 * response buffer. The request itself is still in pending state,
642 * state that in the result code. */
644 state->response.result = WINBINDD_PENDING;
646 if ((!success) || (result != WINBINDD_OK)) {
647 request_error(state);
654 void sendto_child(struct winbindd_cli_state *state,
655 struct winbindd_child *child)
657 async_request(state->mem_ctx, child, &state->request,
658 &state->response, recvfrom_child, state);
661 void sendto_domain(struct winbindd_cli_state *state,
662 struct winbindd_domain *domain)
664 async_domain_request(state->mem_ctx, domain,
665 &state->request, &state->response,
666 recvfrom_child, state);
669 const struct winbindd_child_dispatch_table domain_dispatch_table[] = {
671 { WINBINDD_LOOKUPSID, winbindd_dual_lookupsid, "LOOKUPSID" },
672 { WINBINDD_LOOKUPNAME, winbindd_dual_lookupname, "LOOKUPNAME" },
673 { WINBINDD_LOOKUPRIDS, winbindd_dual_lookuprids, "LOOKUPRIDS" },
674 { WINBINDD_LIST_TRUSTDOM, winbindd_dual_list_trusted_domains, "LIST_TRUSTDOM" },
675 { WINBINDD_INIT_CONNECTION, winbindd_dual_init_connection, "INIT_CONNECTION" },
676 { WINBINDD_GETDCNAME, winbindd_dual_getdcname, "GETDCNAME" },
677 { WINBINDD_SHOW_SEQUENCE, winbindd_dual_show_sequence, "SHOW_SEQUENCE" },
678 { WINBINDD_PAM_AUTH, winbindd_dual_pam_auth, "PAM_AUTH" },
679 { WINBINDD_PAM_AUTH_CRAP, winbindd_dual_pam_auth_crap, "AUTH_CRAP" },
680 { WINBINDD_PAM_LOGOFF, winbindd_dual_pam_logoff, "PAM_LOGOFF" },
681 { WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP,winbindd_dual_pam_chng_pswd_auth_crap,"CHNG_PSWD_AUTH_CRAP" },
682 { WINBINDD_PAM_CHAUTHTOK, winbindd_dual_pam_chauthtok, "PAM_CHAUTHTOK" },
683 { WINBINDD_CHECK_MACHACC, winbindd_dual_check_machine_acct, "CHECK_MACHACC" },
684 { WINBINDD_DUAL_USERINFO, winbindd_dual_userinfo, "DUAL_USERINFO" },
685 { WINBINDD_GETUSERDOMGROUPS, winbindd_dual_getuserdomgroups, "GETUSERDOMGROUPS" },
686 { WINBINDD_DUAL_GETSIDALIASES, winbindd_dual_getsidaliases, "GETSIDALIASES" },
687 { WINBINDD_CCACHE_NTLMAUTH, winbindd_dual_ccache_ntlm_auth, "CCACHE_NTLM_AUTH" },
690 { WINBINDD_NUM_CMDS, NULL, "NONE" }
693 static void child_process_struct_request(struct winbindd_child *child,
694 struct winbindd_cli_state *state)
696 struct winbindd_domain *domain = child->domain;
697 const struct winbindd_child_dispatch_table *table = child->table;
699 DEBUG(4,("child daemon request %d\n", (int)state->request.cmd));
701 ZERO_STRUCT(state->response);
702 state->request.null_term = '\0';
704 /* Free response data - we may be interrupted and receive another
705 command before being able to send this data off. */
707 state->response.result = WINBINDD_ERROR;
708 state->response.length = sizeof(struct winbindd_response);
710 /* Process command */
712 for (; table->fn; table++) {
713 if (state->request.cmd == table->cmd) {
714 DEBUG(10,("process_request: request fn %s\n",
715 table->winbindd_cmd_name ));
716 state->response.result = table->fn(domain, state);
722 DEBUG(1 ,("child_process_request: unknown request fn number %d\n",
723 (int)state->request.cmd ));
724 state->response.result = WINBINDD_ERROR;
728 void setup_domain_child(struct winbindd_domain *domain,
729 struct winbindd_child *child,
730 const struct winbindd_child_dispatch_table *table,
731 const char *explicit_logfile)
733 if (explicit_logfile != NULL) {
734 pstr_sprintf(child->logfilename, "%s/log.winbindd-%s",
735 dyn_LOGFILEBASE, explicit_logfile);
736 } else if (domain != NULL) {
737 pstr_sprintf(child->logfilename, "%s/log.wb-%s",
738 dyn_LOGFILEBASE, domain->name);
740 smb_panic("Internal error: domain == NULL && "
741 "explicit_logfile == NULL");
744 child->domain = domain;
745 child->table = table;
748 struct winbindd_child *children = NULL;
750 void winbind_child_died(pid_t pid)
752 struct winbindd_child *child;
754 for (child = children; child != NULL; child = child->next) {
755 if (child->pid == pid) {
761 DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
765 remove_fd_event(&child->event);
766 close(child->event.fd);
768 child->event.flags = 0;
771 schedule_async_request(child);
774 /* Ensure any negative cache entries with the netbios or realm names are removed. */
776 void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
778 flush_negative_conn_cache_for_domain(domain->name);
779 if (*domain->alt_name) {
780 flush_negative_conn_cache_for_domain(domain->alt_name);
784 /* Set our domains as offline and forward the offline message to our children. */
786 void winbind_msg_offline(struct messaging_context *msg_ctx,
789 struct server_id server_id,
792 struct winbindd_child *child;
793 struct winbindd_domain *domain;
795 DEBUG(10,("winbind_msg_offline: got offline message.\n"));
797 if (!lp_winbind_offline_logon()) {
798 DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
802 /* Set our global state as offline. */
803 if (!set_global_winbindd_state_offline()) {
804 DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
808 /* Set all our domains as offline. */
809 for (domain = domain_list(); domain; domain = domain->next) {
810 if (domain->internal) {
813 DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
814 set_domain_offline(domain);
817 for (child = children; child != NULL; child = child->next) {
818 /* Don't send message to internal childs. We've already
820 if (!child->domain || winbindd_internal_child(child)) {
824 /* Or internal domains (this should not be possible....) */
825 if (child->domain->internal) {
829 /* Each winbindd child should only process requests for one domain - make sure
830 we only set it online / offline for that domain. */
832 DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
833 (unsigned int)child->pid, domain->name ));
835 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
837 (uint8 *)child->domain->name,
838 strlen(child->domain->name)+1);
842 /* Set our domains as online and forward the online message to our children. */
844 void winbind_msg_online(struct messaging_context *msg_ctx,
847 struct server_id server_id,
850 struct winbindd_child *child;
851 struct winbindd_domain *domain;
853 DEBUG(10,("winbind_msg_online: got online message.\n"));
855 if (!lp_winbind_offline_logon()) {
856 DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
860 /* Set our global state as online. */
861 set_global_winbindd_state_online();
863 smb_nscd_flush_user_cache();
864 smb_nscd_flush_group_cache();
866 /* Set all our domains as online. */
867 for (domain = domain_list(); domain; domain = domain->next) {
868 if (domain->internal) {
871 DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain->name));
873 winbindd_flush_negative_conn_cache(domain);
874 set_domain_online_request(domain);
876 /* Send an online message to the idmap child when our
877 primary domain comes back online */
879 if ( domain->primary ) {
880 struct winbindd_child *idmap = idmap_child();
882 if ( idmap->pid != 0 ) {
883 messaging_send_buf(msg_ctx,
884 pid_to_procid(idmap->pid),
886 (uint8 *)domain->name,
887 strlen(domain->name)+1);
893 for (child = children; child != NULL; child = child->next) {
894 /* Don't send message to internal childs. */
895 if (!child->domain || winbindd_internal_child(child)) {
899 /* Or internal domains (this should not be possible....) */
900 if (child->domain->internal) {
904 /* Each winbindd child should only process requests for one domain - make sure
905 we only set it online / offline for that domain. */
907 DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n",
908 (unsigned int)child->pid, child->domain->name ));
910 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
912 (uint8 *)child->domain->name,
913 strlen(child->domain->name)+1);
917 /* Forward the online/offline messages to our children. */
918 void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
921 struct server_id server_id,
924 struct winbindd_child *child;
926 DEBUG(10,("winbind_msg_onlinestatus: got onlinestatus message.\n"));
928 for (child = children; child != NULL; child = child->next) {
929 if (child->domain && child->domain->primary) {
930 DEBUG(10,("winbind_msg_onlinestatus: "
931 "sending message to pid %u of primary domain.\n",
932 (unsigned int)child->pid));
933 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
934 MSG_WINBIND_ONLINESTATUS,
942 void winbind_msg_dump_event_list(struct messaging_context *msg_ctx,
945 struct server_id server_id,
948 struct winbindd_child *child;
950 DEBUG(10,("winbind_msg_dump_event_list received\n"));
952 dump_event_list(winbind_event_context());
954 for (child = children; child != NULL; child = child->next) {
956 DEBUG(10,("winbind_msg_dump_event_list: sending message to pid %u\n",
957 (unsigned int)child->pid));
959 messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
966 static void account_lockout_policy_handler(struct event_context *ctx,
967 struct timed_event *te,
968 const struct timeval *now,
971 struct winbindd_child *child =
972 (struct winbindd_child *)private_data;
973 TALLOC_CTX *mem_ctx = NULL;
974 struct winbindd_methods *methods;
975 SAM_UNK_INFO_12 lockout_policy;
978 DEBUG(10,("account_lockout_policy_handler called\n"));
980 TALLOC_FREE(child->lockout_policy_event);
982 if ( !winbindd_can_contact_domain( child->domain ) ) {
983 DEBUG(10,("account_lockout_policy_handler: Removing myself since I "
984 "do not have an incoming trust to domain %s\n",
985 child->domain->name));
990 methods = child->domain->methods;
992 mem_ctx = talloc_init("account_lockout_policy_handler ctx");
994 result = NT_STATUS_NO_MEMORY;
996 result = methods->lockout_policy(child->domain, mem_ctx, &lockout_policy);
998 TALLOC_FREE(mem_ctx);
1000 if (!NT_STATUS_IS_OK(result)) {
1001 DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
1002 nt_errstr(result)));
1005 child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL,
1006 timeval_current_ofs(3600, 0),
1007 "account_lockout_policy_handler",
1008 account_lockout_policy_handler,
1012 /* Deal with a request to go offline. */
1014 static void child_msg_offline(struct messaging_context *msg,
1017 struct server_id server_id,
1020 struct winbindd_domain *domain;
1021 const char *domainname = (const char *)data->data;
1023 if (data->data == NULL || data->length == 0) {
1027 DEBUG(5,("child_msg_offline received for domain %s.\n", domainname));
1029 if (!lp_winbind_offline_logon()) {
1030 DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
1034 /* Mark the requested domain offline. */
1036 for (domain = domain_list(); domain; domain = domain->next) {
1037 if (domain->internal) {
1040 if (strequal(domain->name, domainname)) {
1041 DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name));
1042 set_domain_offline(domain);
1047 /* Deal with a request to go online. */
1049 static void child_msg_online(struct messaging_context *msg,
1052 struct server_id server_id,
1055 struct winbindd_domain *domain;
1056 const char *domainname = (const char *)data->data;
1058 if (data->data == NULL || data->length == 0) {
1062 DEBUG(5,("child_msg_online received for domain %s.\n", domainname));
1064 if (!lp_winbind_offline_logon()) {
1065 DEBUG(10,("child_msg_online: rejecting online message.\n"));
1069 /* Set our global state as online. */
1070 set_global_winbindd_state_online();
1072 /* Try and mark everything online - delete any negative cache entries
1073 to force a reconnect now. */
1075 for (domain = domain_list(); domain; domain = domain->next) {
1076 if (domain->internal) {
1079 if (strequal(domain->name, domainname)) {
1080 DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name));
1081 winbindd_flush_negative_conn_cache(domain);
1082 set_domain_online_request(domain);
1087 static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
1089 struct winbindd_domain *domain;
1092 if ((buf = talloc_asprintf(mem_ctx, "global:%s ",
1093 get_global_winbindd_state_offline() ?
1094 "Offline":"Online")) == NULL) {
1098 for (domain = domain_list(); domain; domain = domain->next) {
1099 if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ",
1102 "Online":"Offline")) == NULL) {
1107 buf = talloc_asprintf_append_buffer(buf, "\n");
1109 DEBUG(5,("collect_onlinestatus: %s", buf));
1114 static void child_msg_onlinestatus(struct messaging_context *msg_ctx,
1117 struct server_id server_id,
1120 TALLOC_CTX *mem_ctx;
1121 const char *message;
1122 struct server_id *sender;
1124 DEBUG(5,("winbind_msg_onlinestatus received.\n"));
1130 sender = (struct server_id *)data->data;
1132 mem_ctx = talloc_init("winbind_msg_onlinestatus");
1133 if (mem_ctx == NULL) {
1137 message = collect_onlinestatus(mem_ctx);
1138 if (message == NULL) {
1139 talloc_destroy(mem_ctx);
1143 messaging_send_buf(msg_ctx, *sender, MSG_WINBIND_ONLINESTATUS,
1144 (uint8 *)message, strlen(message) + 1);
1146 talloc_destroy(mem_ctx);
1149 static void child_msg_dump_event_list(struct messaging_context *msg,
1152 struct server_id server_id,
1155 DEBUG(5,("child_msg_dump_event_list received\n"));
1157 dump_event_list(winbind_event_context());
1160 static const struct winbind_ndr_cmd {
1162 void (*fn)(struct winbindd_domain *domain,
1163 struct winbindd_cli_state *state);
1164 } ndr_child_cmd_table[] = {
1167 static void child_reply_ndr_error(struct winbindd_cli_state *state,
1168 enum winbind_status result)
1172 state->c.ndr.result = result;
1174 status = winbindd_push_ndr_response(state->mem_ctx, &state->c);
1175 if (!NT_STATUS_IS_OK(status)) {
1176 DEBUG(1,("child_reply_ndr_error: "
1177 "failed to pull request structure: %s\n",
1178 nt_errstr(status)));
1182 if (write_data(state->sock,
1183 (const char *)state->c.out.packet.data,
1184 state->c.out.packet.length) !=
1185 state->c.out.packet.length) {
1186 DEBUG(1,("child_reply_ndr_error: "
1187 "Could not write ndr result\n"));
1192 static void child_process_ndr_request(struct winbindd_domain *domain,
1193 struct winbindd_cli_state *state)
1198 status = winbindd_pull_ndr_request(state->mem_ctx, &state->c);
1199 if (!NT_STATUS_IS_OK(status)) {
1200 DEBUG(1,("child_process_ndr_request: "
1201 "failed to pull request structure: %s\n",
1202 nt_errstr(status)));
1206 for (i=0; i < ARRAY_SIZE(ndr_child_cmd_table); i++) {
1207 if (ndr_child_cmd_table[i].opnum == state->c.in.header.opnum) {
1208 ndr_child_cmd_table[i].fn(domain, state);
1209 child_reply_ndr_error(state, WINBIND_STATUS_OK);
1214 child_reply_ndr_error(state, WINBIND_STATUS_NOT_IMPLEMENTED);
1217 static void child_process_request(struct winbindd_domain *domain,
1218 struct winbindd_cli_state *state)
1220 if (state->is_ndr) {
1221 child_process_ndr_request(domain, state);
1225 child_process_struct_request(domain, state);
1227 SAFE_FREE(state->request.extra_data.data);
1229 cache_store_response(sys_getpid(), &state->response);
1231 SAFE_FREE(state->response.extra_data.data);
1233 /* We just send the result code back, the result
1234 * structure needs to be fetched via the
1235 * winbindd_cache. Hmm. That needs fixing... */
1237 if (write_data(state->sock,
1238 (const char *)&state->response.result,
1239 sizeof(state->response.result)) !=
1240 sizeof(state->response.result)) {
1241 DEBUG(0, ("Could not write result\n"));
1246 static BOOL fork_domain_child(struct winbindd_child *child)
1249 struct winbindd_cli_state state;
1250 struct winbindd_domain *domain;
1252 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) {
1253 DEBUG(0, ("Could not open child pipe: %s\n",
1259 state.pid = sys_getpid();
1264 child->pid = sys_fork();
1266 if (child->pid == -1) {
1267 DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
1271 if (child->pid != 0) {
1274 child->next = child->prev = NULL;
1275 DLIST_ADD(children, child);
1276 child->event.fd = fdpair[1];
1277 child->event.flags = 0;
1278 child->requests = NULL;
1279 add_fd_event(&child->event);
1285 state.sock = fdpair[0];
1288 /* tdb needs special fork handling */
1289 if (tdb_reopen_all(1) == -1) {
1290 DEBUG(0,("tdb_reopen_all failed.\n"));
1294 close_conns_after_fork();
1296 if (!override_logfile) {
1297 lp_set_logfile(child->logfilename);
1302 * For clustering, we need to re-init our ctdbd connection after the
1305 if (!NT_STATUS_IS_OK(messaging_reinit(winbind_messaging_context())))
1308 /* Don't handle the same messages as our parent. */
1309 messaging_deregister(winbind_messaging_context(),
1310 MSG_SMB_CONF_UPDATED, NULL);
1311 messaging_deregister(winbind_messaging_context(),
1312 MSG_SHUTDOWN, NULL);
1313 messaging_deregister(winbind_messaging_context(),
1314 MSG_WINBIND_OFFLINE, NULL);
1315 messaging_deregister(winbind_messaging_context(),
1316 MSG_WINBIND_ONLINE, NULL);
1317 messaging_deregister(winbind_messaging_context(),
1318 MSG_WINBIND_ONLINESTATUS, NULL);
1319 messaging_deregister(winbind_messaging_context(),
1320 MSG_DUMP_EVENT_LIST, NULL);
1322 /* Handle online/offline messages. */
1323 messaging_register(winbind_messaging_context(), NULL,
1324 MSG_WINBIND_OFFLINE, child_msg_offline);
1325 messaging_register(winbind_messaging_context(), NULL,
1326 MSG_WINBIND_ONLINE, child_msg_online);
1327 messaging_register(winbind_messaging_context(), NULL,
1328 MSG_WINBIND_ONLINESTATUS, child_msg_onlinestatus);
1329 messaging_register(winbind_messaging_context(), NULL,
1330 MSG_DUMP_EVENT_LIST, child_msg_dump_event_list);
1332 if ( child->domain ) {
1333 child->domain->startup = True;
1334 child->domain->startup_time = time(NULL);
1337 /* Ensure we have no pending check_online events other
1338 than one for this domain. */
1340 for (domain = domain_list(); domain; domain = domain->next) {
1341 if (domain != child->domain) {
1342 TALLOC_FREE(domain->check_online_event);
1346 /* Ensure we're not handling an event inherited from
1349 cancel_named_event(winbind_event_context(),
1350 "krb5_ticket_refresh_handler");
1352 /* We might be in the idmap child...*/
1353 if (child->domain && !(child->domain->internal) &&
1354 lp_winbind_offline_logon()) {
1356 set_domain_online_request(child->domain);
1358 child->lockout_policy_event = event_add_timed(
1359 winbind_event_context(), NULL, timeval_zero(),
1360 "account_lockout_policy_handler",
1361 account_lockout_policy_handler,
1372 TALLOC_CTX *frame = talloc_stackframe();
1374 run_events(winbind_event_context(), 0, NULL, NULL);
1378 if (child->domain && child->domain->startup &&
1379 (now.tv_sec > child->domain->startup_time + 30)) {
1380 /* No longer in "startup" mode. */
1381 DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
1382 child->domain->name ));
1383 child->domain->startup = False;
1386 tp = get_timed_events_timeout(winbind_event_context(), &t);
1388 DEBUG(11,("select will use timeout of %u.%u seconds\n",
1389 (unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec ));
1392 /* Handle messages */
1394 message_dispatch(winbind_messaging_context());
1397 FD_SET(state.sock, &read_fds);
1399 ret = sys_select(state.sock + 1, &read_fds, NULL, NULL, tp);
1402 DEBUG(11,("nothing is ready yet, continue\n"));
1407 if (ret == -1 && errno == EINTR) {
1408 /* We got a signal - continue. */
1413 if (ret == -1 && errno != EINTR) {
1414 DEBUG(0,("select error occured\n"));
1420 /* fetch a request from the main daemon */
1421 child_read_request(&state);
1423 if (state.finished) {
1424 /* we lost contact with our parent */
1428 child_process_request(child, &state);