1998-08-17 17:11:34 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
service ( connection ) opening and closing
Copyright ( C ) Andrew Tridgell 1992 - 1998
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 "includes.h"
extern int DEBUGLEVEL ;
extern time_t smb_last_time ;
extern int case_default ;
extern BOOL case_preserve ;
extern BOOL short_case_preserve ;
extern BOOL case_mangle ;
extern BOOL case_sensitive ;
extern BOOL use_mangled_map ;
extern fstring remote_machine ;
extern pstring sesssetup_user ;
extern fstring remote_machine ;
/****************************************************************************
load parameters specific to a connection / service
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL become_service ( connection_struct * conn , BOOL do_chdir )
{
extern char magic_char ;
static connection_struct * last_conn ;
int snum ;
if ( ! conn ) {
last_conn = NULL ;
return ( False ) ;
}
conn - > lastused = smb_last_time ;
snum = SNUM ( conn ) ;
if ( do_chdir & &
ChDir ( conn - > connectpath ) ! = 0 & &
ChDir ( conn - > origpath ) ! = 0 ) {
DEBUG ( 0 , ( " chdir (%s) failed \n " ,
conn - > connectpath ) ) ;
return ( False ) ;
}
if ( conn = = last_conn )
return ( True ) ;
last_conn = conn ;
case_default = lp_defaultcase ( snum ) ;
case_preserve = lp_preservecase ( snum ) ;
short_case_preserve = lp_shortpreservecase ( snum ) ;
case_mangle = lp_casemangle ( snum ) ;
case_sensitive = lp_casesensitive ( snum ) ;
magic_char = lp_magicchar ( snum ) ;
use_mangled_map = ( * lp_mangled_map ( snum ) ? True : False ) ;
return ( True ) ;
}
/****************************************************************************
find a service entry
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int find_service ( char * service )
{
int iService ;
string_sub ( service , " \\ " , " / " ) ;
iService = lp_servicenumber ( service ) ;
/* now handle the special case of a home directory */
if ( iService < 0 )
{
char * phome_dir = get_home_dir ( service ) ;
if ( ! phome_dir )
{
/*
* Try mapping the servicename , it may
* be a Windows to unix mapped user name .
*/
if ( map_username ( service ) )
phome_dir = get_home_dir ( service ) ;
}
DEBUG ( 3 , ( " checking for home directory %s gave %s \n " , service ,
phome_dir ? phome_dir : " (NULL) " ) ) ;
if ( phome_dir )
{
int iHomeService ;
if ( ( iHomeService = lp_servicenumber ( HOMES_NAME ) ) > = 0 )
{
lp_add_home ( service , iHomeService , phome_dir ) ;
iService = lp_servicenumber ( service ) ;
}
}
}
/* If we still don't have a service, attempt to add it as a printer. */
if ( iService < 0 )
{
int iPrinterService ;
if ( ( iPrinterService = lp_servicenumber ( PRINTERS_NAME ) ) > = 0 )
{
char * pszTemp ;
DEBUG ( 3 , ( " checking whether %s is a valid printer name... \n " , service ) ) ;
pszTemp = PRINTCAP ;
if ( ( pszTemp ! = NULL ) & & pcap_printername_ok ( service , pszTemp ) )
{
DEBUG ( 3 , ( " %s is a valid printer name \n " , service ) ) ;
DEBUG ( 3 , ( " adding %s as a printer service \n " , service ) ) ;
lp_add_printer ( service , iPrinterService ) ;
iService = lp_servicenumber ( service ) ;
if ( iService < 0 )
DEBUG ( 0 , ( " failed to add %s as a printer service! \n " , service ) ) ;
}
else
DEBUG ( 3 , ( " %s is not a valid printer name \n " , service ) ) ;
}
}
/* just possibly it's a default service? */
if ( iService < 0 )
{
char * pdefservice = lp_defaultservice ( ) ;
if ( pdefservice & & * pdefservice & & ! strequal ( pdefservice , service ) )
{
/*
* We need to do a local copy here as lp_defaultservice ( )
* returns one of the rotating lp_string buffers that
* could get overwritten by the recursive find_service ( ) call
* below . Fix from Josef Hinteregger < joehtg @ joehtg . co . at > .
*/
pstring defservice ;
pstrcpy ( defservice , pdefservice ) ;
iService = find_service ( defservice ) ;
if ( iService > = 0 )
{
string_sub ( service , " _ " , " / " ) ;
iService = lp_add_service ( service , iService ) ;
}
}
}
if ( iService > = 0 )
if ( ! VALID_SNUM ( iService ) )
{
DEBUG ( 0 , ( " Invalid snum %d for %s \n " , iService , service ) ) ;
iService = - 1 ;
}
if ( iService < 0 )
DEBUG ( 3 , ( " find_service() failed to find service %s \n " , service ) ) ;
return ( iService ) ;
}
/****************************************************************************
make a connection to a service
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
connection_struct * make_connection ( char * service , char * user , char * password , int pwlen , char * dev , uint16 vuid , int * ecode )
{
int snum ;
struct passwd * pass = NULL ;
BOOL guest = False ;
BOOL force = False ;
extern int Client ;
connection_struct * conn ;
strlower ( service ) ;
snum = find_service ( service ) ;
if ( snum < 0 ) {
extern int Client ;
if ( strequal ( service , " IPC$ " ) ) {
DEBUG ( 3 , ( " refusing IPC connection \n " ) ) ;
* ecode = ERRnoipc ;
return NULL ;
}
DEBUG ( 0 , ( " %s (%s) couldn't find service %s \n " ,
remote_machine , client_addr ( Client ) , service ) ) ;
* ecode = ERRinvnetname ;
return NULL ;
}
if ( strequal ( service , HOMES_NAME ) ) {
if ( * user & & Get_Pwnam ( user , True ) )
return ( make_connection ( user , user , password ,
pwlen , dev , vuid , ecode ) ) ;
if ( lp_security ( ) ! = SEC_SHARE ) {
if ( validated_username ( vuid ) ) {
pstrcpy ( user , validated_username ( vuid ) ) ;
return ( make_connection ( user , user , password , pwlen , dev , vuid , ecode ) ) ;
}
} else {
/* Security = share. Try with sesssetup_user
* as the username . */
if ( * sesssetup_user ) {
pstrcpy ( user , sesssetup_user ) ;
return ( make_connection ( user , user , password , pwlen , dev , vuid , ecode ) ) ;
}
}
}
if ( ! lp_snum_ok ( snum ) | |
! check_access ( Client ,
lp_hostsallow ( snum ) , lp_hostsdeny ( snum ) ) ) {
* ecode = ERRaccess ;
return NULL ;
}
/* you can only connect to the IPC$ service as an ipc device */
if ( strequal ( service , " IPC$ " ) )
pstrcpy ( dev , " IPC " ) ;
if ( * dev = = ' ? ' | | ! * dev ) {
if ( lp_print_ok ( snum ) ) {
pstrcpy ( dev , " LPT1: " ) ;
} else {
pstrcpy ( dev , " A: " ) ;
}
}
/* if the request is as a printer and you can't print then refuse */
strupper ( dev ) ;
if ( ! lp_print_ok ( snum ) & & ( strncmp ( dev , " LPT " , 3 ) = = 0 ) ) {
DEBUG ( 1 , ( " Attempt to connect to non-printer as a printer \n " ) ) ;
* ecode = ERRinvdevice ;
return NULL ;
}
/* lowercase the user name */
strlower ( user ) ;
/* add it as a possible user name */
add_session_user ( service ) ;
/* shall we let them in? */
if ( ! authorise_login ( snum , user , password , pwlen , & guest , & force , vuid ) ) {
DEBUG ( 2 , ( " Invalid username/password for %s \n " , service ) ) ;
* ecode = ERRbadpw ;
return NULL ;
}
conn = conn_new ( ) ;
if ( ! conn ) {
DEBUG ( 0 , ( " Couldn't find free connection. \n " ) ) ;
* ecode = ERRnoresource ;
conn_free ( conn ) ;
return NULL ;
}
/* find out some info about the user */
pass = Get_Pwnam ( user , True ) ;
if ( pass = = NULL ) {
DEBUG ( 0 , ( " Couldn't find account %s \n " , user ) ) ;
* ecode = ERRbaduid ;
conn_free ( conn ) ;
return NULL ;
}
conn - > read_only = lp_readonly ( snum ) ;
{
pstring list ;
StrnCpy ( list , lp_readlist ( snum ) , sizeof ( pstring ) - 1 ) ;
string_sub ( list , " %S " , service ) ;
if ( user_in_list ( user , list ) )
conn - > read_only = True ;
StrnCpy ( list , lp_writelist ( snum ) , sizeof ( pstring ) - 1 ) ;
string_sub ( list , " %S " , service ) ;
if ( user_in_list ( user , list ) )
conn - > read_only = False ;
}
/* admin user check */
/* JRA - original code denied admin user if the share was
marked read_only . Changed as I don ' t think this is needed ,
but old code left in case there is a problem here .
*/
if ( user_in_list ( user , lp_admin_users ( snum ) )
#if 0
& & ! conn - > read_only
# endif
) {
conn - > admin_user = True ;
DEBUG ( 0 , ( " %s logged in as admin user (root privileges) \n " , user ) ) ;
} else {
conn - > admin_user = False ;
}
conn - > force_user = force ;
conn - > vuid = vuid ;
conn - > uid = pass - > pw_uid ;
conn - > gid = pass - > pw_gid ;
conn - > num_files_open = 0 ;
conn - > lastused = time ( NULL ) ;
conn - > service = snum ;
conn - > used = True ;
conn - > printer = ( strncmp ( dev , " LPT " , 3 ) = = 0 ) ;
conn - > ipc = ( strncmp ( dev , " IPC " , 3 ) = = 0 ) ;
conn - > dirptr = NULL ;
conn - > veto_list = NULL ;
conn - > hide_list = NULL ;
conn - > veto_oplock_list = NULL ;
string_set ( & conn - > dirpath , " " ) ;
string_set ( & conn - > user , user ) ;
# ifdef HAVE_GETGRNAM
if ( * lp_force_group ( snum ) ) {
struct group * gptr ;
pstring gname ;
StrnCpy ( gname , lp_force_group ( snum ) , sizeof ( pstring ) - 1 ) ;
/* default service may be a group name */
string_sub ( gname , " %S " , service ) ;
gptr = ( struct group * ) getgrnam ( gname ) ;
if ( gptr ) {
conn - > gid = gptr - > gr_gid ;
DEBUG ( 3 , ( " Forced group %s \n " , gname ) ) ;
} else {
DEBUG ( 1 , ( " Couldn't find group %s \n " , gname ) ) ;
}
}
# endif
if ( * lp_force_user ( snum ) ) {
struct passwd * pass2 ;
fstring fuser ;
fstrcpy ( fuser , lp_force_user ( snum ) ) ;
pass2 = ( struct passwd * ) Get_Pwnam ( fuser , True ) ;
if ( pass2 ) {
conn - > uid = pass2 - > pw_uid ;
string_set ( & conn - > user , fuser ) ;
fstrcpy ( user , fuser ) ;
conn - > force_user = True ;
DEBUG ( 3 , ( " Forced user %s \n " , fuser ) ) ;
} else {
DEBUG ( 1 , ( " Couldn't find user %s \n " , fuser ) ) ;
}
}
{
pstring s ;
pstrcpy ( s , lp_pathname ( snum ) ) ;
standard_sub ( conn , s ) ;
string_set ( & conn - > connectpath , s ) ;
DEBUG ( 3 , ( " Connect path is %s \n " , s ) ) ;
}
/* groups stuff added by ih */
conn - > ngroups = 0 ;
conn - > groups = NULL ;
if ( ! IS_IPC ( conn ) ) {
/* Find all the groups this uid is in and
store them . Used by become_user ( ) */
setup_groups ( conn - > user , conn - > uid , conn - > gid ,
& conn - > ngroups , & conn - > groups ) ;
/* check number of connections */
if ( ! claim_connection ( conn ,
lp_servicename ( SNUM ( conn ) ) ,
lp_max_connections ( SNUM ( conn ) ) ,
False ) ) {
DEBUG ( 1 , ( " too many connections - rejected \n " ) ) ;
* ecode = ERRnoresource ;
conn_free ( conn ) ;
return NULL ;
}
if ( lp_status ( SNUM ( conn ) ) )
claim_connection ( conn , " STATUS. " ,
MAXSTATUS , False ) ;
} /* IS_IPC */
/* execute any "root preexec = " line */
if ( * lp_rootpreexec ( SNUM ( conn ) ) ) {
pstring cmd ;
pstrcpy ( cmd , lp_rootpreexec ( SNUM ( conn ) ) ) ;
standard_sub ( conn , cmd ) ;
DEBUG ( 5 , ( " cmd=%s \n " , cmd ) ) ;
smbrun ( cmd , NULL , False ) ;
}
if ( ! become_user ( conn , conn - > vuid ) ) {
DEBUG ( 0 , ( " Can't become connected user! \n " ) ) ;
if ( ! IS_IPC ( conn ) ) {
yield_connection ( conn ,
lp_servicename ( SNUM ( conn ) ) ,
lp_max_connections ( SNUM ( conn ) ) ) ;
if ( lp_status ( SNUM ( conn ) ) ) {
yield_connection ( conn , " STATUS. " , MAXSTATUS ) ;
}
}
conn_free ( conn ) ;
* ecode = ERRbadpw ;
return NULL ;
}
if ( ChDir ( conn - > connectpath ) ! = 0 ) {
DEBUG ( 0 , ( " Can't change directory to %s (%s) \n " ,
conn - > connectpath , strerror ( errno ) ) ) ;
unbecome_user ( ) ;
if ( ! IS_IPC ( conn ) ) {
yield_connection ( conn ,
lp_servicename ( SNUM ( conn ) ) ,
lp_max_connections ( SNUM ( conn ) ) ) ;
if ( lp_status ( SNUM ( conn ) ) )
yield_connection ( conn , " STATUS. " , MAXSTATUS ) ;
}
conn_free ( conn ) ;
* ecode = ERRinvnetname ;
return NULL ;
}
string_set ( & conn - > origpath , conn - > connectpath ) ;
# if SOFTLINK_OPTIMISATION
/* resolve any soft links early */
{
pstring s ;
pstrcpy ( s , conn - > connectpath ) ;
GetWd ( s ) ;
string_set ( & conn - > connectpath , s ) ;
ChDir ( conn - > connectpath ) ;
}
# endif
add_session_user ( user ) ;
/* execute any "preexec = " line */
if ( * lp_preexec ( SNUM ( conn ) ) ) {
pstring cmd ;
pstrcpy ( cmd , lp_preexec ( SNUM ( conn ) ) ) ;
standard_sub ( conn , cmd ) ;
smbrun ( cmd , NULL , False ) ;
}
/* we've finished with the sensitive stuff */
unbecome_user ( ) ;
/* Add veto/hide lists */
if ( ! IS_IPC ( conn ) & & ! IS_PRINT ( conn ) ) {
set_namearray ( & conn - > veto_list , lp_veto_files ( SNUM ( conn ) ) ) ;
set_namearray ( & conn - > hide_list , lp_hide_files ( SNUM ( conn ) ) ) ;
set_namearray ( & conn - > veto_oplock_list , lp_veto_oplocks ( SNUM ( conn ) ) ) ;
}
if ( DEBUGLVL ( IS_IPC ( conn ) ? 3 : 1 ) ) {
extern int Client ;
dbgtext ( " %s (%s) " , remote_machine , client_addr ( Client ) ) ;
dbgtext ( " connect to service %s " , lp_servicename ( SNUM ( conn ) ) ) ;
dbgtext ( " as user %s " , user ) ;
1998-09-30 00:24:17 +04:00
dbgtext ( " (uid=%d, gid=%d) " , ( int ) conn - > uid , ( int ) conn - > gid ) ;
1998-08-17 17:11:34 +04:00
dbgtext ( " (pid %d) \n " , ( int ) getpid ( ) ) ;
}
return ( conn ) ;
}
/****************************************************************************
close a cnum
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void close_cnum ( connection_struct * conn , uint16 vuid )
{
extern int Client ;
DirCacheFlush ( SNUM ( conn ) ) ;
unbecome_user ( ) ;
DEBUG ( IS_IPC ( conn ) ? 3 : 1 , ( " %s (%s) closed connection to service %s \n " ,
remote_machine , client_addr ( Client ) ,
lp_servicename ( SNUM ( conn ) ) ) ) ;
yield_connection ( conn ,
lp_servicename ( SNUM ( conn ) ) ,
lp_max_connections ( SNUM ( conn ) ) ) ;
if ( lp_status ( SNUM ( conn ) ) )
yield_connection ( conn , " STATUS. " , MAXSTATUS ) ;
file_close_conn ( conn ) ;
dptr_closecnum ( conn ) ;
/* execute any "postexec = " line */
if ( * lp_postexec ( SNUM ( conn ) ) & &
become_user ( conn , vuid ) ) {
pstring cmd ;
pstrcpy ( cmd , lp_postexec ( SNUM ( conn ) ) ) ;
standard_sub ( conn , cmd ) ;
smbrun ( cmd , NULL , False ) ;
unbecome_user ( ) ;
}
unbecome_user ( ) ;
/* execute any "root postexec = " line */
if ( * lp_rootpostexec ( SNUM ( conn ) ) ) {
pstring cmd ;
pstrcpy ( cmd , lp_rootpostexec ( SNUM ( conn ) ) ) ;
standard_sub ( conn , cmd ) ;
smbrun ( cmd , NULL , False ) ;
}
conn_free ( conn ) ;
}