smbd: remove process shortname arg from reinit_after_fork()
[Samba.git] / source3 / winbindd / winbindd.c
blob50dc6d6bd9237d6c4d5a762596282f29f1ea5356
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) by Tim Potter 2000-2002
7 Copyright (C) Andrew Tridgell 2002
8 Copyright (C) Jelmer Vernooij 2003
9 Copyright (C) Volker Lendecke 2004
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "lib/cmdline/cmdline.h"
27 #include "winbindd.h"
28 #include "nsswitch/winbind_client.h"
29 #include "nsswitch/wb_reqtrans.h"
30 #include "ntdomain.h"
31 #include "librpc/rpc/dcesrv_core.h"
32 #include "librpc/gen_ndr/ndr_lsa_scompat.h"
33 #include "librpc/gen_ndr/ndr_samr_scompat.h"
34 #include "librpc/gen_ndr/ndr_winbind_scompat.h"
35 #include "secrets.h"
36 #include "rpc_client/cli_netlogon.h"
37 #include "idmap.h"
38 #include "lib/addrchange.h"
39 #include "auth.h"
40 #include "messages.h"
41 #include "../lib/util/pidfile.h"
42 #include "util_cluster.h"
43 #include "source4/lib/messaging/irpc.h"
44 #include "source4/lib/messaging/messaging.h"
45 #include "lib/param/param.h"
46 #include "lib/async_req/async_sock.h"
47 #include "libsmb/samlogon_cache.h"
48 #include "libcli/auth/netlogon_creds_cli.h"
49 #include "passdb.h"
50 #include "lib/util/tevent_req_profile.h"
51 #include "lib/gencache.h"
52 #include "rpc_server/rpc_config.h"
53 #include "lib/global_contexts.h"
54 #include "source3/lib/substitute.h"
55 #include "winbindd_traceid.h"
56 #include "lib/util/util_process.h"
58 #undef DBGC_CLASS
59 #define DBGC_CLASS DBGC_WINBIND
61 #define SCRUB_CLIENTS_INTERVAL 5
63 static bool client_is_idle(struct winbindd_cli_state *state);
64 static void remove_client(struct winbindd_cli_state *state);
66 static bool interactive = False;
68 /* Reload configuration */
72 static void winbindd_status(void)
74 struct winbindd_cli_state *tmp;
76 DEBUG(0, ("winbindd status:\n"));
78 /* Print client state information */
80 DEBUG(0, ("\t%d clients currently active\n", winbindd_num_clients()));
82 if (DEBUGLEVEL >= 2 && winbindd_num_clients()) {
83 DEBUG(2, ("\tclient list:\n"));
84 for(tmp = winbindd_client_list(); tmp; tmp = tmp->next) {
85 DEBUGADD(2, ("\t\tpid %lu, sock %d (%s)\n",
86 (unsigned long)tmp->pid, tmp->sock,
87 client_is_idle(tmp) ? "idle" : "active"));
93 handle stdin becoming readable when we are in --foreground mode
95 static void winbindd_stdin_handler(struct tevent_context *ev,
96 struct tevent_fd *fde,
97 uint16_t flags,
98 void *private_data)
100 char c;
101 if (read(0, &c, 1) != 1) {
102 bool *is_parent = talloc_get_type_abort(private_data, bool);
104 /* we have reached EOF on stdin, which means the
105 parent has exited. Shutdown the server */
106 DEBUG(0,("EOF on stdin (is_parent=%d)\n",
107 (int)*is_parent));
108 winbindd_terminate(*is_parent);
112 bool winbindd_setup_stdin_handler(bool parent, bool foreground)
114 bool *is_parent;
116 if (foreground) {
117 struct stat st;
119 is_parent = talloc(global_event_context(), bool);
120 if (!is_parent) {
121 return false;
124 *is_parent = parent;
126 /* if we are running in the foreground then look for
127 EOF on stdin, and exit if it happens. This allows
128 us to die if the parent process dies
129 Only do this on a pipe or socket, no other device.
131 if (fstat(0, &st) != 0) {
132 return false;
134 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
135 tevent_add_fd(global_event_context(),
136 is_parent,
138 TEVENT_FD_READ,
139 winbindd_stdin_handler,
140 is_parent);
144 return true;
147 static void winbindd_sig_chld_handler(struct tevent_context *ev,
148 struct tevent_signal *se,
149 int signum,
150 int count,
151 void *siginfo,
152 void *private_data)
154 pid_t pid;
156 while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
157 winbind_child_died(pid);
161 static bool winbindd_setup_sig_chld_handler(void)
163 struct tevent_signal *se;
165 se = tevent_add_signal(global_event_context(),
166 global_event_context(),
167 SIGCHLD, 0,
168 winbindd_sig_chld_handler,
169 NULL);
170 if (!se) {
171 return false;
174 return true;
177 static void winbindd_sig_usr2_handler(struct tevent_context *ev,
178 struct tevent_signal *se,
179 int signum,
180 int count,
181 void *siginfo,
182 void *private_data)
184 winbindd_status();
187 static bool winbindd_setup_sig_usr2_handler(void)
189 struct tevent_signal *se;
191 se = tevent_add_signal(global_event_context(),
192 global_event_context(),
193 SIGUSR2, 0,
194 winbindd_sig_usr2_handler,
195 NULL);
196 if (!se) {
197 return false;
200 return true;
203 /* React on 'smbcontrol winbindd shutdown' in the same way as on SIGTERM*/
204 static void msg_shutdown(struct messaging_context *msg,
205 void *private_data,
206 uint32_t msg_type,
207 struct server_id server_id,
208 DATA_BLOB *data)
210 /* only the parent waits for this message */
211 DEBUG(0,("Got shutdown message\n"));
212 winbindd_terminate(true);
216 static void winbind_msg_validate_cache(struct messaging_context *msg_ctx,
217 void *private_data,
218 uint32_t msg_type,
219 struct server_id server_id,
220 DATA_BLOB *data)
222 uint8_t ret;
223 pid_t child_pid;
224 NTSTATUS status;
226 DEBUG(10, ("winbindd_msg_validate_cache: got validate-cache "
227 "message.\n"));
230 * call the validation code from a child:
231 * so we don't block the main winbindd and the validation
232 * code can safely use fork/waitpid...
234 child_pid = fork();
236 if (child_pid == -1) {
237 DEBUG(1, ("winbind_msg_validate_cache: Could not fork: %s\n",
238 strerror(errno)));
239 return;
242 if (child_pid != 0) {
243 /* parent */
244 DEBUG(5, ("winbind_msg_validate_cache: child created with "
245 "pid %d.\n", (int)child_pid));
246 return;
249 /* child */
251 status = winbindd_reinit_after_fork(NULL, NULL);
252 if (!NT_STATUS_IS_OK(status)) {
253 DEBUG(1, ("winbindd_reinit_after_fork failed: %s\n",
254 nt_errstr(status)));
255 _exit(0);
258 /* install default SIGCHLD handler: validation code uses fork/waitpid */
259 CatchSignal(SIGCHLD, SIG_DFL);
261 process_set_title("wb: check cache", "validate cache child");
263 ret = (uint8_t)winbindd_validate_cache_nobackup();
264 DEBUG(10, ("winbindd_msg_validata_cache: got return value %d\n", ret));
265 messaging_send_buf(msg_ctx, server_id, MSG_WINBIND_VALIDATE_CACHE, &ret,
266 (size_t)1);
267 _exit(0);
270 static struct winbindd_bool_dispatch_table {
271 enum winbindd_cmd cmd;
272 bool (*fn)(struct winbindd_cli_state *state);
273 const char *cmd_name;
274 } bool_dispatch_table[] = {
275 { WINBINDD_INTERFACE_VERSION,
276 winbindd_interface_version,
277 "INTERFACE_VERSION" },
278 { WINBINDD_INFO,
279 winbindd_info,
280 "INFO" },
281 { WINBINDD_PING,
282 winbindd_ping,
283 "PING" },
284 { WINBINDD_DOMAIN_NAME,
285 winbindd_domain_name,
286 "DOMAIN_NAME" },
287 { WINBINDD_NETBIOS_NAME,
288 winbindd_netbios_name,
289 "NETBIOS_NAME" },
290 { WINBINDD_DC_INFO,
291 winbindd_dc_info,
292 "DC_INFO" },
293 { WINBINDD_CCACHE_NTLMAUTH,
294 winbindd_ccache_ntlm_auth,
295 "NTLMAUTH" },
296 { WINBINDD_CCACHE_SAVE,
297 winbindd_ccache_save,
298 "CCACHE_SAVE" },
299 { WINBINDD_PRIV_PIPE_DIR,
300 winbindd_priv_pipe_dir,
301 "WINBINDD_PRIV_PIPE_DIR" },
302 { WINBINDD_LIST_TRUSTDOM,
303 winbindd_list_trusted_domains,
304 "LIST_TRUSTDOM" },
307 struct winbindd_async_dispatch_table {
308 enum winbindd_cmd cmd;
309 const char *cmd_name;
310 struct tevent_req *(*send_req)(TALLOC_CTX *mem_ctx,
311 struct tevent_context *ev,
312 struct winbindd_cli_state *cli,
313 struct winbindd_request *request);
314 NTSTATUS (*recv_req)(struct tevent_req *req,
315 struct winbindd_response *presp);
318 static struct winbindd_async_dispatch_table async_nonpriv_table[] = {
319 { WINBINDD_LOOKUPSID, "LOOKUPSID",
320 winbindd_lookupsid_send, winbindd_lookupsid_recv },
321 { WINBINDD_LOOKUPSIDS, "LOOKUPSIDS",
322 winbindd_lookupsids_send, winbindd_lookupsids_recv },
323 { WINBINDD_LOOKUPNAME, "LOOKUPNAME",
324 winbindd_lookupname_send, winbindd_lookupname_recv },
325 { WINBINDD_SIDS_TO_XIDS, "SIDS_TO_XIDS",
326 winbindd_sids_to_xids_send, winbindd_sids_to_xids_recv },
327 { WINBINDD_XIDS_TO_SIDS, "XIDS_TO_SIDS",
328 winbindd_xids_to_sids_send, winbindd_xids_to_sids_recv },
329 { WINBINDD_GETPWSID, "GETPWSID",
330 winbindd_getpwsid_send, winbindd_getpwsid_recv },
331 { WINBINDD_GETPWNAM, "GETPWNAM",
332 winbindd_getpwnam_send, winbindd_getpwnam_recv },
333 { WINBINDD_GETPWUID, "GETPWUID",
334 winbindd_getpwuid_send, winbindd_getpwuid_recv },
335 { WINBINDD_GETSIDALIASES, "GETSIDALIASES",
336 winbindd_getsidaliases_send, winbindd_getsidaliases_recv },
337 { WINBINDD_GETUSERDOMGROUPS, "GETUSERDOMGROUPS",
338 winbindd_getuserdomgroups_send, winbindd_getuserdomgroups_recv },
339 { WINBINDD_GETGROUPS, "GETGROUPS",
340 winbindd_getgroups_send, winbindd_getgroups_recv },
341 { WINBINDD_SHOW_SEQUENCE, "SHOW_SEQUENCE",
342 winbindd_show_sequence_send, winbindd_show_sequence_recv },
343 { WINBINDD_GETGRGID, "GETGRGID",
344 winbindd_getgrgid_send, winbindd_getgrgid_recv },
345 { WINBINDD_GETGRNAM, "GETGRNAM",
346 winbindd_getgrnam_send, winbindd_getgrnam_recv },
347 { WINBINDD_GETUSERSIDS, "GETUSERSIDS",
348 winbindd_getusersids_send, winbindd_getusersids_recv },
349 { WINBINDD_LOOKUPRIDS, "LOOKUPRIDS",
350 winbindd_lookuprids_send, winbindd_lookuprids_recv },
351 { WINBINDD_SETPWENT, "SETPWENT",
352 winbindd_setpwent_send, winbindd_setpwent_recv },
353 { WINBINDD_GETPWENT, "GETPWENT",
354 winbindd_getpwent_send, winbindd_getpwent_recv },
355 { WINBINDD_ENDPWENT, "ENDPWENT",
356 winbindd_endpwent_send, winbindd_endpwent_recv },
357 { WINBINDD_DSGETDCNAME, "DSGETDCNAME",
358 winbindd_dsgetdcname_send, winbindd_dsgetdcname_recv },
359 { WINBINDD_GETDCNAME, "GETDCNAME",
360 winbindd_getdcname_send, winbindd_getdcname_recv },
361 { WINBINDD_SETGRENT, "SETGRENT",
362 winbindd_setgrent_send, winbindd_setgrent_recv },
363 { WINBINDD_GETGRENT, "GETGRENT",
364 winbindd_getgrent_send, winbindd_getgrent_recv },
365 { WINBINDD_ENDGRENT, "ENDGRENT",
366 winbindd_endgrent_send, winbindd_endgrent_recv },
367 { WINBINDD_LIST_USERS, "LIST_USERS",
368 winbindd_list_users_send, winbindd_list_users_recv },
369 { WINBINDD_LIST_GROUPS, "LIST_GROUPS",
370 winbindd_list_groups_send, winbindd_list_groups_recv },
371 { WINBINDD_CHECK_MACHACC, "CHECK_MACHACC",
372 winbindd_check_machine_acct_send, winbindd_check_machine_acct_recv },
373 { WINBINDD_PING_DC, "PING_DC",
374 winbindd_ping_dc_send, winbindd_ping_dc_recv },
375 { WINBINDD_PAM_AUTH, "PAM_AUTH",
376 winbindd_pam_auth_send, winbindd_pam_auth_recv },
377 { WINBINDD_PAM_LOGOFF, "PAM_LOGOFF",
378 winbindd_pam_logoff_send, winbindd_pam_logoff_recv },
379 { WINBINDD_PAM_CHAUTHTOK, "PAM_CHAUTHTOK",
380 winbindd_pam_chauthtok_send, winbindd_pam_chauthtok_recv },
381 { WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, "PAM_CHNG_PSWD_AUTH_CRAP",
382 winbindd_pam_chng_pswd_auth_crap_send,
383 winbindd_pam_chng_pswd_auth_crap_recv },
384 { WINBINDD_WINS_BYIP, "WINS_BYIP",
385 winbindd_wins_byip_send, winbindd_wins_byip_recv },
386 { WINBINDD_WINS_BYNAME, "WINS_BYNAME",
387 winbindd_wins_byname_send, winbindd_wins_byname_recv },
388 { WINBINDD_DOMAIN_INFO, "DOMAIN_INFO",
389 winbindd_domain_info_send, winbindd_domain_info_recv },
391 { 0, NULL, NULL, NULL }
394 static struct winbindd_async_dispatch_table async_priv_table[] = {
395 { WINBINDD_ALLOCATE_UID, "ALLOCATE_UID",
396 winbindd_allocate_uid_send, winbindd_allocate_uid_recv },
397 { WINBINDD_ALLOCATE_GID, "ALLOCATE_GID",
398 winbindd_allocate_gid_send, winbindd_allocate_gid_recv },
399 { WINBINDD_CHANGE_MACHACC, "CHANGE_MACHACC",
400 winbindd_change_machine_acct_send, winbindd_change_machine_acct_recv },
401 { WINBINDD_PAM_AUTH_CRAP, "PAM_AUTH_CRAP",
402 winbindd_pam_auth_crap_send, winbindd_pam_auth_crap_recv },
404 { 0, NULL, NULL, NULL }
407 struct process_request_state {
408 struct winbindd_cli_state *cli_state;
409 struct tevent_context *ev;
412 static void process_request_done(struct tevent_req *subreq);
413 static void process_request_written(struct tevent_req *subreq);
415 static struct tevent_req *process_request_send(
416 TALLOC_CTX *mem_ctx,
417 struct tevent_context *ev,
418 struct winbindd_cli_state *cli_state)
420 struct tevent_req *req, *subreq;
421 struct process_request_state *state;
422 struct winbindd_async_dispatch_table *atable;
423 enum winbindd_cmd cmd = cli_state->request->cmd;
424 size_t i;
425 bool ok;
426 static uint64_t request_index = 1;
429 * debug traceid values:
430 * 0 .. inactive
431 * 1 .. not processing a winbind request, but in other code (timers)
432 * >=2 .. winbind request processing
434 if (debug_traceid_get() != 0) {
435 request_index = ++request_index == 0 ? 2 : request_index;
436 debug_traceid_set(request_index);
438 req = tevent_req_create(mem_ctx, &state,
439 struct process_request_state);
440 if (req == NULL) {
441 return NULL;
443 state->cli_state = cli_state;
444 state->ev = ev;
446 ok = tevent_req_set_profile(req);
447 if (!ok) {
448 return tevent_req_post(req, ev);
451 SMB_ASSERT(cli_state->mem_ctx == NULL);
452 cli_state->mem_ctx = talloc_named(cli_state, 0, "winbind request");
453 if (tevent_req_nomem(cli_state->mem_ctx, req)) {
454 return tevent_req_post(req, ev);
457 cli_state->response = talloc_zero(
458 cli_state->mem_ctx,
459 struct winbindd_response);
460 if (tevent_req_nomem(cli_state->response, req)) {
461 return tevent_req_post(req, ev);
463 cli_state->response->result = WINBINDD_PENDING;
464 cli_state->response->length = sizeof(struct winbindd_response);
466 /* Remember who asked us. */
467 cli_state->pid = cli_state->request->pid;
468 memcpy(cli_state->client_name,
469 cli_state->request->client_name,
470 sizeof(cli_state->client_name));
472 cli_state->cmd_name = "unknown request";
473 cli_state->recv_fn = NULL;
475 /* client is newest */
476 winbindd_promote_client(cli_state);
478 for (atable = async_nonpriv_table; atable->send_req; atable += 1) {
479 if (cmd == atable->cmd) {
480 break;
484 if ((atable->send_req == NULL) && cli_state->privileged) {
485 for (atable = async_priv_table; atable->send_req;
486 atable += 1) {
487 if (cmd == atable->cmd) {
488 break;
493 if (atable->send_req != NULL) {
494 cli_state->cmd_name = atable->cmd_name;
495 cli_state->recv_fn = atable->recv_req;
497 DBG_NOTICE("[%s (%d)] Handling async request: %s\n",
498 cli_state->client_name,
499 (int)cli_state->pid,
500 cli_state->cmd_name);
502 subreq = atable->send_req(
503 state,
504 state->ev,
505 cli_state,
506 cli_state->request);
507 if (tevent_req_nomem(subreq, req)) {
508 return tevent_req_post(req, ev);
510 tevent_req_set_callback(subreq, process_request_done, req);
511 return req;
514 for (i=0; i<ARRAY_SIZE(bool_dispatch_table); i++) {
515 if (cmd == bool_dispatch_table[i].cmd) {
516 break;
520 ok = false;
522 if (i < ARRAY_SIZE(bool_dispatch_table)) {
523 cli_state->cmd_name = bool_dispatch_table[i].cmd_name;
525 DBG_DEBUG("process_request: request fn %s\n",
526 bool_dispatch_table[i].cmd_name);
527 ok = bool_dispatch_table[i].fn(cli_state);
530 cli_state->response->result = ok ? WINBINDD_OK : WINBINDD_ERROR;
532 TALLOC_FREE(cli_state->io_req);
533 TALLOC_FREE(cli_state->request);
535 subreq = wb_resp_write_send(
536 state,
537 state->ev,
538 cli_state->out_queue,
539 cli_state->sock,
540 cli_state->response);
541 if (tevent_req_nomem(subreq, req)) {
542 return tevent_req_post(req, ev);
544 tevent_req_set_callback(subreq, process_request_written, req);
546 cli_state->io_req = subreq;
548 return req;
551 static void process_request_done(struct tevent_req *subreq)
553 struct tevent_req *req = tevent_req_callback_data(
554 subreq, struct tevent_req);
555 struct process_request_state *state = tevent_req_data(
556 req, struct process_request_state);
557 struct winbindd_cli_state *cli_state = state->cli_state;
558 NTSTATUS status;
559 bool ok;
561 status = cli_state->recv_fn(subreq, cli_state->response);
562 TALLOC_FREE(subreq);
564 DBG_NOTICE("[%s(%d):%s]: %s\n",
565 cli_state->client_name,
566 (int)cli_state->pid,
567 cli_state->cmd_name,
568 nt_errstr(status));
570 ok = NT_STATUS_IS_OK(status);
571 cli_state->response->result = ok ? WINBINDD_OK : WINBINDD_ERROR;
573 TALLOC_FREE(cli_state->io_req);
574 TALLOC_FREE(cli_state->request);
576 subreq = wb_resp_write_send(
577 state,
578 state->ev,
579 cli_state->out_queue,
580 cli_state->sock,
581 cli_state->response);
582 if (tevent_req_nomem(subreq, req)) {
583 return;
585 tevent_req_set_callback(subreq, process_request_written, req);
587 cli_state->io_req = subreq;
590 static void process_request_written(struct tevent_req *subreq)
592 struct tevent_req *req = tevent_req_callback_data(
593 subreq, struct tevent_req);
594 struct process_request_state *state = tevent_req_data(
595 req, struct process_request_state);
596 struct winbindd_cli_state *cli_state = state->cli_state;
597 ssize_t ret;
598 int err;
600 cli_state->io_req = NULL;
602 ret = wb_resp_write_recv(subreq, &err);
603 TALLOC_FREE(subreq);
604 if (ret == -1) {
605 tevent_req_nterror(req, map_nt_error_from_unix(err));
606 return;
609 DBG_DEBUG("[%s(%d):%s]: delivered response to client\n",
610 cli_state->client_name,
611 (int)cli_state->pid,
612 cli_state->cmd_name);
614 TALLOC_FREE(cli_state->mem_ctx);
615 cli_state->response = NULL;
616 cli_state->cmd_name = "no request";
617 cli_state->recv_fn = NULL;
619 tevent_req_done(req);
622 static NTSTATUS process_request_recv(
623 struct tevent_req *req,
624 TALLOC_CTX *mem_ctx,
625 struct tevent_req_profile **profile)
627 NTSTATUS status;
629 if (tevent_req_is_nterror(req, &status)) {
630 tevent_req_received(req);
631 return status;
634 *profile = tevent_req_move_profile(req, mem_ctx);
635 tevent_req_received(req);
636 return NT_STATUS_OK;
640 * This is the main event loop of winbind requests. It goes through a
641 * state-machine of 3 read/write requests, 4 if you have extra data to send.
643 * An idle winbind client has a read request of 4 bytes outstanding,
644 * finalizing function is request_len_recv, checking the length. request_recv
645 * then processes the packet. The processing function then at some point has
646 * to call request_finished which schedules sending the response.
649 static void winbind_client_request_read(struct tevent_req *req);
650 static void winbind_client_activity(struct tevent_req *req);
651 static void winbind_client_processed(struct tevent_req *req);
653 /* Process a new connection by adding it to the client connection list */
655 static void new_connection(int listen_sock, bool privileged)
657 struct sockaddr_un sunaddr;
658 struct winbindd_cli_state *state;
659 struct tevent_req *req;
660 socklen_t len;
661 int sock;
663 /* Accept connection */
665 len = sizeof(sunaddr);
667 sock = accept(listen_sock, (struct sockaddr *)(void *)&sunaddr, &len);
669 if (sock == -1) {
670 if (errno != EINTR) {
671 D_ERR("Failed to accept socket: %s\n", strerror(errno));
673 return;
675 smb_set_close_on_exec(sock);
677 D_INFO("Accepted client socket %d\n", sock);
679 /* Create new connection structure */
681 if ((state = talloc_zero(NULL, struct winbindd_cli_state)) == NULL) {
682 close(sock);
683 return;
686 state->sock = sock;
688 state->out_queue = tevent_queue_create(state, "winbind client reply");
689 if (state->out_queue == NULL) {
690 close(sock);
691 TALLOC_FREE(state);
692 return;
695 state->privileged = privileged;
697 req = wb_req_read_send(state, global_event_context(), state->sock,
698 WINBINDD_MAX_EXTRA_DATA);
699 if (req == NULL) {
700 TALLOC_FREE(state);
701 close(sock);
702 return;
704 tevent_req_set_callback(req, winbind_client_request_read, state);
705 state->io_req = req;
707 /* Add to connection list */
709 winbindd_add_client(state);
712 static void winbind_client_request_read(struct tevent_req *req)
714 struct winbindd_cli_state *state = tevent_req_callback_data(
715 req, struct winbindd_cli_state);
716 ssize_t ret;
717 int err;
719 state->io_req = NULL;
721 ret = wb_req_read_recv(req, state, &state->request, &err);
722 TALLOC_FREE(req);
723 if (ret == -1) {
724 if (err == EPIPE) {
725 DEBUG(6, ("closing socket %d, client exited\n",
726 state->sock));
727 } else {
728 DEBUG(2, ("Could not read client request from fd %d: "
729 "%s\n", state->sock, strerror(err)));
731 close(state->sock);
732 state->sock = -1;
733 remove_client(state);
734 return;
737 req = wait_for_read_send(state, global_event_context(), state->sock,
738 true);
739 if (req == NULL) {
740 DEBUG(0, ("winbind_client_request_read[%d:%s]:"
741 " wait_for_read_send failed - removing client\n",
742 (int)state->pid, state->cmd_name));
743 remove_client(state);
744 return;
746 tevent_req_set_callback(req, winbind_client_activity, state);
747 state->io_req = req;
749 req = process_request_send(state, global_event_context(), state);
750 if (req == NULL) {
751 DBG_ERR("process_request_send failed\n");
752 remove_client(state);
753 return;
755 tevent_req_set_callback(req, winbind_client_processed, state);
758 static void winbind_client_activity(struct tevent_req *req)
760 struct winbindd_cli_state *state =
761 tevent_req_callback_data(req, struct winbindd_cli_state);
762 int err;
763 bool has_data;
765 has_data = wait_for_read_recv(req, &err);
767 if (has_data) {
768 DEBUG(0, ("winbind_client_activity[%d:%s]:"
769 "unexpected data from client - removing client\n",
770 (int)state->pid, state->cmd_name));
771 } else {
772 if (err == EPIPE) {
773 DEBUG(6, ("winbind_client_activity[%d:%s]: "
774 "client has closed connection - removing "
775 "client\n",
776 (int)state->pid, state->cmd_name));
777 } else {
778 DEBUG(2, ("winbind_client_activity[%d:%s]: "
779 "client socket error (%s) - removing "
780 "client\n",
781 (int)state->pid, state->cmd_name,
782 strerror(err)));
786 remove_client(state);
789 static void winbind_client_processed(struct tevent_req *req)
791 struct winbindd_cli_state *cli_state = tevent_req_callback_data(
792 req, struct winbindd_cli_state);
793 struct tevent_req_profile *profile = NULL;
794 struct timeval start, stop, diff;
795 int threshold;
796 NTSTATUS status;
798 status = process_request_recv(req, cli_state, &profile);
799 TALLOC_FREE(req);
800 if (!NT_STATUS_IS_OK(status)) {
801 DBG_DEBUG("process_request failed: %s\n", nt_errstr(status));
802 remove_client(cli_state);
803 return;
806 tevent_req_profile_get_start(profile, NULL, &start);
807 tevent_req_profile_get_stop(profile, NULL, &stop);
808 diff = tevent_timeval_until(&start, &stop);
810 threshold = lp_parm_int(-1, "winbind", "request profile threshold", 60);
812 if (diff.tv_sec >= threshold) {
813 int depth;
814 char *str;
816 depth = lp_parm_int(
818 "winbind",
819 "request profile depth",
820 INT_MAX);
822 DBG_ERR("request took %u.%.6u seconds\n",
823 (unsigned)diff.tv_sec, (unsigned)diff.tv_usec);
825 str = tevent_req_profile_string(
826 talloc_tos(), profile, 0, depth);
827 if (str != NULL) {
828 /* No "\n", already contained in "str" */
829 DEBUGADD(0, ("%s", str));
831 TALLOC_FREE(str);
834 TALLOC_FREE(profile);
836 req = wb_req_read_send(
837 cli_state,
838 global_event_context(),
839 cli_state->sock,
840 WINBINDD_MAX_EXTRA_DATA);
841 if (req == NULL) {
842 remove_client(cli_state);
843 return;
845 tevent_req_set_callback(req, winbind_client_request_read, cli_state);
846 cli_state->io_req = req;
849 /* Remove a client connection from client connection list */
851 static void remove_client(struct winbindd_cli_state *state)
853 /* It's a dead client - hold a funeral */
855 if (state == NULL) {
856 return;
860 * We need to remove a pending wb_req_read_*
861 * or wb_resp_write_* request before closing the
862 * socket.
864 * This is important as they might have used tevent_add_fd() and we
865 * use the epoll * backend on linux. So we must remove the tevent_fd
866 * before closing the fd.
868 * Otherwise we might hit a race with close_conns_after_fork() (via
869 * winbindd_reinit_after_fork()) where a file descriptor
870 * is still open in a child, which means it's still active in
871 * the parents epoll queue, but the related tevent_fd is already
872 * already gone in the parent.
874 * See bug #11141.
876 TALLOC_FREE(state->io_req);
878 if (state->sock != -1) {
879 char c = 0;
880 int nwritten;
882 /* tell client, we are closing ... */
883 nwritten = write(state->sock, &c, sizeof(c));
884 if (nwritten == -1) {
885 DEBUG(2, ("final write to client failed: %s\n",
886 strerror(errno)));
889 /* Close socket */
891 close(state->sock);
892 state->sock = -1;
895 TALLOC_FREE(state->mem_ctx);
897 /* Remove from list and free */
899 winbindd_remove_client(state);
900 TALLOC_FREE(state);
903 /* Is a client idle? */
905 static bool client_is_idle(struct winbindd_cli_state *state) {
906 return (state->request == NULL &&
907 state->response == NULL &&
908 !state->pwent_state && !state->grent_state);
911 /* Shutdown client connection which has been idle for the longest time */
913 static bool remove_idle_client(void)
915 struct winbindd_cli_state *state, *remove_state = NULL;
916 int nidle = 0;
918 for (state = winbindd_client_list(); state; state = state->next) {
919 if (client_is_idle(state)) {
920 nidle++;
921 /* list is sorted by access time */
922 remove_state = state;
926 if (remove_state) {
927 DEBUG(5,("Found %d idle client connections, shutting down sock %d, pid %u\n",
928 nidle, remove_state->sock, (unsigned int)remove_state->pid));
929 remove_client(remove_state);
930 return True;
933 return False;
937 * Terminate all clients whose requests have taken longer than
938 * "winbind request timeout" seconds to process, or have been
939 * idle for more than "winbind request timeout" seconds.
942 static void remove_timed_out_clients(void)
944 struct winbindd_cli_state *state, *prev = NULL;
945 time_t curr_time = time(NULL);
946 int timeout_val = lp_winbind_request_timeout();
948 for (state = winbindd_client_list_tail(); state; state = prev) {
949 time_t expiry_time;
951 prev = winbindd_client_list_prev(state);
952 expiry_time = state->last_access + timeout_val;
954 if (curr_time <= expiry_time) {
955 /* list is sorted, previous clients in
956 list are newer */
957 break;
960 if (client_is_idle(state)) {
961 DEBUG(5,("Idle client timed out, "
962 "shutting down sock %d, pid %u\n",
963 state->sock,
964 (unsigned int)state->pid));
965 } else {
966 DEBUG(5,("Client request timed out, "
967 "shutting down sock %d, pid %u\n",
968 state->sock,
969 (unsigned int)state->pid));
972 remove_client(state);
976 static void winbindd_scrub_clients_handler(struct tevent_context *ev,
977 struct tevent_timer *te,
978 struct timeval current_time,
979 void *private_data)
981 remove_timed_out_clients();
982 if (tevent_add_timer(ev, ev,
983 timeval_current_ofs(SCRUB_CLIENTS_INTERVAL, 0),
984 winbindd_scrub_clients_handler, NULL) == NULL) {
985 DEBUG(0, ("winbindd: failed to reschedule client scrubber\n"));
986 exit(1);
990 struct winbindd_listen_state {
991 bool privileged;
992 int fd;
995 static void winbindd_listen_fde_handler(struct tevent_context *ev,
996 struct tevent_fd *fde,
997 uint16_t flags,
998 void *private_data)
1000 struct winbindd_listen_state *s = talloc_get_type_abort(private_data,
1001 struct winbindd_listen_state);
1003 while (winbindd_num_clients() > lp_winbind_max_clients() - 1) {
1004 DEBUG(5,("winbindd: Exceeding %d client "
1005 "connections, removing idle "
1006 "connection.\n", lp_winbind_max_clients()));
1007 if (!remove_idle_client()) {
1008 DEBUG(0,("winbindd: Exceeding %d "
1009 "client connections, no idle "
1010 "connection found\n",
1011 lp_winbind_max_clients()));
1012 break;
1015 remove_timed_out_clients();
1016 new_connection(s->fd, s->privileged);
1020 * Winbindd socket accessor functions
1023 static bool winbindd_setup_listeners(void)
1025 struct winbindd_listen_state *pub_state = NULL;
1026 struct winbindd_listen_state *priv_state = NULL;
1027 struct tevent_fd *fde;
1028 int rc;
1029 char *socket_path;
1031 pub_state = talloc(global_event_context(),
1032 struct winbindd_listen_state);
1033 if (!pub_state) {
1034 goto failed;
1037 pub_state->privileged = false;
1038 pub_state->fd = create_pipe_sock(
1039 lp_winbindd_socket_directory(), WINBINDD_SOCKET_NAME, 0755);
1040 if (pub_state->fd == -1) {
1041 goto failed;
1043 rc = listen(pub_state->fd, 5);
1044 if (rc < 0) {
1045 goto failed;
1048 fde = tevent_add_fd(global_event_context(), pub_state, pub_state->fd,
1049 TEVENT_FD_READ, winbindd_listen_fde_handler,
1050 pub_state);
1051 if (fde == NULL) {
1052 close(pub_state->fd);
1053 goto failed;
1055 tevent_fd_set_auto_close(fde);
1057 priv_state = talloc(global_event_context(),
1058 struct winbindd_listen_state);
1059 if (!priv_state) {
1060 goto failed;
1063 socket_path = get_winbind_priv_pipe_dir();
1064 if (socket_path == NULL) {
1065 goto failed;
1068 priv_state->privileged = true;
1069 priv_state->fd = create_pipe_sock(
1070 socket_path, WINBINDD_SOCKET_NAME, 0750);
1071 TALLOC_FREE(socket_path);
1072 if (priv_state->fd == -1) {
1073 goto failed;
1075 rc = listen(priv_state->fd, 5);
1076 if (rc < 0) {
1077 goto failed;
1080 fde = tevent_add_fd(global_event_context(), priv_state,
1081 priv_state->fd, TEVENT_FD_READ,
1082 winbindd_listen_fde_handler, priv_state);
1083 if (fde == NULL) {
1084 close(priv_state->fd);
1085 goto failed;
1087 tevent_fd_set_auto_close(fde);
1089 winbindd_scrub_clients_handler(global_event_context(), NULL,
1090 timeval_current(), NULL);
1091 return true;
1092 failed:
1093 TALLOC_FREE(pub_state);
1094 TALLOC_FREE(priv_state);
1095 return false;
1098 static void winbindd_register_handlers(struct messaging_context *msg_ctx,
1099 bool foreground)
1101 bool scan_trusts = true;
1102 NTSTATUS status;
1103 struct tevent_timer *te = NULL;
1105 /* Setup signal handlers */
1107 if (!winbindd_setup_sig_term_handler(true))
1108 exit(1);
1109 if (!winbindd_setup_stdin_handler(true, foreground))
1110 exit(1);
1111 if (!winbindd_setup_sig_hup_handler(NULL))
1112 exit(1);
1113 if (!winbindd_setup_sig_chld_handler())
1114 exit(1);
1115 if (!winbindd_setup_sig_usr2_handler())
1116 exit(1);
1118 CatchSignal(SIGPIPE, SIG_IGN); /* Ignore sigpipe */
1121 * Ensure all cache and idmap caches are consistent
1122 * and initialized before we startup.
1124 if (!winbindd_cache_validate_and_initialize()) {
1125 exit(1);
1128 /* React on 'smbcontrol winbindd reload-config' in the same way
1129 as to SIGHUP signal */
1130 messaging_register(msg_ctx, NULL,
1131 MSG_SMB_CONF_UPDATED,
1132 winbindd_msg_reload_services_parent);
1133 messaging_register(msg_ctx, NULL,
1134 MSG_SHUTDOWN, msg_shutdown);
1136 /* Handle online/offline messages. */
1137 messaging_register(msg_ctx, NULL,
1138 MSG_WINBIND_OFFLINE, winbind_msg_offline);
1139 messaging_register(msg_ctx, NULL,
1140 MSG_WINBIND_ONLINE, winbind_msg_online);
1141 messaging_register(msg_ctx, NULL,
1142 MSG_WINBIND_ONLINESTATUS, winbind_msg_onlinestatus);
1144 /* Handle domain online/offline messages for domains */
1145 messaging_register(global_messaging_context(), NULL,
1146 MSG_WINBIND_DOMAIN_OFFLINE, winbind_msg_domain_offline);
1147 messaging_register(global_messaging_context(), NULL,
1148 MSG_WINBIND_DOMAIN_ONLINE, winbind_msg_domain_online);
1150 messaging_register(msg_ctx, NULL,
1151 MSG_WINBIND_VALIDATE_CACHE,
1152 winbind_msg_validate_cache);
1154 messaging_register(msg_ctx, NULL,
1155 MSG_WINBIND_DUMP_DOMAIN_LIST,
1156 winbind_msg_dump_domain_list);
1158 messaging_register(msg_ctx, NULL,
1159 MSG_WINBIND_IP_DROPPED,
1160 winbind_msg_ip_dropped_parent);
1162 /* Register handler for MSG_DEBUG. */
1163 messaging_register(msg_ctx, NULL,
1164 MSG_DEBUG,
1165 winbind_msg_debug);
1167 messaging_register(msg_ctx, NULL,
1168 MSG_WINBIND_DISCONNECT_DC,
1169 winbind_disconnect_dc_parent);
1171 netsamlogon_cache_init(); /* Non-critical */
1173 /* clear the cached list of trusted domains */
1175 wcache_tdc_clear();
1177 if (!init_domain_list()) {
1178 DEBUG(0,("unable to initialize domain list\n"));
1179 exit(1);
1182 init_idmap_child();
1183 init_locator_child();
1185 smb_nscd_flush_user_cache();
1186 smb_nscd_flush_group_cache();
1188 if (!lp_winbind_scan_trusted_domains()) {
1189 scan_trusts = false;
1192 if (!lp_allow_trusted_domains()) {
1193 scan_trusts = false;
1196 if (IS_DC) {
1197 scan_trusts = false;
1200 if (scan_trusts) {
1201 if (tevent_add_timer(global_event_context(), NULL, timeval_zero(),
1202 rescan_trusted_domains, NULL) == NULL) {
1203 DEBUG(0, ("Could not trigger rescan_trusted_domains()\n"));
1204 exit(1);
1208 te = tevent_add_timer(global_event_context(),
1209 NULL,
1210 timeval_zero(),
1211 winbindd_ping_offline_domains,
1212 NULL);
1213 if (te == NULL) {
1214 DBG_ERR("Failed to schedule winbindd_ping_offline_domains()\n");
1215 exit(1);
1218 status = wb_irpc_register();
1220 if (!NT_STATUS_IS_OK(status)) {
1221 DEBUG(0, ("Could not register IRPC handlers\n"));
1222 exit(1);
1226 struct winbindd_addrchanged_state {
1227 struct addrchange_context *ctx;
1228 struct tevent_context *ev;
1229 struct messaging_context *msg_ctx;
1232 static void winbindd_addr_changed(struct tevent_req *req);
1234 static void winbindd_init_addrchange(TALLOC_CTX *mem_ctx,
1235 struct tevent_context *ev,
1236 struct messaging_context *msg_ctx)
1238 struct winbindd_addrchanged_state *state;
1239 struct tevent_req *req;
1240 NTSTATUS status;
1242 state = talloc(mem_ctx, struct winbindd_addrchanged_state);
1243 if (state == NULL) {
1244 DEBUG(10, ("talloc failed\n"));
1245 return;
1247 state->ev = ev;
1248 state->msg_ctx = msg_ctx;
1250 status = addrchange_context_create(state, &state->ctx);
1251 if (!NT_STATUS_IS_OK(status)) {
1252 DEBUG(10, ("addrchange_context_create failed: %s\n",
1253 nt_errstr(status)));
1254 TALLOC_FREE(state);
1255 return;
1257 req = addrchange_send(state, ev, state->ctx);
1258 if (req == NULL) {
1259 DEBUG(0, ("addrchange_send failed\n"));
1260 TALLOC_FREE(state);
1261 return;
1263 tevent_req_set_callback(req, winbindd_addr_changed, state);
1266 static void winbindd_addr_changed(struct tevent_req *req)
1268 struct winbindd_addrchanged_state *state = tevent_req_callback_data(
1269 req, struct winbindd_addrchanged_state);
1270 enum addrchange_type type;
1271 struct sockaddr_storage addr;
1272 NTSTATUS status;
1274 status = addrchange_recv(req, &type, &addr);
1275 TALLOC_FREE(req);
1276 if (!NT_STATUS_IS_OK(status)) {
1277 DEBUG(10, ("addrchange_recv failed: %s, stop listening\n",
1278 nt_errstr(status)));
1279 TALLOC_FREE(state);
1280 return;
1282 if (type == ADDRCHANGE_DEL) {
1283 char addrstr[INET6_ADDRSTRLEN];
1284 DATA_BLOB blob;
1286 print_sockaddr(addrstr, sizeof(addrstr), &addr);
1288 DEBUG(3, ("winbindd: kernel (AF_NETLINK) dropped ip %s\n",
1289 addrstr));
1291 blob = data_blob_const(addrstr, strlen(addrstr)+1);
1293 status = messaging_send(state->msg_ctx,
1294 messaging_server_id(state->msg_ctx),
1295 MSG_WINBIND_IP_DROPPED, &blob);
1296 if (!NT_STATUS_IS_OK(status)) {
1297 DEBUG(10, ("messaging_send failed: %s - ignoring\n",
1298 nt_errstr(status)));
1301 req = addrchange_send(state, state->ev, state->ctx);
1302 if (req == NULL) {
1303 DEBUG(0, ("addrchange_send failed\n"));
1304 TALLOC_FREE(state);
1305 return;
1307 tevent_req_set_callback(req, winbindd_addr_changed, state);
1310 /* Main function */
1312 int main(int argc, const char **argv)
1314 static bool log_stdout = False;
1315 struct samba_cmdline_daemon_cfg *cmdline_daemon_cfg = NULL;
1316 struct poptOption long_options[] = {
1317 POPT_AUTOHELP
1319 .longName = "no-caching",
1320 .shortName = 'n',
1321 .argInfo = POPT_ARG_NONE,
1322 .arg = NULL,
1323 .val = 'n',
1324 .descrip = "Disable caching",
1326 POPT_COMMON_SAMBA
1327 POPT_COMMON_DAEMON
1328 POPT_COMMON_VERSION
1329 POPT_TABLEEND
1331 const struct loadparm_substitution *lp_sub =
1332 loadparm_s3_global_substitution();
1333 poptContext pc;
1334 int opt;
1335 TALLOC_CTX *frame;
1336 NTSTATUS status;
1337 bool ok;
1338 const struct dcesrv_endpoint_server *ep_server = NULL;
1339 struct dcesrv_context *dce_ctx = NULL;
1340 size_t winbindd_socket_dir_len = 0;
1341 char *winbindd_priv_socket_dir = NULL;
1342 size_t winbindd_priv_socket_dir_len = 0;
1344 setproctitle_init(argc, discard_const(argv), environ);
1347 * Do this before any other talloc operation
1349 talloc_enable_null_tracking();
1350 frame = talloc_stackframe();
1353 * We want total control over the permissions on created files,
1354 * so set our umask to 0.
1356 umask(0);
1358 smb_init_locale();
1360 /* glibc (?) likes to print "User defined signal 1" and exit if a
1361 SIGUSR[12] is received before a handler is installed */
1363 CatchSignal(SIGUSR1, SIG_IGN);
1364 CatchSignal(SIGUSR2, SIG_IGN);
1366 ok = samba_cmdline_init(frame,
1367 SAMBA_CMDLINE_CONFIG_SERVER,
1368 true /* require_smbconf */);
1369 if (!ok) {
1370 DBG_ERR("Failed to setup cmdline parser\n");
1371 TALLOC_FREE(frame);
1372 exit(1);
1375 cmdline_daemon_cfg = samba_cmdline_get_daemon_cfg();
1377 pc = samba_popt_get_context(getprogname(), argc, argv, long_options, 0);
1378 if (pc == NULL) {
1379 DBG_ERR("Failed to setup popt parser!\n");
1380 TALLOC_FREE(frame);
1381 exit(1);
1384 while ((opt = poptGetNextOpt(pc)) != -1) {
1385 switch (opt) {
1386 case 'n':
1387 winbindd_set_use_cache(false);
1388 break;
1389 default:
1390 d_fprintf(stderr, "\nInvalid option %s: %s\n\n",
1391 poptBadOption(pc, 0), poptStrerror(opt));
1392 poptPrintUsage(pc, stderr, 0);
1393 exit(1);
1397 /* Set environment variable so we don't recursively call ourselves.
1398 This may also be useful interactively. */
1399 if ( !winbind_off() ) {
1400 DEBUG(0,("Failed to disable recusive winbindd calls. Exiting.\n"));
1401 exit(1);
1404 /* Initialise for running in non-root mode */
1405 sec_init();
1407 set_remote_machine_name("winbindd", False);
1409 dump_core_setup("winbindd", lp_logfile(talloc_tos(), lp_sub));
1410 if (cmdline_daemon_cfg->daemon && cmdline_daemon_cfg->interactive) {
1411 d_fprintf(stderr,"\nERROR: "
1412 "Option -i|--interactive is not allowed together with -D|--daemon\n\n");
1413 poptPrintUsage(pc, stderr, 0);
1414 exit(1);
1417 log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
1418 if (cmdline_daemon_cfg->interactive) {
1420 * libcmdline POPT_DAEMON callback sets "fork" to false if "-i"
1421 * for interactive is passed on the commandline. Set it back to
1422 * true. TODO: check if this is correct, smbd and nmbd don't do
1423 * this.
1425 cmdline_daemon_cfg->fork = true;
1426 log_stdout = true;
1429 if (log_stdout && cmdline_daemon_cfg->fork) {
1430 d_fprintf(stderr, "\nERROR: "
1431 "Can't log to stdout (-S) unless daemon is in "
1432 "foreground (-F) or interactive (-i)\n\n");
1433 poptPrintUsage(pc, stderr, 0);
1434 exit(1);
1437 poptFreeContext(pc);
1439 reopen_logs();
1441 DEBUG(0,("winbindd version %s started.\n", samba_version_string()));
1442 DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE));
1444 /* After parsing the configuration file we setup the core path one more time
1445 * as the log file might have been set in the configuration and cores's
1446 * path is by default basename(lp_logfile()).
1448 dump_core_setup("winbindd", lp_logfile(talloc_tos(), lp_sub));
1450 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1451 if (!lp_parm_bool(-1, "server role check", "inhibit", false)) {
1452 DBG_ERR("server role = 'active directory domain controller' not compatible with running the winbindd binary. \n");
1453 DEBUGADD(0, ("You should start 'samba' instead, and it will control starting the internal AD DC winbindd implementation, which is not the same as this one\n"));
1454 exit(1);
1456 /* Main 'samba' daemon will notify */
1457 daemon_sd_notifications(false);
1460 if (lp_security() == SEC_ADS) {
1461 const char *realm = lp_realm();
1462 const char *workgroup = lp_workgroup();
1464 if (workgroup == NULL || strlen(workgroup) == 0) {
1465 DBG_ERR("For 'secuirity = ADS' mode, the 'workgroup' "
1466 "parameter is required to be set!\n");
1467 exit(1);
1470 if (realm == NULL || strlen(realm) == 0) {
1471 DBG_ERR("For 'secuirity = ADS' mode, the 'realm' "
1472 "parameter is required to be set!\n");
1473 exit(1);
1477 winbindd_socket_dir_len = strlen(lp_winbindd_socket_directory());
1478 if (winbindd_socket_dir_len > 0) {
1479 size_t winbindd_socket_len =
1480 winbindd_socket_dir_len + 1 +
1481 strlen(WINBINDD_SOCKET_NAME);
1482 struct sockaddr_un un = {
1483 .sun_family = AF_UNIX,
1485 size_t sun_path_len = sizeof(un.sun_path);
1487 if (winbindd_socket_len >= sun_path_len) {
1488 DBG_ERR("The winbind socket path [%s/%s] is too long "
1489 "(%zu >= %zu)\n",
1490 lp_winbindd_socket_directory(),
1491 WINBINDD_SOCKET_NAME,
1492 winbindd_socket_len,
1493 sun_path_len);
1494 exit(1);
1496 } else {
1497 DBG_ERR("'winbindd_socket_directory' parameter is empty\n");
1498 exit(1);
1501 winbindd_priv_socket_dir = get_winbind_priv_pipe_dir();
1502 winbindd_priv_socket_dir_len = strlen(winbindd_priv_socket_dir);
1503 if (winbindd_priv_socket_dir_len > 0) {
1504 size_t winbindd_priv_socket_len =
1505 winbindd_priv_socket_dir_len + 1 +
1506 strlen(WINBINDD_SOCKET_NAME);
1507 struct sockaddr_un un = {
1508 .sun_family = AF_UNIX,
1510 size_t sun_path_len = sizeof(un.sun_path);
1512 if (winbindd_priv_socket_len >= sun_path_len) {
1513 DBG_ERR("The winbind privileged socket path [%s/%s] is too long "
1514 "(%zu >= %zu)\n",
1515 winbindd_priv_socket_dir,
1516 WINBINDD_SOCKET_NAME,
1517 winbindd_priv_socket_len,
1518 sun_path_len);
1519 exit(1);
1521 } else {
1522 DBG_ERR("'winbindd_priv_socket_directory' parameter is empty\n");
1523 exit(1);
1525 TALLOC_FREE(winbindd_priv_socket_dir);
1527 if (!cluster_probe_ok()) {
1528 exit(1);
1531 /* Initialise messaging system */
1533 if (global_messaging_context() == NULL) {
1534 exit(1);
1537 if (!winbindd_reload_services_file(NULL)) {
1538 DEBUG(0, ("error opening config file\n"));
1539 exit(1);
1543 size_t i;
1544 const char *idmap_backend;
1545 const char *invalid_backends[] = {
1546 "ad", "rfc2307", "rid",
1549 idmap_backend = lp_idmap_default_backend();
1550 for (i = 0; i < ARRAY_SIZE(invalid_backends); i++) {
1551 ok = strequal(idmap_backend, invalid_backends[i]);
1552 if (ok) {
1553 DBG_ERR("FATAL: Invalid idmap backend %s "
1554 "configured as the default backend!\n",
1555 idmap_backend);
1556 exit(1);
1561 ok = directory_create_or_exist(lp_lock_directory(), 0755);
1562 if (!ok) {
1563 DEBUG(0, ("Failed to create directory %s for lock files - %s\n",
1564 lp_lock_directory(), strerror(errno)));
1565 exit(1);
1568 ok = directory_create_or_exist(lp_pid_directory(), 0755);
1569 if (!ok) {
1570 DEBUG(0, ("Failed to create directory %s for pid files - %s\n",
1571 lp_pid_directory(), strerror(errno)));
1572 exit(1);
1575 load_interfaces();
1577 if (!secrets_init()) {
1579 DEBUG(0,("Could not initialize domain trust account secrets. Giving up\n"));
1580 return False;
1583 status = rpccli_pre_open_netlogon_creds();
1584 if (!NT_STATUS_IS_OK(status)) {
1585 DEBUG(0, ("rpccli_pre_open_netlogon_creds() - %s\n",
1586 nt_errstr(status)));
1587 exit(1);
1590 /* Unblock all signals we are interested in as they may have been
1591 blocked by the parent process. */
1593 BlockSignals(False, SIGINT);
1594 BlockSignals(False, SIGQUIT);
1595 BlockSignals(False, SIGTERM);
1596 BlockSignals(False, SIGUSR1);
1597 BlockSignals(False, SIGUSR2);
1598 BlockSignals(False, SIGHUP);
1599 BlockSignals(False, SIGCHLD);
1601 if (!interactive) {
1602 become_daemon(cmdline_daemon_cfg->fork,
1603 cmdline_daemon_cfg->no_process_group,
1604 log_stdout);
1605 } else {
1606 daemon_status("winbindd", "Starting process ...");
1609 pidfile_create(lp_pid_directory(), "winbindd");
1611 #ifdef HAVE_SETPGID
1613 * If we're interactive we want to set our own process group for
1614 * signal management.
1616 if (cmdline_daemon_cfg->interactive &&
1617 !cmdline_daemon_cfg->no_process_group)
1619 setpgid( (pid_t)0, (pid_t)0);
1621 #endif
1623 TimeInit();
1625 /* Don't use winbindd_reinit_after_fork here as
1626 * we're just starting up and haven't created any
1627 * winbindd-specific resources we must free yet. JRA.
1630 status = reinit_after_fork(global_messaging_context(),
1631 global_event_context(),
1632 false);
1633 if (!NT_STATUS_IS_OK(status)) {
1634 exit_daemon("Winbindd reinit_after_fork() failed", map_errno_from_nt_status(status));
1637 if (lp_winbind_debug_traceid()) {
1638 winbind_debug_traceid_setup(global_event_context());
1640 ok = initialize_password_db(true, global_event_context());
1641 if (!ok) {
1642 exit_daemon("Failed to initialize passdb backend! "
1643 "Check the 'passdb backend' variable in your "
1644 "smb.conf file.", EINVAL);
1648 * Do not initialize the parent-child-pipe before becoming
1649 * a daemon: this is used to detect a died parent in the child
1650 * process.
1652 status = init_before_fork();
1653 if (!NT_STATUS_IS_OK(status)) {
1654 exit_daemon(nt_errstr(status), map_errno_from_nt_status(status));
1657 winbindd_register_handlers(global_messaging_context(),
1658 !cmdline_daemon_cfg->fork);
1660 if (!messaging_parent_dgm_cleanup_init(global_messaging_context())) {
1661 exit(1);
1664 status = init_system_session_info(NULL);
1665 if (!NT_STATUS_IS_OK(status)) {
1666 exit_daemon("Winbindd failed to setup system user info", map_errno_from_nt_status(status));
1669 DBG_INFO("Registering DCE/RPC endpoint servers\n");
1671 ep_server = winbind_get_ep_server();
1672 if (ep_server == NULL) {
1673 DBG_ERR("Failed to get 'winbind' endpoint server\n");
1674 exit(1);
1676 status = dcerpc_register_ep_server(ep_server);
1677 if (!NT_STATUS_IS_OK(status)) {
1678 DBG_ERR("Failed to register 'winbind' endpoint "
1679 "server: %s\n", nt_errstr(status));
1680 exit(1);
1683 dce_ctx = global_dcesrv_context();
1685 DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
1687 /* Init all registered ep servers */
1688 status = dcesrv_init_registered_ep_servers(dce_ctx);
1689 if (!NT_STATUS_IS_OK(status)) {
1690 DBG_ERR("Failed to init DCE/RPC endpoint servers: %s\n",
1691 nt_errstr(status));
1692 exit(1);
1695 winbindd_init_addrchange(NULL, global_event_context(),
1696 global_messaging_context());
1698 /* setup listen sockets */
1700 if (!winbindd_setup_listeners()) {
1701 exit_daemon("Winbindd failed to setup listeners", EPIPE);
1704 irpc_add_name(winbind_imessaging_context(), "winbind_server");
1706 TALLOC_FREE(frame);
1708 if (!interactive) {
1709 daemon_ready("winbindd");
1712 gpupdate_init();
1714 /* Loop waiting for requests */
1715 while (1) {
1716 frame = talloc_stackframe();
1718 if (tevent_loop_once(global_event_context()) == -1) {
1719 DEBUG(1, ("tevent_loop_once() failed: %s\n",
1720 strerror(errno)));
1721 return 1;
1724 TALLOC_FREE(frame);
1727 return 0;