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"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
1998-08-17 17:11:34 +04:00
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 ;
2009-10-01 21:23:29 +04:00
if ( connectpath = = NULL | | connectpath [ 0 ] = = ' \0 ' ) {
return false ;
}
2007-11-11 01:43:39 +03:00
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
{
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 ) {
2009-07-21 15:56:17 +04:00
DEBUG ( ( ( errno ! = EACCES ) ? 0 : 3 ) , ( " chdir (%s) failed, reason: %s \n " ,
conn - > connectpath , strerror ( errno ) ) ) ;
1998-08-17 17:11:34 +04:00
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 ) ;
}
2006-11-30 10:38:40 +03:00
static int load_registry_service ( const char * servicename )
{
if ( ! lp_registry_shares ( ) ) {
return - 1 ;
}
2008-12-18 20:01:55 +03:00
if ( ( servicename = = NULL ) | | ( * servicename = = ' \0 ' ) ) {
return - 1 ;
}
2008-03-11 04:02:27 +03:00
if ( strequal ( servicename , GLOBAL_NAME ) ) {
return - 2 ;
}
2009-04-29 03:49:53 +04:00
if ( ! process_registry_service ( servicename ) ) {
2006-11-30 10:38:40 +03:00
return - 1 ;
}
2009-04-29 03:49:53 +04:00
return lp_servicenumber ( servicename ) ;
2006-11-30 10:38:40 +03:00
}
void load_registry_shares ( void )
{
2008-03-12 04:07:37 +03:00
DEBUG ( 8 , ( " load_registry_shares() \n " ) ) ;
2006-11-30 10:38:40 +03:00
if ( ! lp_registry_shares ( ) ) {
return ;
}
2009-04-29 03:49:53 +04:00
process_registry_shares ( ) ;
2006-11-30 10:38:40 +03:00
return ;
}
2001-01-24 22:34:53 +03:00
2008-01-16 18:40:59 +03:00
/****************************************************************************
Add a home service . Returns the new service number or - 1 if fail .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int add_home_service ( const char * service , const char * username , const char * homedir )
{
int iHomeService ;
2009-10-01 21:23:29 +04:00
if ( ! service | | ! homedir | | homedir [ 0 ] = = ' \0 ' )
2008-01-16 18:40:59 +03:00
return - 1 ;
if ( ( iHomeService = lp_servicenumber ( HOMES_NAME ) ) < 0 ) {
if ( ( iHomeService = load_registry_service ( 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 .
*/
{
const char * p = strchr ( service , * lp_winbind_separator ( ) ) ;
/* We only want the 'user' part of the string */
if ( p ) {
service = p + 1 ;
}
}
if ( ! lp_add_home ( service , iHomeService , username , homedir ) ) {
return - 1 ;
}
return lp_servicenumber ( service ) ;
}
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 ;
2009-05-26 18:38:45 +04:00
struct smbd_server_connection * sconn = smbd_server_conn ;
2004-03-06 01:32:45 +03:00
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 .
*/
2009-05-26 18:38:45 +04:00
if ( map_username ( sconn , 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 ;
2008-01-16 18:40:59 +03:00
if ( ( iPrinterService = lp_servicenumber ( PRINTERS_NAME ) ) < 0 ) {
iPrinterService = load_registry_service ( PRINTERS_NAME ) ;
}
if ( iPrinterService ) {
2004-03-06 01:32:45 +03:00
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
}
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 ;
2008-05-07 16:20:15 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2006-02-04 01:19:41 +03:00
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 ;
2008-05-07 16:20:15 +04:00
groupname = talloc_strdup ( talloc_tos ( ) , lp_force_group ( snum ) ) ;
2006-02-04 01:19:41 +03:00
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 ;
}
2008-05-07 16:20:15 +04:00
groupname = talloc_string_sub ( talloc_tos ( ) , groupname ,
2006-02-04 01:19:41 +03:00
" %S " , lp_servicename ( snum ) ) ;
2008-05-07 16:28:23 +04:00
if ( groupname = = NULL ) {
DEBUG ( 1 , ( " talloc_string_sub failed \n " ) ) ;
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
2006-02-04 01:19:41 +03:00
2008-05-07 16:20:15 +04:00
if ( ! lookup_name_smbconf ( talloc_tos ( ) , 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 :
2008-05-07 16:20:15 +04:00
TALLOC_FREE ( frame ) ;
2006-02-04 01:19:41 +03:00
return result ;
}
2008-05-06 19:48:22 +04:00
/****************************************************************************
Create an auth_serversupplied_info structure for a connection_struct
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-26 18:38:45 +04:00
static NTSTATUS create_connection_server_info ( struct smbd_server_connection * sconn ,
TALLOC_CTX * mem_ctx , int snum ,
2008-05-06 19:48:22 +04:00
struct auth_serversupplied_info * vuid_serverinfo ,
DATA_BLOB password ,
struct auth_serversupplied_info * * presult )
{
if ( lp_guest_only ( snum ) ) {
return make_server_info_guest ( mem_ctx , presult ) ;
}
if ( vuid_serverinfo ! = NULL ) {
struct auth_serversupplied_info * result ;
/*
* This is the normal security ! = share case where we have a
* valid vuid from the session setup . */
if ( vuid_serverinfo - > guest ) {
if ( ! lp_guest_ok ( snum ) ) {
DEBUG ( 2 , ( " guest user (from session setup) "
" not permitted to access this share "
" (%s) \n " , lp_servicename ( snum ) ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
} else {
if ( ! user_ok_token ( vuid_serverinfo - > unix_name ,
2008-05-11 03:03:45 +04:00
pdb_get_domain ( vuid_serverinfo - > sam_account ) ,
2008-05-06 19:48:22 +04:00
vuid_serverinfo - > ptok , snum ) ) {
DEBUG ( 2 , ( " user '%s' (from session setup) not "
" permitted to access this share "
" (%s) \n " ,
vuid_serverinfo - > unix_name ,
lp_servicename ( snum ) ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
}
result = copy_serverinfo ( mem_ctx , vuid_serverinfo ) ;
if ( result = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
* presult = result ;
return NT_STATUS_OK ;
}
if ( lp_security ( ) = = SEC_SHARE ) {
fstring user ;
bool guest ;
/* add the sharename as a possible user name if we
are in share mode security */
2009-05-26 18:38:45 +04:00
add_session_user ( sconn , lp_servicename ( snum ) ) ;
2008-05-06 19:48:22 +04:00
/* shall we let them in? */
2009-05-26 18:38:45 +04:00
if ( ! authorise_login ( sconn , snum , user , password , & guest ) ) {
2008-05-06 19:48:22 +04:00
DEBUG ( 2 , ( " Invalid username/password for [%s] \n " ,
lp_servicename ( snum ) ) ) ;
return NT_STATUS_WRONG_PASSWORD ;
}
return make_serverinfo_from_username ( mem_ctx , user , guest ,
presult ) ;
}
DEBUG ( 0 , ( " invalid VUID (vuser) but not in security=share \n " ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
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
2009-05-27 20:26:15 +04:00
connection_struct * make_connection_snum ( struct smbd_server_connection * sconn ,
2009-05-26 18:38:45 +04:00
int snum , user_struct * vuser ,
DATA_BLOB password ,
const char * pdev ,
NTSTATUS * pstatus )
1998-08-17 17:11:34 +04:00
{
connection_struct * conn ;
2009-06-23 02:26:56 +04:00
struct smb_filename * smb_fname_cpath = NULL ;
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 ;
2008-05-06 23:50:08 +04:00
NTSTATUS status ;
2003-03-19 02:49:03 +03:00
fstrcpy ( dev , pdev ) ;
1998-08-17 17:11:34 +04:00
2008-05-06 23:50:08 +04:00
if ( NT_STATUS_IS_ERR ( * pstatus = 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
2009-05-27 13:15:44 +04:00
conn = conn_new ( sconn ) ;
1998-08-17 17:11:34 +04:00
if ( ! conn ) {
DEBUG ( 0 , ( " Couldn't find free connection. \n " ) ) ;
2008-05-06 23:50:08 +04:00
* pstatus = 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
2009-05-26 18:38:45 +04:00
status = create_connection_server_info ( sconn ,
2008-05-07 14:20:18 +04:00
conn , snum , vuser ? vuser - > server_info : NULL , password ,
& conn - > server_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-05-04 14:36:13 +04:00
DEBUG ( 1 , ( " create_connection_server_info failed: %s \n " ,
2008-05-07 14:20:18 +04:00
nt_errstr ( status ) ) ) ;
* pstatus = status ;
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-07 14:20:18 +04:00
return NULL ;
}
2008-05-07 14:42:36 +04:00
if ( ( lp_guest_only ( snum ) ) | | ( lp_security ( ) = = SEC_SHARE ) ) {
2008-05-07 14:20:18 +04:00
conn - > force_user = true ;
1998-08-17 17:11:34 +04:00
}
2009-05-26 18:38:45 +04:00
add_session_user ( sconn , conn - > server_info - > unix_name ) ;
2002-07-15 14:35:28 +04:00
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$ " ) ) ) ;
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 ;
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
if ( * lp_force_user ( snum ) ) {
2008-05-07 16:36:15 +04:00
/*
* Replace conn - > server_info with a completely faked up one
* from the username we are forced into : - )
*/
2008-05-07 15:16:20 +04:00
char * fuser ;
struct auth_serversupplied_info * forced_serverinfo ;
fuser = talloc_string_sub ( conn , lp_force_user ( snum ) , " %S " ,
lp_servicename ( snum ) ) ;
if ( fuser = = NULL ) {
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-07 15:16:20 +04:00
* pstatus = NT_STATUS_NO_MEMORY ;
return NULL ;
}
status = make_serverinfo_from_username (
conn , fuser , conn - > server_info - > guest ,
& forced_serverinfo ) ;
2008-05-06 23:50:08 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = status ;
2002-07-15 14:35:28 +04:00
return NULL ;
1999-12-13 16:27:58 +03:00
}
2008-05-07 15:16:20 +04:00
TALLOC_FREE ( conn - > server_info ) ;
conn - > server_info = forced_serverinfo ;
2006-02-04 01:19:41 +03:00
conn - > force_user = True ;
2008-05-07 15:16:20 +04:00
DEBUG ( 3 , ( " Forced user %s \n " , fuser ) ) ;
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 .
*/
2008-05-07 16:36:15 +04:00
1998-08-17 17:11:34 +04:00
if ( * lp_force_group ( snum ) ) {
2006-02-04 01:19:41 +03:00
2008-05-07 16:36:15 +04:00
status = find_forced_group (
2008-05-08 18:06:42 +04:00
conn - > force_user , snum , conn - > server_info - > unix_name ,
2008-05-07 16:36:15 +04:00
& conn - > server_info - > ptok - > user_sids [ 1 ] ,
2008-06-19 18:54:12 +04:00
& conn - > server_info - > utok . gid ) ;
2008-05-07 16:36:15 +04:00
2008-05-06 23:50:08 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = status ;
2002-07-15 14:35:28 +04:00
return NULL ;
1998-08-17 17:11:34 +04:00
}
2009-03-04 03:08:56 +03:00
/*
* We need to cache this gid , to use within
* change_to_user ( ) separately from the conn - > server_info
* struct . We only use conn - > server_info directly if
* " force_user " was set .
*/
conn - > force_group_gid = conn - > server_info - > utok . gid ;
1998-08-17 17:11:34 +04:00
}
2006-02-04 01:19:41 +03:00
2008-05-07 16:36:15 +04:00
conn - > vuid = ( vuser ! = NULL ) ? vuser - > vuid : UID_FIELD_INVALID ;
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 ( ) ,
2008-05-08 18:06:42 +04:00
lp_servicename ( SNUM ( conn ) ) ,
conn - > server_info - > unix_name ,
2008-05-08 17:53:55 +04:00
conn - > connectpath ,
2008-06-19 18:54:12 +04:00
conn - > server_info - > utok . gid ,
2008-05-11 13:26:33 +04:00
conn - > server_info - > sanitized_username ,
pdb_get_domain ( conn - > server_info - > sam_account ) ,
2007-11-11 01:43:39 +03:00
lp_pathname ( snum ) ) ;
if ( ! s ) {
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = NT_STATUS_NO_MEMORY ;
2007-11-11 01:43:39 +03:00
return NULL ;
}
if ( ! set_conn_connectpath ( conn , s ) ) {
TALLOC_FREE ( s ) ;
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = NT_STATUS_NO_MEMORY ;
2007-11-11 01:43:39 +03:00
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 ;
2007-03-24 00:50:44 +03:00
2008-05-08 17:09:02 +04:00
can_write = share_access_check ( conn - > server_info - > ptok ,
lp_servicename ( snum ) ,
FILE_WRITE_DATA ) ;
2001-04-12 01:19:25 +04:00
if ( ! can_write ) {
2008-05-08 17:09:02 +04:00
if ( ! share_access_check ( conn - > server_info - > ptok ,
2006-07-17 23:50:59 +04:00
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 ) ) ) ;
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = 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 ) ) ) ;
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = 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 ) ) ;
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = NT_STATUS_BAD_NETWORK_NAME ;
2007-11-11 01:43:39 +03:00
return NULL ;
}
2004-05-28 05:54:01 +04:00
}
2007-01-31 17:42:56 +03:00
if ( ( ! conn - > printer ) & & ( ! conn - > ipc ) ) {
2008-04-28 12:31:49 +04:00
conn - > notify_ctx = notify_init ( conn , server_id_self ( ) ,
2007-01-31 17:42:56 +03:00
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 ) ) ) ;
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = 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 " ) ) ;
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = NT_STATUS_INTERNAL_DB_ERROR ;
2007-05-27 20:34:49 +04:00
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 ( ) ,
2008-05-08 18:06:42 +04:00
lp_servicename ( SNUM ( conn ) ) ,
conn - > server_info - > unix_name ,
2008-05-08 17:53:55 +04:00
conn - > connectpath ,
2008-06-19 18:54:12 +04:00
conn - > server_info - > utok . gid ,
2008-05-11 13:26:33 +04:00
conn - > server_info - > sanitized_username ,
pdb_get_domain ( conn - > server_info - > sam_account ) ,
2007-11-11 01:43:39 +03:00
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 ) ) ;
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = 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 ) ) ;
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2008-05-06 23:50:08 +04:00
* pstatus = NT_STATUS_LOGON_FAILURE ;
2001-10-19 00:15:12 +04:00
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 ( ) ,
2008-05-08 18:06:42 +04:00
lp_servicename ( SNUM ( conn ) ) ,
conn - > server_info - > unix_name ,
2008-05-08 17:53:55 +04:00
conn - > connectpath ,
2008-06-19 18:54:12 +04:00
conn - > server_info - > utok . gid ,
2008-05-11 13:26:33 +04:00
conn - > server_info - > sanitized_username ,
pdb_get_domain ( conn - > server_info - > sam_account ) ,
2007-11-11 01:43:39 +03:00
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 ) ) ;
2008-05-06 23:50:08 +04:00
* pstatus = 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 ) ) ;
2008-05-27 08:13:05 +04:00
set_namearray ( & conn - > aio_write_behind_list ,
lp_aio_write_behind ( snum ) ) ;
2005-06-27 21:14:15 +04:00
}
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
2008-05-08 18:06:42 +04:00
if ( SMB_VFS_CONNECT ( conn , lp_servicename ( snum ) ,
conn - > server_info - > unix_name ) < 0 ) {
2005-06-27 21:14:15 +04:00
DEBUG ( 0 , ( " make_connection: VFS make connection failed! \n " ) ) ;
2008-05-06 23:50:08 +04:00
* pstatus = 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 ;
2009-06-23 02:26:56 +04:00
status = create_synthetic_smb_fname ( talloc_tos ( ) , conn - > connectpath ,
NULL , NULL , & smb_fname_cpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
* pstatus = status ;
goto err_root_exit ;
}
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 */
2009-06-23 02:26:56 +04:00
if ( ( ret = SMB_VFS_STAT ( conn , smb_fname_cpath ) ) ! = 0 | |
! S_ISDIR ( smb_fname_cpath - > st . st_ex_mode ) ) {
if ( ret = = 0 & & ! S_ISDIR ( smb_fname_cpath - > st . st_ex_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
}
2008-05-06 23:50:08 +04:00
* pstatus = 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 .
*/
2009-08-25 07:57:37 +04:00
conn - > fs_capabilities = SMB_VFS_FS_CAPABILITIES ( conn , & conn - > ts_res ) ;
2007-12-23 01:01:25 +03:00
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 ) ;
2009-03-09 11:47:59 +03:00
dbgtext ( " %s " , srv_is_signing_active ( smbd_server_conn ) ? " signed " : " " ) ;
2005-04-27 03:52:21 +04:00
dbgtext ( " connect to service %s " , lp_servicename ( snum ) ) ;
2008-05-08 18:06:42 +04:00
dbgtext ( " initially as user %s " ,
conn - > server_info - > unix_name ) ;
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 :
2009-06-23 02:26:56 +04:00
TALLOC_FREE ( smb_fname_cpath ) ;
2007-11-11 01:43:39 +03:00
change_to_root_user ( ) ;
if ( on_err_call_dis_hook ) {
/* Call VFS disconnect hook */
SMB_VFS_DISCONNECT ( conn ) ;
}
yield_connection ( conn , lp_servicename ( snum ) ) ;
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
2007-11-11 01:43:39 +03:00
return NULL ;
1998-08-17 17:11:34 +04:00
}
2002-07-15 14:35:28 +04:00
/****************************************************************************
Make a connection to a service .
*
* @ param service
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-26 18:38:45 +04:00
connection_struct * make_connection ( struct smbd_server_connection * sconn ,
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 " ) ;
}
2009-05-27 13:15:44 +04:00
if ( conn_num_open ( sconn ) > 2047 ) {
2006-09-29 16:47:00 +04:00
* status = NT_STATUS_INSUFF_SERVER_RESOURCES ;
return NULL ;
}
2002-07-15 14:35:28 +04:00
if ( lp_security ( ) ! = SEC_SHARE ) {
2009-05-26 18:38:45 +04:00
vuser = get_valid_user_struct ( sconn , vuid ) ;
2002-07-15 14:35:28 +04:00
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 " ) ) ;
2009-05-26 18:38:45 +04:00
return make_connection_snum ( sconn ,
vuser - > homes_snum ,
2002-08-17 19:27:10 +04:00
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 ) ;
2009-05-26 18:38:45 +04:00
map_username ( sconn , unix_username ) ;
2002-07-15 14:35:28 +04:00
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 ) ) ;
2009-05-26 18:38:45 +04:00
return make_connection_snum ( sconn ,
snum , NULL ,
2002-07-15 14:35:28 +04:00
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 ) ) ;
2009-05-26 18:38:45 +04:00
return make_connection_snum ( sconn ,
vuser - > homes_snum ,
2002-07-15 14:35:28 +04:00
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 ;
}
2009-12-02 22:06:37 +03:00
DEBUG ( 3 , ( " %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 ) ) ;
2009-05-26 18:38:45 +04:00
return make_connection_snum ( sconn , snum , vuser ,
2002-07-15 14:35:28 +04:00
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
2009-08-06 15:22:33 +04:00
void close_cnum ( connection_struct * conn , uint16 vuid )
1998-08-17 17:11:34 +04:00
{
2008-10-13 01:09:18 +04:00
file_close_conn ( conn ) ;
if ( ! IS_IPC ( conn ) ) {
2004-07-09 04:13:55 +04:00
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 ( ) ,
2008-05-08 18:06:42 +04:00
lp_servicename ( SNUM ( conn ) ) ,
conn - > server_info - > unix_name ,
2008-05-08 17:53:55 +04:00
conn - > connectpath ,
2008-06-19 18:54:12 +04:00
conn - > server_info - > utok . gid ,
2008-05-11 13:26:33 +04:00
conn - > server_info - > sanitized_username ,
pdb_get_domain ( conn - > server_info - > sam_account ) ,
2007-11-11 01:43:39 +03:00
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 ( ) ,
2008-05-08 18:06:42 +04:00
lp_servicename ( SNUM ( conn ) ) ,
conn - > server_info - > unix_name ,
2008-05-08 17:53:55 +04:00
conn - > connectpath ,
2008-06-19 18:54:12 +04:00
conn - > server_info - > utok . gid ,
2008-05-11 13:26:33 +04:00
conn - > server_info - > sanitized_username ,
pdb_get_domain ( conn - > server_info - > sam_account ) ,
2007-11-11 01:43:39 +03:00
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
2009-08-06 15:22:33 +04:00
conn_free ( conn ) ;
1998-08-17 17:11:34 +04:00
}