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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 * We fork a child per domain to be able to act non-blocking in the main
26 * winbind daemon. A domain controller thousands of miles away being being
27 * slow replying with a 10.000 user list should not hold up netlogon calls
28 * that can be handled locally.
35 #define DBGC_CLASS DBGC_WINBIND
37 extern BOOL override_logfile
;
39 /* Read some data from a client connection */
41 static void child_read_request(struct winbindd_cli_state
*state
)
47 len
= read_data(state
->sock
, (char *)&state
->request
,
48 sizeof(state
->request
));
50 if (len
!= sizeof(state
->request
)) {
51 DEBUG(len
> 0 ? 0 : 3, ("Got invalid request length: %d\n", (int)len
));
52 state
->finished
= True
;
56 if (state
->request
.extra_len
== 0) {
57 state
->request
.extra_data
.data
= NULL
;
61 DEBUG(10, ("Need to read %d extra bytes\n", (int)state
->request
.extra_len
));
63 state
->request
.extra_data
.data
=
64 SMB_MALLOC_ARRAY(char, state
->request
.extra_len
+ 1);
66 if (state
->request
.extra_data
.data
== NULL
) {
67 DEBUG(0, ("malloc failed\n"));
68 state
->finished
= True
;
72 /* Ensure null termination */
73 state
->request
.extra_data
.data
[state
->request
.extra_len
] = '\0';
75 len
= read_data(state
->sock
, state
->request
.extra_data
.data
,
76 state
->request
.extra_len
);
78 if (len
!= state
->request
.extra_len
) {
79 DEBUG(0, ("Could not read extra data\n"));
80 state
->finished
= True
;
86 * Machinery for async requests sent to children. You set up a
87 * winbindd_request, select a child to query, and issue a async_request
88 * call. When the request is completed, the callback function you specified is
89 * called back with the private pointer you gave to async_request.
92 struct winbindd_async_request
{
93 struct winbindd_async_request
*next
, *prev
;
95 struct winbindd_child
*child
;
96 struct winbindd_request
*request
;
97 struct winbindd_response
*response
;
98 void (*continuation
)(void *private_data
, BOOL success
);
99 struct timed_event
*reply_timeout_event
;
100 pid_t child_pid
; /* pid of the child we're waiting on. Used to detect
101 a restart of the child (child->pid != child_pid). */
105 static void async_main_request_sent(void *private_data
, BOOL success
);
106 static void async_request_sent(void *private_data
, BOOL success
);
107 static void async_reply_recv(void *private_data
, BOOL success
);
108 static void schedule_async_request(struct winbindd_child
*child
);
110 void async_request(TALLOC_CTX
*mem_ctx
, struct winbindd_child
*child
,
111 struct winbindd_request
*request
,
112 struct winbindd_response
*response
,
113 void (*continuation
)(void *private_data
, BOOL success
),
116 struct winbindd_async_request
*state
;
118 SMB_ASSERT(continuation
!= NULL
);
120 state
= TALLOC_P(mem_ctx
, struct winbindd_async_request
);
123 DEBUG(0, ("talloc failed\n"));
124 continuation(private_data
, False
);
128 state
->mem_ctx
= mem_ctx
;
129 state
->child
= child
;
130 state
->request
= request
;
131 state
->response
= response
;
132 state
->continuation
= continuation
;
133 state
->private_data
= private_data
;
135 DLIST_ADD_END(child
->requests
, state
, struct winbindd_async_request
*);
137 schedule_async_request(child
);
142 static void async_main_request_sent(void *private_data
, BOOL success
)
144 struct winbindd_async_request
*state
=
145 talloc_get_type_abort(private_data
, struct winbindd_async_request
);
148 DEBUG(5, ("Could not send async request\n"));
150 state
->response
->length
= sizeof(struct winbindd_response
);
151 state
->response
->result
= WINBINDD_ERROR
;
152 state
->continuation(state
->private_data
, False
);
156 if (state
->request
->extra_len
== 0) {
157 async_request_sent(private_data
, True
);
161 setup_async_write(&state
->child
->event
, state
->request
->extra_data
.data
,
162 state
->request
->extra_len
,
163 async_request_sent
, state
);
166 /****************************************************************
167 Handler triggered if the child winbindd doesn't respond within
169 ****************************************************************/
171 static void async_request_timeout_handler(struct event_context
*ctx
,
172 struct timed_event
*te
,
173 const struct timeval
*now
,
176 struct winbindd_async_request
*state
=
177 talloc_get_type_abort(private_data
, struct winbindd_async_request
);
179 DEBUG(0,("async_request_timeout_handler: child pid %u is not responding. "
180 "Closing connection to it.\n",
183 /* Deal with the reply - set to error. */
184 async_reply_recv(private_data
, False
);
187 /**************************************************************
188 Common function called on both async send and recv fail.
189 Cleans up the child and schedules the next request.
190 **************************************************************/
192 static void async_request_fail(struct winbindd_async_request
*state
)
194 DLIST_REMOVE(state
->child
->requests
, state
);
196 TALLOC_FREE(state
->reply_timeout_event
);
198 SMB_ASSERT(state
->child_pid
!= (pid_t
)0);
200 /* If not already reaped, send kill signal to child. */
201 if (state
->child
->pid
== state
->child_pid
) {
202 kill(state
->child_pid
, SIGTERM
);
205 * Close the socket to the child.
207 winbind_child_died(state
->child_pid
);
210 state
->response
->length
= sizeof(struct winbindd_response
);
211 state
->response
->result
= WINBINDD_ERROR
;
212 state
->continuation(state
->private_data
, False
);
215 static void async_request_sent(void *private_data_data
, BOOL success
)
217 struct winbindd_async_request
*state
=
218 talloc_get_type_abort(private_data_data
, struct winbindd_async_request
);
221 DEBUG(5, ("Could not send async request to child pid %u\n",
222 (unsigned int)state
->child_pid
));
223 async_request_fail(state
);
227 /* Request successfully sent to the child, setup the wait for reply */
229 setup_async_read(&state
->child
->event
,
230 &state
->response
->result
,
231 sizeof(state
->response
->result
),
232 async_reply_recv
, state
);
235 * Set up a timeout of 300 seconds for the response.
236 * If we don't get it close the child socket and
240 state
->reply_timeout_event
= event_add_timed(winbind_event_context(),
242 timeval_current_ofs(300,0),
243 "async_request_timeout",
244 async_request_timeout_handler
,
246 if (!state
->reply_timeout_event
) {
247 smb_panic("async_request_sent: failed to add timeout handler.\n");
251 static void async_reply_recv(void *private_data
, BOOL success
)
253 struct winbindd_async_request
*state
=
254 talloc_get_type_abort(private_data
, struct winbindd_async_request
);
255 struct winbindd_child
*child
= state
->child
;
257 TALLOC_FREE(state
->reply_timeout_event
);
259 state
->response
->length
= sizeof(struct winbindd_response
);
262 DEBUG(5, ("Could not receive async reply from child pid %u\n",
263 (unsigned int)state
->child_pid
));
265 cache_cleanup_response(state
->child_pid
);
266 async_request_fail(state
);
270 SMB_ASSERT(cache_retrieve_response(state
->child_pid
,
273 cache_cleanup_response(state
->child_pid
);
275 DLIST_REMOVE(child
->requests
, state
);
277 schedule_async_request(child
);
279 state
->continuation(state
->private_data
, True
);
282 static BOOL
fork_domain_child(struct winbindd_child
*child
);
284 static void schedule_async_request(struct winbindd_child
*child
)
286 struct winbindd_async_request
*request
= child
->requests
;
288 if (request
== NULL
) {
292 if (child
->event
.flags
!= 0) {
296 if ((child
->pid
== 0) && (!fork_domain_child(child
))) {
297 /* Cancel all outstanding requests */
299 while (request
!= NULL
) {
300 /* request might be free'd in the continuation */
301 struct winbindd_async_request
*next
= request
->next
;
302 request
->continuation(request
->private_data
, False
);
308 /* Now we know who we're sending to - remember the pid. */
309 request
->child_pid
= child
->pid
;
311 setup_async_write(&child
->event
, request
->request
,
312 sizeof(*request
->request
),
313 async_main_request_sent
, request
);
318 struct domain_request_state
{
320 struct winbindd_domain
*domain
;
321 struct winbindd_request
*request
;
322 struct winbindd_response
*response
;
323 void (*continuation
)(void *private_data_data
, BOOL success
);
324 void *private_data_data
;
327 static void domain_init_recv(void *private_data_data
, BOOL success
);
329 void async_domain_request(TALLOC_CTX
*mem_ctx
,
330 struct winbindd_domain
*domain
,
331 struct winbindd_request
*request
,
332 struct winbindd_response
*response
,
333 void (*continuation
)(void *private_data_data
, BOOL success
),
334 void *private_data_data
)
336 struct domain_request_state
*state
;
338 if (domain
->initialized
) {
339 async_request(mem_ctx
, &domain
->child
, request
, response
,
340 continuation
, private_data_data
);
344 state
= TALLOC_P(mem_ctx
, struct domain_request_state
);
346 DEBUG(0, ("talloc failed\n"));
347 continuation(private_data_data
, False
);
351 state
->mem_ctx
= mem_ctx
;
352 state
->domain
= domain
;
353 state
->request
= request
;
354 state
->response
= response
;
355 state
->continuation
= continuation
;
356 state
->private_data_data
= private_data_data
;
358 init_child_connection(domain
, domain_init_recv
, state
);
361 static void recvfrom_child(void *private_data_data
, BOOL success
)
363 struct winbindd_cli_state
*state
=
364 talloc_get_type_abort(private_data_data
, struct winbindd_cli_state
);
365 enum winbindd_result result
= state
->response
.result
;
367 /* This is an optimization: The child has written directly to the
368 * response buffer. The request itself is still in pending state,
369 * state that in the result code. */
371 state
->response
.result
= WINBINDD_PENDING
;
373 if ((!success
) || (result
!= WINBINDD_OK
)) {
374 request_error(state
);
381 void sendto_child(struct winbindd_cli_state
*state
,
382 struct winbindd_child
*child
)
384 async_request(state
->mem_ctx
, child
, &state
->request
,
385 &state
->response
, recvfrom_child
, state
);
388 void sendto_domain(struct winbindd_cli_state
*state
,
389 struct winbindd_domain
*domain
)
391 async_domain_request(state
->mem_ctx
, domain
,
392 &state
->request
, &state
->response
,
393 recvfrom_child
, state
);
396 static void domain_init_recv(void *private_data_data
, BOOL success
)
398 struct domain_request_state
*state
=
399 talloc_get_type_abort(private_data_data
, struct domain_request_state
);
402 DEBUG(5, ("Domain init returned an error\n"));
403 state
->continuation(state
->private_data_data
, False
);
407 async_request(state
->mem_ctx
, &state
->domain
->child
,
408 state
->request
, state
->response
,
409 state
->continuation
, state
->private_data_data
);
412 struct winbindd_child_dispatch_table
{
413 enum winbindd_cmd cmd
;
414 enum winbindd_result (*fn
)(struct winbindd_domain
*domain
,
415 struct winbindd_cli_state
*state
);
416 const char *winbindd_cmd_name
;
419 static struct winbindd_child_dispatch_table child_dispatch_table
[] = {
421 { WINBINDD_LOOKUPSID
, winbindd_dual_lookupsid
, "LOOKUPSID" },
422 { WINBINDD_LOOKUPNAME
, winbindd_dual_lookupname
, "LOOKUPNAME" },
423 { WINBINDD_LOOKUPRIDS
, winbindd_dual_lookuprids
, "LOOKUPRIDS" },
424 { WINBINDD_LIST_TRUSTDOM
, winbindd_dual_list_trusted_domains
, "LIST_TRUSTDOM" },
425 { WINBINDD_INIT_CONNECTION
, winbindd_dual_init_connection
, "INIT_CONNECTION" },
426 { WINBINDD_GETDCNAME
, winbindd_dual_getdcname
, "GETDCNAME" },
427 { WINBINDD_SHOW_SEQUENCE
, winbindd_dual_show_sequence
, "SHOW_SEQUENCE" },
428 { WINBINDD_PAM_AUTH
, winbindd_dual_pam_auth
, "PAM_AUTH" },
429 { WINBINDD_PAM_AUTH_CRAP
, winbindd_dual_pam_auth_crap
, "AUTH_CRAP" },
430 { WINBINDD_PAM_LOGOFF
, winbindd_dual_pam_logoff
, "PAM_LOGOFF" },
431 { WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
,winbindd_dual_pam_chng_pswd_auth_crap
,"CHNG_PSWD_AUTH_CRAP" },
432 { WINBINDD_PAM_CHAUTHTOK
, winbindd_dual_pam_chauthtok
, "PAM_CHAUTHTOK" },
433 { WINBINDD_CHECK_MACHACC
, winbindd_dual_check_machine_acct
, "CHECK_MACHACC" },
434 { WINBINDD_DUAL_SID2UID
, winbindd_dual_sid2uid
, "DUAL_SID2UID" },
435 { WINBINDD_DUAL_SID2GID
, winbindd_dual_sid2gid
, "DUAL_SID2GID" },
436 #if 0 /* DISABLED until we fix the interface in Samba 3.0.26 --jerry */
437 { WINBINDD_DUAL_SIDS2XIDS
, winbindd_dual_sids2xids
, "DUAL_SIDS2XIDS" },
438 #endif /* end DISABLED */
439 { WINBINDD_DUAL_UID2SID
, winbindd_dual_uid2sid
, "DUAL_UID2SID" },
440 { WINBINDD_DUAL_GID2SID
, winbindd_dual_gid2sid
, "DUAL_GID2SID" },
441 { WINBINDD_DUAL_UID2NAME
, winbindd_dual_uid2name
, "DUAL_UID2NAME" },
442 { WINBINDD_DUAL_NAME2UID
, winbindd_dual_name2uid
, "DUAL_NAME2UID" },
443 { WINBINDD_DUAL_GID2NAME
, winbindd_dual_gid2name
, "DUAL_GID2NAME" },
444 { WINBINDD_DUAL_NAME2GID
, winbindd_dual_name2gid
, "DUAL_NAME2GID" },
445 { WINBINDD_DUAL_SET_MAPPING
, winbindd_dual_set_mapping
, "DUAL_SET_MAPPING" },
446 { WINBINDD_DUAL_SET_HWM
, winbindd_dual_set_hwm
, "DUAL_SET_HWMS" },
447 { WINBINDD_DUAL_DUMP_MAPS
, winbindd_dual_dump_maps
, "DUAL_DUMP_MAPS" },
448 { WINBINDD_DUAL_USERINFO
, winbindd_dual_userinfo
, "DUAL_USERINFO" },
449 { WINBINDD_ALLOCATE_UID
, winbindd_dual_allocate_uid
, "ALLOCATE_UID" },
450 { WINBINDD_ALLOCATE_GID
, winbindd_dual_allocate_gid
, "ALLOCATE_GID" },
451 { WINBINDD_GETUSERDOMGROUPS
, winbindd_dual_getuserdomgroups
, "GETUSERDOMGROUPS" },
452 { WINBINDD_DUAL_GETSIDALIASES
, winbindd_dual_getsidaliases
, "GETSIDALIASES" },
453 { WINBINDD_CCACHE_NTLMAUTH
, winbindd_dual_ccache_ntlm_auth
, "CCACHE_NTLM_AUTH" },
456 { WINBINDD_NUM_CMDS
, NULL
, "NONE" }
459 static void child_process_request(struct winbindd_domain
*domain
,
460 struct winbindd_cli_state
*state
)
462 struct winbindd_child_dispatch_table
*table
;
464 /* Free response data - we may be interrupted and receive another
465 command before being able to send this data off. */
467 state
->response
.result
= WINBINDD_ERROR
;
468 state
->response
.length
= sizeof(struct winbindd_response
);
470 state
->mem_ctx
= talloc_init("winbind request");
471 if (state
->mem_ctx
== NULL
)
474 /* Process command */
476 for (table
= child_dispatch_table
; table
->fn
; table
++) {
477 if (state
->request
.cmd
== table
->cmd
) {
478 DEBUG(10,("process_request: request fn %s\n",
479 table
->winbindd_cmd_name
));
480 state
->response
.result
= table
->fn(domain
, state
);
486 DEBUG(10,("process_request: unknown request fn number %d\n",
487 (int)state
->request
.cmd
));
488 state
->response
.result
= WINBINDD_ERROR
;
491 talloc_destroy(state
->mem_ctx
);
494 void setup_domain_child(struct winbindd_domain
*domain
,
495 struct winbindd_child
*child
,
496 const char *explicit_logfile
)
498 if (explicit_logfile
!= NULL
) {
499 pstr_sprintf(child
->logfilename
, "%s/log.winbindd-%s",
500 dyn_LOGFILEBASE
, explicit_logfile
);
501 } else if (domain
!= NULL
) {
502 pstr_sprintf(child
->logfilename
, "%s/log.wb-%s",
503 dyn_LOGFILEBASE
, domain
->name
);
505 smb_panic("Internal error: domain == NULL && "
506 "explicit_logfile == NULL");
509 child
->domain
= domain
;
512 struct winbindd_child
*children
= NULL
;
514 void winbind_child_died(pid_t pid
)
516 struct winbindd_child
*child
;
518 for (child
= children
; child
!= NULL
; child
= child
->next
) {
519 if (child
->pid
== pid
) {
525 DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid
));
529 remove_fd_event(&child
->event
);
530 close(child
->event
.fd
);
532 child
->event
.flags
= 0;
535 schedule_async_request(child
);
538 /* Ensure any negative cache entries with the netbios or realm names are removed. */
540 void winbindd_flush_negative_conn_cache(struct winbindd_domain
*domain
)
542 flush_negative_conn_cache_for_domain(domain
->name
);
543 if (*domain
->alt_name
) {
544 flush_negative_conn_cache_for_domain(domain
->alt_name
);
548 /* Set our domains as offline and forward the offline message to our children. */
550 void winbind_msg_offline(int msg_type
, struct process_id src
,
551 void *buf
, size_t len
, void *private_data
)
553 struct winbindd_child
*child
;
554 struct winbindd_domain
*domain
;
556 DEBUG(10,("winbind_msg_offline: got offline message.\n"));
558 if (!lp_winbind_offline_logon()) {
559 DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
563 /* Set our global state as offline. */
564 if (!set_global_winbindd_state_offline()) {
565 DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
569 /* Set all our domains as offline. */
570 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
571 if (domain
->internal
) {
574 DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain
->name
));
575 set_domain_offline(domain
);
577 /* Send an offline message to the idmap child when our
578 primary domain goes offline */
580 if ( domain
->primary
) {
581 struct winbindd_child
*idmap
= idmap_child();
583 if ( idmap
->pid
!= 0 ) {
584 message_send_pid(pid_to_procid(idmap
->pid
),
587 strlen(domain
->name
)+1,
593 for (child
= children
; child
!= NULL
; child
= child
->next
) {
594 /* Don't send message to idmap child. We've already
596 if (!child
->domain
|| (child
== idmap_child())) {
600 /* Or internal domains (this should not be possible....) */
601 if (child
->domain
->internal
) {
605 /* Each winbindd child should only process requests for one domain - make sure
606 we only set it online / offline for that domain. */
608 DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
609 (unsigned int)child
->pid
, domain
->name
));
611 message_send_pid(pid_to_procid(child
->pid
), MSG_WINBIND_OFFLINE
, child
->domain
->name
,
612 strlen(child
->domain
->name
)+1, False
);
616 /* Set our domains as online and forward the online message to our children. */
618 void winbind_msg_online(int msg_type
, struct process_id src
,
619 void *buf
, size_t len
, void *private_data
)
621 struct winbindd_child
*child
;
622 struct winbindd_domain
*domain
;
624 DEBUG(10,("winbind_msg_online: got online message.\n"));
626 if (!lp_winbind_offline_logon()) {
627 DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
631 /* Set our global state as online. */
632 set_global_winbindd_state_online();
634 smb_nscd_flush_user_cache();
635 smb_nscd_flush_group_cache();
637 /* Set all our domains as online. */
638 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
639 if (domain
->internal
) {
642 DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain
->name
));
644 winbindd_flush_negative_conn_cache(domain
);
645 set_domain_online_request(domain
);
647 /* Send an online message to the idmap child when our
648 primary domain comes back online */
650 if ( domain
->primary
) {
651 struct winbindd_child
*idmap
= idmap_child();
653 if ( idmap
->pid
!= 0 ) {
654 message_send_pid(pid_to_procid(idmap
->pid
),
657 strlen(domain
->name
)+1,
664 for (child
= children
; child
!= NULL
; child
= child
->next
) {
665 /* Don't send message to idmap child. */
666 if (!child
->domain
|| (child
== idmap_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 message_send_pid(pid_to_procid(child
->pid
), MSG_WINBIND_ONLINE
, child
->domain
->name
,
682 strlen(child
->domain
->name
)+1, False
);
686 /* Forward the online/offline messages to our children. */
687 void winbind_msg_onlinestatus(int msg_type
, struct process_id src
,
688 void *buf
, size_t len
, void *private_data
)
690 struct winbindd_child
*child
;
692 DEBUG(10,("winbind_msg_onlinestatus: got onlinestatus message.\n"));
694 for (child
= children
; child
!= NULL
; child
= child
->next
) {
695 if (child
->domain
&& child
->domain
->primary
) {
696 DEBUG(10,("winbind_msg_onlinestatus: "
697 "sending message to pid %u of primary domain.\n",
698 (unsigned int)child
->pid
));
699 message_send_pid(pid_to_procid(child
->pid
),
700 MSG_WINBIND_ONLINESTATUS
, buf
, len
, False
);
707 static void account_lockout_policy_handler(struct event_context
*ctx
,
708 struct timed_event
*te
,
709 const struct timeval
*now
,
712 struct winbindd_child
*child
=
713 (struct winbindd_child
*)private_data
;
714 TALLOC_CTX
*mem_ctx
= NULL
;
715 struct winbindd_methods
*methods
;
716 SAM_UNK_INFO_12 lockout_policy
;
719 DEBUG(10,("account_lockout_policy_handler called\n"));
721 TALLOC_FREE(child
->lockout_policy_event
);
723 methods
= child
->domain
->methods
;
725 mem_ctx
= talloc_init("account_lockout_policy_handler ctx");
727 result
= NT_STATUS_NO_MEMORY
;
729 result
= methods
->lockout_policy(child
->domain
, mem_ctx
, &lockout_policy
);
732 talloc_destroy(mem_ctx
);
734 if (!NT_STATUS_IS_OK(result
)) {
735 DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
739 child
->lockout_policy_event
= event_add_timed(winbind_event_context(), NULL
,
740 timeval_current_ofs(3600, 0),
741 "account_lockout_policy_handler",
742 account_lockout_policy_handler
,
746 /* Deal with a request to go offline. */
748 static void child_msg_offline(int msg_type
, struct process_id src
,
749 void *buf
, size_t len
, void *private_data
)
751 struct winbindd_domain
*domain
;
752 const char *domainname
= (const char *)buf
;
754 if (buf
== NULL
|| len
== 0) {
758 DEBUG(5,("child_msg_offline received for domain %s.\n", domainname
));
760 if (!lp_winbind_offline_logon()) {
761 DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
765 /* Set our global state as offline. */
766 if (!set_global_winbindd_state_offline()) {
767 DEBUG(10,("child_msg_offline: offline request failed.\n"));
771 /* Mark the requested domain offline. */
773 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
774 if (domain
->internal
) {
777 if (strequal(domain
->name
, domainname
)) {
778 DEBUG(5,("child_msg_offline: marking %s offline.\n", domain
->name
));
779 set_domain_offline(domain
);
784 /* Deal with a request to go online. */
786 static void child_msg_online(int msg_type
, struct process_id src
,
787 void *buf
, size_t len
, void *private_data
)
789 struct winbindd_domain
*domain
;
790 const char *domainname
= (const char *)buf
;
792 if (buf
== NULL
|| len
== 0) {
796 DEBUG(5,("child_msg_online received for domain %s.\n", domainname
));
798 if (!lp_winbind_offline_logon()) {
799 DEBUG(10,("child_msg_online: rejecting online message.\n"));
803 /* Set our global state as online. */
804 set_global_winbindd_state_online();
806 /* Try and mark everything online - delete any negative cache entries
807 to force a reconnect now. */
809 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
810 if (domain
->internal
) {
813 if (strequal(domain
->name
, domainname
)) {
814 DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain
->name
));
815 winbindd_flush_negative_conn_cache(domain
);
816 set_domain_online_request(domain
);
821 static const char *collect_onlinestatus(TALLOC_CTX
*mem_ctx
)
823 struct winbindd_domain
*domain
;
826 if ((buf
= talloc_asprintf(mem_ctx
, "global:%s ",
827 get_global_winbindd_state_offline() ?
828 "Offline":"Online")) == NULL
) {
832 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
833 if ((buf
= talloc_asprintf_append(buf
, "%s:%s ",
836 "Online":"Offline")) == NULL
) {
841 buf
= talloc_asprintf_append(buf
, "\n");
843 DEBUG(5,("collect_onlinestatus: %s", buf
));
848 static void child_msg_onlinestatus(int msg_type
, struct process_id src
,
849 void *buf
, size_t len
, void *private_data
)
853 struct process_id
*sender
;
855 DEBUG(5,("winbind_msg_onlinestatus received.\n"));
861 sender
= (struct process_id
*)buf
;
863 mem_ctx
= talloc_init("winbind_msg_onlinestatus");
864 if (mem_ctx
== NULL
) {
868 message
= collect_onlinestatus(mem_ctx
);
869 if (message
== NULL
) {
870 talloc_destroy(mem_ctx
);
874 message_send_pid(*sender
, MSG_WINBIND_ONLINESTATUS
,
875 message
, strlen(message
) + 1, True
);
877 talloc_destroy(mem_ctx
);
880 static BOOL
fork_domain_child(struct winbindd_child
*child
)
883 struct winbindd_cli_state state
;
884 struct winbindd_domain
*domain
;
886 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, fdpair
) != 0) {
887 DEBUG(0, ("Could not open child pipe: %s\n",
893 state
.pid
= sys_getpid();
898 /* Ensure we don't process messages whilst we're
899 changing the disposition for the child. */
902 child
->pid
= sys_fork();
904 if (child
->pid
== -1) {
905 DEBUG(0, ("Could not fork: %s\n", strerror(errno
)));
910 if (child
->pid
!= 0) {
913 child
->next
= child
->prev
= NULL
;
914 DLIST_ADD(children
, child
);
915 child
->event
.fd
= fdpair
[1];
916 child
->event
.flags
= 0;
917 child
->requests
= NULL
;
918 add_fd_event(&child
->event
);
919 /* We're ok with online/offline messages now. */
926 state
.sock
= fdpair
[0];
929 /* tdb needs special fork handling */
930 if (tdb_reopen_all(1) == -1) {
931 DEBUG(0,("tdb_reopen_all failed.\n"));
935 close_conns_after_fork();
937 if (!override_logfile
) {
938 lp_set_logfile(child
->logfilename
);
942 /* Don't handle the same messages as our parent. */
943 message_deregister(MSG_SMB_CONF_UPDATED
);
944 message_deregister(MSG_SHUTDOWN
);
945 message_deregister(MSG_WINBIND_OFFLINE
);
946 message_deregister(MSG_WINBIND_ONLINE
);
947 message_deregister(MSG_WINBIND_ONLINESTATUS
);
949 /* The child is ok with online/offline messages now. */
952 /* Handle online/offline messages. */
953 message_register(MSG_WINBIND_OFFLINE
, child_msg_offline
, NULL
);
954 message_register(MSG_WINBIND_ONLINE
, child_msg_online
, NULL
);
955 message_register(MSG_WINBIND_ONLINESTATUS
, child_msg_onlinestatus
,
958 if ( child
->domain
) {
959 child
->domain
->startup
= True
;
960 child
->domain
->startup_time
= time(NULL
);
963 /* Ensure we have no pending check_online events other
964 than one for this domain. */
966 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
967 if (domain
!= child
->domain
) {
968 TALLOC_FREE(domain
->check_online_event
);
972 /* Ensure we're not handling an event inherited from
975 cancel_named_event(winbind_event_context(),
976 "krb5_ticket_refresh_handler");
978 /* We might be in the idmap child...*/
979 if (child
->domain
&& !(child
->domain
->internal
) &&
980 lp_winbind_offline_logon()) {
982 set_domain_online_request(child
->domain
);
984 child
->lockout_policy_event
= event_add_timed(
985 winbind_event_context(), NULL
, timeval_zero(),
986 "account_lockout_policy_handler",
987 account_lockout_policy_handler
,
999 /* free up any talloc memory */
1001 main_loop_TALLOC_FREE();
1003 run_events(winbind_event_context(), 0, NULL
, NULL
);
1007 if (child
->domain
&& child
->domain
->startup
&&
1008 (now
.tv_sec
> child
->domain
->startup_time
+ 30)) {
1009 /* No longer in "startup" mode. */
1010 DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
1011 child
->domain
->name
));
1012 child
->domain
->startup
= False
;
1015 tp
= get_timed_events_timeout(winbind_event_context(), &t
);
1017 DEBUG(11,("select will use timeout of %u.%u seconds\n",
1018 (unsigned int)tp
->tv_sec
, (unsigned int)tp
->tv_usec
));
1021 /* Handle messages */
1026 FD_SET(state
.sock
, &read_fds
);
1028 ret
= sys_select(state
.sock
+ 1, &read_fds
, NULL
, NULL
, tp
);
1031 DEBUG(11,("nothing is ready yet, continue\n"));
1035 if (ret
== -1 && errno
== EINTR
) {
1036 /* We got a signal - continue. */
1040 if (ret
== -1 && errno
!= EINTR
) {
1041 DEBUG(0,("select error occured\n"));
1046 /* fetch a request from the main daemon */
1047 child_read_request(&state
);
1049 if (state
.finished
) {
1050 /* we lost contact with our parent */
1054 DEBUG(4,("child daemon request %d\n", (int)state
.request
.cmd
));
1056 ZERO_STRUCT(state
.response
);
1057 state
.request
.null_term
= '\0';
1058 child_process_request(child
->domain
, &state
);
1060 SAFE_FREE(state
.request
.extra_data
.data
);
1062 cache_store_response(sys_getpid(), &state
.response
);
1064 SAFE_FREE(state
.response
.extra_data
.data
);
1066 /* We just send the result code back, the result
1067 * structure needs to be fetched via the
1068 * winbindd_cache. Hmm. That needs fixing... */
1070 if (write_data(state
.sock
,
1071 (const char *)&state
.response
.result
,
1072 sizeof(state
.response
.result
)) !=
1073 sizeof(state
.response
.result
)) {
1074 DEBUG(0, ("Could not write result\n"));