1998-08-17 17:11:34 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-08-17 17:11:34 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1998-08-17 17:11:34 +04:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-08-17 17:11:34 +04:00
*/
# include "includes.h"
2001-01-23 04:52:30 +03:00
extern userdom_struct current_user_info ;
1998-08-17 17:11:34 +04:00
2007-11-11 01:43:39 +03:00
static bool canonicalize_connect_path ( connection_struct * conn )
2007-01-31 16:09:07 +03:00
{
# ifdef REALPATH_TAKES_NULL
2007-11-11 01:43:39 +03:00
bool ret ;
char * resolved_name = SMB_VFS_REALPATH ( conn , conn - > connectpath , NULL ) ;
2007-01-31 16:09:07 +03:00
if ( ! resolved_name ) {
2007-11-11 01:43:39 +03:00
return false ;
2007-01-31 16:09:07 +03:00
}
2007-11-11 01:43:39 +03:00
ret = set_conn_connectpath ( conn , resolved_name ) ;
2007-01-31 16:09:07 +03:00
SAFE_FREE ( resolved_name ) ;
2007-11-11 01:43:39 +03:00
return ret ;
2007-01-31 16:09:07 +03:00
# else
char resolved_name_buf [ PATH_MAX + 1 ] ;
2007-11-11 02:02:08 +03:00
char * resolved_name = SMB_VFS_REALPATH ( conn , conn - > connectpath , resolved_name_buf ) ;
2007-01-31 16:09:07 +03:00
if ( ! resolved_name ) {
2007-11-11 01:43:39 +03:00
return false ;
2007-01-31 16:09:07 +03:00
}
2007-11-11 01:43:39 +03:00
return set_conn_connectpath ( conn , resolved_name ) ;
2007-01-31 16:09:07 +03:00
# endif /* REALPATH_TAKES_NULL */
}
2005-12-12 21:21:59 +03:00
/****************************************************************************
Ensure when setting connectpath it is a canonicalized ( no . / // or ../)
absolute path stating in / and not ending in / .
Observent people will notice a similarity between this and check_path_syntax : - ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-11 01:43:39 +03:00
bool set_conn_connectpath ( connection_struct * conn , const char * connectpath )
2005-12-12 21:21:59 +03:00
{
2007-11-11 01:43:39 +03:00
char * destname ;
char * d ;
2005-12-12 21:21:59 +03:00
const char * s = connectpath ;
2007-11-11 01:43:39 +03:00
bool start_of_name_component = true ;
destname = SMB_STRDUP ( connectpath ) ;
if ( ! destname ) {
return false ;
}
d = destname ;
2005-12-12 21:21:59 +03:00
* d + + = ' / ' ; /* Always start with root. */
while ( * s ) {
if ( * s = = ' / ' ) {
/* Eat multiple '/' */
while ( * s = = ' / ' ) {
s + + ;
}
2005-12-13 21:11:50 +03:00
if ( ( d > destname + 1 ) & & ( * s ! = ' \0 ' ) ) {
2005-12-12 21:21:59 +03:00
* d + + = ' / ' ;
}
start_of_name_component = True ;
continue ;
}
if ( start_of_name_component ) {
if ( ( s [ 0 ] = = ' . ' ) & & ( s [ 1 ] = = ' . ' ) & & ( s [ 2 ] = = ' / ' | | s [ 2 ] = = ' \0 ' ) ) {
/* Uh oh - "/../" or "/..\0" ! */
/* Go past the ../ or .. */
if ( s [ 2 ] = = ' / ' ) {
s + = 3 ;
} else {
s + = 2 ; /* Go past the .. */
}
/* If we just added a '/' - delete it */
if ( ( d > destname ) & & ( * ( d - 1 ) = = ' / ' ) ) {
* ( d - 1 ) = ' \0 ' ;
d - - ;
}
/* Are we at the start ? Can't go back further if so. */
if ( d < = destname ) {
* d + + = ' / ' ; /* Can't delete root */
continue ;
}
/* Go back one level... */
/* Decrement d first as d points to the *next* char to write into. */
for ( d - - ; d > destname ; d - - ) {
if ( * d = = ' / ' ) {
break ;
}
}
/* We're still at the start of a name component, just the previous one. */
continue ;
} else if ( ( s [ 0 ] = = ' . ' ) & & ( ( s [ 1 ] = = ' \0 ' ) | | s [ 1 ] = = ' / ' ) ) {
/* Component of pathname can't be "." only - skip the '.' . */
if ( s [ 1 ] = = ' / ' ) {
s + = 2 ;
} else {
s + + ;
}
continue ;
}
}
if ( ! ( * s & 0x80 ) ) {
* d + + = * s + + ;
} else {
2006-09-21 21:00:07 +04:00
size_t siz ;
/* Get the size of the next MB character. */
next_codepoint ( s , & siz ) ;
switch ( siz ) {
case 5 :
* d + + = * s + + ;
/*fall through*/
2005-12-12 21:21:59 +03:00
case 4 :
* d + + = * s + + ;
2006-09-21 21:00:07 +04:00
/*fall through*/
2005-12-12 21:21:59 +03:00
case 3 :
* d + + = * s + + ;
2006-09-21 21:00:07 +04:00
/*fall through*/
2005-12-12 21:21:59 +03:00
case 2 :
* d + + = * s + + ;
2006-09-21 21:00:07 +04:00
/*fall through*/
2005-12-12 21:21:59 +03:00
case 1 :
* d + + = * s + + ;
break ;
default :
break ;
}
}
2007-11-11 01:43:39 +03:00
start_of_name_component = false ;
2005-12-12 21:21:59 +03:00
}
* d = ' \0 ' ;
/* And must not end in '/' */
if ( d > destname + 1 & & ( * ( d - 1 ) = = ' / ' ) ) {
* ( d - 1 ) = ' \0 ' ;
}
2005-12-13 21:11:50 +03:00
DEBUG ( 10 , ( " set_conn_connectpath: service %s, connectpath = %s \n " ,
lp_servicename ( SNUM ( conn ) ) , destname ) ) ;
2005-12-12 21:21:59 +03:00
string_set ( & conn - > connectpath , destname ) ;
2007-11-11 01:43:39 +03:00
SAFE_FREE ( destname ) ;
return true ;
2005-12-12 21:21:59 +03:00
}
1998-08-17 17:11:34 +04:00
/****************************************************************************
2001-10-19 00:15:12 +04:00
Load parameters specific to a connection / service .
1998-08-17 17:11:34 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-19 00:15:12 +04:00
2007-10-19 04:40:25 +04:00
bool set_current_service ( connection_struct * conn , uint16 flags , bool do_chdir )
1998-08-17 17:11:34 +04:00
{
static connection_struct * last_conn ;
2004-06-15 22:36:45 +04:00
static uint16 last_flags ;
1998-08-17 17:11:34 +04:00
int snum ;
if ( ! conn ) {
last_conn = NULL ;
return ( False ) ;
}
2006-04-15 08:07:10 +04:00
conn - > lastused_count + + ;
1998-08-17 17:11:34 +04:00
snum = SNUM ( conn ) ;
if ( do_chdir & &
2000-09-27 23:09:59 +04:00
vfs_ChDir ( conn , conn - > connectpath ) ! = 0 & &
vfs_ChDir ( conn , conn - > origpath ) ! = 0 ) {
1998-08-17 17:11:34 +04:00
DEBUG ( 0 , ( " chdir (%s) failed \n " ,
conn - > connectpath ) ) ;
return ( False ) ;
}
2004-06-15 22:36:45 +04:00
if ( ( conn = = last_conn ) & & ( last_flags = = flags ) ) {
1998-08-17 17:11:34 +04:00
return ( True ) ;
2004-06-15 22:36:45 +04:00
}
1998-08-17 17:11:34 +04:00
last_conn = conn ;
2004-06-15 22:36:45 +04:00
last_flags = flags ;
/* Obey the client case sensitivity requests - only for clients that support it. */
2005-02-03 05:02:54 +03:00
switch ( lp_casesensitive ( snum ) ) {
case Auto :
{
/* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
enum remote_arch_types ra_type = get_remote_arch ( ) ;
if ( ( ra_type ! = RA_SAMBA ) & & ( ra_type ! = RA_CIFSFS ) ) {
/* Client can't support per-packet case sensitive pathnames. */
conn - > case_sensitive = False ;
} else {
conn - > case_sensitive = ! ( flags & FLAG_CASELESS_PATHNAMES ) ;
}
}
break ;
case True :
conn - > case_sensitive = True ;
break ;
default :
2004-06-15 22:36:45 +04:00
conn - > case_sensitive = False ;
2005-02-03 05:02:54 +03:00
break ;
2004-06-15 22:36:45 +04:00
}
1998-08-17 17:11:34 +04:00
return ( True ) ;
}
2001-01-24 22:34:53 +03:00
/****************************************************************************
Add a home service . Returns the new service number or - 1 if fail .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-07-15 14:35:28 +04:00
int add_home_service ( const char * service , const char * username , const char * homedir )
2001-01-24 22:34:53 +03:00
{
int iHomeService ;
if ( ! service | | ! homedir )
return - 1 ;
if ( ( iHomeService = lp_servicenumber ( HOMES_NAME ) ) < 0 )
return - 1 ;
/*
* If this is a winbindd provided username , remove
* the domain component before adding the service .
* Log a warning if the " path= " parameter does not
* include any macros .
*/
2002-07-15 14:35:28 +04:00
{
const char * p = strchr ( service , * lp_winbind_separator ( ) ) ;
/* We only want the 'user' part of the string */
if ( p ) {
service = p + 1 ;
}
}
2002-08-17 19:27:10 +04:00
if ( ! lp_add_home ( service , iHomeService , username , homedir ) ) {
return - 1 ;
}
2002-07-15 14:35:28 +04:00
return lp_servicenumber ( service ) ;
2001-01-24 22:34:53 +03:00
}
1998-08-17 17:11:34 +04:00
2006-11-30 10:38:40 +03:00
static int load_registry_service ( const char * servicename )
{
2006-12-02 13:53:00 +03:00
struct registry_key * key ;
2006-11-30 10:38:40 +03:00
char * path ;
WERROR err ;
2006-12-02 13:53:00 +03:00
uint32 i ;
char * value_name ;
struct registry_value * value ;
2006-11-30 10:38:40 +03:00
2006-12-02 13:53:00 +03:00
int res = - 1 ;
2006-11-30 10:38:40 +03:00
if ( ! lp_registry_shares ( ) ) {
return - 1 ;
}
if ( asprintf ( & path , " %s \\ %s " , KEY_SMBCONF , servicename ) = = - 1 ) {
return - 1 ;
}
2006-12-02 13:53:00 +03:00
err = reg_open_path ( NULL , path , REG_KEY_READ , get_root_nt_token ( ) ,
& key ) ;
2006-11-30 10:38:40 +03:00
SAFE_FREE ( path ) ;
if ( ! W_ERROR_IS_OK ( err ) ) {
return - 1 ;
}
res = lp_add_service ( servicename , - 1 ) ;
if ( res = = - 1 ) {
goto error ;
}
2006-12-02 13:53:00 +03:00
for ( i = 0 ;
W_ERROR_IS_OK ( reg_enumvalue ( key , key , i , & value_name , & value ) ) ;
i + + ) {
switch ( value - > type ) {
2006-11-30 10:38:40 +03:00
case REG_DWORD : {
2006-12-02 13:53:00 +03:00
char * tmp ;
if ( asprintf ( & tmp , " %d " , value - > v . dword ) = = - 1 ) {
2006-11-30 10:38:40 +03:00
continue ;
}
2006-12-02 13:53:00 +03:00
lp_do_parameter ( res , value_name , tmp ) ;
SAFE_FREE ( tmp ) ;
2006-11-30 10:38:40 +03:00
break ;
}
case REG_SZ : {
2006-12-02 13:53:00 +03:00
lp_do_parameter ( res , value_name , value - > v . sz . str ) ;
2006-11-30 10:38:40 +03:00
break ;
}
default :
/* Ignore all the rest */
break ;
}
2006-12-02 13:53:00 +03:00
TALLOC_FREE ( value_name ) ;
TALLOC_FREE ( value ) ;
}
2006-11-30 10:38:40 +03:00
error :
2006-12-02 13:53:00 +03:00
TALLOC_FREE ( key ) ;
return res ;
2006-11-30 10:38:40 +03:00
}
void load_registry_shares ( void )
{
2006-12-02 13:53:00 +03:00
struct registry_key * key ;
char * name ;
2006-11-30 10:38:40 +03:00
WERROR err ;
int i ;
if ( ! lp_registry_shares ( ) ) {
return ;
}
2006-12-02 13:53:00 +03:00
err = reg_open_path ( NULL , KEY_SMBCONF , REG_KEY_READ ,
get_root_nt_token ( ) , & key ) ;
2006-11-30 10:38:40 +03:00
if ( ! ( W_ERROR_IS_OK ( err ) ) ) {
2006-12-02 13:53:00 +03:00
return ;
2006-11-30 10:38:40 +03:00
}
2006-12-02 13:53:00 +03:00
for ( i = 0 ; W_ERROR_IS_OK ( reg_enumkey ( key , key , i , & name , NULL ) ) ; i + + ) {
load_registry_service ( name ) ;
TALLOC_FREE ( name ) ;
2006-11-30 10:38:40 +03:00
}
2006-12-02 13:53:00 +03:00
TALLOC_FREE ( key ) ;
2006-11-30 10:38:40 +03:00
return ;
}
2001-01-24 22:34:53 +03:00
2002-01-16 05:42:07 +03:00
/**
2004-03-06 01:32:45 +03:00
* Find a service entry .
2002-01-16 05:42:07 +03:00
*
* @ param service is modified ( to canonical form ? ? )
* */
2004-03-06 01:32:45 +03:00
2002-01-16 05:42:07 +03:00
int find_service ( fstring service )
1998-08-17 17:11:34 +04:00
{
2004-03-06 01:32:45 +03:00
int iService ;
all_string_sub ( service , " \\ " , " / " , 0 ) ;
iService = lp_servicenumber ( service ) ;
/* now handle the special case of a home directory */
if ( iService < 0 ) {
2007-12-19 17:02:59 +03:00
char * phome_dir = get_user_home_dir ( talloc_tos ( ) , service ) ;
2004-03-06 01:32:45 +03:00
if ( ! phome_dir ) {
/*
* Try mapping the servicename , it may
* be a Windows to unix mapped user name .
*/
if ( map_username ( service ) )
2007-12-19 17:02:59 +03:00
phome_dir = get_user_home_dir (
talloc_tos ( ) , service ) ;
2004-03-06 01:32:45 +03:00
}
DEBUG ( 3 , ( " checking for home directory %s gave %s \n " , service ,
phome_dir ? phome_dir : " (NULL) " ) ) ;
iService = add_home_service ( service , service /* 'username' */ , phome_dir ) ;
}
/* 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 ) {
DEBUG ( 3 , ( " checking whether %s is a valid printer name... \n " , service ) ) ;
2005-01-05 19:20:35 +03:00
if ( pcap_printername_ok ( service ) ) {
2004-03-06 01:32:45 +03:00
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 ) ) ;
}
}
}
/* Check for default vfs service? Unsure whether to implement this */
if ( iService < 0 ) {
}
2007-10-11 00:34:30 +04:00
if ( iService < 0 ) {
iService = load_registry_service ( service ) ;
}
2007-02-21 05:04:28 +03:00
/* Is it a usershare service ? */
if ( iService < 0 & & * lp_usershare_path ( ) ) {
/* Ensure the name is canonicalized. */
strlower_m ( service ) ;
iService = load_usershare_service ( service ) ;
}
2004-03-06 01:32:45 +03:00
/* just possibly it's a default service? */
if ( iService < 0 ) {
char * pdefservice = lp_defaultservice ( ) ;
2004-03-09 03:17:14 +03:00
if ( pdefservice & & * pdefservice & & ! strequal ( pdefservice , service ) & & ! strstr_m ( service , " .. " ) ) {
2004-03-06 01:32:45 +03:00
/*
* 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 > .
*/
2007-11-11 01:43:39 +03:00
char * defservice = SMB_STRDUP ( pdefservice ) ;
if ( ! defservice ) {
goto fail ;
}
2007-02-21 05:04:28 +03:00
/* Disallow anything except explicit share names. */
if ( strequal ( defservice , HOMES_NAME ) | |
strequal ( defservice , PRINTERS_NAME ) | |
2007-02-21 05:11:06 +03:00
strequal ( defservice , " IPC$ " ) ) {
2007-11-11 01:43:39 +03:00
SAFE_FREE ( defservice ) ;
2007-02-21 05:04:28 +03:00
goto fail ;
}
2004-03-06 01:32:45 +03:00
iService = find_service ( defservice ) ;
if ( iService > = 0 ) {
all_string_sub ( service , " _ " , " / " , 0 ) ;
iService = lp_add_service ( service , iService ) ;
}
2007-11-11 01:43:39 +03:00
SAFE_FREE ( defservice ) ;
2004-03-06 01:32:45 +03:00
}
}
if ( iService > = 0 ) {
if ( ! VALID_SNUM ( iService ) ) {
DEBUG ( 0 , ( " Invalid snum %d for %s \n " , iService , service ) ) ;
iService = - 1 ;
}
}
2007-02-21 05:04:28 +03:00
fail :
2004-03-06 01:32:45 +03:00
if ( iService < 0 )
DEBUG ( 3 , ( " find_service() failed to find service %s \n " , service ) ) ;
return ( iService ) ;
1998-08-17 17:11:34 +04:00
}
2001-08-17 11:03:27 +04:00
/****************************************************************************
do some basic sainity checks on the share .
This function modifies dev , ecode .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-03-06 01:32:45 +03:00
2003-03-19 02:49:03 +03:00
static NTSTATUS share_sanity_checks ( int snum , fstring dev )
2001-08-17 11:03:27 +04:00
{
if ( ! lp_snum_ok ( snum ) | |
! check_access ( smbd_server_fd ( ) ,
lp_hostsallow ( snum ) , lp_hostsdeny ( snum ) ) ) {
2001-08-27 23:46:22 +04:00
return NT_STATUS_ACCESS_DENIED ;
2001-08-17 11:03:27 +04:00
}
2002-01-16 05:42:07 +03:00
if ( dev [ 0 ] = = ' ? ' | | ! dev [ 0 ] ) {
2001-08-17 11:03:27 +04:00
if ( lp_print_ok ( snum ) ) {
2003-04-12 03:28:15 +04:00
fstrcpy ( dev , " LPT1: " ) ;
2003-03-30 20:37:10 +04:00
} else if ( strequal ( lp_fstype ( snum ) , " IPC " ) ) {
fstrcpy ( dev , " IPC " ) ;
2001-08-17 11:03:27 +04:00
} else {
2003-03-19 05:01:11 +03:00
fstrcpy ( dev , " A: " ) ;
2001-08-17 11:03:27 +04:00
}
}
2003-07-03 23:11:31 +04:00
strupper_m ( dev ) ;
2003-03-30 20:37:10 +04:00
if ( lp_print_ok ( snum ) ) {
2003-04-12 03:28:15 +04:00
if ( ! strequal ( dev , " LPT1: " ) ) {
2003-03-30 20:37:10 +04:00
return NT_STATUS_BAD_DEVICE_TYPE ;
}
} else if ( strequal ( lp_fstype ( snum ) , " IPC " ) ) {
if ( ! strequal ( dev , " IPC " ) ) {
return NT_STATUS_BAD_DEVICE_TYPE ;
}
} else if ( ! strequal ( dev , " A: " ) ) {
2001-08-27 23:46:22 +04:00
return NT_STATUS_BAD_DEVICE_TYPE ;
2001-08-17 11:03:27 +04:00
}
/* Behave as a printer if we are supposed to */
if ( lp_print_ok ( snum ) & & ( strcmp ( dev , " A: " ) = = 0 ) ) {
2003-04-12 03:28:15 +04:00
fstrcpy ( dev , " LPT1: " ) ;
2001-08-17 11:03:27 +04:00
}
2001-08-27 23:46:22 +04:00
return NT_STATUS_OK ;
2001-08-17 11:03:27 +04:00
}
2007-10-19 04:40:25 +04:00
static NTSTATUS find_forced_user ( connection_struct * conn , bool vuser_is_guest , fstring username )
2006-02-04 01:19:41 +03:00
{
2006-12-10 08:23:47 +03:00
int snum = conn - > params - > service ;
2006-02-04 01:19:41 +03:00
char * fuser , * found_username ;
NTSTATUS result ;
2006-12-10 08:23:47 +03:00
if ( ! ( fuser = talloc_string_sub ( conn - > mem_ctx , lp_force_user ( snum ) , " %S " ,
2006-07-11 22:01:26 +04:00
lp_servicename ( snum ) ) ) ) {
return NT_STATUS_NO_MEMORY ;
2006-02-04 01:19:41 +03:00
}
2006-12-10 08:23:47 +03:00
result = create_token_from_username ( conn - > mem_ctx , fuser , vuser_is_guest ,
& conn - > uid , & conn - > gid , & found_username ,
& conn - > nt_user_token ) ;
2006-02-04 01:19:41 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2006-07-11 22:01:26 +04:00
return result ;
}
2006-02-04 01:19:41 +03:00
fstrcpy ( username , found_username ) ;
2006-12-10 08:23:47 +03:00
TALLOC_FREE ( fuser ) ;
TALLOC_FREE ( found_username ) ;
2006-07-11 22:01:26 +04:00
return NT_STATUS_OK ;
2006-02-04 01:19:41 +03:00
}
/*
* Go through lookup_name etc to find the force ' d group .
*
* Create a new token from src_token , replacing the primary group sid with the
* one found .
*/
2007-10-19 04:40:25 +04:00
static NTSTATUS find_forced_group ( bool force_user ,
2006-02-04 01:19:41 +03:00
int snum , const char * username ,
DOM_SID * pgroup_sid ,
gid_t * pgid )
{
NTSTATUS result = NT_STATUS_NO_SUCH_GROUP ;
TALLOC_CTX * mem_ctx ;
DOM_SID group_sid ;
2006-09-08 18:28:06 +04:00
enum lsa_SidType type ;
2006-02-04 01:19:41 +03:00
char * groupname ;
2007-10-19 04:40:25 +04:00
bool user_must_be_member = False ;
2006-02-04 01:19:41 +03:00
gid_t gid ;
2006-11-14 23:21:23 +03:00
ZERO_STRUCTP ( pgroup_sid ) ;
* pgid = ( gid_t ) - 1 ;
2006-02-04 01:19:41 +03:00
mem_ctx = talloc_new ( NULL ) ;
if ( mem_ctx = = NULL ) {
DEBUG ( 0 , ( " talloc_new failed \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
groupname = talloc_strdup ( mem_ctx , lp_force_group ( snum ) ) ;
if ( groupname = = NULL ) {
DEBUG ( 1 , ( " talloc_strdup failed \n " ) ) ;
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
if ( groupname [ 0 ] = = ' + ' ) {
user_must_be_member = True ;
groupname + = 1 ;
}
groupname = talloc_string_sub ( mem_ctx , groupname ,
" %S " , lp_servicename ( snum ) ) ;
2006-08-05 00:35:52 +04:00
if ( ! lookup_name_smbconf ( mem_ctx , groupname ,
2006-02-04 01:19:41 +03:00
LOOKUP_NAME_ALL | LOOKUP_NAME_GROUP ,
NULL , NULL , & group_sid , & type ) ) {
2006-08-05 00:35:52 +04:00
DEBUG ( 10 , ( " lookup_name_smbconf(%s) failed \n " ,
2006-02-04 01:19:41 +03:00
groupname ) ) ;
goto done ;
}
if ( ( type ! = SID_NAME_DOM_GRP ) & & ( type ! = SID_NAME_ALIAS ) & &
( type ! = SID_NAME_WKN_GRP ) ) {
DEBUG ( 10 , ( " %s is a %s, not a group \n " , groupname ,
sid_type_lookup ( type ) ) ) ;
goto done ;
}
if ( ! sid_to_gid ( & group_sid , & gid ) ) {
DEBUG ( 10 , ( " sid_to_gid(%s) for %s failed \n " ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( & group_sid ) , groupname ) ) ;
2006-02-04 01:19:41 +03:00
goto done ;
}
/*
* If the user has been forced and the forced group starts with a ' + ' ,
* then we only set the group to be the forced group if the forced
* user is a member of that group . Otherwise , the meaning of the ' + '
* would be ignored .
*/
if ( force_user & & user_must_be_member ) {
2006-02-13 20:08:25 +03:00
if ( user_in_group_sid ( username , & group_sid ) ) {
2006-02-04 01:19:41 +03:00
sid_copy ( pgroup_sid , & group_sid ) ;
* pgid = gid ;
DEBUG ( 3 , ( " Forced group %s for member %s \n " ,
groupname , username ) ) ;
2006-11-14 23:21:23 +03:00
} else {
DEBUG ( 0 , ( " find_forced_group: forced user %s is not a member "
" of forced group %s. Disallowing access. \n " ,
username , groupname ) ) ;
result = NT_STATUS_MEMBER_NOT_IN_GROUP ;
goto done ;
2006-02-04 01:19:41 +03:00
}
} else {
sid_copy ( pgroup_sid , & group_sid ) ;
* pgid = gid ;
DEBUG ( 3 , ( " Forced group %s \n " , groupname ) ) ;
}
result = NT_STATUS_OK ;
done :
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( mem_ctx ) ;
2006-02-04 01:19:41 +03:00
return result ;
}
1998-08-17 17:11:34 +04:00
/****************************************************************************
2002-07-15 14:35:28 +04:00
Make a connection , given the snum to connect to , and the vuser of the
connecting user if appropriate .
1998-08-17 17:11:34 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-19 00:15:12 +04:00
2002-07-15 14:35:28 +04:00
static connection_struct * make_connection_snum ( int snum , user_struct * vuser ,
DATA_BLOB password ,
2005-12-17 20:13:45 +03:00
const char * pdev ,
NTSTATUS * status )
1998-08-17 17:11:34 +04:00
{
1999-12-13 16:27:58 +03:00
struct passwd * pass = NULL ;
2007-10-19 04:40:25 +04:00
bool guest = False ;
1998-08-17 17:11:34 +04:00
connection_struct * conn ;
2005-03-19 21:21:39 +03:00
SMB_STRUCT_STAT st ;
2001-09-15 16:55:59 +04:00
fstring user ;
2003-03-19 02:49:03 +03:00
fstring dev ;
2005-10-03 22:14:09 +04:00
int ret ;
2007-11-04 04:15:45 +03:00
char addr [ INET6_ADDRSTRLEN ] ;
2007-11-11 01:43:39 +03:00
bool on_err_call_dis_hook = false ;
2003-03-19 02:49:03 +03:00
2002-07-15 14:35:28 +04:00
* user = 0 ;
2003-03-19 02:49:03 +03:00
fstrcpy ( dev , pdev ) ;
2005-06-03 09:35:04 +04:00
SET_STAT_INVALID ( st ) ;
1998-08-17 17:11:34 +04:00
2002-07-15 14:35:28 +04:00
if ( NT_STATUS_IS_ERR ( * status = share_sanity_checks ( snum , dev ) ) ) {
1998-08-17 17:11:34 +04:00
return NULL ;
2001-08-17 11:03:27 +04:00
}
2000-07-25 10:10:59 +04:00
1998-08-17 17:11:34 +04:00
conn = conn_new ( ) ;
if ( ! conn ) {
DEBUG ( 0 , ( " Couldn't find free connection. \n " ) ) ;
2001-08-27 23:46:22 +04:00
* status = NT_STATUS_INSUFFICIENT_RESOURCES ;
1998-08-17 17:11:34 +04:00
return NULL ;
}
2006-12-10 08:23:47 +03:00
conn - > params - > service = snum ;
2006-05-14 19:24:14 +04:00
conn - > nt_user_token = NULL ;
2002-07-15 14:35:28 +04:00
if ( lp_guest_only ( snum ) ) {
2002-08-17 19:27:10 +04:00
const char * guestname = lp_guestaccount ( ) ;
2006-05-14 19:24:14 +04:00
NTSTATUS status2 ;
2006-12-10 02:55:20 +03:00
char * found_username = NULL ;
2002-07-15 14:35:28 +04:00
guest = True ;
2006-02-04 01:19:41 +03:00
pass = getpwnam_alloc ( NULL , guestname ) ;
2002-07-15 14:35:28 +04:00
if ( ! pass ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 0 , ( " make_connection_snum: Invalid guest "
" account %s?? \n " , guestname ) ) ;
2002-07-15 14:35:28 +04:00
conn_free ( conn ) ;
* status = NT_STATUS_NO_SUCH_USER ;
return NULL ;
}
2006-12-10 08:23:47 +03:00
status2 = create_token_from_username ( conn - > mem_ctx , pass - > pw_name , True ,
2006-05-14 19:24:14 +04:00
& conn - > uid , & conn - > gid ,
& found_username ,
& conn - > nt_user_token ) ;
if ( ! NT_STATUS_IS_OK ( status2 ) ) {
2006-12-10 08:23:47 +03:00
TALLOC_FREE ( pass ) ;
2006-05-14 19:24:14 +04:00
conn_free ( conn ) ;
* status = status2 ;
return NULL ;
}
fstrcpy ( user , found_username ) ;
string_set ( & conn - > user , user ) ;
2002-07-15 14:35:28 +04:00
conn - > force_user = True ;
2006-12-10 02:55:20 +03:00
TALLOC_FREE ( found_username ) ;
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( pass ) ;
2002-07-15 14:35:28 +04:00
DEBUG ( 3 , ( " Guest only user %s \n " , user ) ) ;
} else if ( vuser ) {
if ( vuser - > guest ) {
if ( ! lp_guest_ok ( snum ) ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 2 , ( " guest user (from session setup) "
" not permitted to access this share "
" (%s) \n " , lp_servicename ( snum ) ) ) ;
2002-07-15 14:35:28 +04:00
conn_free ( conn ) ;
* status = NT_STATUS_ACCESS_DENIED ;
return NULL ;
}
} else {
2006-02-04 01:19:41 +03:00
if ( ! user_ok_token ( vuser - > user . unix_name ,
vuser - > nt_user_token , snum ) ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 2 , ( " user '%s' (from session setup) not "
" permitted to access this share "
" (%s) \n " , vuser - > user . unix_name ,
lp_servicename ( snum ) ) ) ;
2002-07-15 14:35:28 +04:00
conn_free ( conn ) ;
* status = NT_STATUS_ACCESS_DENIED ;
return NULL ;
}
}
conn - > vuid = vuser - > vuid ;
conn - > uid = vuser - > uid ;
conn - > gid = vuser - > gid ;
string_set ( & conn - > user , vuser - > user . unix_name ) ;
fstrcpy ( user , vuser - > user . unix_name ) ;
guest = vuser - > guest ;
} else if ( lp_security ( ) = = SEC_SHARE ) {
2006-05-14 19:24:14 +04:00
NTSTATUS status2 ;
2006-12-10 02:55:20 +03:00
char * found_username = NULL ;
2006-12-10 08:23:47 +03:00
2002-07-15 14:35:28 +04:00
/* add it as a possible user name if we
are in share mode security */
add_session_user ( lp_servicename ( snum ) ) ;
/* shall we let them in? */
if ( ! authorise_login ( snum , user , password , & guest ) ) {
DEBUG ( 2 , ( " Invalid username/password for [%s] \n " ,
lp_servicename ( snum ) ) ) ;
conn_free ( conn ) ;
* status = NT_STATUS_WRONG_PASSWORD ;
return NULL ;
}
2007-12-19 17:02:59 +03:00
pass = Get_Pwnam_alloc ( talloc_tos ( ) , user ) ;
2006-12-10 08:23:47 +03:00
status2 = create_token_from_username ( conn - > mem_ctx , pass - > pw_name , True ,
2006-05-14 19:24:14 +04:00
& conn - > uid , & conn - > gid ,
& found_username ,
& conn - > nt_user_token ) ;
2007-12-19 17:02:59 +03:00
TALLOC_FREE ( pass ) ;
2006-05-14 19:24:14 +04:00
if ( ! NT_STATUS_IS_OK ( status2 ) ) {
conn_free ( conn ) ;
* status = status2 ;
return NULL ;
}
fstrcpy ( user , found_username ) ;
string_set ( & conn - > user , user ) ;
2006-12-10 02:55:20 +03:00
TALLOC_FREE ( found_username ) ;
2002-09-25 19:19:00 +04:00
conn - > force_user = True ;
2002-07-15 14:35:28 +04:00
} else {
DEBUG ( 0 , ( " invalid VUID (vuser) but not in security=share \n " ) ) ;
1998-08-17 17:11:34 +04:00
conn_free ( conn ) ;
2002-07-15 14:35:28 +04:00
* status = NT_STATUS_ACCESS_DENIED ;
1998-08-17 17:11:34 +04:00
return NULL ;
}
2002-07-15 14:35:28 +04:00
add_session_user ( user ) ;
2007-11-04 09:20:10 +03:00
safe_strcpy ( conn - > client_address ,
client_addr ( get_client_fd ( ) , addr , sizeof ( addr ) ) ,
sizeof ( conn - > client_address ) - 1 ) ;
1998-08-17 17:11:34 +04:00
conn - > num_files_open = 0 ;
2006-04-15 08:07:10 +04:00
conn - > lastused = conn - > lastused_count = time ( NULL ) ;
1998-08-17 17:11:34 +04:00
conn - > used = True ;
conn - > printer = ( strncmp ( dev , " LPT " , 3 ) = = 0 ) ;
2005-12-17 20:13:45 +03:00
conn - > ipc = ( ( strncmp ( dev , " IPC " , 3 ) = = 0 ) | |
( lp_enable_asu_support ( ) & & strequal ( dev , " ADMIN$ " ) ) ) ;
1998-08-17 17:11:34 +04:00
conn - > dirptr = NULL ;
2004-05-07 22:37:47 +04:00
/* Case options for the share. */
2004-06-15 22:36:45 +04:00
if ( lp_casesensitive ( snum ) = = Auto ) {
2005-12-17 20:13:45 +03:00
/* We will be setting this per packet. Set to be case
* insensitive for now . */
2004-06-15 22:36:45 +04:00
conn - > case_sensitive = False ;
} else {
2007-10-19 04:40:25 +04:00
conn - > case_sensitive = ( bool ) lp_casesensitive ( snum ) ;
2004-06-15 22:36:45 +04:00
}
2004-05-07 22:37:47 +04:00
conn - > case_preserve = lp_preservecase ( snum ) ;
conn - > short_case_preserve = lp_shortpreservecase ( snum ) ;
2007-12-28 10:51:03 +03:00
conn - > encrypt_level = lp_smb_encrypt ( snum ) ;
1998-08-17 17:11:34 +04:00
conn - > veto_list = NULL ;
conn - > hide_list = NULL ;
conn - > veto_oplock_list = NULL ;
2007-10-11 00:34:30 +04:00
conn - > aio_write_behind_list = NULL ;
1998-08-17 17:11:34 +04:00
string_set ( & conn - > dirpath , " " ) ;
string_set ( & conn - > user , user ) ;
2004-02-13 22:05:25 +03:00
2006-07-11 22:01:26 +04:00
conn - > read_only = lp_readonly ( SNUM ( conn ) ) ;
2004-02-13 22:05:25 +03:00
conn - > admin_user = False ;
2001-08-17 12:12:33 +04:00
1999-12-13 16:27:58 +03:00
/*
2006-02-04 01:19:41 +03:00
* If force user is true , then store the given userid and the gid of
* the user we ' re forcing .
* For auxiliary groups see below .
1999-12-13 16:27:58 +03:00
*/
if ( * lp_force_user ( snum ) ) {
2006-02-04 01:19:41 +03:00
NTSTATUS status2 ;
2006-12-10 08:23:47 +03:00
status2 = find_forced_user ( conn ,
( vuser ! = NULL ) & & vuser - > guest ,
user ) ;
2006-02-04 01:19:41 +03:00
if ( ! NT_STATUS_IS_OK ( status2 ) ) {
2002-07-15 14:35:28 +04:00
conn_free ( conn ) ;
2006-02-04 01:19:41 +03:00
* status = status2 ;
2002-07-15 14:35:28 +04:00
return NULL ;
1999-12-13 16:27:58 +03:00
}
2006-02-04 01:19:41 +03:00
string_set ( & conn - > user , user ) ;
conn - > force_user = True ;
DEBUG ( 3 , ( " Forced user %s \n " , user ) ) ;
1999-04-04 10:22:22 +04:00
}
1999-12-13 16:27:58 +03:00
/*
* If force group is true , then override
* any groupid stored for the connecting user .
*/
1998-08-17 17:11:34 +04:00
if ( * lp_force_group ( snum ) ) {
2006-02-04 01:19:41 +03:00
NTSTATUS status2 ;
DOM_SID group_sid ;
status2 = find_forced_group ( conn - > force_user ,
snum , user ,
& group_sid , & conn - > gid ) ;
if ( ! NT_STATUS_IS_OK ( status2 ) ) {
2002-07-15 14:35:28 +04:00
conn_free ( conn ) ;
2006-02-04 01:19:41 +03:00
* status = status2 ;
2002-07-15 14:35:28 +04:00
return NULL ;
1998-08-17 17:11:34 +04:00
}
2005-12-17 20:13:45 +03:00
2006-02-04 01:19:41 +03:00
if ( ( conn - > nt_user_token = = NULL ) & & ( vuser ! = NULL ) ) {
/* Not force user and not security=share, but force
* group . vuser has a token to copy */
conn - > nt_user_token = dup_nt_token (
NULL , vuser - > nt_user_token ) ;
if ( conn - > nt_user_token = = NULL ) {
DEBUG ( 0 , ( " dup_nt_token failed \n " ) ) ;
conn_free ( conn ) ;
* status = NT_STATUS_NO_MEMORY ;
return NULL ;
2005-12-17 20:13:45 +03:00
}
2006-02-04 01:19:41 +03:00
}
/* If conn->nt_user_token is still NULL, we have
* security = share . This means ignore the SID , as we had no
* vuser to copy from */
if ( conn - > nt_user_token ! = NULL ) {
/* Overwrite the primary group sid */
sid_copy ( & conn - > nt_user_token - > user_sids [ 1 ] ,
& group_sid ) ;
2005-12-17 20:13:45 +03:00
}
conn - > force_group = True ;
1998-08-17 17:11:34 +04:00
}
2006-02-04 01:19:41 +03:00
if ( conn - > nt_user_token ! = NULL ) {
size_t i ;
/* We have a share-specific token from force [user|group].
* This means we have to create the list of unix groups from
* the list of sids . */
conn - > ngroups = 0 ;
conn - > groups = NULL ;
for ( i = 0 ; i < conn - > nt_user_token - > num_sids ; i + + ) {
gid_t gid ;
DOM_SID * sid = & conn - > nt_user_token - > user_sids [ i ] ;
if ( ! sid_to_gid ( sid , & gid ) ) {
DEBUG ( 10 , ( " Could not convert SID %s to gid, "
" ignoring it \n " ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( sid ) ) ) ;
2006-02-04 01:19:41 +03:00
continue ;
}
2006-12-10 08:23:47 +03:00
if ( ! add_gid_to_array_unique ( conn - > mem_ctx , gid , & conn - > groups ,
2006-12-09 05:58:18 +03:00
& conn - > ngroups ) ) {
DEBUG ( 0 , ( " add_gid_to_array_unique failed \n " ) ) ;
conn_free ( conn ) ;
* status = NT_STATUS_NO_MEMORY ;
return NULL ;
}
2006-02-04 01:19:41 +03:00
}
}
1998-08-17 17:11:34 +04:00
{
2007-11-11 01:43:39 +03:00
char * s = talloc_sub_advanced ( talloc_tos ( ) ,
lp_servicename ( SNUM ( conn ) ) , conn - > user ,
conn - > connectpath , conn - > gid ,
get_current_username ( ) ,
current_user_info . domain ,
lp_pathname ( snum ) ) ;
if ( ! s ) {
conn_free ( conn ) ;
* status = NT_STATUS_NO_MEMORY ;
return NULL ;
}
if ( ! set_conn_connectpath ( conn , s ) ) {
TALLOC_FREE ( s ) ;
conn_free ( conn ) ;
* status = NT_STATUS_NO_MEMORY ;
return NULL ;
}
2005-12-17 20:13:45 +03:00
DEBUG ( 3 , ( " Connect path is '%s' for service [%s] \n " , s ,
lp_servicename ( snum ) ) ) ;
2007-11-11 01:43:39 +03:00
TALLOC_FREE ( s ) ;
1998-08-17 17:11:34 +04:00
}
2001-04-12 01:19:25 +04:00
/*
* New code to check if there ' s a share security descripter
* added from NT server manager . This is done after the
* smb . conf checks are done as we need a uid and token . JRA .
2002-09-25 19:19:00 +04:00
*
2001-04-12 01:19:25 +04:00
*/
{
2007-10-19 04:40:25 +04:00
bool can_write = False ;
2006-07-17 23:50:59 +04:00
NT_USER_TOKEN * token = conn - > nt_user_token ?
2007-03-24 00:50:44 +03:00
conn - > nt_user_token :
( vuser ? vuser - > nt_user_token : NULL ) ;
/*
* I don ' t believe this can happen . But the
* logic above is convoluted enough to confuse
* automated checkers , so be sure . JRA .
*/
if ( token = = NULL ) {
DEBUG ( 0 , ( " make_connection: connection to %s "
" denied due to missing "
" NT token. \n " ,
lp_servicename ( snum ) ) ) ;
conn_free ( conn ) ;
* status = NT_STATUS_ACCESS_DENIED ;
return NULL ;
}
2006-07-17 23:50:59 +04:00
2007-03-24 00:50:44 +03:00
can_write = share_access_check ( token ,
2006-07-17 23:50:59 +04:00
lp_servicename ( snum ) ,
2005-12-17 20:13:45 +03:00
FILE_WRITE_DATA ) ;
2001-04-12 01:19:25 +04:00
if ( ! can_write ) {
2006-07-17 23:50:59 +04:00
if ( ! share_access_check ( token ,
lp_servicename ( snum ) ,
2005-12-17 20:13:45 +03:00
FILE_READ_DATA ) ) {
2001-04-12 01:19:25 +04:00
/* No access, read or write. */
2005-12-17 20:13:45 +03:00
DEBUG ( 0 , ( " make_connection: connection to %s "
" denied due to security "
" descriptor. \n " ,
2002-07-15 14:35:28 +04:00
lp_servicename ( snum ) ) ) ;
2001-08-17 12:57:58 +04:00
conn_free ( conn ) ;
2002-07-15 14:35:28 +04:00
* status = NT_STATUS_ACCESS_DENIED ;
2001-04-12 01:19:25 +04:00
return NULL ;
} else {
conn - > read_only = True ;
}
}
}
2000-08-04 02:38:43 +04:00
/* Initialise VFS function pointers */
2001-10-18 04:27:20 +04:00
if ( ! smbd_vfs_init ( conn ) ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 0 , ( " vfs_init failed for service %s \n " ,
lp_servicename ( snum ) ) ) ;
2001-08-17 12:57:58 +04:00
conn_free ( conn ) ;
2003-01-06 10:40:39 +03:00
* status = NT_STATUS_BAD_NETWORK_NAME ;
2001-06-30 02:32:24 +04:00
return NULL ;
2000-08-04 02:38:43 +04:00
}
2004-05-28 05:54:01 +04:00
/*
2005-12-17 20:13:45 +03:00
* If widelinks are disallowed we need to canonicalise the connect
* path here to ensure we don ' t have any symlinks in the
* connectpath . We will be checking all paths on this connection are
* below this directory . We must do this after the VFS init as we
* depend on the realpath ( ) pointer in the vfs table . JRA .
2004-05-28 05:54:01 +04:00
*/
if ( ! lp_widelinks ( snum ) ) {
2007-11-11 01:43:39 +03:00
if ( ! canonicalize_connect_path ( conn ) ) {
DEBUG ( 0 , ( " canonicalize_connect_path failed "
" for service %s, path %s \n " ,
lp_servicename ( snum ) ,
conn - > connectpath ) ) ;
conn_free ( conn ) ;
* status = NT_STATUS_BAD_NETWORK_NAME ;
return NULL ;
}
2004-05-28 05:54:01 +04:00
}
2007-01-31 17:42:56 +03:00
if ( ( ! conn - > printer ) & & ( ! conn - > ipc ) ) {
conn - > notify_ctx = notify_init ( conn - > mem_ctx , server_id_self ( ) ,
smbd_messaging_context ( ) ,
smbd_event_context ( ) ,
2007-02-01 16:36:02 +03:00
conn ) ;
2007-01-31 17:42:56 +03:00
}
2001-09-20 11:09:28 +04:00
/* ROOT Activities: */
2007-05-27 20:34:49 +04:00
/*
* Enforce the max connections parameter .
*/
if ( ( lp_max_connections ( snum ) > 0 )
& & ( count_current_connections ( lp_servicename ( SNUM ( conn ) ) , True ) > =
lp_max_connections ( snum ) ) ) {
DEBUG ( 1 , ( " Max connections (%d) exceeded for %s \n " ,
lp_max_connections ( snum ) , lp_servicename ( snum ) ) ) ;
2001-08-17 12:44:04 +04:00
conn_free ( conn ) ;
2002-07-15 14:35:28 +04:00
* status = NT_STATUS_INSUFFICIENT_RESOURCES ;
2001-08-17 12:44:04 +04:00
return NULL ;
}
2001-09-20 11:09:28 +04:00
2007-05-27 20:34:49 +04:00
/*
* Get us an entry in the connections db
*/
if ( ! claim_connection ( conn , lp_servicename ( snum ) , 0 ) ) {
DEBUG ( 1 , ( " Could not store connections entry \n " ) ) ;
conn_free ( conn ) ;
* status = NT_STATUS_INTERNAL_DB_ERROR ;
return NULL ;
}
2005-12-17 20:13:45 +03:00
/* Preexecs are done here as they might make the dir we are to ChDir
* to below */
1998-08-17 17:11:34 +04:00
/* execute any "root preexec = " line */
2005-04-27 03:52:21 +04:00
if ( * lp_rootpreexec ( snum ) ) {
2007-11-11 01:43:39 +03:00
char * cmd = talloc_sub_advanced ( talloc_tos ( ) ,
lp_servicename ( SNUM ( conn ) ) , conn - > user ,
conn - > connectpath , conn - > gid ,
get_current_username ( ) ,
current_user_info . domain ,
lp_rootpreexec ( snum ) ) ;
1998-08-17 17:11:34 +04:00
DEBUG ( 5 , ( " cmd=%s \n " , cmd ) ) ;
2001-04-13 23:12:06 +04:00
ret = smbrun ( cmd , NULL ) ;
2007-11-11 01:43:39 +03:00
TALLOC_FREE ( cmd ) ;
2005-04-27 03:52:21 +04:00
if ( ret ! = 0 & & lp_rootpreexec_close ( snum ) ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 1 , ( " root preexec gave %d - failing "
" connection \n " , ret ) ) ;
2005-04-27 03:52:21 +04:00
yield_connection ( conn , lp_servicename ( snum ) ) ;
1999-12-13 16:27:58 +03:00
conn_free ( conn ) ;
2003-01-06 10:40:39 +03:00
* status = NT_STATUS_ACCESS_DENIED ;
1999-12-13 16:27:58 +03:00
return NULL ;
}
1998-08-17 17:11:34 +04:00
}
2001-09-20 11:09:28 +04:00
/* USER Activites: */
2001-10-19 00:15:12 +04:00
if ( ! change_to_user ( conn , conn - > vuid ) ) {
/* No point continuing if they fail the basic checks */
DEBUG ( 0 , ( " Can't become connected user! \n " ) ) ;
2005-04-27 03:52:21 +04:00
yield_connection ( conn , lp_servicename ( snum ) ) ;
2001-10-19 00:15:12 +04:00
conn_free ( conn ) ;
* status = NT_STATUS_LOGON_FAILURE ;
return NULL ;
}
2002-11-18 09:12:47 +03:00
2005-12-17 20:13:45 +03:00
/* Remember that a different vuid can connect later without these
* checks . . . */
2002-07-15 14:35:28 +04:00
2005-12-17 20:13:45 +03:00
/* Preexecs are done here as they might make the dir we are to ChDir
* to below */
2001-09-20 11:09:28 +04:00
/* execute any "preexec = " line */
2005-04-27 03:52:21 +04:00
if ( * lp_preexec ( snum ) ) {
2007-11-11 01:43:39 +03:00
char * cmd = talloc_sub_advanced ( talloc_tos ( ) ,
lp_servicename ( SNUM ( conn ) ) , conn - > user ,
conn - > connectpath , conn - > gid ,
get_current_username ( ) ,
current_user_info . domain ,
lp_preexec ( snum ) ) ;
2001-09-20 11:09:28 +04:00
ret = smbrun ( cmd , NULL ) ;
2007-11-11 01:43:39 +03:00
TALLOC_FREE ( cmd ) ;
2005-04-27 03:52:21 +04:00
if ( ret ! = 0 & & lp_preexec_close ( snum ) ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 1 , ( " preexec gave %d - failing connection \n " ,
ret ) ) ;
2003-01-06 10:40:39 +03:00
* status = NT_STATUS_ACCESS_DENIED ;
2007-11-11 01:43:39 +03:00
goto err_root_exit ;
2001-09-20 11:09:28 +04:00
}
1998-08-17 17:11:34 +04:00
}
2003-09-07 20:36:13 +04:00
# ifdef WITH_FAKE_KASERVER
2005-04-27 03:52:21 +04:00
if ( lp_afs_share ( snum ) ) {
2003-09-23 18:52:21 +04:00
afs_login ( conn ) ;
}
2003-09-07 20:36:13 +04:00
# endif
2002-07-15 14:35:28 +04:00
2005-06-27 21:14:15 +04:00
/* Add veto/hide lists */
if ( ! IS_IPC ( conn ) & & ! IS_PRINT ( conn ) ) {
set_namearray ( & conn - > veto_list , lp_veto_files ( snum ) ) ;
set_namearray ( & conn - > hide_list , lp_hide_files ( snum ) ) ;
set_namearray ( & conn - > veto_oplock_list , lp_veto_oplocks ( snum ) ) ;
}
2005-12-17 20:13:45 +03:00
/* Invoke VFS make connection hook - do this before the VFS_STAT call
to allow any filesystems needing user credentials to initialize
themselves . */
2005-06-27 21:14:15 +04:00
if ( SMB_VFS_CONNECT ( conn , lp_servicename ( snum ) , user ) < 0 ) {
DEBUG ( 0 , ( " make_connection: VFS make connection failed! \n " ) ) ;
* status = NT_STATUS_UNSUCCESSFUL ;
2007-11-11 01:43:39 +03:00
goto err_root_exit ;
2005-06-27 21:14:15 +04:00
}
2007-11-11 01:43:39 +03:00
/* Any error exit after here needs to call the disconnect hook. */
on_err_call_dis_hook = true ;
2002-07-15 14:35:28 +04:00
/* win2000 does not check the permissions on the directory
during the tree connect , instead relying on permission
check during individual operations . To match this behaviour
I have disabled this chdir check ( tridge ) */
/* the alternative is just to check the directory exists */
2005-12-17 20:13:45 +03:00
if ( ( ret = SMB_VFS_STAT ( conn , conn - > connectpath , & st ) ) ! = 0 | |
! S_ISDIR ( st . st_mode ) ) {
2005-10-03 22:14:09 +04:00
if ( ret = = 0 & & ! S_ISDIR ( st . st_mode ) ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 0 , ( " '%s' is not a directory, when connecting to "
" [%s] \n " , conn - > connectpath ,
lp_servicename ( snum ) ) ) ;
2005-10-03 22:14:09 +04:00
} else {
2005-12-17 20:13:45 +03:00
DEBUG ( 0 , ( " '%s' does not exist or permission denied "
" when connecting to [%s] Error was %s \n " ,
conn - > connectpath , lp_servicename ( snum ) ,
strerror ( errno ) ) ) ;
2005-10-03 22:14:09 +04:00
}
2002-07-15 14:35:28 +04:00
* status = NT_STATUS_BAD_NETWORK_NAME ;
2007-11-11 01:43:39 +03:00
goto err_root_exit ;
2002-07-15 14:35:28 +04:00
}
2007-09-13 01:48:20 +04:00
1998-08-17 17:11:34 +04:00
string_set ( & conn - > origpath , conn - > connectpath ) ;
2007-09-13 01:48:20 +04:00
1998-08-17 17:11:34 +04:00
# if SOFTLINK_OPTIMISATION
2002-07-15 14:35:28 +04:00
/* resolve any soft links early if possible */
if ( vfs_ChDir ( conn , conn - > connectpath ) = = 0 ) {
2008-01-10 04:11:04 +03:00
TALLOC_CTX * ctx = talloc_tos ( ) ;
2007-09-13 01:48:20 +04:00
char * s = vfs_GetWd ( ctx , s ) ;
if ( ! s ) {
* status = map_nt_error_from_unix ( errno ) ;
2007-11-11 01:43:39 +03:00
goto err_root_exit ;
}
if ( ! set_conn_connectpath ( conn , s ) ) {
* status = NT_STATUS_NO_MEMORY ;
goto err_root_exit ;
2007-09-13 01:48:20 +04:00
}
2000-09-27 23:09:59 +04:00
vfs_ChDir ( conn , conn - > connectpath ) ;
1998-08-17 17:11:34 +04:00
}
# endif
2007-09-13 01:48:20 +04:00
2007-12-23 01:01:25 +03:00
/* Figure out the characteristics of the underlying filesystem. This
* assumes that all the filesystem mounted withing a share path have
* the same characteristics , which is likely but not guaranteed .
*/
{
vfs_statvfs_struct svfs ;
conn - > fs_capabilities =
FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES ;
if ( SMB_VFS_STATVFS ( conn , conn - > connectpath , & svfs ) = = 0 ) {
conn - > fs_capabilities = svfs . FsCapabilities ;
}
}
1999-12-13 16:27:58 +03:00
/*
* Print out the ' connected as ' stuff here as we need
2001-09-20 11:09:28 +04:00
* to know the effective uid and gid we will be using
* ( at least initially ) .
1999-12-13 16:27:58 +03:00
*/
if ( DEBUGLVL ( IS_IPC ( conn ) ? 3 : 1 ) ) {
2005-12-17 20:13:45 +03:00
dbgtext ( " %s (%s) " , get_remote_machine_name ( ) ,
conn - > client_address ) ;
2003-08-03 11:20:05 +04:00
dbgtext ( " %s " , srv_is_signing_active ( ) ? " signed " : " " ) ;
2005-04-27 03:52:21 +04:00
dbgtext ( " connect to service %s " , lp_servicename ( snum ) ) ;
2001-09-20 11:09:28 +04:00
dbgtext ( " initially as user %s " , user ) ;
1999-12-13 16:27:58 +03:00
dbgtext ( " (uid=%d, gid=%d) " , ( int ) geteuid ( ) , ( int ) getegid ( ) ) ;
2000-05-02 06:23:41 +04:00
dbgtext ( " (pid %d) \n " , ( int ) sys_getpid ( ) ) ;
1998-08-17 17:11:34 +04:00
}
2007-09-13 01:48:20 +04:00
2001-10-19 00:15:12 +04:00
/* we've finished with the user stuff - go back to root */
change_to_root_user ( ) ;
2000-08-04 02:38:43 +04:00
return ( conn ) ;
2007-11-11 01:43:39 +03:00
err_root_exit :
change_to_root_user ( ) ;
if ( on_err_call_dis_hook ) {
/* Call VFS disconnect hook */
SMB_VFS_DISCONNECT ( conn ) ;
}
yield_connection ( conn , lp_servicename ( snum ) ) ;
conn_free ( conn ) ;
return NULL ;
1998-08-17 17:11:34 +04:00
}
2002-07-15 14:35:28 +04:00
/***************************************************************************************
Simple wrapper function for make_connection ( ) to include a call to
vfs_chdir ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-12-17 20:13:45 +03:00
connection_struct * make_connection_with_chdir ( const char * service_in ,
DATA_BLOB password ,
const char * dev , uint16 vuid ,
NTSTATUS * status )
2002-07-15 14:35:28 +04:00
{
connection_struct * conn = NULL ;
conn = make_connection ( service_in , password , dev , vuid , status ) ;
/*
* make_connection ( ) does not change the directory for us any more
* so we have to do it as a separate step - - jerry
*/
if ( conn & & vfs_ChDir ( conn , conn - > connectpath ) ! = 0 ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 0 , ( " move_driver_to_download_area: Can't change "
" directory to %s for [print$] (%s) \n " ,
2002-07-15 14:35:28 +04:00
conn - > connectpath , strerror ( errno ) ) ) ;
yield_connection ( conn , lp_servicename ( SNUM ( conn ) ) ) ;
conn_free ( conn ) ;
* status = NT_STATUS_UNSUCCESSFUL ;
return NULL ;
}
return conn ;
}
/****************************************************************************
Make a connection to a service .
*
* @ param service
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
connection_struct * make_connection ( const char * service_in , DATA_BLOB password ,
2005-12-17 20:13:45 +03:00
const char * pdev , uint16 vuid ,
NTSTATUS * status )
2002-07-15 14:35:28 +04:00
{
uid_t euid ;
user_struct * vuser = NULL ;
2003-01-15 21:57:41 +03:00
fstring service ;
2003-03-19 02:49:03 +03:00
fstring dev ;
2002-07-15 14:35:28 +04:00
int snum = - 1 ;
2007-11-04 04:15:45 +03:00
char addr [ INET6_ADDRSTRLEN ] ;
2003-04-14 07:48:26 +04:00
2003-03-19 02:49:03 +03:00
fstrcpy ( dev , pdev ) ;
2002-07-15 14:35:28 +04:00
2005-12-17 20:13:45 +03:00
/* This must ONLY BE CALLED AS ROOT. As it exits this function as
* root . */
2002-07-15 14:35:28 +04:00
if ( ! non_root_mode ( ) & & ( euid = geteuid ( ) ) ! = 0 ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 0 , ( " make_connection: PANIC ERROR. Called as nonroot "
" (%u) \n " , ( unsigned int ) euid ) ) ;
2002-07-15 14:35:28 +04:00
smb_panic ( " make_connection: PANIC ERROR. Called as nonroot \n " ) ;
}
2006-09-29 16:47:00 +04:00
if ( conn_num_open ( ) > 2047 ) {
* status = NT_STATUS_INSUFF_SERVER_RESOURCES ;
return NULL ;
}
2002-07-15 14:35:28 +04:00
if ( lp_security ( ) ! = SEC_SHARE ) {
vuser = get_valid_user_struct ( vuid ) ;
if ( ! vuser ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 1 , ( " make_connection: refusing to connect with "
" no session setup \n " ) ) ;
2002-08-17 19:27:10 +04:00
* status = NT_STATUS_ACCESS_DENIED ;
2002-07-15 14:35:28 +04:00
return NULL ;
}
}
2005-12-17 20:13:45 +03:00
/* Logic to try and connect to the correct [homes] share, preferably
without too many getpwnam ( ) lookups . This is particulary nasty for
winbind usernames , where the share name isn ' t the same as unix
username .
2002-07-15 14:35:28 +04:00
2005-12-17 20:13:45 +03:00
The snum of the homes share is stored on the vuser at session setup
time .
2002-07-15 14:35:28 +04:00
*/
if ( strequal ( service_in , HOMES_NAME ) ) {
if ( lp_security ( ) ! = SEC_SHARE ) {
2007-05-14 16:16:20 +04:00
DATA_BLOB no_pw = data_blob_null ;
2002-08-17 19:27:10 +04:00
if ( vuser - > homes_snum = = - 1 ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 2 , ( " [homes] share not available for "
" this user because it was not found "
" or created at session setup "
" time \n " ) ) ;
2002-08-17 19:27:10 +04:00
* status = NT_STATUS_BAD_NETWORK_NAME ;
return NULL ;
2002-07-15 14:35:28 +04:00
}
2005-12-17 20:13:45 +03:00
DEBUG ( 5 , ( " making a connection to [homes] service "
" created at session setup time \n " ) ) ;
2002-08-17 19:27:10 +04:00
return make_connection_snum ( vuser - > homes_snum ,
vuser , no_pw ,
dev , status ) ;
2002-07-15 14:35:28 +04:00
} else {
2005-12-17 20:13:45 +03:00
/* Security = share. Try with
* current_user_info . smb_name as the username . */
2002-07-15 14:35:28 +04:00
if ( * current_user_info . smb_name ) {
fstring unix_username ;
fstrcpy ( unix_username ,
current_user_info . smb_name ) ;
map_username ( unix_username ) ;
snum = find_service ( unix_username ) ;
}
if ( snum ! = - 1 ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 5 , ( " making a connection to 'homes' "
" service %s based on "
" security=share \n " , service_in ) ) ;
2002-07-15 14:35:28 +04:00
return make_connection_snum ( snum , NULL ,
password ,
dev , status ) ;
}
}
} else if ( ( lp_security ( ) ! = SEC_SHARE ) & & ( vuser - > homes_snum ! = - 1 )
2005-12-17 20:13:45 +03:00
& & strequal ( service_in ,
lp_servicename ( vuser - > homes_snum ) ) ) {
2007-05-14 16:16:20 +04:00
DATA_BLOB no_pw = data_blob_null ;
2005-12-17 20:13:45 +03:00
DEBUG ( 5 , ( " making a connection to 'homes' service [%s] "
" created at session setup time \n " , service_in ) ) ;
2002-07-15 14:35:28 +04:00
return make_connection_snum ( vuser - > homes_snum ,
vuser , no_pw ,
dev , status ) ;
}
2003-01-15 21:57:41 +03:00
fstrcpy ( service , service_in ) ;
2002-07-15 14:35:28 +04:00
2003-07-03 23:11:31 +04:00
strlower_m ( service ) ;
2002-07-15 14:35:28 +04:00
snum = find_service ( service ) ;
if ( snum < 0 ) {
2005-12-17 20:19:21 +03:00
if ( strequal ( service , " IPC$ " ) | |
( lp_enable_asu_support ( ) & & strequal ( service , " ADMIN$ " ) ) ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 3 , ( " refusing IPC connection to %s \n " , service ) ) ;
* status = NT_STATUS_ACCESS_DENIED ;
return NULL ;
}
DEBUG ( 0 , ( " %s (%s) couldn't find service %s \n " ,
2007-11-04 04:41:26 +03:00
get_remote_machine_name ( ) ,
2007-11-04 09:20:10 +03:00
client_addr ( get_client_fd ( ) , addr , sizeof ( addr ) ) ,
2007-11-04 04:41:26 +03:00
service ) ) ;
2002-07-15 14:35:28 +04:00
* status = NT_STATUS_BAD_NETWORK_NAME ;
return NULL ;
}
2002-12-28 02:03:22 +03:00
/* Handle non-Dfs clients attempting connections to msdfs proxy */
if ( lp_host_msdfs ( ) & & ( * lp_msdfs_proxy ( snum ) ! = ' \0 ' ) ) {
2005-12-17 20:13:45 +03:00
DEBUG ( 3 , ( " refusing connection to dfs proxy share '%s' "
" (pointing to %s) \n " ,
2004-09-21 17:04:35 +04:00
service , lp_msdfs_proxy ( snum ) ) ) ;
2002-12-28 02:03:22 +03:00
* status = NT_STATUS_BAD_NETWORK_NAME ;
return NULL ;
}
2002-07-15 14:35:28 +04:00
DEBUG ( 5 , ( " making a connection to 'normal' service %s \n " , service ) ) ;
return make_connection_snum ( snum , vuser ,
password ,
dev , status ) ;
}
1998-08-17 17:11:34 +04:00
/****************************************************************************
2005-04-27 03:52:21 +04:00
Close a cnum .
1998-08-17 17:11:34 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-04-27 03:52:21 +04:00
1998-08-17 17:11:34 +04:00
void close_cnum ( connection_struct * conn , uint16 vuid )
{
2004-07-09 04:13:55 +04:00
if ( IS_IPC ( conn ) ) {
pipe_close_conn ( conn ) ;
} else {
file_close_conn ( conn ) ;
dptr_closecnum ( conn ) ;
}
2004-05-13 04:20:50 +04:00
2001-10-19 00:15:12 +04:00
change_to_root_user ( ) ;
1998-08-17 17:11:34 +04:00
DEBUG ( IS_IPC ( conn ) ? 3 : 1 , ( " %s (%s) closed connection to service %s \n " ,
2005-12-17 20:13:45 +03:00
get_remote_machine_name ( ) ,
conn - > client_address ,
1998-08-17 17:11:34 +04:00
lp_servicename ( SNUM ( conn ) ) ) ) ;
2003-05-12 03:34:18 +04:00
/* Call VFS disconnect hook */
2003-05-14 14:59:01 +04:00
SMB_VFS_DISCONNECT ( conn ) ;
2000-02-03 08:17:25 +03:00
2002-01-14 22:34:28 +03:00
yield_connection ( conn , lp_servicename ( SNUM ( conn ) ) ) ;
1998-08-17 17:11:34 +04:00
2003-10-03 19:11:24 +04:00
/* make sure we leave the directory available for unmount */
vfs_ChDir ( conn , " / " ) ;
1998-08-17 17:11:34 +04:00
/* execute any "postexec = " line */
if ( * lp_postexec ( SNUM ( conn ) ) & &
2001-10-19 00:15:12 +04:00
change_to_user ( conn , vuid ) ) {
2007-11-11 01:43:39 +03:00
char * cmd = talloc_sub_advanced ( talloc_tos ( ) ,
lp_servicename ( SNUM ( conn ) ) , conn - > user ,
conn - > connectpath , conn - > gid ,
get_current_username ( ) ,
current_user_info . domain ,
lp_postexec ( SNUM ( conn ) ) ) ;
2001-04-13 23:12:06 +04:00
smbrun ( cmd , NULL ) ;
2007-11-11 01:43:39 +03:00
TALLOC_FREE ( cmd ) ;
2001-10-19 00:15:12 +04:00
change_to_root_user ( ) ;
1998-08-17 17:11:34 +04:00
}
2001-10-19 00:15:12 +04:00
change_to_root_user ( ) ;
1998-08-17 17:11:34 +04:00
/* execute any "root postexec = " line */
if ( * lp_rootpostexec ( SNUM ( conn ) ) ) {
2007-11-11 01:43:39 +03:00
char * cmd = talloc_sub_advanced ( talloc_tos ( ) ,
lp_servicename ( SNUM ( conn ) ) , conn - > user ,
conn - > connectpath , conn - > gid ,
get_current_username ( ) ,
current_user_info . domain ,
lp_rootpostexec ( SNUM ( conn ) ) ) ;
2001-04-13 23:12:06 +04:00
smbrun ( cmd , NULL ) ;
2007-11-11 01:43:39 +03:00
TALLOC_FREE ( cmd ) ;
1998-08-17 17:11:34 +04:00
}
2002-07-15 14:35:28 +04:00
1998-08-17 17:11:34 +04:00
conn_free ( conn ) ;
}