2000-05-09 15:43:00 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-05-09 15:43:00 +04:00
Winbind daemon for ntdom nss module
2002-11-07 10:17:09 +03:00
Copyright ( C ) by Tim Potter 2000 - 2002
2002-07-15 14:35:28 +04:00
Copyright ( C ) Andrew Tridgell 2002
2003-04-14 07:53:58 +04:00
Copyright ( C ) Jelmer Vernooij 2003
2000-05-09 15:43:00 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "winbindd.h"
2002-07-15 14:35:28 +04:00
BOOL opt_nocache = False ;
2003-07-15 08:19:57 +04:00
BOOL opt_dual_daemon = True ;
2000-05-09 15:43:00 +04:00
/* Reload configuration */
2001-05-07 08:32:40 +04:00
static BOOL reload_services_file ( BOOL test )
2000-05-09 15:43:00 +04:00
{
BOOL ret ;
2001-05-07 08:32:40 +04:00
if ( lp_loaded ( ) ) {
pstring fname ;
pstrcpy ( fname , lp_configfile ( ) ) ;
2001-11-19 05:49:53 +03:00
if ( file_exist ( fname , NULL ) & & ! strcsequal ( fname , dyn_CONFIGFILE ) ) {
pstrcpy ( dyn_CONFIGFILE , fname ) ;
2001-05-07 08:32:40 +04:00
test = False ;
}
}
2000-05-09 15:43:00 +04:00
reopen_logs ( ) ;
2001-11-19 05:49:53 +03:00
ret = lp_load ( dyn_CONFIGFILE , False , False , True ) ;
2000-05-09 15:43:00 +04:00
reopen_logs ( ) ;
load_interfaces ( ) ;
return ( ret ) ;
}
2003-07-15 21:21:21 +04:00
2001-11-23 14:18:20 +03:00
# if DUMP_CORE
/**************************************************************************** **
Prepare to dump a core file - carefully !
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL dump_core ( void )
{
char * p ;
pstring dname ;
2001-12-21 01:27:05 +03:00
pstrcpy ( dname , lp_logfile ( ) ) ;
2001-11-23 14:18:20 +03:00
if ( ( p = strrchr ( dname , ' / ' ) ) )
* p = 0 ;
pstrcat ( dname , " /corefiles " ) ;
mkdir ( dname , 0700 ) ;
sys_chown ( dname , getuid ( ) , getgid ( ) ) ;
chmod ( dname , 0700 ) ;
if ( chdir ( dname ) )
return ( False ) ;
umask ( ~ ( 0700 ) ) ;
# ifdef HAVE_GETRLIMIT
# ifdef RLIMIT_CORE
{
struct rlimit rlp ;
getrlimit ( RLIMIT_CORE , & rlp ) ;
rlp . rlim_cur = MAX ( 4 * 1024 * 1024 , rlp . rlim_cur ) ;
setrlimit ( RLIMIT_CORE , & rlp ) ;
getrlimit ( RLIMIT_CORE , & rlp ) ;
DEBUG ( 3 , ( " Core limits now %d %d \n " , ( int ) rlp . rlim_cur , ( int ) rlp . rlim_max ) ) ;
}
# endif
# endif
DEBUG ( 0 , ( " Dumping core in %s \n " , dname ) ) ;
abort ( ) ;
return ( True ) ;
} /* dump_core */
# endif
/**************************************************************************** **
Handle a fault . .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void fault_quit ( void )
{
# if DUMP_CORE
dump_core ( ) ;
# endif
}
2001-11-14 09:18:13 +03:00
static void winbindd_status ( void )
2000-05-09 15:43:00 +04:00
{
2001-05-07 08:32:40 +04:00
struct winbindd_cli_state * tmp ;
2001-11-14 09:18:13 +03:00
DEBUG ( 0 , ( " winbindd status: \n " ) ) ;
2001-05-07 08:32:40 +04:00
/* Print client state information */
2002-11-02 04:36:42 +03:00
DEBUG ( 0 , ( " \t %d clients currently active \n " , winbindd_num_clients ( ) ) ) ;
2001-05-07 08:32:40 +04:00
2002-11-02 04:36:42 +03:00
if ( DEBUGLEVEL > = 2 & & winbindd_num_clients ( ) ) {
2001-05-07 08:32:40 +04:00
DEBUG ( 2 , ( " \t client list: \n " ) ) ;
2002-11-02 04:36:42 +03:00
for ( tmp = winbindd_client_list ( ) ; tmp ; tmp = tmp - > next ) {
2003-07-22 08:31:20 +04:00
DEBUG ( 2 , ( " \t \t pid %lu, sock %d, rbl %d, wbl %d \n " ,
( unsigned long ) tmp - > pid , tmp - > sock , tmp - > read_buf_len ,
2001-05-07 08:32:40 +04:00
tmp - > write_buf_len ) ) ;
}
}
}
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Print winbindd status to log file */
2000-05-09 15:43:00 +04:00
2001-11-15 06:23:15 +03:00
static void print_winbindd_status ( void )
2001-05-07 08:32:40 +04:00
{
2001-11-14 09:18:13 +03:00
winbindd_status ( ) ;
2001-11-15 00:49:30 +03:00
winbindd_cm_status ( ) ;
2000-05-09 15:43:00 +04:00
}
/* Flush client cache */
2001-11-15 06:23:15 +03:00
static void flush_caches ( void )
2000-05-09 15:43:00 +04:00
{
2003-06-21 08:05:01 +04:00
#if 0
2001-12-10 02:59:42 +03:00
/* Clear cached user and group enumation info */
2003-06-21 08:05:01 +04:00
if ( ! opt_dual_daemon ) /* Until we have coherent cache flush. */
wcache_flush_cache ( ) ;
# endif
/* We need to invalidate cached user list entries on a SIGHUP
otherwise cached access denied errors due to restrict anonymous
hang around until the sequence number changes . */
wcache_invalidate_cache ( ) ;
2000-05-09 15:43:00 +04:00
}
/* Handle the signal by unlinking socket and exiting */
2001-11-15 00:49:30 +03:00
static void terminate ( void )
2000-05-09 15:43:00 +04:00
{
2001-05-07 08:32:40 +04:00
pstring path ;
2002-01-19 23:21:29 +03:00
2003-05-12 22:12:31 +04:00
idmap_close ( ) ;
2001-05-07 08:32:40 +04:00
/* Remove socket file */
2003-07-23 16:33:59 +04:00
pstr_sprintf ( path , " %s/%s " ,
2001-05-07 08:32:40 +04:00
WINBINDD_SOCKET_DIR , WINBINDD_SOCKET_NAME ) ;
unlink ( path ) ;
exit ( 0 ) ;
}
2000-05-09 15:43:00 +04:00
2001-11-15 00:49:30 +03:00
static BOOL do_sigterm ;
static void termination_handler ( int signum )
{
do_sigterm = True ;
2002-02-01 02:26:12 +03:00
sys_select_signal ( ) ;
2001-11-15 00:49:30 +03:00
}
2002-01-10 09:20:03 +03:00
static BOOL do_sigusr2 ;
2000-05-09 15:43:00 +04:00
2002-01-10 09:20:03 +03:00
static void sigusr2_handler ( int signum )
2001-05-07 08:32:40 +04:00
{
2002-01-10 09:20:03 +03:00
do_sigusr2 = True ;
2002-02-01 02:26:12 +03:00
sys_select_signal ( ) ;
2000-05-09 15:43:00 +04:00
}
2001-05-07 08:32:40 +04:00
static BOOL do_sighup ;
2000-05-09 15:43:00 +04:00
static void sighup_handler ( int signum )
{
2001-05-07 08:32:40 +04:00
do_sighup = True ;
2002-02-01 02:26:12 +03:00
sys_select_signal ( ) ;
2000-05-09 15:43:00 +04:00
}
2003-07-15 21:21:21 +04:00
/* React on 'smbcontrol winbindd reload-config' in the same way as on SIGHUP*/
static void msg_reload_services ( int msg_type , pid_t src , void * buf , size_t len )
{
/* Flush various caches */
flush_caches ( ) ;
reload_services_file ( True ) ;
}
/* React on 'smbcontrol winbindd shutdown' in the same way as on SIGTERM*/
static void msg_shutdown ( int msg_type , pid_t src , void * buf , size_t len )
{
terminate ( ) ;
}
2001-05-07 08:32:40 +04:00
struct dispatch_table {
enum winbindd_cmd cmd ;
enum winbindd_result ( * fn ) ( struct winbindd_cli_state * state ) ;
2003-01-03 11:28:12 +03:00
const char * winbindd_cmd_name ;
2001-05-07 08:32:40 +04:00
} ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
static struct dispatch_table dispatch_table [ ] = {
/* User functions */
2000-05-09 15:43:00 +04:00
2002-01-10 09:20:03 +03:00
{ WINBINDD_GETPWNAM , winbindd_getpwnam , " GETPWNAM " } ,
{ WINBINDD_GETPWUID , winbindd_getpwuid , " GETPWUID " } ,
2001-10-05 04:20:06 +04:00
2001-11-14 07:44:36 +03:00
{ WINBINDD_SETPWENT , winbindd_setpwent , " SETPWENT " } ,
{ WINBINDD_ENDPWENT , winbindd_endpwent , " ENDPWENT " } ,
{ WINBINDD_GETPWENT , winbindd_getpwent , " GETPWENT " } ,
2001-10-05 04:20:06 +04:00
2001-11-14 07:44:36 +03:00
{ WINBINDD_GETGROUPS , winbindd_getgroups , " GETGROUPS " } ,
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Group functions */
2000-05-09 15:43:00 +04:00
2002-01-10 09:20:03 +03:00
{ WINBINDD_GETGRNAM , winbindd_getgrnam , " GETGRNAM " } ,
{ WINBINDD_GETGRGID , winbindd_getgrgid , " GETGRGID " } ,
2001-11-14 07:44:36 +03:00
{ WINBINDD_SETGRENT , winbindd_setgrent , " SETGRENT " } ,
{ WINBINDD_ENDGRENT , winbindd_endgrent , " ENDGRENT " } ,
{ WINBINDD_GETGRENT , winbindd_getgrent , " GETGRENT " } ,
2002-07-15 14:35:28 +04:00
{ WINBINDD_GETGRLST , winbindd_getgrent , " GETGRLST " } ,
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* PAM auth functions */
2000-05-09 15:43:00 +04:00
2001-11-14 07:44:36 +03:00
{ WINBINDD_PAM_AUTH , winbindd_pam_auth , " PAM_AUTH " } ,
{ WINBINDD_PAM_AUTH_CRAP , winbindd_pam_auth_crap , " AUTH_CRAP " } ,
{ WINBINDD_PAM_CHAUTHTOK , winbindd_pam_chauthtok , " CHAUTHTOK " } ,
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Enumeration functions */
2000-05-09 15:43:00 +04:00
2001-11-15 22:40:00 +03:00
{ WINBINDD_LIST_USERS , winbindd_list_users , " LIST_USERS " } ,
{ WINBINDD_LIST_GROUPS , winbindd_list_groups , " LIST_GROUPS " } ,
2001-11-14 07:44:36 +03:00
{ WINBINDD_LIST_TRUSTDOM , winbindd_list_trusted_domains , " LIST_TRUSTDOM " } ,
2002-01-31 14:49:29 +03:00
{ WINBINDD_SHOW_SEQUENCE , winbindd_show_sequence , " SHOW_SEQUENCE " } ,
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* SID related functions */
2000-05-09 15:43:00 +04:00
2001-11-14 07:44:36 +03:00
{ WINBINDD_LOOKUPSID , winbindd_lookupsid , " LOOKUPSID " } ,
{ WINBINDD_LOOKUPNAME , winbindd_lookupname , " LOOKUPNAME " } ,
2000-05-09 15:43:00 +04:00
2001-11-15 22:40:00 +03:00
/* Lookup related functions */
2000-05-09 15:43:00 +04:00
2001-11-14 07:44:36 +03:00
{ WINBINDD_SID_TO_UID , winbindd_sid_to_uid , " SID_TO_UID " } ,
{ WINBINDD_SID_TO_GID , winbindd_sid_to_gid , " SID_TO_GID " } ,
{ WINBINDD_GID_TO_SID , winbindd_gid_to_sid , " GID_TO_SID " } ,
{ WINBINDD_UID_TO_SID , winbindd_uid_to_sid , " UID_TO_SID " } ,
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Miscellaneous */
2000-05-09 15:43:00 +04:00
2001-11-14 07:44:36 +03:00
{ WINBINDD_CHECK_MACHACC , winbindd_check_machine_acct , " CHECK_MACHACC " } ,
2002-01-10 13:23:54 +03:00
{ WINBINDD_PING , winbindd_ping , " PING " } ,
2002-01-10 14:28:14 +03:00
{ WINBINDD_INFO , winbindd_info , " INFO " } ,
{ WINBINDD_INTERFACE_VERSION , winbindd_interface_version , " INTERFACE_VERSION " } ,
2002-01-26 12:55:38 +03:00
{ WINBINDD_DOMAIN_NAME , winbindd_domain_name , " DOMAIN_NAME " } ,
2003-01-28 15:07:02 +03:00
{ WINBINDD_NETBIOS_NAME , winbindd_netbios_name , " NETBIOS_NAME " } ,
2003-03-24 12:54:13 +03:00
{ WINBINDD_PRIV_PIPE_DIR , winbindd_priv_pipe_dir , " WINBINDD_PRIV_PIPE_DIR " } ,
2000-05-09 15:43:00 +04:00
2002-03-29 18:37:39 +03:00
/* WINS functions */
{ WINBINDD_WINS_BYNAME , winbindd_wins_byname , " WINS_BYNAME " } ,
{ WINBINDD_WINS_BYIP , winbindd_wins_byip , " WINS_BYIP " } ,
2003-07-09 20:44:47 +04:00
/* UNIX account management functions */
{ WINBINDD_CREATE_USER , winbindd_create_user , " CREATE_USER " } ,
{ WINBINDD_CREATE_GROUP , winbindd_create_group , " CREATE_GROUP " } ,
{ WINBINDD_ADD_USER_TO_GROUP , winbindd_add_user_to_group , " ADD_USER_TO_GROUP " } ,
{ WINBINDD_REMOVE_USER_FROM_GROUP , winbindd_remove_user_from_group , " REMOVE_USER_FROM_GROUP " } ,
{ WINBINDD_SET_USER_PRIMARY_GROUP , winbindd_set_user_primary_group , " SET_USER_PRIMARY_GROUP " } ,
{ WINBINDD_DELETE_USER , winbindd_delete_user , " DELETE_USER " } ,
{ WINBINDD_DELETE_GROUP , winbindd_delete_group , " DELETE_GROUP " } ,
2001-05-07 08:32:40 +04:00
/* End of list */
2000-05-09 15:43:00 +04:00
2001-11-14 07:44:36 +03:00
{ WINBINDD_NUM_CMDS , NULL , " NONE " }
2001-05-07 08:32:40 +04:00
} ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
static void process_request ( struct winbindd_cli_state * state )
2000-05-09 15:43:00 +04:00
{
2001-05-07 08:32:40 +04:00
struct dispatch_table * table = dispatch_table ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Free response data - we may be interrupted and receive another
command before being able to send this data off . */
2000-05-09 15:43:00 +04:00
2001-09-17 08:52:45 +04:00
SAFE_FREE ( state - > response . extra_data ) ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
ZERO_STRUCT ( state - > response ) ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
state - > response . result = WINBINDD_ERROR ;
state - > response . length = sizeof ( struct winbindd_response ) ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Process command */
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
for ( table = dispatch_table ; table - > fn ; table + + ) {
if ( state - > request . cmd = = table - > cmd ) {
2001-11-14 07:44:36 +03:00
DEBUG ( 10 , ( " process_request: request fn %s \n " , table - > winbindd_cmd_name ) ) ;
2001-05-07 08:32:40 +04:00
state - > response . result = table - > fn ( state ) ;
break ;
}
}
2000-05-09 15:43:00 +04:00
2001-11-14 07:44:36 +03:00
if ( ! table - > fn )
DEBUG ( 10 , ( " process_request: unknown request fn number %d \n " , ( int ) state - > request . cmd ) ) ;
2001-05-07 08:32:40 +04:00
/* In case extra data pointer is NULL */
2000-05-09 15:43:00 +04:00
2001-10-05 04:20:06 +04:00
if ( ! state - > response . extra_data )
2001-05-07 08:32:40 +04:00
state - > response . length = sizeof ( struct winbindd_response ) ;
2000-05-09 15:43:00 +04:00
}
2001-05-07 08:32:40 +04:00
/* Process a new connection by adding it to the client connection list */
2000-05-09 15:43:00 +04:00
2003-04-07 11:32:51 +04:00
static void new_connection ( int listen_sock , BOOL privileged )
2000-05-09 15:43:00 +04:00
{
2001-05-07 08:32:40 +04:00
struct sockaddr_un sunaddr ;
struct winbindd_cli_state * state ;
2001-06-25 06:53:13 +04:00
socklen_t len ;
int sock ;
2001-05-07 08:32:40 +04:00
/* Accept connection */
len = sizeof ( sunaddr ) ;
2001-11-15 00:49:30 +03:00
do {
2002-11-02 04:36:42 +03:00
sock = accept ( listen_sock , ( struct sockaddr * ) & sunaddr , & len ) ;
2001-11-15 00:49:30 +03:00
} while ( sock = = - 1 & & errno = = EINTR ) ;
if ( sock = = - 1 )
2001-05-07 08:32:40 +04:00
return ;
DEBUG ( 6 , ( " accepted socket %d \n " , sock ) ) ;
/* Create new connection structure */
2001-10-05 04:20:06 +04:00
if ( ( state = ( struct winbindd_cli_state * )
malloc ( sizeof ( * state ) ) ) = = NULL )
2001-05-07 08:32:40 +04:00
return ;
ZERO_STRUCTP ( state ) ;
state - > sock = sock ;
2003-02-28 03:25:55 +03:00
state - > last_access = time ( NULL ) ;
2003-04-07 11:32:51 +04:00
state - > privileged = privileged ;
2003-03-24 12:54:13 +03:00
2001-05-07 08:32:40 +04:00
/* Add to connection list */
2002-11-02 04:36:42 +03:00
winbindd_add_client ( state ) ;
2001-05-07 08:32:40 +04:00
}
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Remove a client connection from client connection list */
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
static void remove_client ( struct winbindd_cli_state * state )
{
/* It's a dead client - hold a funeral */
if ( state ! = NULL ) {
/* Close socket */
close ( state - > sock ) ;
/* Free any getent state */
free_getent_state ( state - > getpwent_state ) ;
free_getent_state ( state - > getgrent_state ) ;
/* We may have some extra data that was not freed if the
client was killed unexpectedly */
2001-09-17 08:52:45 +04:00
SAFE_FREE ( state - > response . extra_data ) ;
2001-05-07 08:32:40 +04:00
/* Remove from list and free */
2002-11-02 04:36:42 +03:00
winbindd_remove_client ( state ) ;
2001-09-17 08:52:45 +04:00
SAFE_FREE ( state ) ;
2001-05-07 08:32:40 +04:00
}
}
2000-05-09 15:43:00 +04:00
2002-07-15 14:35:28 +04:00
2003-02-28 03:25:55 +03:00
/* Shutdown client connection which has been idle for the longest time */
static BOOL remove_idle_client ( void )
{
struct winbindd_cli_state * state , * remove_state = NULL ;
time_t last_access = 0 ;
int nidle = 0 ;
for ( state = winbindd_client_list ( ) ; state ; state = state - > next ) {
if ( state - > read_buf_len = = 0 & & state - > write_buf_len = = 0 & &
! state - > getpwent_state & & ! state - > getgrent_state ) {
nidle + + ;
if ( ! last_access | | state - > last_access < last_access ) {
last_access = state - > last_access ;
remove_state = state ;
}
}
}
if ( remove_state ) {
DEBUG ( 5 , ( " Found %d idle client connections, shutting down sock %d, pid %u \n " ,
nidle , remove_state - > sock , ( unsigned int ) remove_state - > pid ) ) ;
remove_client ( remove_state ) ;
return True ;
}
return False ;
}
2001-05-07 08:32:40 +04:00
/* Process a complete received packet from a client */
2000-05-09 15:43:00 +04:00
2002-07-15 14:35:28 +04:00
void winbind_process_packet ( struct winbindd_cli_state * state )
2001-05-07 08:32:40 +04:00
{
/* Process request */
2002-08-17 21:00:51 +04:00
/* Ensure null termination of entire request */
2002-12-20 04:25:27 +03:00
state - > request . null_term = ' \0 ' ;
2002-08-17 21:00:51 +04:00
2001-05-07 08:32:40 +04:00
state - > pid = state - > request . pid ;
process_request ( state ) ;
/* Update client state */
state - > read_buf_len = 0 ;
state - > write_buf_len = sizeof ( struct winbindd_response ) ;
2002-07-15 14:35:28 +04:00
/* we might need to send it to the dual daemon */
if ( opt_dual_daemon ) {
dual_send_request ( state ) ;
}
2000-05-09 15:43:00 +04:00
}
/* Read some data from a client connection */
2002-07-15 14:35:28 +04:00
void winbind_client_read ( struct winbindd_cli_state * state )
2000-05-09 15:43:00 +04:00
{
2001-05-07 08:32:40 +04:00
int n ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Read data */
2002-10-16 01:33:16 +04:00
n = sys_read ( state - > sock , state - > read_buf_len +
( char * ) & state - > request ,
sizeof ( state - > request ) - state - > read_buf_len ) ;
2001-05-07 08:32:40 +04:00
2003-11-07 01:11:08 +03:00
DEBUG ( 10 , ( " client_read: read %d bytes. Need %ld more for a full request. \n " , n , ( unsigned long ) ( sizeof ( state - > request ) - n - state - > read_buf_len ) ) ) ;
2001-11-14 07:44:36 +03:00
2001-05-07 08:32:40 +04:00
/* Read failed, kill client */
if ( n = = - 1 | | n = = 0 ) {
2003-07-22 08:31:20 +04:00
DEBUG ( 5 , ( " read failed on sock %d, pid %lu: %s \n " ,
state - > sock , ( unsigned long ) state - > pid ,
2001-05-07 08:32:40 +04:00
( n = = - 1 ) ? strerror ( errno ) : " EOF " ) ) ;
state - > finished = True ;
return ;
}
/* Update client state */
state - > read_buf_len + = n ;
2003-02-28 03:25:55 +03:00
state - > last_access = time ( NULL ) ;
2000-05-09 15:43:00 +04:00
}
/* Write some data to a client connection */
static void client_write ( struct winbindd_cli_state * state )
{
2001-05-07 08:32:40 +04:00
char * data ;
int num_written ;
/* Write some data */
2003-10-13 21:31:02 +04:00
/*
* The fancy calculation of data below allows us to handle the
* case where write ( sys_write ) does not write all the data we
* gave it . In that case , we will come back through here again
* because of the loop above us , and we want to pick up where
* we left off .
*/
2001-05-07 08:32:40 +04:00
if ( ! state - > write_extra_data ) {
/* Write response structure */
data = ( char * ) & state - > response + sizeof ( state - > response ) -
state - > write_buf_len ;
} else {
/* Write extra data */
data = ( char * ) state - > response . extra_data +
state - > response . length -
sizeof ( struct winbindd_response ) -
state - > write_buf_len ;
}
2002-10-16 01:33:16 +04:00
num_written = sys_write ( state - > sock , data , state - > write_buf_len ) ;
2001-05-07 08:32:40 +04:00
2001-11-14 07:44:36 +03:00
DEBUG ( 10 , ( " client_write: wrote %d bytes. \n " , num_written ) ) ;
2001-05-07 08:32:40 +04:00
/* Write failed, kill cilent */
if ( num_written = = - 1 | | num_written = = 0 ) {
2003-07-22 08:31:20 +04:00
DEBUG ( 3 , ( " write failed on sock %d, pid %lu: %s \n " ,
state - > sock , ( unsigned long ) state - > pid ,
2001-05-07 08:32:40 +04:00
( num_written = = - 1 ) ? strerror ( errno ) : " EOF " ) ) ;
state - > finished = True ;
2001-09-17 08:52:45 +04:00
SAFE_FREE ( state - > response . extra_data ) ;
2001-05-07 08:32:40 +04:00
return ;
}
/* Update client state */
state - > write_buf_len - = num_written ;
2003-02-28 03:25:55 +03:00
state - > last_access = time ( NULL ) ;
2001-05-07 08:32:40 +04:00
/* Have we written all data? */
if ( state - > write_buf_len = = 0 ) {
/* Take care of extra data */
if ( state - > write_extra_data ) {
2001-09-17 08:52:45 +04:00
SAFE_FREE ( state - > response . extra_data ) ;
2001-05-07 08:32:40 +04:00
state - > write_extra_data = False ;
2001-11-14 07:44:36 +03:00
DEBUG ( 10 , ( " client_write: client_write: complete response written. \n " ) ) ;
2001-05-07 08:32:40 +04:00
} else if ( state - > response . length >
sizeof ( struct winbindd_response ) ) {
/* Start writing extra data */
state - > write_buf_len =
state - > response . length -
sizeof ( struct winbindd_response ) ;
2001-11-14 07:44:36 +03:00
DEBUG ( 10 , ( " client_write: need to write %d extra data bytes. \n " , ( int ) state - > write_buf_len ) ) ;
2001-05-07 08:32:40 +04:00
state - > write_extra_data = True ;
}
}
}
2000-05-09 15:43:00 +04:00
2003-02-28 03:25:55 +03:00
/* Process incoming clients on listen_sock. We use a tricky non-blocking,
2001-05-07 08:32:40 +04:00
non - forking , non - threaded model which allows us to handle many
simultaneous connections while remaining impervious to many denial of
service attacks . */
2000-05-09 15:43:00 +04:00
2002-11-02 04:36:42 +03:00
static void process_loop ( void )
2001-05-07 08:32:40 +04:00
{
/* We'll be doing this a lot */
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
while ( 1 ) {
struct winbindd_cli_state * state ;
fd_set r_fds , w_fds ;
2003-03-24 12:54:13 +03:00
int maxfd , listen_sock , listen_priv_sock , selret ;
2001-05-07 08:32:40 +04:00
struct timeval timeout ;
2000-05-09 15:43:00 +04:00
2002-03-27 01:33:06 +03:00
/* Handle messages */
message_dispatch ( ) ;
2003-08-26 01:45:57 +04:00
/* refresh the trusted domain cache */
2003-08-09 03:53:13 +04:00
2003-08-26 01:45:57 +04:00
rescan_trusted_domains ( ) ;
2002-11-07 10:17:09 +03:00
2001-05-07 08:32:40 +04:00
/* Free up temporary memory */
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
lp_talloc_free ( ) ;
2002-02-18 14:39:36 +03:00
main_loop_talloc_free ( ) ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Initialise fd lists for select() */
2000-05-09 15:43:00 +04:00
2002-11-02 04:36:42 +03:00
listen_sock = open_winbindd_socket ( ) ;
2003-03-24 12:54:13 +03:00
listen_priv_sock = open_winbindd_priv_socket ( ) ;
2002-12-20 04:25:27 +03:00
2003-03-24 12:54:13 +03:00
if ( listen_sock = = - 1 | | listen_priv_sock = = - 1 ) {
2002-12-20 04:25:27 +03:00
perror ( " open_winbind_socket " ) ;
exit ( 1 ) ;
}
2003-03-24 12:54:13 +03:00
maxfd = MAX ( listen_sock , listen_priv_sock ) ;
2002-11-02 04:36:42 +03:00
2001-05-07 08:32:40 +04:00
FD_ZERO ( & r_fds ) ;
FD_ZERO ( & w_fds ) ;
2002-11-02 04:36:42 +03:00
FD_SET ( listen_sock , & r_fds ) ;
2003-03-24 12:54:13 +03:00
FD_SET ( listen_priv_sock , & r_fds ) ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
timeout . tv_sec = WINBINDD_ESTABLISH_LOOP ;
timeout . tv_usec = 0 ;
2000-05-09 15:43:00 +04:00
2002-07-15 14:35:28 +04:00
if ( opt_dual_daemon ) {
maxfd = dual_select_setup ( & w_fds , maxfd ) ;
}
2001-05-07 08:32:40 +04:00
/* Set up client readers and writers */
2000-05-09 15:43:00 +04:00
2002-11-02 04:36:42 +03:00
state = winbindd_client_list ( ) ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
while ( state ) {
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Dispose of client connection if it is marked as
finished */
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
if ( state - > finished ) {
struct winbindd_cli_state * next = state - > next ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
remove_client ( state ) ;
state = next ;
continue ;
}
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Select requires we know the highest fd used */
2000-05-09 15:43:00 +04:00
2001-11-15 00:49:30 +03:00
if ( state - > sock > maxfd )
maxfd = state - > sock ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Add fd for reading */
2000-05-09 15:43:00 +04:00
2001-10-05 04:20:06 +04:00
if ( state - > read_buf_len ! = sizeof ( state - > request ) )
2001-05-07 08:32:40 +04:00
FD_SET ( state - > sock , & r_fds ) ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Add fd for writing */
2000-05-09 15:43:00 +04:00
2001-10-05 04:20:06 +04:00
if ( state - > write_buf_len )
2001-05-07 08:32:40 +04:00
FD_SET ( state - > sock , & w_fds ) ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
state = state - > next ;
}
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Call select */
2000-05-09 15:43:00 +04:00
2002-02-01 02:26:12 +03:00
selret = sys_select ( maxfd + 1 , & r_fds , & w_fds , NULL , & timeout ) ;
2000-05-09 15:43:00 +04:00
2001-11-15 00:49:30 +03:00
if ( selret = = 0 )
continue ;
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
if ( ( selret = = - 1 & & errno ! = EINTR ) | | selret = = 0 ) {
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Select error, something is badly wrong */
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
perror ( " select " ) ;
exit ( 1 ) ;
}
2000-05-09 15:43:00 +04:00
2003-02-28 03:25:55 +03:00
/* Create a new connection if listen_sock readable */
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
if ( selret > 0 ) {
2000-05-09 15:43:00 +04:00
2002-07-15 14:35:28 +04:00
if ( opt_dual_daemon ) {
dual_select ( & w_fds ) ;
}
2003-02-28 03:25:55 +03:00
if ( FD_ISSET ( listen_sock , & r_fds ) ) {
while ( winbindd_num_clients ( ) > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1 ) {
DEBUG ( 5 , ( " winbindd: Exceeding %d client connections, removing idle connection. \n " ,
WINBINDD_MAX_SIMULTANEOUS_CLIENTS ) ) ;
if ( ! remove_idle_client ( ) ) {
DEBUG ( 0 , ( " winbindd: Exceeding %d client connections, no idle connection found \n " ,
WINBINDD_MAX_SIMULTANEOUS_CLIENTS ) ) ;
break ;
}
}
2003-04-07 11:32:51 +04:00
/* new, non-privileged connection */
2003-03-24 12:54:13 +03:00
new_connection ( listen_sock , False ) ;
}
if ( FD_ISSET ( listen_priv_sock , & r_fds ) ) {
while ( winbindd_num_clients ( ) > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1 ) {
DEBUG ( 5 , ( " winbindd: Exceeding %d client connections, removing idle connection. \n " ,
WINBINDD_MAX_SIMULTANEOUS_CLIENTS ) ) ;
if ( ! remove_idle_client ( ) ) {
DEBUG ( 0 , ( " winbindd: Exceeding %d client connections, no idle connection found \n " ,
WINBINDD_MAX_SIMULTANEOUS_CLIENTS ) ) ;
break ;
}
}
2003-04-07 11:32:51 +04:00
/* new, privileged connection */
2003-03-24 12:54:13 +03:00
new_connection ( listen_priv_sock , True ) ;
2003-02-28 03:25:55 +03:00
}
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Process activity on client connections */
2000-05-09 15:43:00 +04:00
2002-11-02 04:36:42 +03:00
for ( state = winbindd_client_list ( ) ; state ;
state = state - > next ) {
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Data available for reading */
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
if ( FD_ISSET ( state - > sock , & r_fds ) ) {
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Read data */
2000-05-09 15:43:00 +04:00
2002-07-15 14:35:28 +04:00
winbind_client_read ( state ) ;
2001-11-14 08:33:55 +03:00
2001-11-14 23:02:02 +03:00
/*
* If we have the start of a
2001-11-14 08:33:55 +03:00
* packet , then check the
* length field to make sure
* the client ' s not talking
2001-11-14 23:02:02 +03:00
* Mock Swedish .
*/
2002-01-11 02:45:29 +03:00
if ( state - > read_buf_len > = sizeof ( uint32 )
& & * ( uint32 * ) & state - > request ! = sizeof ( state - > request ) ) {
2003-11-07 01:11:08 +03:00
DEBUG ( 0 , ( " process_loop: Invalid request size from pid %lu: %d bytes sent, should be %ld \n " ,
( unsigned long ) state - > request . pid , * ( uint32 * ) & state - > request , ( unsigned long ) sizeof ( state - > request ) ) ) ;
2001-11-14 23:02:02 +03:00
2002-01-11 02:45:29 +03:00
remove_client ( state ) ;
break ;
2001-11-14 08:33:55 +03:00
}
2001-11-14 23:02:02 +03:00
2001-05-07 08:32:40 +04:00
/* A request packet might be
complete */
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
if ( state - > read_buf_len = =
sizeof ( state - > request ) ) {
2002-07-15 14:35:28 +04:00
winbind_process_packet ( state ) ;
2001-05-07 08:32:40 +04:00
}
}
2000-05-09 15:43:00 +04:00
2001-05-07 08:32:40 +04:00
/* Data available for writing */
2000-05-09 15:43:00 +04:00
2001-10-05 04:20:06 +04:00
if ( FD_ISSET ( state - > sock , & w_fds ) )
2001-05-07 08:32:40 +04:00
client_write ( state ) ;
}
}
2001-11-15 00:49:30 +03:00
2002-04-04 07:03:39 +04:00
#if 0
winbindd_check_cache_size ( time ( NULL ) ) ;
# endif
2001-11-15 00:49:30 +03:00
/* Check signal handling things */
if ( do_sigterm )
terminate ( ) ;
if ( do_sighup ) {
2002-11-02 04:36:42 +03:00
DEBUG ( 3 , ( " got SIGHUP \n " ) ) ;
2001-11-15 00:49:30 +03:00
2003-07-15 21:21:21 +04:00
msg_reload_services ( MSG_SMB_CONF_UPDATED , ( pid_t ) 0 , NULL , 0 ) ;
2001-11-15 00:49:30 +03:00
do_sighup = False ;
}
2002-01-10 09:20:03 +03:00
if ( do_sigusr2 ) {
2001-11-15 06:23:15 +03:00
print_winbindd_status ( ) ;
2002-01-10 09:20:03 +03:00
do_sigusr2 = False ;
2001-11-15 00:49:30 +03:00
}
2001-05-07 08:32:40 +04:00
}
2000-05-09 15:43:00 +04:00
}
/* Main function */
struct winbindd_state server_state ; /* Server state information */
2003-04-14 07:53:58 +04:00
int main ( int argc , char * * argv )
2000-05-09 15:43:00 +04:00
{
2001-12-21 01:27:05 +03:00
pstring logfile ;
2003-04-14 07:53:58 +04:00
static BOOL interactive = False ;
static BOOL Fork = True ;
static BOOL log_stdout = False ;
struct poptOption long_options [ ] = {
POPT_AUTOHELP
{ " stdout " , ' S ' , POPT_ARG_VAL , & log_stdout , True , " Log to stdout " } ,
{ " foreground " , ' F ' , POPT_ARG_VAL , & Fork , False , " Daemon in foreground mode " } ,
{ " interactive " , ' i ' , POPT_ARG_NONE , NULL , ' i ' , " Interactive mode " } ,
2003-07-15 08:19:57 +04:00
{ " single-daemon " , ' Y ' , POPT_ARG_VAL , & opt_dual_daemon , False , " Single daemon mode " } ,
2003-04-14 07:53:58 +04:00
{ " no-caching " , ' n ' , POPT_ARG_VAL , & opt_nocache , False , " Disable caching " } ,
POPT_COMMON_SAMBA
POPT_TABLEEND
} ;
poptContext pc ;
2002-03-14 05:15:08 +03:00
int opt ;
2001-05-07 08:32:40 +04:00
2001-11-22 02:00:59 +03:00
/* glibc (?) likes to print "User defined signal 1" and exit if a
2002-03-27 01:33:06 +03:00
SIGUSR [ 12 ] is received before a handler is installed */
2001-11-15 06:23:15 +03:00
2002-03-27 01:33:06 +03:00
CatchSignal ( SIGUSR1 , SIG_IGN ) ;
2002-01-10 09:20:03 +03:00
CatchSignal ( SIGUSR2 , SIG_IGN ) ;
2001-11-15 06:23:15 +03:00
2001-11-23 14:18:20 +03:00
fault_setup ( ( void ( * ) ( void * ) ) fault_quit ) ;
2001-12-21 05:23:38 +03:00
2001-11-15 00:49:30 +03:00
/* Initialise for running in non-root mode */
2001-10-05 04:20:06 +04:00
2001-07-08 22:25:19 +04:00
sec_init ( ) ;
2001-05-08 07:52:07 +04:00
2003-04-14 07:53:58 +04:00
set_remote_machine_name ( " winbindd " , False ) ;
2001-05-07 08:32:40 +04:00
/* Set environment variable so we don't recursively call ourselves.
This may also be useful interactively . */
2001-10-05 04:20:06 +04:00
2003-02-19 15:31:16 +03:00
setenv ( WINBINDD_DONT_ENV , " 1 " , 1 ) ;
2001-05-07 08:32:40 +04:00
/* Initialise samba/rpc client stuff */
2003-04-14 07:53:58 +04:00
pc = poptGetContext ( " winbindd " , argc , ( const char * * ) argv , long_options ,
POPT_CONTEXT_KEEP_FIRST ) ;
2001-05-07 08:32:40 +04:00
2003-04-14 07:53:58 +04:00
while ( ( opt = poptGetNextOpt ( pc ) ) ! = - 1 ) {
switch ( opt ) {
2001-12-10 02:59:42 +03:00
/* Don't become a daemon */
2000-05-09 15:43:00 +04:00
case ' i ' :
interactive = True ;
2003-01-03 20:39:30 +03:00
log_stdout = True ;
Fork = False ;
2000-05-09 15:43:00 +04:00
break ;
}
2001-05-07 08:32:40 +04:00
}
2000-05-09 15:43:00 +04:00
2003-04-14 07:53:58 +04:00
2003-01-03 20:39:30 +03:00
if ( log_stdout & & Fork ) {
printf ( " Can't log to stdout (-S) unless daemon is in foreground +(-F) or interactive (-i) \n " ) ;
2003-04-14 07:53:58 +04:00
poptPrintUsage ( pc , stderr , 0 ) ;
2003-01-03 20:39:30 +03:00
exit ( 1 ) ;
}
2003-07-23 16:33:59 +04:00
pstr_sprintf ( logfile , " %s/log.winbindd " , dyn_LOGFILEBASE ) ;
2001-12-21 01:27:05 +03:00
lp_set_logfile ( logfile ) ;
2003-01-03 20:39:30 +03:00
setup_logging ( " winbindd " , log_stdout ) ;
2001-05-07 08:32:40 +04:00
reopen_logs ( ) ;
2000-05-09 15:43:00 +04:00
2003-08-20 21:13:38 +04:00
DEBUG ( 1 , ( " winbindd version %s started. \n " , SAMBA_VERSION_STRING ) ) ;
2003-04-22 21:32:02 +04:00
DEBUGADD ( 1 , ( " Copyright The Samba Team 2000-2003 \n " ) ) ;
2001-12-20 21:37:43 +03:00
if ( ! reload_services_file ( False ) ) {
DEBUG ( 0 , ( " error opening config file \n " ) ) ;
exit ( 1 ) ;
}
/* Setup names. */
2002-01-22 03:35:05 +03:00
2002-11-13 02:20:50 +03:00
if ( ! init_names ( ) )
exit ( 1 ) ;
2000-05-09 15:43:00 +04:00
2003-05-06 06:32:47 +04:00
load_interfaces ( ) ;
if ( ! secrets_init ( ) ) {
DEBUG ( 0 , ( " Could not initialize domain trust account secrets. Giving up \n " ) ) ;
return False ;
}
/* Enable netbios namecache */
namecache_enable ( ) ;
/* Check winbindd parameters are valid */
ZERO_STRUCT ( server_state ) ;
if ( ! winbindd_param_init ( ) )
return 1 ;
/* Winbind daemon initialisation */
2003-06-24 18:02:21 +04:00
if ( ! winbindd_upgrade_idmap ( ) )
return 1 ;
2003-06-28 00:55:48 +04:00
if ( ! idmap_init ( lp_idmap_backend ( ) ) )
2003-05-06 06:32:47 +04:00
return 1 ;
/* Unblock all signals we are interested in as they may have been
blocked by the parent process . */
BlockSignals ( False , SIGINT ) ;
BlockSignals ( False , SIGQUIT ) ;
BlockSignals ( False , SIGTERM ) ;
BlockSignals ( False , SIGUSR1 ) ;
BlockSignals ( False , SIGUSR2 ) ;
BlockSignals ( False , SIGHUP ) ;
/* Setup signal handlers */
CatchSignal ( SIGINT , termination_handler ) ; /* Exit on these sigs */
CatchSignal ( SIGQUIT , termination_handler ) ;
CatchSignal ( SIGTERM , termination_handler ) ;
CatchSignal ( SIGPIPE , SIG_IGN ) ; /* Ignore sigpipe */
CatchSignal ( SIGUSR2 , sigusr2_handler ) ; /* Debugging sigs */
CatchSignal ( SIGHUP , sighup_handler ) ;
2003-04-14 07:53:58 +04:00
if ( ! interactive )
2003-01-03 20:39:30 +03:00
become_daemon ( Fork ) ;
2000-05-09 15:43:00 +04:00
2003-04-14 07:53:58 +04:00
pidfile_create ( " winbindd " ) ;
2002-09-25 19:19:00 +04:00
2001-12-30 04:46:38 +03:00
# if HAVE_SETPGID
/*
* If we ' re interactive we want to set our own process group for
* signal management .
*/
if ( interactive )
setpgid ( ( pid_t ) 0 , ( pid_t ) 0 ) ;
# endif
2002-11-07 10:17:09 +03:00
if ( opt_dual_daemon ) {
do_dual_daemon ( ) ;
2002-07-15 14:35:28 +04:00
}
2001-05-07 08:32:40 +04:00
2002-03-27 01:33:06 +03:00
/* Initialise messaging system */
if ( ! message_init ( ) ) {
DEBUG ( 0 , ( " unable to initialise messaging system \n " ) ) ;
exit ( 1 ) ;
}
2003-07-15 21:21:21 +04:00
/* React on 'smbcontrol winbindd reload-config' in the same way
as to SIGHUP signal */
message_register ( MSG_SMB_CONF_UPDATED , msg_reload_services ) ;
message_register ( MSG_SHUTDOWN , msg_shutdown ) ;
2003-04-14 07:53:58 +04:00
poptFreeContext ( pc ) ;
2002-03-27 01:33:06 +03:00
2003-06-21 08:05:01 +04:00
netsamlogon_cache_init ( ) ; /* Non-critical */
2001-05-07 08:32:40 +04:00
/* Loop waiting for requests */
2000-05-09 15:43:00 +04:00
2002-11-02 04:36:42 +03:00
process_loop ( ) ;
2000-05-09 15:43:00 +04:00
2003-04-23 15:54:56 +04:00
trustdom_cache_shutdown ( ) ;
2001-05-07 08:32:40 +04:00
return 0 ;
2000-05-09 15:43:00 +04:00
}