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_request_fail(struct winbindd_async_request
*state
);
106 static void async_main_request_sent(void *private_data
, BOOL success
);
107 static void async_request_sent(void *private_data
, BOOL success
);
108 static void async_reply_recv(void *private_data
, BOOL success
);
109 static void schedule_async_request(struct winbindd_child
*child
);
111 void async_request(TALLOC_CTX
*mem_ctx
, struct winbindd_child
*child
,
112 struct winbindd_request
*request
,
113 struct winbindd_response
*response
,
114 void (*continuation
)(void *private_data
, BOOL success
),
117 struct winbindd_async_request
*state
;
119 SMB_ASSERT(continuation
!= NULL
);
121 state
= TALLOC_P(mem_ctx
, struct winbindd_async_request
);
124 DEBUG(0, ("talloc failed\n"));
125 continuation(private_data
, False
);
129 state
->mem_ctx
= mem_ctx
;
130 state
->child
= child
;
131 state
->reply_timeout_event
= NULL
;
132 state
->request
= request
;
133 state
->response
= response
;
134 state
->continuation
= continuation
;
135 state
->private_data
= private_data
;
137 DLIST_ADD_END(child
->requests
, state
, struct winbindd_async_request
*);
139 schedule_async_request(child
);
144 static void async_main_request_sent(void *private_data
, BOOL success
)
146 struct winbindd_async_request
*state
=
147 talloc_get_type_abort(private_data
, struct winbindd_async_request
);
150 DEBUG(5, ("Could not send async request\n"));
151 async_request_fail(state
);
155 if (state
->request
->extra_len
== 0) {
156 async_request_sent(private_data
, True
);
160 setup_async_write(&state
->child
->event
, state
->request
->extra_data
.data
,
161 state
->request
->extra_len
,
162 async_request_sent
, state
);
165 /****************************************************************
166 Handler triggered if the child winbindd doesn't respond within
168 ****************************************************************/
170 static void async_request_timeout_handler(struct event_context
*ctx
,
171 struct timed_event
*te
,
172 const struct timeval
*now
,
175 struct winbindd_async_request
*state
=
176 talloc_get_type_abort(private_data
, struct winbindd_async_request
);
178 DEBUG(0,("async_request_timeout_handler: child pid %u is not responding. "
179 "Closing connection to it.\n",
182 /* Deal with the reply - set to error. */
183 async_reply_recv(private_data
, False
);
186 /**************************************************************
187 Common function called on both async send and recv fail.
188 Cleans up the child and schedules the next request.
189 **************************************************************/
191 static void async_request_fail(struct winbindd_async_request
*state
)
193 DLIST_REMOVE(state
->child
->requests
, state
);
195 TALLOC_FREE(state
->reply_timeout_event
);
197 /* If child exists and is not already reaped,
198 send kill signal to child. */
200 if ((state
->child
->pid
!= (pid_t
)0) &&
201 (state
->child
->pid
!= (pid_t
)-1) &&
202 (state
->child
->pid
== state
->child_pid
)) {
203 kill(state
->child_pid
, SIGTERM
);
206 * Close the socket to the child.
208 winbind_child_died(state
->child_pid
);
211 state
->response
->length
= sizeof(struct winbindd_response
);
212 state
->response
->result
= WINBINDD_ERROR
;
213 state
->continuation(state
->private_data
, False
);
216 static void async_request_sent(void *private_data_data
, BOOL success
)
218 struct winbindd_async_request
*state
=
219 talloc_get_type_abort(private_data_data
, struct winbindd_async_request
);
222 DEBUG(5, ("Could not send async request to child pid %u\n",
223 (unsigned int)state
->child_pid
));
224 async_request_fail(state
);
228 /* Request successfully sent to the child, setup the wait for reply */
230 setup_async_read(&state
->child
->event
,
231 &state
->response
->result
,
232 sizeof(state
->response
->result
),
233 async_reply_recv
, state
);
236 * Set up a timeout of 300 seconds for the response.
237 * If we don't get it close the child socket and
241 state
->reply_timeout_event
= event_add_timed(winbind_event_context(),
243 timeval_current_ofs(300,0),
244 "async_request_timeout",
245 async_request_timeout_handler
,
247 if (!state
->reply_timeout_event
) {
248 smb_panic("async_request_sent: failed to add timeout handler.\n");
252 static void async_reply_recv(void *private_data
, BOOL success
)
254 struct winbindd_async_request
*state
=
255 talloc_get_type_abort(private_data
, struct winbindd_async_request
);
256 struct winbindd_child
*child
= state
->child
;
258 TALLOC_FREE(state
->reply_timeout_event
);
260 state
->response
->length
= sizeof(struct winbindd_response
);
263 DEBUG(5, ("Could not receive async reply from child pid %u\n",
264 (unsigned int)state
->child_pid
));
266 cache_cleanup_response(state
->child_pid
);
267 async_request_fail(state
);
271 SMB_ASSERT(cache_retrieve_response(state
->child_pid
,
274 cache_cleanup_response(state
->child_pid
);
276 DLIST_REMOVE(child
->requests
, state
);
278 schedule_async_request(child
);
280 state
->continuation(state
->private_data
, True
);
283 static BOOL
fork_domain_child(struct winbindd_child
*child
);
285 static void schedule_async_request(struct winbindd_child
*child
)
287 struct winbindd_async_request
*request
= child
->requests
;
289 if (request
== NULL
) {
293 if (child
->event
.flags
!= 0) {
298 * This may be a reschedule, so we might
299 * have an existing timeout event pending on
300 * the first entry in the child->requests list
301 * (we only send one request at a time).
302 * Ensure we free it before we reschedule.
303 * Bug #5814, from hargagan <shargagan@novell.com>.
307 TALLOC_FREE(request
->reply_timeout_event
);
309 if ((child
->pid
== 0) && (!fork_domain_child(child
))) {
310 /* fork_domain_child failed.
311 Cancel all outstanding requests */
313 while (request
!= NULL
) {
314 /* request might be free'd in the continuation */
315 struct winbindd_async_request
*next
= request
->next
;
317 async_request_fail(request
);
323 /* Now we know who we're sending to - remember the pid. */
324 request
->child_pid
= child
->pid
;
326 setup_async_write(&child
->event
, request
->request
,
327 sizeof(*request
->request
),
328 async_main_request_sent
, request
);
333 struct domain_request_state
{
335 struct winbindd_domain
*domain
;
336 struct winbindd_request
*request
;
337 struct winbindd_response
*response
;
338 void (*continuation
)(void *private_data_data
, BOOL success
);
339 void *private_data_data
;
342 static void domain_init_recv(void *private_data_data
, BOOL success
);
344 void async_domain_request(TALLOC_CTX
*mem_ctx
,
345 struct winbindd_domain
*domain
,
346 struct winbindd_request
*request
,
347 struct winbindd_response
*response
,
348 void (*continuation
)(void *private_data_data
, BOOL success
),
349 void *private_data_data
)
351 struct domain_request_state
*state
;
353 if (domain
->initialized
) {
354 async_request(mem_ctx
, &domain
->child
, request
, response
,
355 continuation
, private_data_data
);
359 state
= TALLOC_P(mem_ctx
, struct domain_request_state
);
361 DEBUG(0, ("talloc failed\n"));
362 continuation(private_data_data
, False
);
366 state
->mem_ctx
= mem_ctx
;
367 state
->domain
= domain
;
368 state
->request
= request
;
369 state
->response
= response
;
370 state
->continuation
= continuation
;
371 state
->private_data_data
= private_data_data
;
373 init_child_connection(domain
, domain_init_recv
, state
);
376 static void recvfrom_child(void *private_data_data
, BOOL success
)
378 struct winbindd_cli_state
*state
=
379 talloc_get_type_abort(private_data_data
, struct winbindd_cli_state
);
380 enum winbindd_result result
= state
->response
.result
;
382 /* This is an optimization: The child has written directly to the
383 * response buffer. The request itself is still in pending state,
384 * state that in the result code. */
386 state
->response
.result
= WINBINDD_PENDING
;
388 if ((!success
) || (result
!= WINBINDD_OK
)) {
389 request_error(state
);
396 void sendto_child(struct winbindd_cli_state
*state
,
397 struct winbindd_child
*child
)
399 async_request(state
->mem_ctx
, child
, &state
->request
,
400 &state
->response
, recvfrom_child
, state
);
403 void sendto_domain(struct winbindd_cli_state
*state
,
404 struct winbindd_domain
*domain
)
406 async_domain_request(state
->mem_ctx
, domain
,
407 &state
->request
, &state
->response
,
408 recvfrom_child
, state
);
411 static void domain_init_recv(void *private_data_data
, BOOL success
)
413 struct domain_request_state
*state
=
414 talloc_get_type_abort(private_data_data
, struct domain_request_state
);
417 DEBUG(5, ("Domain init returned an error\n"));
418 state
->continuation(state
->private_data_data
, False
);
422 async_request(state
->mem_ctx
, &state
->domain
->child
,
423 state
->request
, state
->response
,
424 state
->continuation
, state
->private_data_data
);
427 struct winbindd_child_dispatch_table
{
428 enum winbindd_cmd cmd
;
429 enum winbindd_result (*fn
)(struct winbindd_domain
*domain
,
430 struct winbindd_cli_state
*state
);
431 const char *winbindd_cmd_name
;
434 static struct winbindd_child_dispatch_table child_dispatch_table
[] = {
436 { WINBINDD_LOOKUPSID
, winbindd_dual_lookupsid
, "LOOKUPSID" },
437 { WINBINDD_LOOKUPNAME
, winbindd_dual_lookupname
, "LOOKUPNAME" },
438 { WINBINDD_LOOKUPRIDS
, winbindd_dual_lookuprids
, "LOOKUPRIDS" },
439 { WINBINDD_LIST_TRUSTDOM
, winbindd_dual_list_trusted_domains
, "LIST_TRUSTDOM" },
440 { WINBINDD_INIT_CONNECTION
, winbindd_dual_init_connection
, "INIT_CONNECTION" },
441 { WINBINDD_GETDCNAME
, winbindd_dual_getdcname
, "GETDCNAME" },
442 { WINBINDD_SHOW_SEQUENCE
, winbindd_dual_show_sequence
, "SHOW_SEQUENCE" },
443 { WINBINDD_PAM_AUTH
, winbindd_dual_pam_auth
, "PAM_AUTH" },
444 { WINBINDD_PAM_AUTH_CRAP
, winbindd_dual_pam_auth_crap
, "AUTH_CRAP" },
445 { WINBINDD_PAM_LOGOFF
, winbindd_dual_pam_logoff
, "PAM_LOGOFF" },
446 { WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
,winbindd_dual_pam_chng_pswd_auth_crap
,"CHNG_PSWD_AUTH_CRAP" },
447 { WINBINDD_PAM_CHAUTHTOK
, winbindd_dual_pam_chauthtok
, "PAM_CHAUTHTOK" },
448 { WINBINDD_CHECK_MACHACC
, winbindd_dual_check_machine_acct
, "CHECK_MACHACC" },
449 { WINBINDD_DUAL_SID2UID
, winbindd_dual_sid2uid
, "DUAL_SID2UID" },
450 { WINBINDD_DUAL_SID2GID
, winbindd_dual_sid2gid
, "DUAL_SID2GID" },
451 #if 0 /* DISABLED until we fix the interface in Samba 3.0.26 --jerry */
452 { WINBINDD_DUAL_SIDS2XIDS
, winbindd_dual_sids2xids
, "DUAL_SIDS2XIDS" },
453 #endif /* end DISABLED */
454 { WINBINDD_DUAL_UID2SID
, winbindd_dual_uid2sid
, "DUAL_UID2SID" },
455 { WINBINDD_DUAL_GID2SID
, winbindd_dual_gid2sid
, "DUAL_GID2SID" },
456 { WINBINDD_DUAL_UID2NAME
, winbindd_dual_uid2name
, "DUAL_UID2NAME" },
457 { WINBINDD_DUAL_NAME2UID
, winbindd_dual_name2uid
, "DUAL_NAME2UID" },
458 { WINBINDD_DUAL_GID2NAME
, winbindd_dual_gid2name
, "DUAL_GID2NAME" },
459 { WINBINDD_DUAL_NAME2GID
, winbindd_dual_name2gid
, "DUAL_NAME2GID" },
460 { WINBINDD_DUAL_SET_MAPPING
, winbindd_dual_set_mapping
, "DUAL_SET_MAPPING" },
461 { WINBINDD_DUAL_SET_HWM
, winbindd_dual_set_hwm
, "DUAL_SET_HWMS" },
462 { WINBINDD_DUAL_DUMP_MAPS
, winbindd_dual_dump_maps
, "DUAL_DUMP_MAPS" },
463 { WINBINDD_DUAL_USERINFO
, winbindd_dual_userinfo
, "DUAL_USERINFO" },
464 { WINBINDD_ALLOCATE_UID
, winbindd_dual_allocate_uid
, "ALLOCATE_UID" },
465 { WINBINDD_ALLOCATE_GID
, winbindd_dual_allocate_gid
, "ALLOCATE_GID" },
466 { WINBINDD_GETUSERDOMGROUPS
, winbindd_dual_getuserdomgroups
, "GETUSERDOMGROUPS" },
467 { WINBINDD_DUAL_GETSIDALIASES
, winbindd_dual_getsidaliases
, "GETSIDALIASES" },
468 { WINBINDD_CCACHE_NTLMAUTH
, winbindd_dual_ccache_ntlm_auth
, "CCACHE_NTLM_AUTH" },
471 { WINBINDD_NUM_CMDS
, NULL
, "NONE" }
474 static void child_process_request(struct winbindd_domain
*domain
,
475 struct winbindd_cli_state
*state
)
477 struct winbindd_child_dispatch_table
*table
;
479 /* Free response data - we may be interrupted and receive another
480 command before being able to send this data off. */
482 state
->response
.result
= WINBINDD_ERROR
;
483 state
->response
.length
= sizeof(struct winbindd_response
);
485 state
->mem_ctx
= talloc_init("winbind request");
486 if (state
->mem_ctx
== NULL
)
489 /* Process command */
491 for (table
= child_dispatch_table
; table
->fn
; table
++) {
492 if (state
->request
.cmd
== table
->cmd
) {
493 DEBUG(10,("process_request: request fn %s\n",
494 table
->winbindd_cmd_name
));
495 state
->response
.result
= table
->fn(domain
, state
);
501 DEBUG(10,("process_request: unknown request fn number %d\n",
502 (int)state
->request
.cmd
));
503 state
->response
.result
= WINBINDD_ERROR
;
506 talloc_destroy(state
->mem_ctx
);
509 void setup_domain_child(struct winbindd_domain
*domain
,
510 struct winbindd_child
*child
,
511 const char *explicit_logfile
)
513 if (explicit_logfile
!= NULL
) {
514 pstr_sprintf(child
->logfilename
, "%s/log.winbindd-%s",
515 dyn_LOGFILEBASE
, explicit_logfile
);
516 } else if (domain
!= NULL
) {
517 pstr_sprintf(child
->logfilename
, "%s/log.wb-%s",
518 dyn_LOGFILEBASE
, domain
->name
);
520 smb_panic("Internal error: domain == NULL && "
521 "explicit_logfile == NULL");
524 child
->domain
= domain
;
527 struct winbindd_child
*children
= NULL
;
529 void winbind_child_died(pid_t pid
)
531 struct winbindd_child
*child
;
533 for (child
= children
; child
!= NULL
; child
= child
->next
) {
534 if (child
->pid
== pid
) {
540 DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid
));
544 /* This will be re-added in fork_domain_child() */
546 DLIST_REMOVE(children
, child
);
548 remove_fd_event(&child
->event
);
549 close(child
->event
.fd
);
551 child
->event
.flags
= 0;
554 if (child
->requests
) {
556 * schedule_async_request() will also
557 * clear this event but the call is
558 * idempotent so it doesn't hurt to
559 * cover all possible future code
562 TALLOC_FREE(child
->requests
->reply_timeout_event
);
565 schedule_async_request(child
);
568 /* Ensure any negative cache entries with the netbios or realm names are removed. */
570 void winbindd_flush_negative_conn_cache(struct winbindd_domain
*domain
)
572 flush_negative_conn_cache_for_domain(domain
->name
);
573 if (*domain
->alt_name
) {
574 flush_negative_conn_cache_for_domain(domain
->alt_name
);
578 /* Set our domains as offline and forward the offline message to our children. */
580 void winbind_msg_offline(int msg_type
, struct process_id src
,
581 void *buf
, size_t len
, void *private_data
)
583 struct winbindd_child
*child
;
584 struct winbindd_domain
*domain
;
586 DEBUG(10,("winbind_msg_offline: got offline message.\n"));
588 if (!lp_winbind_offline_logon()) {
589 DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
593 /* Set our global state as offline. */
594 if (!set_global_winbindd_state_offline()) {
595 DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
599 /* Set all our domains as offline. */
600 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
601 if (domain
->internal
) {
604 DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain
->name
));
605 set_domain_offline(domain
);
607 /* Send an offline message to the idmap child when our
608 primary domain goes offline */
610 if ( domain
->primary
) {
611 struct winbindd_child
*idmap
= idmap_child();
613 if ( idmap
->pid
!= 0 ) {
614 message_send_pid(pid_to_procid(idmap
->pid
),
617 strlen(domain
->name
)+1,
623 for (child
= children
; child
!= NULL
; child
= child
->next
) {
624 /* Don't send message to idmap child. We've already
626 if (!child
->domain
|| (child
== idmap_child())) {
630 /* Or internal domains (this should not be possible....) */
631 if (child
->domain
->internal
) {
635 /* Each winbindd child should only process requests for one domain - make sure
636 we only set it online / offline for that domain. */
638 DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
639 (unsigned int)child
->pid
, domain
->name
));
641 message_send_pid(pid_to_procid(child
->pid
), MSG_WINBIND_OFFLINE
, child
->domain
->name
,
642 strlen(child
->domain
->name
)+1, False
);
646 /* Set our domains as online and forward the online message to our children. */
648 void winbind_msg_online(int msg_type
, struct process_id src
,
649 void *buf
, size_t len
, void *private_data
)
651 struct winbindd_child
*child
;
652 struct winbindd_domain
*domain
;
654 DEBUG(10,("winbind_msg_online: got online message.\n"));
656 if (!lp_winbind_offline_logon()) {
657 DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
661 /* Set our global state as online. */
662 set_global_winbindd_state_online();
664 smb_nscd_flush_user_cache();
665 smb_nscd_flush_group_cache();
667 /* Set all our domains as online. */
668 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
669 if (domain
->internal
) {
672 DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain
->name
));
674 winbindd_flush_negative_conn_cache(domain
);
675 set_domain_online_request(domain
);
677 /* Send an online message to the idmap child when our
678 primary domain comes back online */
680 if ( domain
->primary
) {
681 struct winbindd_child
*idmap
= idmap_child();
683 if ( idmap
->pid
!= 0 ) {
684 message_send_pid(pid_to_procid(idmap
->pid
),
687 strlen(domain
->name
)+1,
694 for (child
= children
; child
!= NULL
; child
= child
->next
) {
695 /* Don't send message to idmap child. */
696 if (!child
->domain
|| (child
== idmap_child())) {
700 /* Or internal domains (this should not be possible....) */
701 if (child
->domain
->internal
) {
705 /* Each winbindd child should only process requests for one domain - make sure
706 we only set it online / offline for that domain. */
708 DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n",
709 (unsigned int)child
->pid
, child
->domain
->name
));
711 message_send_pid(pid_to_procid(child
->pid
), MSG_WINBIND_ONLINE
, child
->domain
->name
,
712 strlen(child
->domain
->name
)+1, False
);
716 /* Forward the online/offline messages to our children. */
717 void winbind_msg_onlinestatus(int msg_type
, struct process_id src
,
718 void *buf
, size_t len
, void *private_data
)
720 struct winbindd_child
*child
;
722 DEBUG(10,("winbind_msg_onlinestatus: got onlinestatus message.\n"));
724 for (child
= children
; child
!= NULL
; child
= child
->next
) {
725 if (child
->domain
&& child
->domain
->primary
) {
726 DEBUG(10,("winbind_msg_onlinestatus: "
727 "sending message to pid %u of primary domain.\n",
728 (unsigned int)child
->pid
));
729 message_send_pid(pid_to_procid(child
->pid
),
730 MSG_WINBIND_ONLINESTATUS
, buf
, len
, False
);
737 static void account_lockout_policy_handler(struct event_context
*ctx
,
738 struct timed_event
*te
,
739 const struct timeval
*now
,
742 struct winbindd_child
*child
=
743 (struct winbindd_child
*)private_data
;
744 TALLOC_CTX
*mem_ctx
= NULL
;
745 struct winbindd_methods
*methods
;
746 SAM_UNK_INFO_12 lockout_policy
;
749 DEBUG(10,("account_lockout_policy_handler called\n"));
751 TALLOC_FREE(child
->lockout_policy_event
);
753 methods
= child
->domain
->methods
;
755 mem_ctx
= talloc_init("account_lockout_policy_handler ctx");
757 result
= NT_STATUS_NO_MEMORY
;
759 result
= methods
->lockout_policy(child
->domain
, mem_ctx
, &lockout_policy
);
762 talloc_destroy(mem_ctx
);
764 if (!NT_STATUS_IS_OK(result
)) {
765 DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
769 child
->lockout_policy_event
= event_add_timed(winbind_event_context(), NULL
,
770 timeval_current_ofs(3600, 0),
771 "account_lockout_policy_handler",
772 account_lockout_policy_handler
,
776 /* Deal with a request to go offline. */
778 static void child_msg_offline(int msg_type
, struct process_id src
,
779 void *buf
, size_t len
, void *private_data
)
781 struct winbindd_domain
*domain
;
782 struct winbindd_domain
*primary_domain
= NULL
;
783 const char *domainname
= (const char *)buf
;
785 if (buf
== NULL
|| len
== 0) {
789 DEBUG(5,("child_msg_offline received for domain %s.\n", domainname
));
791 if (!lp_winbind_offline_logon()) {
792 DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
796 /* Set our global state as offline. */
797 if (!set_global_winbindd_state_offline()) {
798 DEBUG(10,("child_msg_offline: offline request failed.\n"));
802 primary_domain
= find_our_domain();
804 /* Mark the requested domain offline. */
806 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
807 if (domain
->internal
) {
810 if (strequal(domain
->name
, domainname
)) {
811 DEBUG(5,("child_msg_offline: marking %s offline.\n", domain
->name
));
812 set_domain_offline(domain
);
813 /* we are in the trusted domain, set the primary domain
815 if (domain
!= primary_domain
) {
816 set_domain_offline(primary_domain
);
822 /* Deal with a request to go online. */
824 static void child_msg_online(int msg_type
, struct process_id src
,
825 void *buf
, size_t len
, void *private_data
)
827 struct winbindd_domain
*domain
;
828 struct winbindd_domain
*primary_domain
= NULL
;
829 const char *domainname
= (const char *)buf
;
831 if (buf
== NULL
|| len
== 0) {
835 DEBUG(5,("child_msg_online received for domain %s.\n", domainname
));
837 if (!lp_winbind_offline_logon()) {
838 DEBUG(10,("child_msg_online: rejecting online message.\n"));
842 primary_domain
= find_our_domain();
844 /* Set our global state as online. */
845 set_global_winbindd_state_online();
847 /* Try and mark everything online - delete any negative cache entries
848 to force a reconnect now. */
850 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
851 if (domain
->internal
) {
854 if (strequal(domain
->name
, domainname
)) {
855 DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain
->name
));
856 winbindd_flush_negative_conn_cache(domain
);
857 set_domain_online_request(domain
);
859 /* we can be in trusted domain, which will contact primary domain
860 * we have to bring primary domain online in trusted domain process
861 * see, winbindd_dual_pam_auth() --> winbindd_dual_pam_auth_samlogon()
862 * --> contact_domain = find_our_domain()
864 if (domain
!= primary_domain
) {
865 winbindd_flush_negative_conn_cache(primary_domain
);
866 set_domain_online_request(primary_domain
);
872 static const char *collect_onlinestatus(TALLOC_CTX
*mem_ctx
)
874 struct winbindd_domain
*domain
;
877 if ((buf
= talloc_asprintf(mem_ctx
, "global:%s ",
878 get_global_winbindd_state_offline() ?
879 "Offline":"Online")) == NULL
) {
883 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
884 if ((buf
= talloc_asprintf_append(buf
, "%s:%s ",
887 "Online":"Offline")) == NULL
) {
892 buf
= talloc_asprintf_append(buf
, "\n");
894 DEBUG(5,("collect_onlinestatus: %s", buf
));
899 static void child_msg_onlinestatus(int msg_type
, struct process_id src
,
900 void *buf
, size_t len
, void *private_data
)
904 struct process_id
*sender
;
906 DEBUG(5,("winbind_msg_onlinestatus received.\n"));
912 sender
= (struct process_id
*)buf
;
914 mem_ctx
= talloc_init("winbind_msg_onlinestatus");
915 if (mem_ctx
== NULL
) {
919 message
= collect_onlinestatus(mem_ctx
);
920 if (message
== NULL
) {
921 talloc_destroy(mem_ctx
);
925 message_send_pid(*sender
, MSG_WINBIND_ONLINESTATUS
,
926 message
, strlen(message
) + 1, True
);
928 talloc_destroy(mem_ctx
);
931 bool reinit_after_fork(struct messaging_context
*msg_ctx
,
932 struct event_context
*ev_ctx
,
933 bool parent_longlived
);
934 void ccache_remove_all_after_fork(void);
936 bool winbindd_reinit_after_fork(const char *logfile
)
938 struct winbindd_domain
*dom
;
939 struct winbindd_child
*cl
;
941 if (!reinit_after_fork(NULL
,
942 winbind_event_context(), true)) {
943 DEBUG(0, ("reinit_after_fork failed.\n"));
947 close_conns_after_fork();
949 if (!override_logfile
&& logfile
) {
950 lp_set_logfile(logfile
);
954 /* Don't handle the same messages as our parent. */
955 message_deregister(MSG_SMB_CONF_UPDATED
);
956 message_deregister(MSG_SHUTDOWN
);
957 message_deregister(MSG_WINBIND_OFFLINE
);
958 message_deregister(MSG_WINBIND_ONLINE
);
959 message_deregister(MSG_WINBIND_ONLINESTATUS
);
961 ccache_remove_all_after_fork();
963 for (dom
= domain_list(); dom
; dom
= dom
->next
) {
964 TALLOC_FREE(dom
->check_online_event
);
967 for (cl
= children
; cl
; cl
= cl
->next
) {
968 struct winbindd_async_request
*request
;
970 for (request
= cl
->requests
; request
; request
= request
->next
) {
971 TALLOC_FREE(request
->reply_timeout_event
);
973 TALLOC_FREE(cl
->lockout_policy_event
);
979 static BOOL
fork_domain_child(struct winbindd_child
*child
)
982 struct winbindd_cli_state state
;
983 struct winbindd_domain
*primary_domain
= NULL
;
985 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, fdpair
) != 0) {
986 DEBUG(0, ("Could not open child pipe: %s\n",
992 state
.pid
= sys_getpid();
994 /* Ensure we don't process messages whilst we're
995 changing the disposition for the child. */
998 child
->pid
= sys_fork();
1000 if (child
->pid
== -1) {
1001 DEBUG(0, ("Could not fork: %s\n", strerror(errno
)));
1006 if (child
->pid
!= 0) {
1009 child
->next
= child
->prev
= NULL
;
1010 DLIST_ADD(children
, child
);
1011 child
->event
.fd
= fdpair
[1];
1012 child
->event
.flags
= 0;
1013 add_fd_event(&child
->event
);
1014 /* We're ok with online/offline messages now. */
1021 /* Stop zombies in children */
1024 state
.sock
= fdpair
[0];
1027 /* tdb needs special fork handling */
1028 if (!winbindd_reinit_after_fork(child
->logfilename
)) {
1029 DEBUG(0, ("winbindd_reinit_after_fork failed.\n"));
1033 /* The child is ok with online/offline messages now. */
1036 /* Handle online/offline messages. */
1037 message_register(MSG_WINBIND_OFFLINE
, child_msg_offline
, NULL
);
1038 message_register(MSG_WINBIND_ONLINE
, child_msg_online
, NULL
);
1039 message_register(MSG_WINBIND_ONLINESTATUS
, child_msg_onlinestatus
,
1042 primary_domain
= find_our_domain();
1044 if (primary_domain
== NULL
) {
1045 smb_panic("no primary domain found");
1048 /* It doesn't matter if we allow cache login,
1049 * try to bring domain online after fork. */
1050 if ( child
->domain
) {
1051 child
->domain
->startup
= True
;
1052 child
->domain
->startup_time
= time(NULL
);
1053 /* we can be in primary domain or in trusted domain
1054 * If we are in trusted domain, set the primary domain
1055 * in start-up mode */
1056 if (!(child
->domain
->internal
)) {
1057 set_domain_online_request(child
->domain
);
1058 if (!(child
->domain
->primary
)) {
1059 primary_domain
->startup
= True
;
1060 primary_domain
->startup_time
= time(NULL
);
1061 set_domain_online_request(primary_domain
);
1066 /* We might be in the idmap child...*/
1067 if (child
->domain
&& !(child
->domain
->internal
) &&
1068 lp_winbind_offline_logon()) {
1070 set_domain_online_request(child
->domain
);
1072 if (primary_domain
!= child
->domain
) {
1073 /* We need to talk to the primary
1074 * domain as well as the trusted
1075 * domain inside a trusted domain
1078 * winbindd_dual_pam_auth_samlogon()
1079 * especially the calling of
1080 * contact_domain = find_our_domain()
1081 * in the non-DC case for details.
1083 set_domain_online_request(primary_domain
);
1086 child
->lockout_policy_event
= event_add_timed(
1087 winbind_event_context(), NULL
, timeval_zero(),
1088 "account_lockout_policy_handler",
1089 account_lockout_policy_handler
,
1101 /* free up any talloc memory */
1103 main_loop_TALLOC_FREE();
1105 /* check for signals */
1106 winbind_check_sigterm(false);
1107 winbind_check_sighup(override_logfile
? NULL
:
1108 child
->logfilename
);
1110 run_events(winbind_event_context(), 0, NULL
, NULL
);
1114 if (child
->domain
&& child
->domain
->startup
&&
1115 (now
.tv_sec
> child
->domain
->startup_time
+ 30)) {
1116 /* No longer in "startup" mode. */
1117 DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
1118 child
->domain
->name
));
1119 child
->domain
->startup
= False
;
1122 tp
= get_timed_events_timeout(winbind_event_context(), &t
);
1124 DEBUG(11,("select will use timeout of %u.%u seconds\n",
1125 (unsigned int)tp
->tv_sec
, (unsigned int)tp
->tv_usec
));
1128 /* Handle messages */
1133 FD_SET(state
.sock
, &read_fds
);
1135 ret
= sys_select(state
.sock
+ 1, &read_fds
, NULL
, NULL
, tp
);
1138 DEBUG(11,("nothing is ready yet, continue\n"));
1142 if (ret
== -1 && errno
== EINTR
) {
1143 /* We got a signal - continue. */
1147 if (ret
== -1 && errno
!= EINTR
) {
1148 DEBUG(0,("select error occured\n"));
1153 /* fetch a request from the main daemon */
1154 child_read_request(&state
);
1156 if (state
.finished
) {
1157 /* we lost contact with our parent */
1161 DEBUG(4,("child daemon request %d\n", (int)state
.request
.cmd
));
1163 ZERO_STRUCT(state
.response
);
1164 state
.request
.null_term
= '\0';
1165 child_process_request(child
->domain
, &state
);
1167 SAFE_FREE(state
.request
.extra_data
.data
);
1169 cache_store_response(sys_getpid(), &state
.response
);
1171 SAFE_FREE(state
.response
.extra_data
.data
);
1173 /* We just send the result code back, the result
1174 * structure needs to be fetched via the
1175 * winbindd_cache. Hmm. That needs fixing... */
1177 if (write_data(state
.sock
,
1178 (const char *)&state
.response
.result
,
1179 sizeof(state
.response
.result
)) !=
1180 sizeof(state
.response
.result
)) {
1181 DEBUG(0, ("Could not write result\n"));