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
);
102 static void async_main_request_sent(void *private_data
, BOOL success
);
103 static void async_request_sent(void *private_data
, BOOL success
);
104 static void async_reply_recv(void *private_data
, BOOL success
);
105 static void schedule_async_request(struct winbindd_child
*child
);
107 void async_request(TALLOC_CTX
*mem_ctx
, struct winbindd_child
*child
,
108 struct winbindd_request
*request
,
109 struct winbindd_response
*response
,
110 void (*continuation
)(void *private_data
, BOOL success
),
113 struct winbindd_async_request
*state
;
115 SMB_ASSERT(continuation
!= NULL
);
117 state
= TALLOC_P(mem_ctx
, struct winbindd_async_request
);
120 DEBUG(0, ("talloc failed\n"));
121 continuation(private_data
, False
);
125 state
->mem_ctx
= mem_ctx
;
126 state
->child
= child
;
127 state
->request
= request
;
128 state
->response
= response
;
129 state
->continuation
= continuation
;
130 state
->private_data
= private_data
;
132 DLIST_ADD_END(child
->requests
, state
, struct winbindd_async_request
*);
134 schedule_async_request(child
);
139 static void async_main_request_sent(void *private_data
, BOOL success
)
141 struct winbindd_async_request
*state
=
142 talloc_get_type_abort(private_data
, struct winbindd_async_request
);
145 DEBUG(5, ("Could not send async request\n"));
147 state
->response
->length
= sizeof(struct winbindd_response
);
148 state
->response
->result
= WINBINDD_ERROR
;
149 state
->continuation(state
->private_data
, False
);
153 if (state
->request
->extra_len
== 0) {
154 async_request_sent(private_data
, True
);
158 setup_async_write(&state
->child
->event
, state
->request
->extra_data
.data
,
159 state
->request
->extra_len
,
160 async_request_sent
, state
);
163 static void async_request_sent(void *private_data_data
, BOOL success
)
165 struct winbindd_async_request
*state
=
166 talloc_get_type_abort(private_data_data
, struct winbindd_async_request
);
169 DEBUG(5, ("Could not send async request\n"));
171 state
->response
->length
= sizeof(struct winbindd_response
);
172 state
->response
->result
= WINBINDD_ERROR
;
173 state
->continuation(state
->private_data
, False
);
177 /* Request successfully sent to the child, setup the wait for reply */
179 setup_async_read(&state
->child
->event
,
180 &state
->response
->result
,
181 sizeof(state
->response
->result
),
182 async_reply_recv
, state
);
185 static void async_reply_recv(void *private_data
, BOOL success
)
187 struct winbindd_async_request
*state
=
188 talloc_get_type_abort(private_data
, struct winbindd_async_request
);
189 struct winbindd_child
*child
= state
->child
;
191 state
->response
->length
= sizeof(struct winbindd_response
);
194 DEBUG(5, ("Could not receive async reply\n"));
196 cache_cleanup_response(child
->pid
);
197 DLIST_REMOVE(child
->requests
, state
);
199 state
->response
->result
= WINBINDD_ERROR
;
200 state
->continuation(state
->private_data
, False
);
204 SMB_ASSERT(cache_retrieve_response(child
->pid
,
207 cache_cleanup_response(child
->pid
);
209 DLIST_REMOVE(child
->requests
, state
);
211 schedule_async_request(child
);
213 state
->continuation(state
->private_data
, True
);
216 static BOOL
fork_domain_child(struct winbindd_child
*child
);
218 static void schedule_async_request(struct winbindd_child
*child
)
220 struct winbindd_async_request
*request
= child
->requests
;
222 if (request
== NULL
) {
226 if (child
->event
.flags
!= 0) {
230 if ((child
->pid
== 0) && (!fork_domain_child(child
))) {
231 /* Cancel all outstanding requests */
233 while (request
!= NULL
) {
234 /* request might be free'd in the continuation */
235 struct winbindd_async_request
*next
= request
->next
;
236 request
->continuation(request
->private_data
, False
);
242 setup_async_write(&child
->event
, request
->request
,
243 sizeof(*request
->request
),
244 async_main_request_sent
, request
);
249 struct domain_request_state
{
251 struct winbindd_domain
*domain
;
252 struct winbindd_request
*request
;
253 struct winbindd_response
*response
;
254 void (*continuation
)(void *private_data_data
, BOOL success
);
255 void *private_data_data
;
258 static void domain_init_recv(void *private_data_data
, BOOL success
);
260 void async_domain_request(TALLOC_CTX
*mem_ctx
,
261 struct winbindd_domain
*domain
,
262 struct winbindd_request
*request
,
263 struct winbindd_response
*response
,
264 void (*continuation
)(void *private_data_data
, BOOL success
),
265 void *private_data_data
)
267 struct domain_request_state
*state
;
269 if (domain
->initialized
) {
270 async_request(mem_ctx
, &domain
->child
, request
, response
,
271 continuation
, private_data_data
);
275 state
= TALLOC_P(mem_ctx
, struct domain_request_state
);
277 DEBUG(0, ("talloc failed\n"));
278 continuation(private_data_data
, False
);
282 state
->mem_ctx
= mem_ctx
;
283 state
->domain
= domain
;
284 state
->request
= request
;
285 state
->response
= response
;
286 state
->continuation
= continuation
;
287 state
->private_data_data
= private_data_data
;
289 init_child_connection(domain
, domain_init_recv
, state
);
292 static void recvfrom_child(void *private_data_data
, BOOL success
)
294 struct winbindd_cli_state
*state
=
295 talloc_get_type_abort(private_data_data
, struct winbindd_cli_state
);
296 enum winbindd_result result
= state
->response
.result
;
298 /* This is an optimization: The child has written directly to the
299 * response buffer. The request itself is still in pending state,
300 * state that in the result code. */
302 state
->response
.result
= WINBINDD_PENDING
;
304 if ((!success
) || (result
!= WINBINDD_OK
)) {
305 request_error(state
);
312 void sendto_child(struct winbindd_cli_state
*state
,
313 struct winbindd_child
*child
)
315 async_request(state
->mem_ctx
, child
, &state
->request
,
316 &state
->response
, recvfrom_child
, state
);
319 void sendto_domain(struct winbindd_cli_state
*state
,
320 struct winbindd_domain
*domain
)
322 async_domain_request(state
->mem_ctx
, domain
,
323 &state
->request
, &state
->response
,
324 recvfrom_child
, state
);
327 static void domain_init_recv(void *private_data_data
, BOOL success
)
329 struct domain_request_state
*state
=
330 talloc_get_type_abort(private_data_data
, struct domain_request_state
);
333 DEBUG(5, ("Domain init returned an error\n"));
334 state
->continuation(state
->private_data_data
, False
);
338 async_request(state
->mem_ctx
, &state
->domain
->child
,
339 state
->request
, state
->response
,
340 state
->continuation
, state
->private_data_data
);
343 struct winbindd_child_dispatch_table
{
344 enum winbindd_cmd cmd
;
345 enum winbindd_result (*fn
)(struct winbindd_domain
*domain
,
346 struct winbindd_cli_state
*state
);
347 const char *winbindd_cmd_name
;
350 static struct winbindd_child_dispatch_table child_dispatch_table
[] = {
352 { WINBINDD_LOOKUPSID
, winbindd_dual_lookupsid
, "LOOKUPSID" },
353 { WINBINDD_LOOKUPNAME
, winbindd_dual_lookupname
, "LOOKUPNAME" },
354 { WINBINDD_LOOKUPRIDS
, winbindd_dual_lookuprids
, "LOOKUPRIDS" },
355 { WINBINDD_LIST_TRUSTDOM
, winbindd_dual_list_trusted_domains
, "LIST_TRUSTDOM" },
356 { WINBINDD_INIT_CONNECTION
, winbindd_dual_init_connection
, "INIT_CONNECTION" },
357 { WINBINDD_GETDCNAME
, winbindd_dual_getdcname
, "GETDCNAME" },
358 { WINBINDD_SHOW_SEQUENCE
, winbindd_dual_show_sequence
, "SHOW_SEQUENCE" },
359 { WINBINDD_PAM_AUTH
, winbindd_dual_pam_auth
, "PAM_AUTH" },
360 { WINBINDD_PAM_AUTH_CRAP
, winbindd_dual_pam_auth_crap
, "AUTH_CRAP" },
361 { WINBINDD_PAM_LOGOFF
, winbindd_dual_pam_logoff
, "PAM_LOGOFF" },
362 { WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
,winbindd_dual_pam_chng_pswd_auth_crap
,"CHNG_PSWD_AUTH_CRAP" },
363 { WINBINDD_PAM_CHAUTHTOK
, winbindd_dual_pam_chauthtok
, "PAM_CHAUTHTOK" },
364 { WINBINDD_CHECK_MACHACC
, winbindd_dual_check_machine_acct
, "CHECK_MACHACC" },
365 { WINBINDD_DUAL_SID2UID
, winbindd_dual_sid2uid
, "DUAL_SID2UID" },
366 { WINBINDD_DUAL_SID2GID
, winbindd_dual_sid2gid
, "DUAL_SID2GID" },
367 { WINBINDD_DUAL_SIDS2XIDS
, winbindd_dual_sids2xids
, "DUAL_SIDS2XIDS" },
368 { WINBINDD_DUAL_UID2SID
, winbindd_dual_uid2sid
, "DUAL_UID2SID" },
369 { WINBINDD_DUAL_GID2SID
, winbindd_dual_gid2sid
, "DUAL_GID2SID" },
370 { WINBINDD_DUAL_UID2NAME
, winbindd_dual_uid2name
, "DUAL_UID2NAME" },
371 { WINBINDD_DUAL_NAME2UID
, winbindd_dual_name2uid
, "DUAL_NAME2UID" },
372 { WINBINDD_DUAL_GID2NAME
, winbindd_dual_gid2name
, "DUAL_GID2NAME" },
373 { WINBINDD_DUAL_NAME2GID
, winbindd_dual_name2gid
, "DUAL_NAME2GID" },
374 { WINBINDD_DUAL_SET_MAPPING
, winbindd_dual_set_mapping
, "DUAL_SET_MAPPING" },
375 { WINBINDD_DUAL_SET_HWM
, winbindd_dual_set_hwm
, "DUAL_SET_HWMS" },
376 { WINBINDD_DUAL_DUMP_MAPS
, winbindd_dual_dump_maps
, "DUAL_DUMP_MAPS" },
377 { WINBINDD_DUAL_USERINFO
, winbindd_dual_userinfo
, "DUAL_USERINFO" },
378 { WINBINDD_ALLOCATE_UID
, winbindd_dual_allocate_uid
, "ALLOCATE_UID" },
379 { WINBINDD_ALLOCATE_GID
, winbindd_dual_allocate_gid
, "ALLOCATE_GID" },
380 { WINBINDD_GETUSERDOMGROUPS
, winbindd_dual_getuserdomgroups
, "GETUSERDOMGROUPS" },
381 { WINBINDD_DUAL_GETSIDALIASES
, winbindd_dual_getsidaliases
, "GETSIDALIASES" },
382 { WINBINDD_CCACHE_NTLMAUTH
, winbindd_dual_ccache_ntlm_auth
, "CCACHE_NTLM_AUTH" },
385 { WINBINDD_NUM_CMDS
, NULL
, "NONE" }
388 static void child_process_request(struct winbindd_domain
*domain
,
389 struct winbindd_cli_state
*state
)
391 struct winbindd_child_dispatch_table
*table
;
393 /* Free response data - we may be interrupted and receive another
394 command before being able to send this data off. */
396 state
->response
.result
= WINBINDD_ERROR
;
397 state
->response
.length
= sizeof(struct winbindd_response
);
399 state
->mem_ctx
= talloc_init("winbind request");
400 if (state
->mem_ctx
== NULL
)
403 /* Process command */
405 for (table
= child_dispatch_table
; table
->fn
; table
++) {
406 if (state
->request
.cmd
== table
->cmd
) {
407 DEBUG(10,("process_request: request fn %s\n",
408 table
->winbindd_cmd_name
));
409 state
->response
.result
= table
->fn(domain
, state
);
415 DEBUG(10,("process_request: unknown request fn number %d\n",
416 (int)state
->request
.cmd
));
417 state
->response
.result
= WINBINDD_ERROR
;
420 talloc_destroy(state
->mem_ctx
);
423 void setup_domain_child(struct winbindd_domain
*domain
,
424 struct winbindd_child
*child
,
425 const char *explicit_logfile
)
427 if (explicit_logfile
!= NULL
) {
428 pstr_sprintf(child
->logfilename
, "%s/log.winbindd-%s",
429 dyn_LOGFILEBASE
, explicit_logfile
);
430 } else if (domain
!= NULL
) {
431 pstr_sprintf(child
->logfilename
, "%s/log.wb-%s",
432 dyn_LOGFILEBASE
, domain
->name
);
434 smb_panic("Internal error: domain == NULL && "
435 "explicit_logfile == NULL");
438 child
->domain
= domain
;
441 struct winbindd_child
*children
= NULL
;
443 void winbind_child_died(pid_t pid
)
445 struct winbindd_child
*child
;
447 for (child
= children
; child
!= NULL
; child
= child
->next
) {
448 if (child
->pid
== pid
) {
454 DEBUG(0, ("Unknown child %d died!\n", pid
));
458 remove_fd_event(&child
->event
);
459 close(child
->event
.fd
);
461 child
->event
.flags
= 0;
464 schedule_async_request(child
);
467 /* Ensure any negative cache entries with the netbios or realm names are removed. */
469 void winbindd_flush_negative_conn_cache(struct winbindd_domain
*domain
)
471 flush_negative_conn_cache_for_domain(domain
->name
);
472 if (*domain
->alt_name
) {
473 flush_negative_conn_cache_for_domain(domain
->alt_name
);
477 /* Set our domains as offline and forward the offline message to our children. */
479 void winbind_msg_offline(int msg_type
, struct process_id src
,
480 void *buf
, size_t len
, void *private_data
)
482 struct winbindd_child
*child
;
483 struct winbindd_domain
*domain
;
485 DEBUG(10,("winbind_msg_offline: got offline message.\n"));
487 if (!lp_winbind_offline_logon()) {
488 DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
492 /* Set our global state as offline. */
493 if (!set_global_winbindd_state_offline()) {
494 DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
498 /* Set all our domains as offline. */
499 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
500 if (domain
->internal
) {
503 DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain
->name
));
504 set_domain_offline(domain
);
507 for (child
= children
; child
!= NULL
; child
= child
->next
) {
508 /* Don't send message to idmap child. */
509 if (!child
->domain
|| (child
== idmap_child())) {
513 /* Or internal domains (this should not be possible....) */
514 if (child
->domain
->internal
) {
518 /* Each winbindd child should only process requests for one domain - make sure
519 we only set it online / offline for that domain. */
521 DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
522 (unsigned int)child
->pid
, domain
->name
));
524 message_send_pid(pid_to_procid(child
->pid
), MSG_WINBIND_OFFLINE
, child
->domain
->name
,
525 strlen(child
->domain
->name
)+1, False
);
529 /* Set our domains as online and forward the online message to our children. */
531 void winbind_msg_online(int msg_type
, struct process_id src
,
532 void *buf
, size_t len
, void *private_data
)
534 struct winbindd_child
*child
;
535 struct winbindd_domain
*domain
;
537 DEBUG(10,("winbind_msg_online: got online message.\n"));
539 if (!lp_winbind_offline_logon()) {
540 DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
544 /* Set our global state as online. */
545 set_global_winbindd_state_online();
547 smb_nscd_flush_user_cache();
548 smb_nscd_flush_group_cache();
550 /* Set all our domains as online. */
551 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
552 if (domain
->internal
) {
555 DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain
->name
));
557 winbindd_flush_negative_conn_cache(domain
);
558 set_domain_online_request(domain
);
561 for (child
= children
; child
!= NULL
; child
= child
->next
) {
562 /* Don't send message to idmap child. */
563 if (!child
->domain
|| (child
== idmap_child())) {
567 /* Or internal domains (this should not be possible....) */
568 if (child
->domain
->internal
) {
572 /* Each winbindd child should only process requests for one domain - make sure
573 we only set it online / offline for that domain. */
575 DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n",
576 (unsigned int)child
->pid
, child
->domain
->name
));
578 message_send_pid(pid_to_procid(child
->pid
), MSG_WINBIND_ONLINE
, child
->domain
->name
,
579 strlen(child
->domain
->name
)+1, False
);
583 /* Forward the online/offline messages to our children. */
584 void winbind_msg_onlinestatus(int msg_type
, struct process_id src
,
585 void *buf
, size_t len
, void *private_data
)
587 struct winbindd_child
*child
;
589 DEBUG(10,("winbind_msg_onlinestatus: got onlinestatus message.\n"));
591 for (child
= children
; child
!= NULL
; child
= child
->next
) {
592 if (child
->domain
&& child
->domain
->primary
) {
593 DEBUG(10,("winbind_msg_onlinestatus: "
594 "sending message to pid %u of primary domain.\n",
595 (unsigned int)child
->pid
));
596 message_send_pid(pid_to_procid(child
->pid
),
597 MSG_WINBIND_ONLINESTATUS
, buf
, len
, False
);
604 static void account_lockout_policy_handler(struct event_context
*ctx
,
605 struct timed_event
*te
,
606 const struct timeval
*now
,
609 struct winbindd_child
*child
=
610 (struct winbindd_child
*)private_data
;
611 TALLOC_CTX
*mem_ctx
= NULL
;
612 struct winbindd_methods
*methods
;
613 SAM_UNK_INFO_12 lockout_policy
;
616 DEBUG(10,("account_lockout_policy_handler called\n"));
618 if (child
->lockout_policy_event
) {
619 TALLOC_FREE(child
->lockout_policy_event
);
622 methods
= child
->domain
->methods
;
624 mem_ctx
= talloc_init("account_lockout_policy_handler ctx");
626 result
= NT_STATUS_NO_MEMORY
;
628 result
= methods
->lockout_policy(child
->domain
, mem_ctx
, &lockout_policy
);
631 talloc_destroy(mem_ctx
);
633 if (!NT_STATUS_IS_OK(result
)) {
634 DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
638 child
->lockout_policy_event
= event_add_timed(winbind_event_context(), NULL
,
639 timeval_current_ofs(3600, 0),
640 "account_lockout_policy_handler",
641 account_lockout_policy_handler
,
645 /* Deal with a request to go offline. */
647 static void child_msg_offline(int msg_type
, struct process_id src
,
648 void *buf
, size_t len
, void *private_data
)
650 struct winbindd_domain
*domain
;
651 const char *domainname
= (const char *)buf
;
653 if (buf
== NULL
|| len
== 0) {
657 DEBUG(5,("child_msg_offline received for domain %s.\n", domainname
));
659 if (!lp_winbind_offline_logon()) {
660 DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
664 /* Set our global state as offline. */
665 if (!set_global_winbindd_state_offline()) {
666 DEBUG(10,("child_msg_offline: offline request failed.\n"));
670 /* Mark the requested domain offline. */
672 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
673 if (domain
->internal
) {
676 if (strequal(domain
->name
, domainname
)) {
677 DEBUG(5,("child_msg_offline: marking %s offline.\n", domain
->name
));
678 set_domain_offline(domain
);
683 /* Deal with a request to go online. */
685 static void child_msg_online(int msg_type
, struct process_id src
,
686 void *buf
, size_t len
, void *private_data
)
688 struct winbindd_domain
*domain
;
689 const char *domainname
= (const char *)buf
;
691 if (buf
== NULL
|| len
== 0) {
695 DEBUG(5,("child_msg_online received for domain %s.\n", domainname
));
697 if (!lp_winbind_offline_logon()) {
698 DEBUG(10,("child_msg_online: rejecting online message.\n"));
702 /* Set our global state as online. */
703 set_global_winbindd_state_online();
705 /* Try and mark everything online - delete any negative cache entries
706 to force a reconnect now. */
708 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
709 if (domain
->internal
) {
712 if (strequal(domain
->name
, domainname
)) {
713 DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain
->name
));
714 winbindd_flush_negative_conn_cache(domain
);
715 set_domain_online_request(domain
);
720 static const char *collect_onlinestatus(TALLOC_CTX
*mem_ctx
)
722 struct winbindd_domain
*domain
;
725 if ((buf
= talloc_asprintf(mem_ctx
, "global:%s ",
726 get_global_winbindd_state_offline() ?
727 "Offline":"Online")) == NULL
) {
731 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
732 if ((buf
= talloc_asprintf_append(buf
, "%s:%s ",
735 "Online":"Offline")) == NULL
) {
740 buf
= talloc_asprintf_append(buf
, "\n");
742 DEBUG(5,("collect_onlinestatus: %s", buf
));
747 static void child_msg_onlinestatus(int msg_type
, struct process_id src
,
748 void *buf
, size_t len
, void *private_data
)
752 struct process_id
*sender
;
754 DEBUG(5,("winbind_msg_onlinestatus received.\n"));
760 sender
= (struct process_id
*)buf
;
762 mem_ctx
= talloc_init("winbind_msg_onlinestatus");
763 if (mem_ctx
== NULL
) {
767 message
= collect_onlinestatus(mem_ctx
);
768 if (message
== NULL
) {
769 talloc_destroy(mem_ctx
);
773 message_send_pid(*sender
, MSG_WINBIND_ONLINESTATUS
,
774 message
, strlen(message
) + 1, True
);
776 talloc_destroy(mem_ctx
);
779 static BOOL
fork_domain_child(struct winbindd_child
*child
)
782 struct winbindd_cli_state state
;
783 struct winbindd_domain
*domain
;
785 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, fdpair
) != 0) {
786 DEBUG(0, ("Could not open child pipe: %s\n",
792 state
.pid
= sys_getpid();
797 /* Ensure we don't process messages whilst we're
798 changing the disposition for the child. */
801 child
->pid
= sys_fork();
803 if (child
->pid
== -1) {
804 DEBUG(0, ("Could not fork: %s\n", strerror(errno
)));
809 if (child
->pid
!= 0) {
812 child
->next
= child
->prev
= NULL
;
813 DLIST_ADD(children
, child
);
814 child
->event
.fd
= fdpair
[1];
815 child
->event
.flags
= 0;
816 child
->requests
= NULL
;
817 add_fd_event(&child
->event
);
818 /* We're ok with online/offline messages now. */
825 state
.sock
= fdpair
[0];
828 /* tdb needs special fork handling */
829 if (tdb_reopen_all(1) == -1) {
830 DEBUG(0,("tdb_reopen_all failed.\n"));
834 close_conns_after_fork();
836 if (!override_logfile
) {
837 lp_set_logfile(child
->logfilename
);
841 /* Don't handle the same messages as our parent. */
842 message_deregister(MSG_SMB_CONF_UPDATED
);
843 message_deregister(MSG_SHUTDOWN
);
844 message_deregister(MSG_WINBIND_OFFLINE
);
845 message_deregister(MSG_WINBIND_ONLINE
);
846 message_deregister(MSG_WINBIND_ONLINESTATUS
);
848 /* The child is ok with online/offline messages now. */
851 /* Handle online/offline messages. */
852 message_register(MSG_WINBIND_OFFLINE
, child_msg_offline
, NULL
);
853 message_register(MSG_WINBIND_ONLINE
, child_msg_online
, NULL
);
854 message_register(MSG_WINBIND_ONLINESTATUS
, child_msg_onlinestatus
,
857 if ( child
->domain
) {
858 child
->domain
->startup
= True
;
859 child
->domain
->startup_time
= time(NULL
);
862 /* Ensure we have no pending check_online events other
863 than one for this domain. */
865 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
866 if (domain
!= child
->domain
) {
867 if (domain
->check_online_event
) {
868 TALLOC_FREE(domain
->check_online_event
);
873 /* Ensure we're not handling an event inherited from
876 cancel_named_event(winbind_event_context(),
877 "krb5_ticket_refresh_handler");
879 /* We might be in the idmap child...*/
880 if (child
->domain
&& !(child
->domain
->internal
) &&
881 lp_winbind_offline_logon()) {
883 set_domain_online_request(child
->domain
);
885 child
->lockout_policy_event
= event_add_timed(
886 winbind_event_context(), NULL
, timeval_zero(),
887 "account_lockout_policy_handler",
888 account_lockout_policy_handler
,
900 /* free up any talloc memory */
902 main_loop_TALLOC_FREE();
904 run_events(winbind_event_context(), 0, NULL
, NULL
);
908 if (child
->domain
&& child
->domain
->startup
&&
909 (now
.tv_sec
> child
->domain
->startup_time
+ 30)) {
910 /* No longer in "startup" mode. */
911 DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
912 child
->domain
->name
));
913 child
->domain
->startup
= False
;
916 tp
= get_timed_events_timeout(winbind_event_context(), &t
);
918 DEBUG(11,("select will use timeout of %u.%u seconds\n",
919 (unsigned int)tp
->tv_sec
, (unsigned int)tp
->tv_usec
));
922 /* Handle messages */
927 FD_SET(state
.sock
, &read_fds
);
929 ret
= sys_select(state
.sock
+ 1, &read_fds
, NULL
, NULL
, tp
);
932 DEBUG(11,("nothing is ready yet, continue\n"));
936 if (ret
== -1 && errno
== EINTR
) {
937 /* We got a signal - continue. */
941 if (ret
== -1 && errno
!= EINTR
) {
942 DEBUG(0,("select error occured\n"));
947 /* fetch a request from the main daemon */
948 child_read_request(&state
);
950 if (state
.finished
) {
951 /* we lost contact with our parent */
955 DEBUG(4,("child daemon request %d\n", (int)state
.request
.cmd
));
957 ZERO_STRUCT(state
.response
);
958 state
.request
.null_term
= '\0';
959 child_process_request(child
->domain
, &state
);
961 SAFE_FREE(state
.request
.extra_data
.data
);
963 cache_store_response(sys_getpid(), &state
.response
);
965 SAFE_FREE(state
.response
.extra_data
.data
);
967 /* We just send the result code back, the result
968 * structure needs to be fetched via the
969 * winbindd_cache. Hmm. That needs fixing... */
971 if (write_data(state
.sock
,
972 (const char *)&state
.response
.result
,
973 sizeof(state
.response
.result
)) !=
974 sizeof(state
.response
.result
)) {
975 DEBUG(0, ("Could not write result\n"));