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
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.
26 BOOL opt_nocache
= False
;
27 BOOL opt_dual_daemon
= False
;
29 /* Reload configuration */
31 static BOOL
reload_services_file(BOOL test
)
39 pstrcpy(fname
,lp_configfile());
40 if (file_exist(fname
,NULL
) && !strcsequal(fname
,dyn_CONFIGFILE
)) {
41 pstrcpy(dyn_CONFIGFILE
,fname
);
46 snprintf(logfile
, sizeof(logfile
), "%s/log.winbindd", dyn_LOGFILEBASE
);
47 lp_set_logfile(logfile
);
50 ret
= lp_load(dyn_CONFIGFILE
,False
,False
,True
);
52 snprintf(logfile
, sizeof(logfile
), "%s/log.winbindd", dyn_LOGFILEBASE
);
53 lp_set_logfile(logfile
);
61 /*******************************************************************
62 Print out all talloc memory info.
63 ********************************************************************/
65 void return_all_talloc_info(int msg_type
, pid_t src_pid
, void *buf
, size_t len
)
67 TALLOC_CTX
*ctx
= talloc_init("info context");
73 info
= talloc_describe_all(ctx
);
76 message_send_pid(src_pid
, MSG_TALLOC_USAGE
, info
, info
? strlen(info
) + 1: 0, True
);
82 /**************************************************************************** **
83 Prepare to dump a core file - carefully!
84 **************************************************************************** */
86 static BOOL
dump_core(void)
90 pstrcpy( dname
, lp_logfile() );
91 if ((p
=strrchr(dname
,'/')))
93 pstrcat( dname
, "/corefiles" );
95 sys_chown( dname
, getuid(), getgid() );
101 #ifdef HAVE_GETRLIMIT
105 getrlimit( RLIMIT_CORE
, &rlp
);
106 rlp
.rlim_cur
= MAX( 4*1024*1024, rlp
.rlim_cur
);
107 setrlimit( RLIMIT_CORE
, &rlp
);
108 getrlimit( RLIMIT_CORE
, &rlp
);
109 DEBUG( 3, ( "Core limits now %d %d\n", (int)rlp
.rlim_cur
, (int)rlp
.rlim_max
) );
114 DEBUG(0,("Dumping core in %s\n",dname
));
120 /**************************************************************************** **
122 **************************************************************************** */
124 static void fault_quit(void)
131 static void winbindd_status(void)
133 struct winbindd_cli_state
*tmp
;
135 DEBUG(0, ("winbindd status:\n"));
137 /* Print client state information */
139 DEBUG(0, ("\t%d clients currently active\n", winbindd_num_clients()));
141 if (DEBUGLEVEL
>= 2 && winbindd_num_clients()) {
142 DEBUG(2, ("\tclient list:\n"));
143 for(tmp
= winbindd_client_list(); tmp
; tmp
= tmp
->next
) {
144 DEBUG(2, ("\t\tpid %d, sock %d, rbl %d, wbl %d\n",
145 tmp
->pid
, tmp
->sock
, tmp
->read_buf_len
,
146 tmp
->write_buf_len
));
151 /* Print winbindd status to log file */
153 static void print_winbindd_status(void)
156 winbindd_idmap_status();
157 winbindd_cm_status();
160 /* Flush client cache */
162 static void flush_caches(void)
164 /* Clear cached user and group enumation info */
165 wcache_flush_cache();
168 /* Handle the signal by unlinking socket and exiting */
170 static void terminate(void)
174 winbindd_idmap_close();
176 /* Remove socket file */
177 snprintf(path
, sizeof(path
), "%s/%s",
178 WINBINDD_SOCKET_DIR
, WINBINDD_SOCKET_NAME
);
183 static BOOL do_sigterm
;
185 static void termination_handler(int signum
)
191 static BOOL do_sigusr2
;
193 static void sigusr2_handler(int signum
)
199 static BOOL do_sighup
;
201 static void sighup_handler(int signum
)
207 struct dispatch_table
{
208 enum winbindd_cmd cmd
;
209 enum winbindd_result (*fn
)(struct winbindd_cli_state
*state
);
210 const char *winbindd_cmd_name
;
213 static struct dispatch_table dispatch_table
[] = {
217 { WINBINDD_GETPWNAM
, winbindd_getpwnam
, "GETPWNAM" },
218 { WINBINDD_GETPWUID
, winbindd_getpwuid
, "GETPWUID" },
220 { WINBINDD_SETPWENT
, winbindd_setpwent
, "SETPWENT" },
221 { WINBINDD_ENDPWENT
, winbindd_endpwent
, "ENDPWENT" },
222 { WINBINDD_GETPWENT
, winbindd_getpwent
, "GETPWENT" },
224 { WINBINDD_GETGROUPS
, winbindd_getgroups
, "GETGROUPS" },
226 /* Group functions */
228 { WINBINDD_GETGRNAM
, winbindd_getgrnam
, "GETGRNAM" },
229 { WINBINDD_GETGRGID
, winbindd_getgrgid
, "GETGRGID" },
230 { WINBINDD_SETGRENT
, winbindd_setgrent
, "SETGRENT" },
231 { WINBINDD_ENDGRENT
, winbindd_endgrent
, "ENDGRENT" },
232 { WINBINDD_GETGRENT
, winbindd_getgrent
, "GETGRENT" },
233 { WINBINDD_GETGRLST
, winbindd_getgrent
, "GETGRLST" },
235 /* PAM auth functions */
237 { WINBINDD_PAM_AUTH
, winbindd_pam_auth
, "PAM_AUTH" },
238 { WINBINDD_PAM_AUTH_CRAP
, winbindd_pam_auth_crap
, "AUTH_CRAP" },
239 { WINBINDD_PAM_CHAUTHTOK
, winbindd_pam_chauthtok
, "CHAUTHTOK" },
241 /* Enumeration functions */
243 { WINBINDD_LIST_USERS
, winbindd_list_users
, "LIST_USERS" },
244 { WINBINDD_LIST_GROUPS
, winbindd_list_groups
, "LIST_GROUPS" },
245 { WINBINDD_LIST_TRUSTDOM
, winbindd_list_trusted_domains
, "LIST_TRUSTDOM" },
246 { WINBINDD_SHOW_SEQUENCE
, winbindd_show_sequence
, "SHOW_SEQUENCE" },
248 /* SID related functions */
250 { WINBINDD_LOOKUPSID
, winbindd_lookupsid
, "LOOKUPSID" },
251 { WINBINDD_LOOKUPNAME
, winbindd_lookupname
, "LOOKUPNAME" },
253 /* Lookup related functions */
255 { WINBINDD_SID_TO_UID
, winbindd_sid_to_uid
, "SID_TO_UID" },
256 { WINBINDD_SID_TO_GID
, winbindd_sid_to_gid
, "SID_TO_GID" },
257 { WINBINDD_GID_TO_SID
, winbindd_gid_to_sid
, "GID_TO_SID" },
258 { WINBINDD_UID_TO_SID
, winbindd_uid_to_sid
, "UID_TO_SID" },
262 { WINBINDD_CHECK_MACHACC
, winbindd_check_machine_acct
, "CHECK_MACHACC" },
263 { WINBINDD_PING
, winbindd_ping
, "PING" },
264 { WINBINDD_INFO
, winbindd_info
, "INFO" },
265 { WINBINDD_INTERFACE_VERSION
, winbindd_interface_version
, "INTERFACE_VERSION" },
266 { WINBINDD_DOMAIN_NAME
, winbindd_domain_name
, "DOMAIN_NAME" },
267 { WINBINDD_NETBIOS_NAME
, winbindd_netbios_name
, "NETBIOS_NAME" },
271 { WINBINDD_WINS_BYNAME
, winbindd_wins_byname
, "WINS_BYNAME" },
272 { WINBINDD_WINS_BYIP
, winbindd_wins_byip
, "WINS_BYIP" },
276 { WINBINDD_NUM_CMDS
, NULL
, "NONE" }
279 static void process_request(struct winbindd_cli_state
*state
)
281 struct dispatch_table
*table
= dispatch_table
;
283 /* Free response data - we may be interrupted and receive another
284 command before being able to send this data off. */
286 SAFE_FREE(state
->response
.extra_data
);
288 ZERO_STRUCT(state
->response
);
290 state
->response
.result
= WINBINDD_ERROR
;
291 state
->response
.length
= sizeof(struct winbindd_response
);
293 /* Process command */
295 for (table
= dispatch_table
; table
->fn
; table
++) {
296 if (state
->request
.cmd
== table
->cmd
) {
297 DEBUG(10,("process_request: request fn %s\n", table
->winbindd_cmd_name
));
298 state
->response
.result
= table
->fn(state
);
304 DEBUG(10,("process_request: unknown request fn number %d\n", (int)state
->request
.cmd
));
306 /* In case extra data pointer is NULL */
308 if (!state
->response
.extra_data
)
309 state
->response
.length
= sizeof(struct winbindd_response
);
312 /* Process a new connection by adding it to the client connection list */
314 static void new_connection(int listen_sock
)
316 struct sockaddr_un sunaddr
;
317 struct winbindd_cli_state
*state
;
321 /* Accept connection */
323 len
= sizeof(sunaddr
);
326 sock
= accept(listen_sock
, (struct sockaddr
*)&sunaddr
, &len
);
327 } while (sock
== -1 && errno
== EINTR
);
332 DEBUG(6,("accepted socket %d\n", sock
));
334 /* Create new connection structure */
336 if ((state
= (struct winbindd_cli_state
*)
337 malloc(sizeof(*state
))) == NULL
)
343 state
->last_access
= time(NULL
);
345 /* Add to connection list */
347 winbindd_add_client(state
);
350 /* Remove a client connection from client connection list */
352 static void remove_client(struct winbindd_cli_state
*state
)
354 /* It's a dead client - hold a funeral */
362 /* Free any getent state */
364 free_getent_state(state
->getpwent_state
);
365 free_getent_state(state
->getgrent_state
);
367 /* We may have some extra data that was not freed if the
368 client was killed unexpectedly */
370 SAFE_FREE(state
->response
.extra_data
);
372 /* Remove from list and free */
374 winbindd_remove_client(state
);
380 /* Shutdown client connection which has been idle for the longest time */
382 static BOOL
remove_idle_client(void)
384 struct winbindd_cli_state
*state
, *remove_state
= NULL
;
385 time_t last_access
= 0;
388 for (state
= winbindd_client_list(); state
; state
= state
->next
) {
389 if (state
->read_buf_len
== 0 && state
->write_buf_len
== 0 &&
390 !state
->getpwent_state
&& !state
->getgrent_state
) {
392 if (!last_access
|| state
->last_access
< last_access
) {
393 last_access
= state
->last_access
;
394 remove_state
= state
;
400 DEBUG(5,("Found %d idle client connections, shutting down sock %d, pid %u\n",
401 nidle
, remove_state
->sock
, (unsigned int)remove_state
->pid
));
402 remove_client(remove_state
);
409 /* Process a complete received packet from a client */
411 void winbind_process_packet(struct winbindd_cli_state
*state
)
413 /* Process request */
415 /* Ensure null termination of entire request */
416 state
->request
.null_term
= '\0';
418 state
->pid
= state
->request
.pid
;
420 process_request(state
);
422 /* Update client state */
424 state
->read_buf_len
= 0;
425 state
->write_buf_len
= sizeof(struct winbindd_response
);
427 /* we might need to send it to the dual daemon */
428 if (opt_dual_daemon
) {
429 dual_send_request(state
);
433 /* Read some data from a client connection */
435 void winbind_client_read(struct winbindd_cli_state
*state
)
441 n
= sys_read(state
->sock
, state
->read_buf_len
+
442 (char *)&state
->request
,
443 sizeof(state
->request
) - state
->read_buf_len
);
445 DEBUG(10,("client_read: read %d bytes. Need %d more for a full request.\n", n
, sizeof(state
->request
) - n
- state
->read_buf_len
));
447 /* Read failed, kill client */
449 if (n
== -1 || n
== 0) {
450 DEBUG(5,("read failed on sock %d, pid %d: %s\n",
451 state
->sock
, state
->pid
,
452 (n
== -1) ? strerror(errno
) : "EOF"));
454 state
->finished
= True
;
458 /* Update client state */
460 state
->read_buf_len
+= n
;
461 state
->last_access
= time(NULL
);
464 /* Write some data to a client connection */
466 static void client_write(struct winbindd_cli_state
*state
)
471 /* Write some data */
473 if (!state
->write_extra_data
) {
475 /* Write response structure */
477 data
= (char *)&state
->response
+ sizeof(state
->response
) -
478 state
->write_buf_len
;
482 /* Write extra data */
484 data
= (char *)state
->response
.extra_data
+
485 state
->response
.length
-
486 sizeof(struct winbindd_response
) -
487 state
->write_buf_len
;
490 num_written
= sys_write(state
->sock
, data
, state
->write_buf_len
);
492 DEBUG(10,("client_write: wrote %d bytes.\n", num_written
));
494 /* Write failed, kill cilent */
496 if (num_written
== -1 || num_written
== 0) {
498 DEBUG(3,("write failed on sock %d, pid %d: %s\n",
499 state
->sock
, state
->pid
,
500 (num_written
== -1) ? strerror(errno
) : "EOF"));
502 state
->finished
= True
;
504 SAFE_FREE(state
->response
.extra_data
);
509 /* Update client state */
511 state
->write_buf_len
-= num_written
;
512 state
->last_access
= time(NULL
);
514 /* Have we written all data? */
516 if (state
->write_buf_len
== 0) {
518 /* Take care of extra data */
520 if (state
->write_extra_data
) {
522 SAFE_FREE(state
->response
.extra_data
);
524 state
->write_extra_data
= False
;
526 DEBUG(10,("client_write: client_write: complete response written.\n"));
528 } else if (state
->response
.length
>
529 sizeof(struct winbindd_response
)) {
531 /* Start writing extra data */
533 state
->write_buf_len
=
534 state
->response
.length
-
535 sizeof(struct winbindd_response
);
537 DEBUG(10,("client_write: need to write %d extra data bytes.\n", (int)state
->write_buf_len
));
539 state
->write_extra_data
= True
;
544 /* Process incoming clients on listen_sock. We use a tricky non-blocking,
545 non-forking, non-threaded model which allows us to handle many
546 simultaneous connections while remaining impervious to many denial of
549 static void process_loop(void)
551 /* We'll be doing this a lot */
554 struct winbindd_cli_state
*state
;
556 int maxfd
, listen_sock
, selret
;
557 struct timeval timeout
;
559 /* Handle messages */
563 /* rescan the trusted domains list. This must be done
564 regularly to cope with transitive trusts */
565 rescan_trusted_domains(False
);
567 /* Free up temporary memory */
570 main_loop_talloc_free();
572 /* Initialise fd lists for select() */
574 listen_sock
= open_winbindd_socket();
576 if (listen_sock
== -1) {
577 perror("open_winbind_socket");
585 FD_SET(listen_sock
, &r_fds
);
587 timeout
.tv_sec
= WINBINDD_ESTABLISH_LOOP
;
590 if (opt_dual_daemon
) {
591 maxfd
= dual_select_setup(&w_fds
, maxfd
);
594 /* Set up client readers and writers */
596 state
= winbindd_client_list();
600 /* Dispose of client connection if it is marked as
603 if (state
->finished
) {
604 struct winbindd_cli_state
*next
= state
->next
;
606 remove_client(state
);
611 /* Select requires we know the highest fd used */
613 if (state
->sock
> maxfd
)
616 /* Add fd for reading */
618 if (state
->read_buf_len
!= sizeof(state
->request
))
619 FD_SET(state
->sock
, &r_fds
);
621 /* Add fd for writing */
623 if (state
->write_buf_len
)
624 FD_SET(state
->sock
, &w_fds
);
631 selret
= sys_select(maxfd
+ 1, &r_fds
, &w_fds
, NULL
, &timeout
);
636 if ((selret
== -1 && errno
!= EINTR
) || selret
== 0) {
638 /* Select error, something is badly wrong */
644 /* Create a new connection if listen_sock readable */
648 if (opt_dual_daemon
) {
652 if (FD_ISSET(listen_sock
, &r_fds
)) {
653 while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS
- 1) {
654 DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n",
655 WINBINDD_MAX_SIMULTANEOUS_CLIENTS
));
656 if (!remove_idle_client()) {
657 DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n",
658 WINBINDD_MAX_SIMULTANEOUS_CLIENTS
));
662 new_connection(listen_sock
);
665 /* Process activity on client connections */
667 for (state
= winbindd_client_list(); state
;
668 state
= state
->next
) {
670 /* Data available for reading */
672 if (FD_ISSET(state
->sock
, &r_fds
)) {
676 winbind_client_read(state
);
679 * If we have the start of a
680 * packet, then check the
681 * length field to make sure
682 * the client's not talking
686 if (state
->read_buf_len
>= sizeof(uint32
)
687 && *(uint32
*) &state
->request
!= sizeof(state
->request
)) {
688 DEBUG(0,("process_loop: Invalid request size from pid %d: %d bytes sent, should be %d\n",
689 state
->request
.pid
, *(uint32
*) &state
->request
, sizeof(state
->request
)));
691 remove_client(state
);
695 /* A request packet might be
698 if (state
->read_buf_len
==
699 sizeof(state
->request
)) {
700 winbind_process_packet(state
);
704 /* Data available for writing */
706 if (FD_ISSET(state
->sock
, &w_fds
))
712 winbindd_check_cache_size(time(NULL
));
715 /* Check signal handling things */
722 DEBUG(3, ("got SIGHUP\n"));
724 /* Flush various caches */
727 reload_services_file(True
);
732 print_winbindd_status();
740 these are split out from the main winbindd for use by the background daemon
742 BOOL
winbind_setup_common(void)
746 if (!secrets_init()) {
748 DEBUG(0,("Could not initialize domain trust account secrets. Giving up\n"));
752 namecache_enable(); /* Enable netbios namecache */
754 /* Check winbindd parameters are valid */
756 ZERO_STRUCT(server_state
);
758 if (!winbindd_param_init())
761 /* Winbind daemon initialisation */
763 if (!winbindd_idmap_init())
766 /* Unblock all signals we are interested in as they may have been
767 blocked by the parent process. */
769 BlockSignals(False
, SIGINT
);
770 BlockSignals(False
, SIGQUIT
);
771 BlockSignals(False
, SIGTERM
);
772 BlockSignals(False
, SIGUSR1
);
773 BlockSignals(False
, SIGUSR2
);
774 BlockSignals(False
, SIGHUP
);
776 /* Setup signal handlers */
778 CatchSignal(SIGINT
, termination_handler
); /* Exit on these sigs */
779 CatchSignal(SIGQUIT
, termination_handler
);
780 CatchSignal(SIGTERM
, termination_handler
);
782 CatchSignal(SIGPIPE
, SIG_IGN
); /* Ignore sigpipe */
784 CatchSignal(SIGUSR2
, sigusr2_handler
); /* Debugging sigs */
785 CatchSignal(SIGHUP
, sighup_handler
);
793 struct winbindd_state server_state
; /* Server state information */
796 static void usage(void)
798 printf("Usage: winbindd [options]\n");
799 printf("\t-F daemon in foreground mode\n");
800 printf("\t-S log to stdout\n");
801 printf("\t-i interactive mode\n");
802 printf("\t-B dual daemon mode\n");
803 printf("\t-n disable cacheing\n");
804 printf("\t-d level set debug level\n");
805 printf("\t-s configfile choose smb.conf location\n");
806 printf("\t-h show this help message\n");
809 int main(int argc
, char **argv
)
811 extern BOOL AllowDebugChange
;
813 BOOL interactive
= False
;
815 BOOL log_stdout
= False
;
818 /* glibc (?) likes to print "User defined signal 1" and exit if a
819 SIGUSR[12] is received before a handler is installed */
821 CatchSignal(SIGUSR1
, SIG_IGN
);
822 CatchSignal(SIGUSR2
, SIG_IGN
);
824 fault_setup((void (*)(void *))fault_quit
);
826 snprintf(logfile
, sizeof(logfile
), "%s/log.winbindd", dyn_LOGFILEBASE
);
827 lp_set_logfile(logfile
);
829 /* Initialise for running in non-root mode */
833 /* Set environment variable so we don't recursively call ourselves.
834 This may also be useful interactively. */
836 setenv(WINBINDD_DONT_ENV
, "1", 1);
838 /* Initialise samba/rpc client stuff */
840 while ((opt
= getopt(argc
, argv
, "FSid:s:nhB")) != EOF
) {
849 /* Don't become a daemon */
856 /* dual daemon system */
858 opt_dual_daemon
= True
;
861 /* disable cacheing */
866 /* Run with specified debug level */
868 DEBUGLEVEL
= atoi(optarg
);
869 AllowDebugChange
= False
;
872 /* Load a different smb.conf file */
874 pstrcpy(dyn_CONFIGFILE
,optarg
);
882 printf("Unknown option %c\n", (char)opt
);
887 if (log_stdout
&& Fork
) {
888 printf("Can't log to stdout (-S) unless daemon is in foreground +(-F) or interactive (-i)\n");
893 snprintf(logfile
, sizeof(logfile
), "%s/log.winbindd", dyn_LOGFILEBASE
);
894 lp_set_logfile(logfile
);
895 setup_logging("winbindd", log_stdout
?DEBUG_STDOUT
:DEBUG_FILE
);
898 DEBUG(1, ("winbindd version %s started.\n", VERSION
) );
899 DEBUGADD( 1, ( "Copyright The Samba Team 2000-2001\n" ) );
901 if (!reload_services_file(False
)) {
902 DEBUG(0, ("error opening config file\n"));
913 pidfile_create("winbindd");
919 * If we're interactive we want to set our own process group for
923 setpgid( (pid_t
)0, (pid_t
)0);
926 if (!winbind_setup_common()) {
930 if (opt_dual_daemon
) {
934 /* Initialise messaging system */
936 if (!message_init()) {
937 DEBUG(0, ("unable to initialise messaging system\n"));
941 register_msg_pool_usage();
942 message_register(MSG_REQ_TALLOC_USAGE
, return_all_talloc_info
);
944 /* Loop waiting for requests */
948 trustdom_cache_shutdown();
949 uni_group_cache_shutdown();