1996-05-04 11:50:46 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
Main SMB server routines
1997-05-08 05:14:17 +04:00
Copyright ( C ) Andrew Tridgell 1992 - 1997
1996-05-04 11:50:46 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include "trans2.h"
pstring servicesf = CONFIGFILE ;
extern pstring debugf ;
extern pstring sesssetup_user ;
1997-05-20 04:32:51 +04:00
extern fstring myworkgroup ;
1996-05-04 11:50:46 +04:00
char * InBuffer = NULL ;
char * OutBuffer = NULL ;
char * last_inbuf = NULL ;
1996-12-10 21:00:22 +03:00
int am_parent = 1 ;
int atexit_set = 0 ;
1996-05-04 11:50:46 +04:00
/* the last message the was processed */
int last_message = - 1 ;
/* a useful macro to debug the last message processed */
# define LAST_MESSAGE() smb_fn_name(last_message)
extern pstring scope ;
extern int DEBUGLEVEL ;
extern int case_default ;
extern BOOL case_sensitive ;
extern BOOL case_preserve ;
extern BOOL use_mangled_map ;
extern BOOL short_case_preserve ;
extern BOOL case_mangle ;
1997-10-27 16:38:07 +03:00
time_t smb_last_time = ( time_t ) 0 ;
1996-05-04 11:50:46 +04:00
1996-07-30 19:47:30 +04:00
extern int smb_read_error ;
1996-05-04 11:50:46 +04:00
extern pstring user_socket_options ;
connection_struct Connections [ MAX_CONNECTIONS ] ;
files_struct Files [ MAX_OPEN_FILES ] ;
1997-01-09 21:02:17 +03:00
/*
* Indirection for file fd ' s . Needed as POSIX locking
* is based on file / process , not fd / process .
*/
file_fd_struct FileFd [ MAX_OPEN_FILES ] ;
int max_file_fd_used = 0 ;
1996-05-04 11:50:46 +04:00
extern int Protocol ;
1997-02-28 23:39:36 +03:00
/*
* Size of data we can send to client . Set
* by the client for all protocols above CORE .
* Set by us for CORE protocol .
*/
int max_send = BUFFER_SIZE ;
/*
* Size of the data we can receive . Set by us .
* Can be modified by the max xmit parameter .
*/
int max_recv = BUFFER_SIZE ;
1996-05-04 11:50:46 +04:00
/* a fnum to use when chaining */
int chain_fnum = - 1 ;
/* number of open connections */
static int num_connections_open = 0 ;
1997-09-23 23:19:06 +04:00
/* Oplock ipc UDP socket. */
int oplock_sock = - 1 ;
1997-09-25 04:25:44 +04:00
uint16 oplock_port = 0 ;
1997-09-26 23:26:56 +04:00
/* Current number of oplocks we have outstanding. */
1997-10-02 07:26:07 +04:00
int32 global_oplocks_open = 0 ;
1997-09-23 23:19:06 +04:00
1997-09-30 06:38:19 +04:00
BOOL global_oplock_break = False ;
1996-05-04 11:50:46 +04:00
extern fstring remote_machine ;
1997-10-25 14:58:18 +04:00
extern pstring OriginalDir ;
1996-05-04 11:50:46 +04:00
/* these can be set by some functions to override the error codes */
int unix_ERR_class = SUCCESS ;
int unix_ERR_code = 0 ;
extern int extra_time_offset ;
extern pstring myhostname ;
static int find_free_connection ( int hash ) ;
/* for readability... */
# define IS_DOS_READONLY(test_mode) (((test_mode) & aRONLY) != 0)
# define IS_DOS_DIR(test_mode) (((test_mode) & aDIR) != 0)
# define IS_DOS_ARCHIVE(test_mode) (((test_mode) & aARCH) != 0)
# define IS_DOS_SYSTEM(test_mode) (((test_mode) & aSYSTEM) != 0)
# define IS_DOS_HIDDEN(test_mode) (((test_mode) & aHIDDEN) != 0)
1996-12-10 21:00:22 +03:00
/****************************************************************************
when exiting , take the whole family
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void * dflt_sig ( void )
{
exit_server ( " caught signal " ) ;
1997-05-20 04:32:51 +04:00
return 0 ; /* Keep -Wall happy :-) */
1996-12-10 21:00:22 +03:00
}
/****************************************************************************
Send a SIGTERM to our process group .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void killkids ( void )
{
if ( am_parent ) kill ( 0 , SIGTERM ) ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
change a dos mode to a unix mode
base permission for files :
everybody gets read bit set
dos readonly is represented in unix by removing everyone ' s write bit
dos archive is represented in unix by the user ' s execute bit
dos system is represented in unix by the group ' s execute bit
dos hidden is represented in unix by the other ' s execute bit
1997-06-19 04:18:23 +04:00
Then apply create mask ,
then add force bits .
1996-05-04 11:50:46 +04:00
base permission for directories :
dos directory is represented in unix by unix ' s dir bit and the exec bit
1997-06-19 04:18:23 +04:00
Then apply create mask ,
then add force bits .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
mode_t unix_mode ( int cnum , int dosmode )
{
mode_t result = ( S_IRUSR | S_IRGRP | S_IROTH ) ;
if ( ! IS_DOS_READONLY ( dosmode ) )
result | = ( S_IWUSR | S_IWGRP | S_IWOTH ) ;
1997-02-23 08:18:09 +03:00
if ( IS_DOS_DIR ( dosmode ) ) {
1997-06-17 00:49:15 +04:00
/* We never make directories read only for the owner as under DOS a user
can always create a file in a read - only directory . */
1996-05-04 11:50:46 +04:00
result | = ( S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR ) ;
1997-06-19 04:18:23 +04:00
/* Apply directory mask */
1997-06-17 00:49:15 +04:00
result & = lp_dir_mode ( SNUM ( cnum ) ) ;
1997-06-19 04:18:23 +04:00
/* Add in force bits */
result | = lp_force_dir_mode ( SNUM ( cnum ) ) ;
1997-02-23 08:18:09 +03:00
} else {
if ( MAP_ARCHIVE ( cnum ) & & IS_DOS_ARCHIVE ( dosmode ) )
result | = S_IXUSR ;
1996-05-04 11:50:46 +04:00
1997-02-23 08:18:09 +03:00
if ( MAP_SYSTEM ( cnum ) & & IS_DOS_SYSTEM ( dosmode ) )
result | = S_IXGRP ;
1996-05-04 11:50:46 +04:00
1997-02-23 08:18:09 +03:00
if ( MAP_HIDDEN ( cnum ) & & IS_DOS_HIDDEN ( dosmode ) )
result | = S_IXOTH ;
1996-05-04 11:50:46 +04:00
1997-06-19 04:18:23 +04:00
/* Apply mode mask */
result & = lp_create_mode ( SNUM ( cnum ) ) ;
/* Add in force bits */
result | = lp_force_create_mode ( SNUM ( cnum ) ) ;
1997-02-23 08:18:09 +03:00
}
1996-05-04 11:50:46 +04:00
return ( result ) ;
}
/****************************************************************************
change a unix mode to a dos mode
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int dos_mode ( int cnum , char * path , struct stat * sbuf )
{
int result = 0 ;
1996-06-04 10:42:03 +04:00
extern struct current_user current_user ;
1996-05-04 11:50:46 +04:00
1997-10-02 06:36:11 +04:00
DEBUG ( 8 , ( " dos_mode: %d %s \n " , cnum , path ) ) ;
1997-07-06 17:48:10 +04:00
1996-05-04 11:50:46 +04:00
if ( CAN_WRITE ( cnum ) & & ! lp_alternate_permissions ( SNUM ( cnum ) ) ) {
if ( ! ( ( sbuf - > st_mode & S_IWOTH ) | |
Connections [ cnum ] . admin_user | |
1996-06-04 10:42:03 +04:00
( ( sbuf - > st_mode & S_IWUSR ) & & current_user . uid = = sbuf - > st_uid ) | |
1996-05-04 11:50:46 +04:00
( ( sbuf - > st_mode & S_IWGRP ) & &
1996-06-04 10:42:03 +04:00
in_group ( sbuf - > st_gid , current_user . gid ,
current_user . ngroups , current_user . igroups ) ) ) )
1996-05-04 11:50:46 +04:00
result | = aRONLY ;
} else {
if ( ( sbuf - > st_mode & S_IWUSR ) = = 0 )
result | = aRONLY ;
}
1997-07-25 02:42:16 +04:00
if ( MAP_ARCHIVE ( cnum ) & & ( ( sbuf - > st_mode & S_IXUSR ) ! = 0 ) )
1996-05-04 11:50:46 +04:00
result | = aARCH ;
if ( MAP_SYSTEM ( cnum ) & & ( ( sbuf - > st_mode & S_IXGRP ) ! = 0 ) )
result | = aSYSTEM ;
if ( MAP_HIDDEN ( cnum ) & & ( ( sbuf - > st_mode & S_IXOTH ) ! = 0 ) )
result | = aHIDDEN ;
if ( S_ISDIR ( sbuf - > st_mode ) )
result = aDIR | ( result & aRONLY ) ;
1997-10-09 10:36:04 +04:00
# ifdef S_ISLNK
1996-05-04 11:50:46 +04:00
# if LINKS_READ_ONLY
if ( S_ISLNK ( sbuf - > st_mode ) & & S_ISDIR ( sbuf - > st_mode ) )
result | = aRONLY ;
1997-10-09 10:36:04 +04:00
# endif
1996-05-04 11:50:46 +04:00
# endif
/* hide files with a name starting with a . */
if ( lp_hide_dot_files ( SNUM ( cnum ) ) )
{
char * p = strrchr ( path , ' / ' ) ;
if ( p )
p + + ;
else
p = path ;
if ( p [ 0 ] = = ' . ' & & p [ 1 ] ! = ' . ' & & p [ 1 ] ! = 0 )
result | = aHIDDEN ;
}
1997-07-08 20:54:44 +04:00
/* Optimization : Only call is_hidden_path if it's not already
hidden . */
1997-07-24 21:25:11 +04:00
if ( ! ( result & aHIDDEN ) & & IS_HIDDEN_PATH ( cnum , path ) )
1997-07-06 17:48:10 +04:00
{
result | = aHIDDEN ;
}
1997-10-02 06:36:11 +04:00
DEBUG ( 8 , ( " dos_mode returning " ) ) ;
1997-07-06 17:48:10 +04:00
1997-10-02 06:36:11 +04:00
if ( result & aHIDDEN ) DEBUG ( 8 , ( " h " ) ) ;
if ( result & aRONLY ) DEBUG ( 8 , ( " r " ) ) ;
if ( result & aSYSTEM ) DEBUG ( 8 , ( " s " ) ) ;
if ( result & aDIR ) DEBUG ( 8 , ( " d " ) ) ;
if ( result & aARCH ) DEBUG ( 8 , ( " a " ) ) ;
1997-07-06 17:48:10 +04:00
1997-10-02 06:36:11 +04:00
DEBUG ( 8 , ( " \n " ) ) ;
1997-07-06 17:48:10 +04:00
1996-05-04 11:50:46 +04:00
return ( result ) ;
}
/*******************************************************************
chmod a file - but preserve some bits
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int dos_chmod ( int cnum , char * fname , int dosmode , struct stat * st )
{
struct stat st1 ;
int mask = 0 ;
int tmp ;
int unixmode ;
if ( ! st ) {
st = & st1 ;
if ( sys_stat ( fname , st ) ) return ( - 1 ) ;
}
if ( S_ISDIR ( st - > st_mode ) ) dosmode | = aDIR ;
if ( dos_mode ( cnum , fname , st ) = = dosmode ) return ( 0 ) ;
unixmode = unix_mode ( cnum , dosmode ) ;
/* preserve the s bits */
mask | = ( S_ISUID | S_ISGID ) ;
/* preserve the t bit */
# ifdef S_ISVTX
mask | = S_ISVTX ;
# endif
/* possibly preserve the x bits */
if ( ! MAP_ARCHIVE ( cnum ) ) mask | = S_IXUSR ;
if ( ! MAP_SYSTEM ( cnum ) ) mask | = S_IXGRP ;
if ( ! MAP_HIDDEN ( cnum ) ) mask | = S_IXOTH ;
unixmode | = ( st - > st_mode & mask ) ;
/* if we previously had any r bits set then leave them alone */
if ( ( tmp = st - > st_mode & ( S_IRUSR | S_IRGRP | S_IROTH ) ) ) {
unixmode & = ~ ( S_IRUSR | S_IRGRP | S_IROTH ) ;
unixmode | = tmp ;
}
/* if we previously had any w bits set then leave them alone
if the new mode is not rdonly */
if ( ! IS_DOS_READONLY ( dosmode ) & &
( tmp = st - > st_mode & ( S_IWUSR | S_IWGRP | S_IWOTH ) ) ) {
unixmode & = ~ ( S_IWUSR | S_IWGRP | S_IWOTH ) ;
unixmode | = tmp ;
}
1996-05-04 14:48:19 +04:00
1996-08-13 12:57:55 +04:00
return ( sys_chmod ( fname , unixmode ) ) ;
1996-05-04 11:50:46 +04:00
}
1997-10-20 22:52:04 +04:00
/*******************************************************************
Wrapper around sys_utime that possibly allows DOS semantics rather
than POSIX .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int file_utime ( int cnum , char * fname , struct utimbuf * times )
{
extern struct current_user current_user ;
struct stat sb ;
int ret = - 1 ;
1997-10-21 17:03:46 +04:00
errno = 0 ;
1997-10-20 22:52:04 +04:00
if ( sys_utime ( fname , times ) = = 0 )
return 0 ;
1997-10-21 17:15:20 +04:00
if ( ( errno ! = EPERM ) & & ( errno ! = EACCES ) )
1997-10-21 17:03:46 +04:00
return - 1 ;
if ( ! lp_dos_filetimes ( SNUM ( cnum ) ) )
1997-10-20 22:52:04 +04:00
return - 1 ;
/* We have permission (given by the Samba admin) to
break POSIX semantics and allow a user to change
the time on a file they don ' t own but can write to
( as DOS does ) .
*/
if ( sys_stat ( fname , & sb ) ! = 0 )
return - 1 ;
/* Check if we have write access. */
1997-10-21 16:55:49 +04:00
if ( CAN_WRITE ( cnum ) ) {
if ( ( ( sb . st_mode & S_IWOTH ) | |
Connections [ cnum ] . admin_user | |
( ( sb . st_mode & S_IWUSR ) & & current_user . uid = = sb . st_uid ) | |
( ( sb . st_mode & S_IWGRP ) & &
in_group ( sb . st_gid , current_user . gid ,
current_user . ngroups , current_user . igroups ) ) ) ) {
/* We are allowed to become root and change the filetime. */
become_root ( False ) ;
ret = sys_utime ( fname , times ) ;
unbecome_root ( False ) ;
}
1997-10-20 22:52:04 +04:00
}
return ret ;
}
/*******************************************************************
Change a filetime - possibly allowing DOS semantics .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL set_filetime ( int cnum , char * fname , time_t mtime )
{
struct utimbuf times ;
if ( null_mtime ( mtime ) ) return ( True ) ;
times . modtime = times . actime = mtime ;
if ( file_utime ( cnum , fname , & times ) ) {
DEBUG ( 4 , ( " set_filetime(%s) failed: %s \n " , fname , strerror ( errno ) ) ) ;
}
return ( True ) ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
check if two filenames are equal
this needs to be careful about whether we are case sensitive
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL fname_equal ( char * name1 , char * name2 )
{
int l1 = strlen ( name1 ) ;
int l2 = strlen ( name2 ) ;
/* handle filenames ending in a single dot */
if ( l1 - l2 = = 1 & & name1 [ l1 - 1 ] = = ' . ' & & lp_strip_dot ( ) )
{
BOOL ret ;
name1 [ l1 - 1 ] = 0 ;
ret = fname_equal ( name1 , name2 ) ;
name1 [ l1 - 1 ] = ' . ' ;
return ( ret ) ;
}
if ( l2 - l1 = = 1 & & name2 [ l2 - 1 ] = = ' . ' & & lp_strip_dot ( ) )
{
BOOL ret ;
name2 [ l2 - 1 ] = 0 ;
ret = fname_equal ( name1 , name2 ) ;
name2 [ l2 - 1 ] = ' . ' ;
return ( ret ) ;
}
/* now normal filename handling */
if ( case_sensitive )
return ( strcmp ( name1 , name2 ) = = 0 ) ;
return ( strequal ( name1 , name2 ) ) ;
}
/****************************************************************************
mangle the 2 nd name and check if it is then equal to the first name
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL mangled_equal ( char * name1 , char * name2 )
{
pstring tmpname ;
1997-02-12 01:53:29 +03:00
if ( is_8_3 ( name2 , True ) )
1996-05-04 11:50:46 +04:00
return ( False ) ;
strcpy ( tmpname , name2 ) ;
mangle_name_83 ( tmpname ) ;
return ( strequal ( name1 , tmpname ) ) ;
}
/****************************************************************************
scan a directory to find a filename , matching without case sensitivity
If the name looks like a mangled name then try via the mangling functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-07-24 21:25:11 +04:00
static BOOL scan_directory ( char * path , char * name , int cnum , BOOL docache )
1996-05-04 11:50:46 +04:00
{
void * cur_dir ;
char * dname ;
BOOL mangled ;
1996-05-05 15:26:58 +04:00
pstring name2 ;
1996-05-04 11:50:46 +04:00
mangled = is_mangled ( name ) ;
/* handle null paths */
if ( * path = = 0 )
path = " . " ;
1997-07-24 21:25:11 +04:00
if ( docache & & ( dname = DirCacheCheck ( path , name , SNUM ( cnum ) ) ) ) {
1996-05-04 11:50:46 +04:00
strcpy ( name , dname ) ;
return ( True ) ;
}
if ( mangled )
check_mangled_stack ( name ) ;
/* open the directory */
1997-07-24 21:25:11 +04:00
if ( ! ( cur_dir = OpenDir ( cnum , path , True ) ) )
1996-05-04 11:50:46 +04:00
{
DEBUG ( 3 , ( " scan dir didn't open dir [%s] \n " , path ) ) ;
return ( False ) ;
}
/* now scan for matching names */
while ( ( dname = ReadDirName ( cur_dir ) ) )
{
if ( * dname = = ' . ' & &
( strequal ( dname , " . " ) | | strequal ( dname , " .. " ) ) )
continue ;
1997-09-26 22:55:29 +04:00
pstrcpy ( name2 , dname ) ;
1997-07-24 21:25:11 +04:00
if ( ! name_map_mangle ( name2 , False , SNUM ( cnum ) ) ) continue ;
1996-05-04 11:50:46 +04:00
if ( ( mangled & & mangled_equal ( name , name2 ) )
1997-08-28 22:59:52 +04:00
| | fname_equal ( name , name2 ) ) /* name2 here was changed to dname - since 1.9.16p2 - not sure of reason (jra) */
1996-05-04 11:50:46 +04:00
{
/* we've found the file, change it's name and return */
1997-07-24 21:25:11 +04:00
if ( docache ) DirCacheAdd ( path , name , dname , SNUM ( cnum ) ) ;
1996-05-04 11:50:46 +04:00
strcpy ( name , dname ) ;
CloseDir ( cur_dir ) ;
return ( True ) ;
}
}
CloseDir ( cur_dir ) ;
return ( False ) ;
}
/****************************************************************************
This routine is called to convert names from the dos namespace to unix
namespace . It needs to handle any case conversions , mangling , format
changes etc .
We assume that we have already done a chdir ( ) to the right " root " directory
for this service .
The function will return False if some part of the name except for the last
part cannot be resolved
1997-01-13 22:41:08 +03:00
If the saved_last_component ! = 0 , then the unmodified last component
of the pathname is returned there . This is used in an exceptional
case in reply_mv ( so far ) . If saved_last_component = = 0 then nothing
is returned there .
1997-08-21 00:32:23 +04:00
The bad_path arg is set to True if the filename walk failed . This is
used to pick the correct error code to return between ENOENT and ENOTDIR
as Windows applications depend on ERRbadpath being returned if a component
of a pathname does not exist .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-08-21 00:32:23 +04:00
BOOL unix_convert ( char * name , int cnum , pstring saved_last_component , BOOL * bad_path )
1996-05-04 11:50:46 +04:00
{
struct stat st ;
char * start , * end ;
pstring dirpath ;
1997-08-21 00:32:23 +04:00
int saved_errno ;
1996-05-04 11:50:46 +04:00
* dirpath = 0 ;
1997-08-21 00:32:23 +04:00
* bad_path = False ;
1997-01-13 22:41:08 +03:00
if ( saved_last_component )
* saved_last_component = 0 ;
1996-05-04 11:50:46 +04:00
/* convert to basic unix format - removing \ chars and cleaning it up */
unix_format ( name ) ;
unix_clean_name ( name ) ;
/* names must be relative to the root of the service - trim any leading /.
also trim trailing / ' s */
trim_string ( name , " / " , " / " ) ;
1997-02-12 01:53:29 +03:00
/*
* Ensure saved_last_component is valid even if file exists .
*/
if ( saved_last_component ) {
end = strrchr ( name , ' / ' ) ;
if ( end )
strcpy ( saved_last_component , end + 1 ) ;
else
strcpy ( saved_last_component , name ) ;
}
if ( ! case_sensitive & &
( ! case_preserve | | ( is_8_3 ( name , False ) & & ! short_case_preserve ) ) )
strnorm ( name ) ;
1996-05-04 11:50:46 +04:00
/* check if it's a printer file */
if ( Connections [ cnum ] . printer )
{
1997-02-12 01:53:29 +03:00
if ( ( ! * name ) | | strchr ( name , ' / ' ) | | ! is_8_3 ( name , True ) )
1996-05-04 11:50:46 +04:00
{
1996-05-04 14:48:19 +04:00
char * s ;
1996-05-04 11:50:46 +04:00
fstring name2 ;
sprintf ( name2 , " %.6s.XXXXXX " , remote_machine ) ;
1996-05-04 14:48:19 +04:00
/* sanitise the name */
for ( s = name2 ; * s ; s + + )
if ( ! issafe ( * s ) ) * s = ' _ ' ;
1996-05-04 11:50:46 +04:00
strcpy ( name , ( char * ) mktemp ( name2 ) ) ;
}
return ( True ) ;
}
/* stat the name - if it exists then we are all done! */
if ( sys_stat ( name , & st ) = = 0 )
return ( True ) ;
1997-08-21 00:32:23 +04:00
saved_errno = errno ;
1996-05-04 11:50:46 +04:00
DEBUG ( 5 , ( " unix_convert(%s,%d) \n " , name , cnum ) ) ;
/* a special case - if we don't have any mangling chars and are case
sensitive then searching won ' t help */
if ( case_sensitive & & ! is_mangled ( name ) & &
1997-08-21 00:32:23 +04:00
! lp_strip_dot ( ) & & ! use_mangled_map & & ( saved_errno ! = ENOENT ) )
1996-05-04 11:50:46 +04:00
return ( False ) ;
/* now we need to recursively match the name against the real
directory structure */
start = name ;
while ( strncmp ( start , " ./ " , 2 ) = = 0 )
start + = 2 ;
/* now match each part of the path name separately, trying the names
as is first , then trying to scan the directory for matching names */
for ( ; start ; start = ( end ? end + 1 : ( char * ) NULL ) )
{
/* pinpoint the end of this section of the filename */
end = strchr ( start , ' / ' ) ;
/* chop the name at this point */
1997-01-13 22:41:08 +03:00
if ( end ) * end = 0 ;
if ( saved_last_component ! = 0 )
1997-08-21 00:32:23 +04:00
strcpy ( saved_last_component , end ? end + 1 : start ) ;
1996-05-04 11:50:46 +04:00
/* check if the name exists up to this point */
if ( sys_stat ( name , & st ) = = 0 )
{
/* it exists. it must either be a directory or this must be
the last part of the path for it to be OK */
if ( end & & ! ( st . st_mode & S_IFDIR ) )
{
/* an intermediate part of the name isn't a directory */
DEBUG ( 5 , ( " Not a dir %s \n " , start ) ) ;
* end = ' / ' ;
return ( False ) ;
}
}
else
{
pstring rest ;
* rest = 0 ;
/* remember the rest of the pathname so it can be restored
later */
1997-09-26 22:55:29 +04:00
if ( end ) pstrcpy ( rest , end + 1 ) ;
1996-05-04 11:50:46 +04:00
/* try to find this part of the path in the directory */
if ( strchr ( start , ' ? ' ) | | strchr ( start , ' * ' ) | |
1997-07-24 21:25:11 +04:00
! scan_directory ( dirpath , start , cnum , end ? True : False ) )
1996-05-04 11:50:46 +04:00
{
if ( end )
{
/* an intermediate part of the name can't be found */
DEBUG ( 5 , ( " Intermediate not found %s \n " , start ) ) ;
* end = ' / ' ;
1997-08-21 00:32:23 +04:00
/* We need to return the fact that the intermediate
name resolution failed . This is used to return an
error of ERRbadpath rather than ERRbadfile . Some
Windows applications depend on the difference between
these two errors .
*/
* bad_path = True ;
1996-05-04 11:50:46 +04:00
return ( False ) ;
}
/* just the last part of the name doesn't exist */
/* we may need to strupper() or strlower() it in case
this conversion is being used for file creation
purposes */
/* if the filename is of mixed case then don't normalise it */
if ( ! case_preserve & &
( ! strhasupper ( start ) | | ! strhaslower ( start ) ) )
strnorm ( start ) ;
/* check on the mangled stack to see if we can recover the
base of the filename */
if ( is_mangled ( start ) )
check_mangled_stack ( start ) ;
DEBUG ( 5 , ( " New file %s \n " , start ) ) ;
return ( True ) ;
}
/* restore the rest of the string */
if ( end )
{
strcpy ( start + strlen ( start ) + 1 , rest ) ;
end = start + strlen ( start ) ;
}
}
/* add to the dirpath that we have resolved so far */
if ( * dirpath ) strcat ( dirpath , " / " ) ;
strcat ( dirpath , start ) ;
/* restore the / that we wiped out earlier */
if ( end ) * end = ' / ' ;
}
/* the name has been resolved */
DEBUG ( 5 , ( " conversion finished %s \n " , name ) ) ;
return ( True ) ;
}
/****************************************************************************
normalise for DOS usage
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void disk_norm ( int * bsize , int * dfree , int * dsize )
{
/* check if the disk is beyond the max disk size */
int maxdisksize = lp_maxdisksize ( ) ;
if ( maxdisksize ) {
/* convert to blocks - and don't overflow */
maxdisksize = ( ( maxdisksize * 1024 ) / ( * bsize ) ) * 1024 ;
if ( * dsize > maxdisksize ) * dsize = maxdisksize ;
if ( * dfree > maxdisksize ) * dfree = maxdisksize - 1 ; /* the -1 should stop
applications getting
div by 0 errors */
}
while ( * dfree > WORDMAX | | * dsize > WORDMAX | | * bsize < 512 )
{
* dfree / = 2 ;
* dsize / = 2 ;
* bsize * = 2 ;
if ( * bsize > WORDMAX )
{
* bsize = WORDMAX ;
if ( * dsize > WORDMAX )
* dsize = WORDMAX ;
if ( * dfree > WORDMAX )
* dfree = WORDMAX ;
break ;
}
}
}
/****************************************************************************
return number of 1 K blocks available on a path and total number
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int disk_free ( char * path , int * bsize , int * dfree , int * dsize )
{
char * df_command = lp_dfree_command ( ) ;
1997-07-01 05:19:13 +04:00
int dfree_retval ;
# ifdef QUOTAS
int dfreeq_retval ;
int dfreeq = 0 ;
int bsizeq = * bsize ;
int dsizeq = * dsize ;
# endif
1996-05-04 11:50:46 +04:00
# ifndef NO_STATFS
# ifdef USE_STATVFS
struct statvfs fs ;
# else
# ifdef ULTRIX
struct fs_data fs ;
# else
struct statfs fs ;
# endif
# endif
# endif
/* possibly use system() to get the result */
if ( df_command & & * df_command )
{
int ret ;
pstring syscmd ;
pstring outfile ;
1996-10-24 04:09:08 +04:00
sprintf ( outfile , " %s/dfree.smb.%d " , tmpdir ( ) , ( int ) getpid ( ) ) ;
1996-05-04 11:50:46 +04:00
sprintf ( syscmd , " %s %s " , df_command , path ) ;
standard_sub_basic ( syscmd ) ;
1996-10-04 13:31:07 +04:00
ret = smbrun ( syscmd , outfile , False ) ;
1996-05-04 11:50:46 +04:00
DEBUG ( 3 , ( " Running the command `%s' gave %d \n " , syscmd , ret ) ) ;
{
1997-07-01 05:19:13 +04:00
FILE * f = fopen ( outfile , " r " ) ;
* dsize = 0 ;
* dfree = 0 ;
* bsize = 1024 ;
if ( f )
{
fscanf ( f , " %d %d %d " , dsize , dfree , bsize ) ;
fclose ( f ) ;
}
else
DEBUG ( 0 , ( " Can't open %s \n " , outfile ) ) ;
1996-05-04 11:50:46 +04:00
}
unlink ( outfile ) ;
disk_norm ( bsize , dfree , dsize ) ;
1997-07-01 05:19:13 +04:00
dfree_retval = ( ( * bsize ) / 1024 ) * ( * dfree ) ;
# ifdef QUOTAS
/* Ensure we return the min value between the users quota and
what ' s free on the disk . Thanks to Albrecht Gebhardt
< albrecht . gebhardt @ uni - klu . ac . at > for this fix .
*/
if ( disk_quotas ( path , & bsizeq , & dfreeq , & dsizeq ) )
{
disk_norm ( & bsizeq , & dfreeq , & dsizeq ) ;
dfreeq_retval = ( ( bsizeq ) / 1024 ) * ( dfreeq ) ;
dfree_retval = ( dfree_retval < dfreeq_retval ) ?
dfree_retval : dfreeq_retval ;
/* maybe dfree and dfreeq are calculated using different bsizes
so convert dfree from bsize into bsizeq */
1997-10-09 00:34:13 +04:00
/* avoid overflows due to multiplication, so do not:
* dfree = ( ( * dfree ) * ( * bsize ) ) / ( bsizeq ) ;
bsize and bsizeq are powers of 2 so its better to
to divide them getting a multiplication or division factor
for dfree . Rene Nieuwenhuizen ( 07 - 10 - 1997 ) */
if ( * bsize > = bsizeq )
* dfree = * dfree * ( * bsize / bsizeq ) ;
else
* dfree = * dfree / ( bsizeq / * bsize ) ;
1997-07-01 05:19:13 +04:00
* dfree = ( * dfree < dfreeq ) ? * dfree : dfreeq ;
* bsize = bsizeq ;
* dsize = dsizeq ;
}
# endif
return ( dfree_retval ) ;
1996-05-04 11:50:46 +04:00
}
# ifdef NO_STATFS
DEBUG ( 1 , ( " Warning - no statfs function \n " ) ) ;
return ( 1 ) ;
# else
# ifdef STATFS4
if ( statfs ( path , & fs , sizeof ( fs ) , 0 ) ! = 0 )
# else
# ifdef USE_STATVFS
if ( statvfs ( path , & fs ) )
# else
# ifdef STATFS3
if ( statfs ( path , & fs , sizeof ( fs ) ) = = - 1 )
# else
if ( statfs ( path , & fs ) = = - 1 )
# endif /* STATFS3 */
# endif /* USE_STATVFS */
# endif /* STATFS4 */
{
DEBUG ( 3 , ( " dfree call failed code errno=%d \n " , errno ) ) ;
* bsize = 1024 ;
* dfree = 1 ;
* dsize = 1 ;
return ( ( ( * bsize ) / 1024 ) * ( * dfree ) ) ;
}
# ifdef ULTRIX
* bsize = 1024 ;
* dfree = fs . fd_req . bfree ;
* dsize = fs . fd_req . btot ;
# else
# ifdef USE_STATVFS
* bsize = fs . f_frsize ;
# else
# ifdef USE_F_FSIZE
/* eg: osf1 has f_fsize = fundamental filesystem block size,
f_bsize = optimal transfer block size ( MX : 94 - 04 - 19 ) */
* bsize = fs . f_fsize ;
# else
* bsize = fs . f_bsize ;
# endif /* STATFS3 */
# endif /* USE_STATVFS */
# ifdef STATFS4
* dfree = fs . f_bfree ;
# else
* dfree = fs . f_bavail ;
# endif /* STATFS4 */
* dsize = fs . f_blocks ;
# endif /* ULTRIX */
# if defined(SCO) || defined(ISC) || defined(MIPS)
* bsize = 512 ;
# endif
/* handle rediculous bsize values - some OSes are broken */
if ( ( * bsize ) < 512 | | ( * bsize ) > 0xFFFF ) * bsize = 1024 ;
disk_norm ( bsize , dfree , dsize ) ;
if ( * bsize < 256 )
* bsize = 512 ;
if ( ( * dsize ) < 1 )
{
DEBUG ( 0 , ( " dfree seems to be broken on your system \n " ) ) ;
* dsize = 20 * 1024 * 1024 / ( * bsize ) ;
* dfree = MAX ( 1 , * dfree ) ;
}
1997-07-01 05:19:13 +04:00
dfree_retval = ( ( * bsize ) / 1024 ) * ( * dfree ) ;
# ifdef QUOTAS
/* Ensure we return the min value between the users quota and
what ' s free on the disk . Thanks to Albrecht Gebhardt
< albrecht . gebhardt @ uni - klu . ac . at > for this fix .
*/
if ( disk_quotas ( path , & bsizeq , & dfreeq , & dsizeq ) )
{
disk_norm ( & bsizeq , & dfreeq , & dsizeq ) ;
dfreeq_retval = ( ( bsizeq ) / 1024 ) * ( dfreeq ) ;
dfree_retval = ( dfree_retval < dfreeq_retval ) ?
dfree_retval : dfreeq_retval ;
/* maybe dfree and dfreeq are calculated using different bsizes
so convert dfree from bsize into bsizeq */
1997-10-09 00:34:13 +04:00
/* avoid overflows due to multiplication, so do not:
* dfree = ( ( * dfree ) * ( * bsize ) ) / ( bsizeq ) ;
bsize and bsizeq are powers of 2 so its better to
to divide them getting a multiplication or division factor
for dfree . Rene Nieuwenhuizen ( 07 - 10 - 1997 ) */
if ( * bsize > = bsizeq )
* dfree = * dfree * ( * bsize / bsizeq ) ;
else
* dfree = * dfree / ( bsizeq / * bsize ) ;
1997-07-01 05:19:13 +04:00
* dfree = ( * dfree < dfreeq ) ? * dfree : dfreeq ;
* bsize = bsizeq ;
* dsize = dsizeq ;
}
# endif
return ( dfree_retval ) ;
1996-05-04 11:50:46 +04:00
# endif
}
/****************************************************************************
wrap it to get filenames right
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sys_disk_free ( char * path , int * bsize , int * dfree , int * dsize )
{
return ( disk_free ( dos_to_unix ( path , False ) , bsize , dfree , dsize ) ) ;
}
/****************************************************************************
check a filename - possibly caling reducename
This is called by every routine before it allows an operation on a filename .
It does any final confirmation necessary to ensure that the filename is
a valid one for the user to access .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL check_name ( char * name , int cnum )
{
BOOL ret ;
errno = 0 ;
1997-07-24 21:25:11 +04:00
if ( IS_VETO_PATH ( cnum , name ) )
1996-12-10 21:00:22 +03:00
{
DEBUG ( 5 , ( " file path name %s vetoed \n " , name ) ) ;
return ( 0 ) ;
}
1996-05-04 11:50:46 +04:00
ret = reduce_name ( name , Connections [ cnum ] . connectpath , lp_widelinks ( SNUM ( cnum ) ) ) ;
1997-07-19 00:21:32 +04:00
/* Check if we are allowing users to follow symlinks */
/* Patch from David Clerc <David.Clerc@cui.unige.ch>
University of Geneva */
1997-10-09 10:36:04 +04:00
# ifdef S_ISLNK
1997-07-19 00:21:32 +04:00
if ( ! lp_symlinks ( SNUM ( cnum ) ) )
{
struct stat statbuf ;
if ( ( sys_lstat ( name , & statbuf ) ! = - 1 ) & &
( S_ISLNK ( statbuf . st_mode ) ) )
{
DEBUG ( 3 , ( " check_name: denied: file path name %s is a symlink \n " , name ) ) ;
ret = 0 ;
}
}
1997-10-09 10:36:04 +04:00
# endif
1997-07-19 00:21:32 +04:00
1996-05-04 11:50:46 +04:00
if ( ! ret )
DEBUG ( 5 , ( " check_name on %s failed \n " , name ) ) ;
return ( ret ) ;
}
/****************************************************************************
check a filename - possibly caling reducename
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void check_for_pipe ( char * fname )
{
/* special case of pipe opens */
char s [ 10 ] ;
StrnCpy ( s , fname , 9 ) ;
strlower ( s ) ;
if ( strstr ( s , " pipe/ " ) )
{
DEBUG ( 3 , ( " Rejecting named pipe open for %s \n " , fname ) ) ;
unix_ERR_class = ERRSRV ;
unix_ERR_code = ERRaccess ;
}
}
1997-01-09 21:02:17 +03:00
/****************************************************************************
fd support routines - attempt to do a sys_open
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-03 07:34:19 +04:00
static int fd_attempt_open ( char * fname , int flags , int mode )
1997-01-09 21:02:17 +03:00
{
int fd = sys_open ( fname , flags , mode ) ;
/* Fix for files ending in '.' */
if ( ( fd = = - 1 ) & & ( errno = = ENOENT ) & &
( strchr ( fname , ' . ' ) = = NULL ) )
{
strcat ( fname , " . " ) ;
fd = sys_open ( fname , flags , mode ) ;
}
# if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
if ( ( fd = = - 1 ) & & ( errno = = ENAMETOOLONG ) )
{
int max_len ;
char * p = strrchr ( fname , ' / ' ) ;
if ( p = = fname ) /* name is "/xxx" */
{
max_len = pathconf ( " / " , _PC_NAME_MAX ) ;
p + + ;
}
else if ( ( p = = NULL ) | | ( p = = fname ) )
{
p = fname ;
max_len = pathconf ( " . " , _PC_NAME_MAX ) ;
}
else
{
* p = ' \0 ' ;
max_len = pathconf ( fname , _PC_NAME_MAX ) ;
* p = ' / ' ;
p + + ;
}
if ( strlen ( p ) > max_len )
{
char tmp = p [ max_len ] ;
p [ max_len ] = ' \0 ' ;
if ( ( fd = sys_open ( fname , flags , mode ) ) = = - 1 )
p [ max_len ] = tmp ;
}
}
# endif
return fd ;
}
/****************************************************************************
fd support routines - attempt to find an already open file by dev
and inode - increments the ref_count of the returned file_fd_struct * .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-03 07:34:19 +04:00
static file_fd_struct * fd_get_already_open ( struct stat * sbuf )
1997-01-09 21:02:17 +03:00
{
int i ;
file_fd_struct * fd_ptr ;
if ( sbuf = = 0 )
return 0 ;
for ( i = 0 ; i < = max_file_fd_used ; i + + ) {
fd_ptr = & FileFd [ i ] ;
if ( ( fd_ptr - > ref_count > 0 ) & &
1997-05-20 04:32:51 +04:00
( ( ( uint32 ) sbuf - > st_dev ) = = fd_ptr - > dev ) & &
( ( ( uint32 ) sbuf - > st_ino ) = = fd_ptr - > inode ) ) {
1997-01-09 21:02:17 +03:00
fd_ptr - > ref_count + + ;
DEBUG ( 3 ,
( " Re-used file_fd_struct %d, dev = %x, inode = %x, ref_count = %d \n " ,
i , fd_ptr - > dev , fd_ptr - > inode , fd_ptr - > ref_count ) ) ;
return fd_ptr ;
}
}
return 0 ;
}
/****************************************************************************
fd support routines - attempt to find a empty slot in the FileFd array .
Increments the ref_count of the returned entry .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-03 07:34:19 +04:00
static file_fd_struct * fd_get_new ( )
1997-01-09 21:02:17 +03:00
{
int i ;
file_fd_struct * fd_ptr ;
for ( i = 0 ; i < MAX_OPEN_FILES ; i + + ) {
fd_ptr = & FileFd [ i ] ;
if ( fd_ptr - > ref_count = = 0 ) {
1997-05-20 04:32:51 +04:00
fd_ptr - > dev = ( uint32 ) - 1 ;
fd_ptr - > inode = ( uint32 ) - 1 ;
1997-01-09 21:02:17 +03:00
fd_ptr - > fd = - 1 ;
fd_ptr - > fd_readonly = - 1 ;
fd_ptr - > fd_writeonly = - 1 ;
fd_ptr - > real_open_flags = - 1 ;
fd_ptr - > ref_count + + ;
/* Increment max used counter if neccessary, cuts down
on search time when re - using */
if ( i > max_file_fd_used )
max_file_fd_used = i ;
DEBUG ( 3 , ( " Allocated new file_fd_struct %d, dev = %x, inode = %x \n " ,
i , fd_ptr - > dev , fd_ptr - > inode ) ) ;
return fd_ptr ;
}
}
DEBUG ( 1 , ( " ERROR! Out of file_fd structures - perhaps increase MAX_OPEN_FILES? \
n " ));
return 0 ;
}
/****************************************************************************
fd support routines - attempt to re - open an already open fd as O_RDWR .
Save the already open fd ( we cannot close due to POSIX file locking braindamage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-03 07:34:19 +04:00
static void fd_attempt_reopen ( char * fname , int mode , file_fd_struct * fd_ptr )
1997-01-09 21:02:17 +03:00
{
int fd = sys_open ( fname , O_RDWR , mode ) ;
if ( fd = = - 1 )
return ;
if ( fd_ptr - > real_open_flags = = O_RDONLY )
fd_ptr - > fd_readonly = fd_ptr - > fd ;
if ( fd_ptr - > real_open_flags = = O_WRONLY )
fd_ptr - > fd_writeonly = fd_ptr - > fd ;
fd_ptr - > fd = fd ;
fd_ptr - > real_open_flags = O_RDWR ;
}
/****************************************************************************
fd support routines - attempt to close the file referenced by this fd .
Decrements the ref_count and returns it .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-03 07:34:19 +04:00
static int fd_attempt_close ( file_fd_struct * fd_ptr )
1997-01-09 21:02:17 +03:00
{
DEBUG ( 3 , ( " fd_attempt_close on file_fd_struct %d, fd = %d, dev = %x, inode = %x, open_flags = %d, ref_count = %d. \n " ,
fd_ptr - & FileFd [ 0 ] ,
fd_ptr - > fd , fd_ptr - > dev , fd_ptr - > inode ,
fd_ptr - > real_open_flags ,
fd_ptr - > ref_count ) ) ;
if ( fd_ptr - > ref_count > 0 ) {
fd_ptr - > ref_count - - ;
if ( fd_ptr - > ref_count = = 0 ) {
if ( fd_ptr - > fd ! = - 1 )
close ( fd_ptr - > fd ) ;
if ( fd_ptr - > fd_readonly ! = - 1 )
close ( fd_ptr - > fd_readonly ) ;
if ( fd_ptr - > fd_writeonly ! = - 1 )
close ( fd_ptr - > fd_writeonly ) ;
fd_ptr - > fd = - 1 ;
fd_ptr - > fd_readonly = - 1 ;
fd_ptr - > fd_writeonly = - 1 ;
fd_ptr - > real_open_flags = - 1 ;
1997-05-20 04:32:51 +04:00
fd_ptr - > dev = ( uint32 ) - 1 ;
fd_ptr - > inode = ( uint32 ) - 1 ;
1997-01-09 21:02:17 +03:00
}
}
return fd_ptr - > ref_count ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
open a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-05-28 00:28:45 +04:00
static void open_file ( int fnum , int cnum , char * fname1 , int flags , int mode , struct stat * sbuf )
1996-05-04 11:50:46 +04:00
{
1996-10-05 14:41:13 +04:00
extern struct current_user current_user ;
1996-05-04 11:50:46 +04:00
pstring fname ;
1997-01-09 21:02:17 +03:00
struct stat statbuf ;
file_fd_struct * fd_ptr ;
1997-09-26 23:26:56 +04:00
files_struct * fsp = & Files [ fnum ] ;
1996-05-04 11:50:46 +04:00
1997-09-26 23:26:56 +04:00
fsp - > open = False ;
fsp - > fd_ptr = 0 ;
1997-10-03 07:34:19 +04:00
fsp - > granted_oplock = False ;
1996-05-04 11:50:46 +04:00
errno = EPERM ;
1997-09-26 22:55:29 +04:00
pstrcpy ( fname , fname1 ) ;
1996-05-04 11:50:46 +04:00
/* check permissions */
if ( ( flags ! = O_RDONLY ) & & ! CAN_WRITE ( cnum ) & & ! Connections [ cnum ] . printer )
{
DEBUG ( 3 , ( " Permission denied opening %s \n " , fname ) ) ;
check_for_pipe ( fname ) ;
return ;
}
/* this handles a bug in Win95 - it doesn't say to create the file when it
should */
if ( Connections [ cnum ] . printer )
flags | = O_CREAT ;
/*
if ( flags = = O_WRONLY )
DEBUG ( 3 , ( " Bug in client? Set O_WRONLY without O_CREAT \n " ) ) ;
*/
1997-01-09 21:02:17 +03:00
/*
* Ensure we have a valid struct stat so we can search the
* open fd table .
*/
if ( sbuf = = 0 ) {
if ( stat ( fname , & statbuf ) < 0 ) {
if ( errno ! = ENOENT ) {
DEBUG ( 3 , ( " Error doing stat on file %s (%s) \n " ,
fname , strerror ( errno ) ) ) ;
check_for_pipe ( fname ) ;
return ;
}
sbuf = 0 ;
} else {
sbuf = & statbuf ;
}
}
1996-05-04 11:50:46 +04:00
1997-01-09 21:02:17 +03:00
/*
* Check to see if we have this file already
* open . If we do , just use the already open fd and increment the
* reference count ( fd_get_already_open increments the ref_count ) .
*/
if ( ( fd_ptr = fd_get_already_open ( sbuf ) ) ! = 0 ) {
int accmode = ( flags & ( O_RDONLY | O_WRONLY | O_RDWR ) ) ;
/* File was already open. */
if ( ( flags & O_CREAT ) & & ( flags & O_EXCL ) ) {
fd_ptr - > ref_count - - ;
errno = EEXIST ;
return ;
}
/*
* If not opened O_RDWR try
* and do that here - a chmod may have been done
* between the last open and now .
*/
if ( fd_ptr - > real_open_flags ! = O_RDWR )
fd_attempt_reopen ( fname , mode , fd_ptr ) ;
/*
* Ensure that if we wanted write access
* it has been opened for write , and if we wanted read it
* was open for read .
*/
if ( ( ( accmode = = O_WRONLY ) & & ( fd_ptr - > real_open_flags = = O_RDONLY ) ) | |
( ( accmode = = O_RDONLY ) & & ( fd_ptr - > real_open_flags = = O_WRONLY ) ) | |
( ( accmode = = O_RDWR ) & & ( fd_ptr - > real_open_flags ! = O_RDWR ) ) ) {
DEBUG ( 3 , ( " Error opening (already open for flags=%d) file %s (%s) (flags=%d) \n " ,
fd_ptr - > real_open_flags , fname , strerror ( EACCES ) , flags ) ) ;
check_for_pipe ( fname ) ;
fd_ptr - > ref_count - - ;
return ;
}
} else {
int open_flags ;
/* We need to allocate a new file_fd_struct (this increments the
ref_count ) . */
if ( ( fd_ptr = fd_get_new ( ) ) = = 0 )
return ;
/*
* Whatever the requested flags , attempt read / write access ,
* as we don ' t know what flags future file opens may require .
* If this fails , try again with the required flags .
* Even if we open read / write when only read access was
* requested the setting of the can_write flag in
* the file_struct will protect us from errant
* write requests . We never need to worry about O_APPEND
* as this is not set anywhere in Samba .
*/
fd_ptr - > real_open_flags = O_RDWR ;
/* Set the flags as needed without the read/write modes. */
open_flags = flags & ~ ( O_RDWR | O_WRONLY | O_RDONLY ) ;
fd_ptr - > fd = fd_attempt_open ( fname , open_flags | O_RDWR , mode ) ;
1997-02-03 22:48:56 +03:00
/*
* On some systems opening a file for R / W access on a read only
* filesystems sets errno to EROFS .
*/
# ifdef EROFS
if ( ( fd_ptr - > fd = = - 1 ) & & ( ( errno = = EACCES ) | | ( errno = = EROFS ) ) ) {
# else /* No EROFS */
1997-01-09 21:02:17 +03:00
if ( ( fd_ptr - > fd = = - 1 ) & & ( errno = = EACCES ) ) {
1997-02-03 22:48:56 +03:00
# endif /* EROFS */
1997-01-09 21:02:17 +03:00
if ( flags & O_WRONLY ) {
fd_ptr - > fd = fd_attempt_open ( fname , open_flags | O_WRONLY , mode ) ;
fd_ptr - > real_open_flags = O_WRONLY ;
} else {
fd_ptr - > fd = fd_attempt_open ( fname , open_flags | O_RDONLY , mode ) ;
fd_ptr - > real_open_flags = O_RDONLY ;
}
}
}
1996-05-04 11:50:46 +04:00
1997-01-09 21:02:17 +03:00
if ( ( fd_ptr - > fd > = 0 ) & &
1996-05-04 11:50:46 +04:00
Connections [ cnum ] . printer & & lp_minprintspace ( SNUM ( cnum ) ) ) {
pstring dname ;
int dum1 , dum2 , dum3 ;
char * p ;
1997-09-26 22:55:29 +04:00
pstrcpy ( dname , fname ) ;
1996-05-04 11:50:46 +04:00
p = strrchr ( dname , ' / ' ) ;
if ( p ) * p = 0 ;
if ( sys_disk_free ( dname , & dum1 , & dum2 , & dum3 ) <
lp_minprintspace ( SNUM ( cnum ) ) ) {
1997-01-09 21:02:17 +03:00
fd_attempt_close ( fd_ptr ) ;
1997-09-26 23:26:56 +04:00
fsp - > fd_ptr = 0 ;
1997-01-09 21:02:17 +03:00
if ( fd_ptr - > ref_count = = 0 )
sys_unlink ( fname ) ;
1996-05-04 11:50:46 +04:00
errno = ENOSPC ;
return ;
}
}
1997-01-09 21:02:17 +03:00
if ( fd_ptr - > fd < 0 )
1996-05-04 11:50:46 +04:00
{
DEBUG ( 3 , ( " Error opening file %s (%s) (flags=%d) \n " ,
fname , strerror ( errno ) , flags ) ) ;
1997-01-09 21:02:17 +03:00
/* Ensure the ref_count is decremented. */
fd_attempt_close ( fd_ptr ) ;
1996-05-04 11:50:46 +04:00
check_for_pipe ( fname ) ;
return ;
}
1997-01-09 21:02:17 +03:00
if ( fd_ptr - > fd > = 0 )
1996-05-04 11:50:46 +04:00
{
1997-01-09 21:02:17 +03:00
if ( sbuf = = 0 ) {
/* Do the fstat */
if ( fstat ( fd_ptr - > fd , & statbuf ) = = - 1 ) {
/* Error - backout !! */
DEBUG ( 3 , ( " Error doing fstat on fd %d, file %s (%s) \n " ,
fd_ptr - > fd , fname , strerror ( errno ) ) ) ;
/* Ensure the ref_count is decremented. */
fd_attempt_close ( fd_ptr ) ;
return ;
}
sbuf = & statbuf ;
}
/* Set the correct entries in fd_ptr. */
1997-05-20 04:32:51 +04:00
fd_ptr - > dev = ( uint32 ) sbuf - > st_dev ;
fd_ptr - > inode = ( uint32 ) sbuf - > st_ino ;
1997-01-09 21:02:17 +03:00
1997-09-26 23:26:56 +04:00
fsp - > fd_ptr = fd_ptr ;
1996-05-04 11:50:46 +04:00
Connections [ cnum ] . num_files_open + + ;
1997-09-26 23:26:56 +04:00
fsp - > mode = sbuf - > st_mode ;
GetTimeOfDay ( & fsp - > open_time ) ;
fsp - > uid = current_user . id ;
fsp - > size = 0 ;
fsp - > pos = - 1 ;
fsp - > open = True ;
fsp - > mmap_ptr = NULL ;
fsp - > mmap_size = 0 ;
fsp - > can_lock = True ;
fsp - > can_read = ( ( flags & O_WRONLY ) = = 0 ) ;
fsp - > can_write = ( ( flags & ( O_WRONLY | O_RDWR ) ) ! = 0 ) ;
fsp - > share_mode = 0 ;
fsp - > print_file = Connections [ cnum ] . printer ;
fsp - > modified = False ;
fsp - > granted_oplock = False ;
fsp - > cnum = cnum ;
string_set ( & fsp - > name , dos_to_unix ( fname , False ) ) ;
fsp - > wbmpx_ptr = NULL ;
1996-05-04 11:50:46 +04:00
/*
* If the printer is marked as postscript output a leading
* file identifier to ensure the file is treated as a raw
* postscript file .
* This has a similar effect as CtrlD = 0 in WIN . INI file .
* tim @ fsg . com 09 / 06 / 94
*/
1997-09-26 23:26:56 +04:00
if ( fsp - > print_file & & POSTSCRIPT ( cnum ) & &
fsp - > can_write )
1996-05-04 11:50:46 +04:00
{
DEBUG ( 3 , ( " Writing postscript line \n " ) ) ;
write_file ( fnum , " %! \n " , 3 ) ;
}
DEBUG ( 2 , ( " %s %s opened file %s read=%s write=%s (numopen=%d fnum=%d) \n " ,
timestring ( ) , Connections [ cnum ] . user , fname ,
1997-09-26 23:26:56 +04:00
BOOLSTR ( fsp - > can_read ) , BOOLSTR ( fsp - > can_write ) ,
1996-05-04 11:50:46 +04:00
Connections [ cnum ] . num_files_open , fnum ) ) ;
}
# if USE_MMAP
/* mmap it if read-only */
1997-09-26 23:26:56 +04:00
if ( ! fsp - > can_write )
1996-05-04 11:50:46 +04:00
{
1997-09-26 23:26:56 +04:00
fsp - > mmap_size = file_size ( fname ) ;
fsp - > mmap_ptr = ( char * ) mmap ( NULL , fsp - > mmap_size ,
PROT_READ , MAP_SHARED , fsp - > fd_ptr - > fd , 0 ) ;
1996-05-04 11:50:46 +04:00
1997-09-26 23:26:56 +04:00
if ( fsp - > mmap_ptr = = ( char * ) - 1 | | ! fsp - > mmap_ptr )
1996-05-04 11:50:46 +04:00
{
DEBUG ( 3 , ( " Failed to mmap() %s - %s \n " , fname , strerror ( errno ) ) ) ;
1997-09-26 23:26:56 +04:00
fsp - > mmap_ptr = NULL ;
1996-05-04 11:50:46 +04:00
}
}
# endif
}
/*******************************************************************
sync a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void sync_file ( int fnum )
{
# ifndef NO_FSYNC
1997-01-09 21:02:17 +03:00
fsync ( Files [ fnum ] . fd_ptr - > fd ) ;
1996-05-04 11:50:46 +04:00
# endif
}
/****************************************************************************
run a file if it is a magic script
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void check_magic ( int fnum , int cnum )
{
if ( ! * lp_magicscript ( SNUM ( cnum ) ) )
return ;
DEBUG ( 5 , ( " checking magic for %s \n " , Files [ fnum ] . name ) ) ;
{
char * p ;
if ( ! ( p = strrchr ( Files [ fnum ] . name , ' / ' ) ) )
p = Files [ fnum ] . name ;
else
p + + ;
if ( ! strequal ( lp_magicscript ( SNUM ( cnum ) ) , p ) )
return ;
}
{
int ret ;
pstring magic_output ;
pstring fname ;
1997-09-26 22:55:29 +04:00
pstrcpy ( fname , Files [ fnum ] . name ) ;
1996-05-04 11:50:46 +04:00
if ( * lp_magicoutput ( SNUM ( cnum ) ) )
1997-09-26 22:55:29 +04:00
pstrcpy ( magic_output , lp_magicoutput ( SNUM ( cnum ) ) ) ;
1996-05-04 11:50:46 +04:00
else
sprintf ( magic_output , " %s.out " , fname ) ;
chmod ( fname , 0755 ) ;
1996-10-04 13:31:07 +04:00
ret = smbrun ( fname , magic_output , False ) ;
1996-05-04 11:50:46 +04:00
DEBUG ( 3 , ( " Invoking magic command %s gave %d \n " , fname , ret ) ) ;
unlink ( fname ) ;
}
}
/****************************************************************************
close a file - possibly invalidating the read prediction
1997-10-16 01:53:59 +04:00
If normal_close is 1 then this came from a normal SMBclose ( or equivalent )
operation otherwise it came as the result of some other operation such as
the closing of the connection . In the latter case printing and
magic scripts are not run
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-16 01:53:59 +04:00
void close_file ( int fnum , BOOL normal_close )
1996-05-04 11:50:46 +04:00
{
1997-05-20 04:32:51 +04:00
files_struct * fs_p = & Files [ fnum ] ;
int cnum = fs_p - > cnum ;
uint32 dev = fs_p - > fd_ptr - > dev ;
uint32 inode = fs_p - > fd_ptr - > inode ;
1997-10-20 12:46:00 +04:00
int token ;
1997-05-20 04:32:51 +04:00
1997-10-27 16:38:07 +03:00
# if USE_READ_PREDICTION
1997-05-20 04:32:51 +04:00
invalidate_read_prediction ( fs_p - > fd_ptr - > fd ) ;
1997-10-27 16:38:07 +03:00
# endif
1997-05-20 04:32:51 +04:00
fs_p - > open = False ;
1996-05-04 11:50:46 +04:00
Connections [ cnum ] . num_files_open - - ;
1997-05-20 04:32:51 +04:00
if ( fs_p - > wbmpx_ptr )
1997-09-30 06:38:19 +04:00
{
free ( ( char * ) fs_p - > wbmpx_ptr ) ;
fs_p - > wbmpx_ptr = NULL ;
}
1996-05-04 11:50:46 +04:00
# if USE_MMAP
1997-05-20 04:32:51 +04:00
if ( fs_p - > mmap_ptr )
1997-09-30 06:38:19 +04:00
{
munmap ( fs_p - > mmap_ptr , fs_p - > mmap_size ) ;
fs_p - > mmap_ptr = NULL ;
}
1996-05-04 11:50:46 +04:00
# endif
if ( lp_share_modes ( SNUM ( cnum ) ) )
1997-05-20 04:32:51 +04:00
{
lock_share_entry ( cnum , dev , inode , & token ) ;
del_share_mode ( token , fnum ) ;
}
fd_attempt_close ( fs_p - > fd_ptr ) ;
1996-05-04 11:50:46 +04:00
1997-05-20 04:32:51 +04:00
if ( lp_share_modes ( SNUM ( cnum ) ) )
unlock_share_entry ( cnum , dev , inode , token ) ;
1996-05-04 11:50:46 +04:00
/* NT uses smbclose to start a print - weird */
1997-10-16 01:53:59 +04:00
if ( normal_close & & fs_p - > print_file )
1996-05-04 11:50:46 +04:00
print_file ( fnum ) ;
/* check for magic scripts */
1997-10-16 01:53:59 +04:00
if ( normal_close )
check_magic ( fnum , cnum ) ;
1996-05-04 11:50:46 +04:00
DEBUG ( 2 , ( " %s %s closed file %s (numopen=%d) \n " ,
1997-05-20 04:32:51 +04:00
timestring ( ) , Connections [ cnum ] . user , fs_p - > name ,
1996-05-04 11:50:46 +04:00
Connections [ cnum ] . num_files_open ) ) ;
}
enum { AFAIL , AREAD , AWRITE , AALL } ;
/*******************************************************************
reproduce the share mode access table
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int access_table ( int new_deny , int old_deny , int old_mode ,
int share_pid , char * fname )
{
if ( new_deny = = DENY_ALL | | old_deny = = DENY_ALL ) return ( AFAIL ) ;
if ( new_deny = = DENY_DOS | | old_deny = = DENY_DOS ) {
1997-10-03 07:15:24 +04:00
int pid = getpid ( ) ;
if ( old_deny = = new_deny & & share_pid = = pid )
1996-05-04 11:50:46 +04:00
return ( AALL ) ;
if ( old_mode = = 0 ) return ( AREAD ) ;
/* the new smbpub.zip spec says that if the file extension is
. com , . dll , . exe or . sym then allow the open . I will force
it to read - only as this seems sensible although the spec is
a little unclear on this . */
if ( ( fname = strrchr ( fname , ' . ' ) ) ) {
if ( strequal ( fname , " .com " ) | |
strequal ( fname , " .dll " ) | |
strequal ( fname , " .exe " ) | |
strequal ( fname , " .sym " ) )
return ( AREAD ) ;
}
return ( AFAIL ) ;
}
switch ( new_deny )
{
case DENY_WRITE :
if ( old_deny = = DENY_WRITE & & old_mode = = 0 ) return ( AREAD ) ;
if ( old_deny = = DENY_READ & & old_mode = = 0 ) return ( AWRITE ) ;
if ( old_deny = = DENY_NONE & & old_mode = = 0 ) return ( AALL ) ;
return ( AFAIL ) ;
case DENY_READ :
if ( old_deny = = DENY_WRITE & & old_mode = = 1 ) return ( AREAD ) ;
if ( old_deny = = DENY_READ & & old_mode = = 1 ) return ( AWRITE ) ;
if ( old_deny = = DENY_NONE & & old_mode = = 1 ) return ( AALL ) ;
return ( AFAIL ) ;
case DENY_NONE :
if ( old_deny = = DENY_WRITE ) return ( AREAD ) ;
if ( old_deny = = DENY_READ ) return ( AWRITE ) ;
if ( old_deny = = DENY_NONE ) return ( AALL ) ;
return ( AFAIL ) ;
}
return ( AFAIL ) ;
}
/*******************************************************************
check if the share mode on a file allows it to be deleted or unlinked
return True if sharing doesn ' t prevent the operation
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL check_file_sharing ( int cnum , char * fname )
{
1997-05-20 04:32:51 +04:00
int i ;
int ret = False ;
1997-10-20 12:46:00 +04:00
share_mode_entry * old_shares = 0 ;
1997-05-20 04:32:51 +04:00
int num_share_modes ;
struct stat sbuf ;
1997-10-20 12:46:00 +04:00
int token ;
1997-05-20 04:32:51 +04:00
int pid = getpid ( ) ;
1997-10-02 03:32:22 +04:00
uint32 dev , inode ;
1996-05-04 11:50:46 +04:00
1997-05-20 04:32:51 +04:00
if ( ! lp_share_modes ( SNUM ( cnum ) ) )
return True ;
if ( stat ( fname , & sbuf ) = = - 1 ) return ( True ) ;
1997-10-02 03:32:22 +04:00
dev = ( uint32 ) sbuf . st_dev ;
inode = ( uint32 ) sbuf . st_ino ;
1997-05-20 04:32:51 +04:00
1997-10-02 03:32:22 +04:00
lock_share_entry ( cnum , dev , inode , & token ) ;
num_share_modes = get_share_modes ( cnum , token , dev , inode , & old_shares ) ;
/*
* Check if the share modes will give us access .
*/
if ( num_share_modes ! = 0 )
1997-05-20 04:32:51 +04:00
{
1997-10-02 03:32:22 +04:00
BOOL broke_oplock ;
do
{
broke_oplock = False ;
for ( i = 0 ; i < num_share_modes ; i + + )
{
1997-10-20 12:46:00 +04:00
share_mode_entry * share_entry = & old_shares [ i ] ;
1997-10-02 03:32:22 +04:00
/*
1997-10-03 07:15:24 +04:00
* Break oplocks before checking share modes . See comment in
* open_file_shared for details .
* Check if someone has an oplock on this file . If so we must
* break it before continuing .
1997-10-02 03:32:22 +04:00
*/
if ( share_entry - > op_type & BATCH_OPLOCK )
{
DEBUG ( 5 , ( " check_file_sharing: breaking oplock (%x) on file %s, \
dev = % x , inode = % x \ n " , share_entry->op_type, fname, dev, inode));
1997-05-20 04:32:51 +04:00
1997-10-02 03:32:22 +04:00
/* Oplock break.... */
unlock_share_entry ( cnum , dev , inode , token ) ;
if ( request_oplock_break ( share_entry , dev , inode ) = = False )
{
free ( ( char * ) old_shares ) ;
DEBUG ( 0 , ( " check_file_sharing: FAILED when breaking oplock (%x) on file %s, \
dev = % x , inode = % x \ n " , old_shares[i].op_type, fname, dev, inode));
return False ;
}
lock_share_entry ( cnum , dev , inode , & token ) ;
broke_oplock = True ;
break ;
}
1997-10-03 07:15:24 +04:00
/* someone else has a share lock on it, check to see
if we can too */
if ( ( share_entry - > share_mode ! = DENY_DOS ) | | ( share_entry - > pid ! = pid ) )
goto free_and_exit ;
1997-10-02 03:32:22 +04:00
} /* end for */
if ( broke_oplock )
{
free ( ( char * ) old_shares ) ;
num_share_modes = get_share_modes ( cnum , token , dev , inode , & old_shares ) ;
}
} while ( broke_oplock ) ;
1997-05-20 04:32:51 +04:00
}
1996-05-04 11:50:46 +04:00
/* XXXX exactly what share mode combinations should be allowed for
deleting / renaming ? */
1997-05-20 04:32:51 +04:00
/* If we got here then either there were no share modes or
all share modes were DENY_DOS and the pid = = getpid ( ) */
ret = True ;
free_and_exit :
1997-10-02 03:32:22 +04:00
unlock_share_entry ( cnum , dev , inode , token ) ;
1997-05-20 04:32:51 +04:00
if ( old_shares ! = NULL )
free ( ( char * ) old_shares ) ;
return ( ret ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
C . Hoch 11 / 22 / 95
Helper for open_file_shared .
Truncate a file after checking locking ; close file if locked .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-20 12:46:00 +04:00
static void truncate_unless_locked ( int fnum , int cnum , int token ,
BOOL * share_locked )
1996-05-04 11:50:46 +04:00
{
if ( Files [ fnum ] . can_write ) {
if ( is_locked ( fnum , cnum , 0x3FFFFFFF , 0 ) ) {
1997-05-28 00:28:45 +04:00
/* If share modes are in force for this connection we
have the share entry locked . Unlock it before closing . */
if ( * share_locked & & lp_share_modes ( SNUM ( cnum ) ) )
unlock_share_entry ( cnum , Files [ fnum ] . fd_ptr - > dev ,
Files [ fnum ] . fd_ptr - > inode , token ) ;
1997-10-16 01:53:59 +04:00
close_file ( fnum , False ) ;
1997-05-28 00:28:45 +04:00
/* Share mode no longer locked. */
* share_locked = False ;
1996-05-04 11:50:46 +04:00
errno = EACCES ;
unix_ERR_class = ERRDOS ;
unix_ERR_code = ERRlock ;
}
else
1997-01-09 21:02:17 +03:00
ftruncate ( Files [ fnum ] . fd_ptr - > fd , 0 ) ;
1996-05-04 11:50:46 +04:00
}
}
1997-09-26 23:26:56 +04:00
/****************************************************************************
check if we can open a file with a share mode
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-20 12:46:00 +04:00
int check_share_mode ( share_mode_entry * share , int deny_mode , char * fname ,
1997-09-26 23:26:56 +04:00
BOOL fcbopen , int * flags )
{
int old_open_mode = share - > share_mode & 0xF ;
int old_deny_mode = ( share - > share_mode > > 4 ) & 7 ;
if ( old_deny_mode > 4 | | old_open_mode > 2 )
{
DEBUG ( 0 , ( " Invalid share mode found (%d,%d,%d) on file %s \n " ,
deny_mode , old_deny_mode , old_open_mode , fname ) ) ;
return False ;
}
{
int access_allowed = access_table ( deny_mode , old_deny_mode , old_open_mode ,
share - > pid , fname ) ;
if ( ( access_allowed = = AFAIL ) | |
( ! fcbopen & & ( access_allowed = = AREAD & & * flags = = O_RDWR ) ) | |
( access_allowed = = AREAD & & * flags = = O_WRONLY ) | |
( access_allowed = = AWRITE & & * flags = = O_RDONLY ) )
{
DEBUG ( 2 , ( " Share violation on file (%d,%d,%d,%d,%s) = %d \n " ,
deny_mode , old_deny_mode , old_open_mode ,
share - > pid , fname , access_allowed ) ) ;
return False ;
}
if ( access_allowed = = AREAD )
* flags = O_RDONLY ;
if ( access_allowed = = AWRITE )
* flags = O_WRONLY ;
}
return True ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
open a file with a share mode
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void open_file_shared ( int fnum , int cnum , char * fname , int share_mode , int ofun ,
1997-09-26 23:26:56 +04:00
int mode , int oplock_request , int * Access , int * action )
1996-05-04 11:50:46 +04:00
{
1997-05-20 04:32:51 +04:00
files_struct * fs_p = & Files [ fnum ] ;
1996-05-04 11:50:46 +04:00
int flags = 0 ;
int flags2 = 0 ;
int deny_mode = ( share_mode > > 4 ) & 7 ;
struct stat sbuf ;
BOOL file_existed = file_exist ( fname , & sbuf ) ;
1997-05-20 04:32:51 +04:00
BOOL share_locked = False ;
1996-05-04 11:50:46 +04:00
BOOL fcbopen = False ;
1997-10-20 12:46:00 +04:00
int token ;
1997-05-20 04:32:51 +04:00
uint32 dev = 0 ;
uint32 inode = 0 ;
1997-10-02 03:32:22 +04:00
int num_share_modes = 0 ;
1996-05-04 11:50:46 +04:00
1997-05-20 04:32:51 +04:00
fs_p - > open = False ;
fs_p - > fd_ptr = 0 ;
1996-05-04 11:50:46 +04:00
/* this is for OS/2 EAs - try and say we don't support them */
1997-05-20 04:32:51 +04:00
if ( strstr ( fname , " .+,;=[]. " ) )
{
1996-05-04 11:50:46 +04:00
unix_ERR_class = ERRDOS ;
1997-09-06 01:32:32 +04:00
/* OS/2 Workplace shell fix may be main code stream in a later release. */
# ifdef OS2_WPS_FIX
unix_ERR_code = ERRcannotopen ;
# else /* OS2_WPS_FIX */
1996-05-04 11:50:46 +04:00
unix_ERR_code = ERROR_EAS_NOT_SUPPORTED ;
1997-09-06 01:32:32 +04:00
# endif /* OS2_WPS_FIX */
1996-05-04 11:50:46 +04:00
return ;
}
1997-05-20 04:32:51 +04:00
if ( ( ofun & 0x3 ) = = 0 & & file_existed )
{
1996-05-04 11:50:46 +04:00
errno = EEXIST ;
return ;
}
if ( ofun & 0x10 )
flags2 | = O_CREAT ;
if ( ( ofun & 0x3 ) = = 2 )
flags2 | = O_TRUNC ;
/* note that we ignore the append flag as
append does not mean the same thing under dos and unix */
switch ( share_mode & 0xF )
1997-05-20 04:32:51 +04:00
{
1996-05-04 11:50:46 +04:00
case 1 :
flags = O_WRONLY ;
break ;
case 0xF :
fcbopen = True ;
flags = O_RDWR ;
break ;
case 2 :
flags = O_RDWR ;
break ;
default :
flags = O_RDONLY ;
break ;
1997-05-20 04:32:51 +04:00
}
1996-05-04 11:50:46 +04:00
if ( flags ! = O_RDONLY & & file_existed & &
1997-05-20 04:32:51 +04:00
( ! CAN_WRITE ( cnum ) | | IS_DOS_READONLY ( dos_mode ( cnum , fname , & sbuf ) ) ) )
{
if ( ! fcbopen )
{
1996-05-04 11:50:46 +04:00
errno = EACCES ;
return ;
}
flags = O_RDONLY ;
}
1997-05-20 04:32:51 +04:00
if ( deny_mode > DENY_NONE & & deny_mode ! = DENY_FCB )
{
1996-05-04 11:50:46 +04:00
DEBUG ( 2 , ( " Invalid deny mode %d on file %s \n " , deny_mode , fname ) ) ;
errno = EINVAL ;
return ;
}
if ( deny_mode = = DENY_FCB ) deny_mode = DENY_DOS ;
1997-05-20 04:32:51 +04:00
if ( lp_share_modes ( SNUM ( cnum ) ) )
{
int i ;
1997-10-20 12:46:00 +04:00
share_mode_entry * old_shares = 0 ;
1997-05-20 04:32:51 +04:00
1996-05-04 11:50:46 +04:00
if ( file_existed )
1997-05-20 04:32:51 +04:00
{
dev = ( uint32 ) sbuf . st_dev ;
inode = ( uint32 ) sbuf . st_ino ;
lock_share_entry ( cnum , dev , inode , & token ) ;
share_locked = True ;
1997-10-02 03:32:22 +04:00
num_share_modes = get_share_modes ( cnum , token , dev , inode , & old_shares ) ;
1997-05-20 04:32:51 +04:00
}
1996-05-04 11:50:46 +04:00
1997-09-26 23:26:56 +04:00
/*
* Check if the share modes will give us access .
*/
1996-05-04 11:50:46 +04:00
1997-10-02 03:32:22 +04:00
if ( share_locked & & ( num_share_modes ! = 0 ) )
1997-09-26 23:26:56 +04:00
{
BOOL broke_oplock ;
1996-05-04 11:50:46 +04:00
1997-09-26 23:26:56 +04:00
do
1996-05-04 11:50:46 +04:00
{
1997-09-30 06:38:19 +04:00
1997-09-26 23:26:56 +04:00
broke_oplock = False ;
1997-10-02 03:32:22 +04:00
for ( i = 0 ; i < num_share_modes ; i + + )
1997-05-20 04:32:51 +04:00
{
1997-10-20 12:46:00 +04:00
share_mode_entry * share_entry = & old_shares [ i ] ;
1997-09-30 06:38:19 +04:00
1997-09-26 23:26:56 +04:00
/*
1997-10-03 07:15:24 +04:00
* By observation of NetBench , oplocks are broken * before * share
* modes are checked . This allows a file to be closed by the client
* if the share mode would deny access and the client has an oplock .
* Check if someone has an oplock on this file . If so we must break
* it before continuing .
1997-09-26 23:26:56 +04:00
*/
1997-09-30 06:38:19 +04:00
if ( share_entry - > op_type & ( EXCLUSIVE_OPLOCK | BATCH_OPLOCK ) )
1997-09-26 23:26:56 +04:00
{
1997-09-30 06:38:19 +04:00
1997-10-02 03:32:22 +04:00
DEBUG ( 5 , ( " open_file_shared: breaking oplock (%x) on file %s, \
1997-09-30 06:38:19 +04:00
dev = % x , inode = % x \ n " , share_entry->op_type, fname, dev, inode));
1997-09-26 23:26:56 +04:00
/* Oplock break.... */
unlock_share_entry ( cnum , dev , inode , token ) ;
1997-09-30 06:38:19 +04:00
if ( request_oplock_break ( share_entry , dev , inode ) = = False )
1997-09-26 23:26:56 +04:00
{
free ( ( char * ) old_shares ) ;
1997-10-02 03:32:22 +04:00
DEBUG ( 0 , ( " open_file_shared: FAILED when breaking oplock (%x) on file %s, \
1997-09-30 06:38:19 +04:00
dev = % x , inode = % x \ n " , old_shares[i].op_type, fname, dev, inode));
errno = EACCES ;
unix_ERR_class = ERRDOS ;
unix_ERR_code = ERRbadshare ;
return ;
1997-09-26 23:26:56 +04:00
}
lock_share_entry ( cnum , dev , inode , & token ) ;
broke_oplock = True ;
break ;
}
1997-10-03 07:15:24 +04:00
/* someone else has a share lock on it, check to see
if we can too */
if ( check_share_mode ( share_entry , deny_mode , fname , fcbopen , & flags ) = = False )
{
free ( ( char * ) old_shares ) ;
unlock_share_entry ( cnum , dev , inode , token ) ;
errno = EACCES ;
unix_ERR_class = ERRDOS ;
unix_ERR_code = ERRbadshare ;
return ;
}
1997-09-30 06:38:19 +04:00
} /* end for */
1997-09-26 23:26:56 +04:00
if ( broke_oplock )
{
free ( ( char * ) old_shares ) ;
1997-10-02 03:32:22 +04:00
num_share_modes = get_share_modes ( cnum , token , dev , inode , & old_shares ) ;
1997-09-26 23:26:56 +04:00
}
} while ( broke_oplock ) ;
1996-05-04 11:50:46 +04:00
}
1997-09-26 23:26:56 +04:00
1997-05-20 04:32:51 +04:00
if ( old_shares ! = 0 )
free ( ( char * ) old_shares ) ;
1996-05-04 11:50:46 +04:00
}
DEBUG ( 4 , ( " calling open_file with flags=0x%X flags2=0x%X mode=0%o \n " ,
flags , flags2 , mode ) ) ;
1997-01-23 22:39:57 +03:00
open_file ( fnum , cnum , fname , flags | ( flags2 & ~ ( O_TRUNC ) ) , mode , file_existed ? & sbuf : 0 ) ;
1997-05-20 04:32:51 +04:00
if ( ! fs_p - > open & & flags = = O_RDWR & & errno ! = ENOENT & & fcbopen )
{
1996-05-04 11:50:46 +04:00
flags = O_RDONLY ;
1997-01-23 22:39:57 +03:00
open_file ( fnum , cnum , fname , flags , mode , file_existed ? & sbuf : 0 ) ;
1996-05-04 11:50:46 +04:00
}
1997-05-20 04:32:51 +04:00
if ( fs_p - > open )
{
1996-05-04 11:50:46 +04:00
int open_mode = 0 ;
1997-05-20 04:32:51 +04:00
if ( ( share_locked = = False ) & & lp_share_modes ( SNUM ( cnum ) ) )
{
/* We created the file - thus we must now lock the share entry before creating it. */
dev = fs_p - > fd_ptr - > dev ;
inode = fs_p - > fd_ptr - > inode ;
lock_share_entry ( cnum , dev , inode , & token ) ;
share_locked = True ;
1996-05-04 11:50:46 +04:00
}
1997-05-20 04:32:51 +04:00
switch ( flags )
{
case O_RDONLY :
open_mode = 0 ;
break ;
case O_RDWR :
open_mode = 2 ;
break ;
case O_WRONLY :
open_mode = 1 ;
break ;
}
fs_p - > share_mode = ( deny_mode < < 4 ) | open_mode ;
1996-05-04 11:50:46 +04:00
1997-05-20 04:32:51 +04:00
if ( Access )
1996-05-04 11:50:46 +04:00
( * Access ) = open_mode ;
1997-05-20 04:32:51 +04:00
if ( action )
{
1996-05-04 11:50:46 +04:00
if ( file_existed & & ! ( flags2 & O_TRUNC ) ) * action = 1 ;
if ( ! file_existed ) * action = 2 ;
if ( file_existed & & ( flags2 & O_TRUNC ) ) * action = 3 ;
}
1997-05-28 00:28:45 +04:00
/* We must create the share mode entry before truncate as
truncate can fail due to locking and have to close the
file ( which expects the share_mode_entry to be there ) .
*/
1997-05-20 04:32:51 +04:00
if ( lp_share_modes ( SNUM ( cnum ) ) )
1997-10-02 03:32:22 +04:00
{
uint16 port = 0 ;
/* JRA. Currently this only services Exlcusive and batch
oplocks ( no other opens on this file ) . This needs to
be extended to level II oplocks ( multiple reader
oplocks ) . */
1997-10-02 07:14:32 +04:00
if ( oplock_request & & ( num_share_modes = = 0 ) & & lp_oplocks ( SNUM ( cnum ) ) )
1997-10-02 03:32:22 +04:00
{
fs_p - > granted_oplock = True ;
global_oplocks_open + + ;
port = oplock_port ;
DEBUG ( 5 , ( " open_file_shared: granted oplock (%x) on file %s, \
dev = % x , inode = % x \ n " , oplock_request, fname, dev, inode));
1997-10-02 04:57:59 +04:00
}
else
{
port = 0 ;
oplock_request = 0 ;
}
1997-10-02 03:32:22 +04:00
set_share_mode ( token , fnum , port , oplock_request ) ;
}
1997-05-28 00:28:45 +04:00
if ( ( flags2 & O_TRUNC ) & & file_existed )
truncate_unless_locked ( fnum , cnum , token , & share_locked ) ;
1997-05-20 04:32:51 +04:00
}
1996-05-04 11:50:46 +04:00
1997-05-20 04:32:51 +04:00
if ( share_locked & & lp_share_modes ( SNUM ( cnum ) ) )
unlock_share_entry ( cnum , dev , inode , token ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
seek a file . Try to avoid the seek if possible
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-08-19 23:22:26 +04:00
int seek_file ( int fnum , uint32 pos )
1996-05-04 11:50:46 +04:00
{
1997-08-19 23:22:26 +04:00
uint32 offset = 0 ;
1996-05-04 11:50:46 +04:00
if ( Files [ fnum ] . print_file & & POSTSCRIPT ( Files [ fnum ] . cnum ) )
offset = 3 ;
1997-08-19 23:22:26 +04:00
Files [ fnum ] . pos = ( int ) ( lseek ( Files [ fnum ] . fd_ptr - > fd , pos + offset , SEEK_SET )
- offset ) ;
1996-05-04 11:50:46 +04:00
return ( Files [ fnum ] . pos ) ;
}
/****************************************************************************
read from a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-08-19 23:22:26 +04:00
int read_file ( int fnum , char * data , uint32 pos , int n )
1996-05-04 11:50:46 +04:00
{
1996-07-30 19:47:30 +04:00
int ret = 0 , readret ;
1996-05-04 11:50:46 +04:00
1997-10-27 16:38:07 +03:00
# if USE_READ_PREDICTION
1996-05-04 11:50:46 +04:00
if ( ! Files [ fnum ] . can_write )
{
1997-01-09 21:02:17 +03:00
ret = read_predict ( Files [ fnum ] . fd_ptr - > fd , pos , data , NULL , n ) ;
1996-05-04 11:50:46 +04:00
data + = ret ;
1996-07-30 19:47:30 +04:00
n - = ret ;
1996-05-04 11:50:46 +04:00
pos + = ret ;
}
1997-10-27 16:38:07 +03:00
# endif
1996-05-04 11:50:46 +04:00
# if USE_MMAP
if ( Files [ fnum ] . mmap_ptr )
{
1997-08-19 23:22:26 +04:00
int num = MIN ( n , ( int ) ( Files [ fnum ] . mmap_size - pos ) ) ;
1996-05-04 11:50:46 +04:00
if ( num > 0 )
{
memcpy ( data , Files [ fnum ] . mmap_ptr + pos , num ) ;
data + = num ;
pos + = num ;
1996-07-30 19:47:30 +04:00
n - = num ;
1996-05-04 11:50:46 +04:00
ret + = num ;
}
}
# endif
1996-07-30 19:47:30 +04:00
if ( n < = 0 )
1996-05-04 11:50:46 +04:00
return ( ret ) ;
if ( seek_file ( fnum , pos ) ! = pos )
{
DEBUG ( 3 , ( " Failed to seek to %d \n " , pos ) ) ;
return ( ret ) ;
}
1996-07-30 19:47:30 +04:00
if ( n > 0 ) {
1997-01-09 21:02:17 +03:00
readret = read ( Files [ fnum ] . fd_ptr - > fd , data , n ) ;
1996-07-30 19:47:30 +04:00
if ( readret > 0 ) ret + = readret ;
}
1996-05-04 11:50:46 +04:00
return ( ret ) ;
}
/****************************************************************************
write to a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int write_file ( int fnum , char * data , int n )
{
if ( ! Files [ fnum ] . can_write ) {
errno = EPERM ;
return ( 0 ) ;
}
1996-05-04 14:48:19 +04:00
if ( ! Files [ fnum ] . modified ) {
struct stat st ;
Files [ fnum ] . modified = True ;
1997-01-09 21:02:17 +03:00
if ( fstat ( Files [ fnum ] . fd_ptr - > fd , & st ) = = 0 ) {
1996-05-04 14:48:19 +04:00
int dosmode = dos_mode ( Files [ fnum ] . cnum , Files [ fnum ] . name , & st ) ;
if ( MAP_ARCHIVE ( Files [ fnum ] . cnum ) & & ! IS_DOS_ARCHIVE ( dosmode ) ) {
dos_chmod ( Files [ fnum ] . cnum , Files [ fnum ] . name , dosmode | aARCH , & st ) ;
}
}
}
1996-05-04 11:50:46 +04:00
1997-01-09 21:02:17 +03:00
return ( write_data ( Files [ fnum ] . fd_ptr - > fd , data , n ) ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
load parameters specific to a connection / service
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL become_service ( int cnum , BOOL do_chdir )
{
extern char magic_char ;
static int last_cnum = - 1 ;
int snum ;
if ( ! OPEN_CNUM ( cnum ) )
{
last_cnum = - 1 ;
return ( False ) ;
}
Connections [ cnum ] . lastused = smb_last_time ;
snum = SNUM ( cnum ) ;
if ( do_chdir & &
ChDir ( Connections [ cnum ] . connectpath ) ! = 0 & &
ChDir ( Connections [ cnum ] . origpath ) ! = 0 )
{
DEBUG ( 0 , ( " %s chdir (%s) failed cnum=%d \n " , timestring ( ) ,
Connections [ cnum ] . connectpath , cnum ) ) ;
return ( False ) ;
}
if ( cnum = = last_cnum )
return ( True ) ;
last_cnum = cnum ;
case_default = lp_defaultcase ( snum ) ;
case_preserve = lp_preservecase ( snum ) ;
short_case_preserve = lp_shortpreservecase ( snum ) ;
case_mangle = lp_casemangle ( snum ) ;
case_sensitive = lp_casesensitive ( snum ) ;
magic_char = lp_magicchar ( snum ) ;
use_mangled_map = ( * lp_mangled_map ( snum ) ? True : False ) ;
return ( True ) ;
}
/****************************************************************************
find a service entry
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int find_service ( char * service )
{
int iService ;
string_sub ( service , " \\ " , " / " ) ;
iService = lp_servicenumber ( service ) ;
/* now handle the special case of a home directory */
if ( iService < 0 )
{
char * phome_dir = get_home_dir ( service ) ;
DEBUG ( 3 , ( " checking for home directory %s gave %s \n " , service ,
phome_dir ? phome_dir : " (NULL) " ) ) ;
if ( phome_dir )
{
int iHomeService ;
if ( ( iHomeService = lp_servicenumber ( HOMES_NAME ) ) > = 0 )
{
lp_add_home ( service , iHomeService , phome_dir ) ;
iService = lp_servicenumber ( service ) ;
}
}
}
/* If we still don't have a service, attempt to add it as a printer. */
if ( iService < 0 )
{
int iPrinterService ;
if ( ( iPrinterService = lp_servicenumber ( PRINTERS_NAME ) ) > = 0 )
{
char * pszTemp ;
DEBUG ( 3 , ( " checking whether %s is a valid printer name... \n " , service ) ) ;
pszTemp = PRINTCAP ;
if ( ( pszTemp ! = NULL ) & & pcap_printername_ok ( service , pszTemp ) )
{
DEBUG ( 3 , ( " %s is a valid printer name \n " , service ) ) ;
DEBUG ( 3 , ( " adding %s as a printer service \n " , service ) ) ;
lp_add_printer ( service , iPrinterService ) ;
iService = lp_servicenumber ( service ) ;
if ( iService < 0 )
DEBUG ( 0 , ( " failed to add %s as a printer service! \n " , service ) ) ;
}
else
DEBUG ( 3 , ( " %s is not a valid printer name \n " , service ) ) ;
}
}
/* just possibly it's a default service? */
if ( iService < 0 )
{
char * defservice = lp_defaultservice ( ) ;
if ( defservice & & * defservice & & ! strequal ( defservice , service ) ) {
iService = find_service ( defservice ) ;
if ( iService > = 0 ) {
string_sub ( service , " _ " , " / " ) ;
iService = lp_add_service ( service , iService ) ;
}
}
}
if ( iService > = 0 )
if ( ! VALID_SNUM ( iService ) )
{
DEBUG ( 0 , ( " Invalid snum %d for %s \n " , iService , service ) ) ;
iService = - 1 ;
}
if ( iService < 0 )
DEBUG ( 3 , ( " find_service() failed to find service %s \n " , service ) ) ;
return ( iService ) ;
}
/****************************************************************************
create an error packet from a cached error .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int cached_error_packet ( char * inbuf , char * outbuf , int fnum , int line )
{
write_bmpx_struct * wbmpx = Files [ fnum ] . wbmpx_ptr ;
int32 eclass = wbmpx - > wr_errclass ;
int32 err = wbmpx - > wr_error ;
/* We can now delete the auxiliary struct */
free ( ( char * ) wbmpx ) ;
Files [ fnum ] . wbmpx_ptr = NULL ;
return error_packet ( inbuf , outbuf , eclass , err , line ) ;
}
struct
{
int unixerror ;
int smbclass ;
int smbcode ;
} unix_smb_errmap [ ] =
{
{ EPERM , ERRDOS , ERRnoaccess } ,
{ EACCES , ERRDOS , ERRnoaccess } ,
{ ENOENT , ERRDOS , ERRbadfile } ,
1997-10-02 18:11:34 +04:00
{ ENOTDIR , ERRDOS , ERRbadpath } ,
1996-05-04 11:50:46 +04:00
{ EIO , ERRHRD , ERRgeneral } ,
{ EBADF , ERRSRV , ERRsrverror } ,
{ EINVAL , ERRSRV , ERRsrverror } ,
{ EEXIST , ERRDOS , ERRfilexists } ,
{ ENFILE , ERRDOS , ERRnofids } ,
{ EMFILE , ERRDOS , ERRnofids } ,
{ ENOSPC , ERRHRD , ERRdiskfull } ,
# ifdef EDQUOT
{ EDQUOT , ERRHRD , ERRdiskfull } ,
# endif
# ifdef ENOTEMPTY
{ ENOTEMPTY , ERRDOS , ERRnoaccess } ,
# endif
# ifdef EXDEV
{ EXDEV , ERRDOS , ERRdiffdevice } ,
# endif
{ EROFS , ERRHRD , ERRnowrite } ,
{ 0 , 0 , 0 }
} ;
/****************************************************************************
create an error packet from errno
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int unix_error_packet ( char * inbuf , char * outbuf , int def_class , uint32 def_code , int line )
{
int eclass = def_class ;
int ecode = def_code ;
int i = 0 ;
if ( unix_ERR_class ! = SUCCESS )
{
eclass = unix_ERR_class ;
ecode = unix_ERR_code ;
unix_ERR_class = SUCCESS ;
unix_ERR_code = 0 ;
}
else
{
while ( unix_smb_errmap [ i ] . smbclass ! = 0 )
1997-09-03 02:21:38 +04:00
{
if ( unix_smb_errmap [ i ] . unixerror = = errno )
1996-05-04 11:50:46 +04:00
{
eclass = unix_smb_errmap [ i ] . smbclass ;
ecode = unix_smb_errmap [ i ] . smbcode ;
break ;
}
i + + ;
1997-09-03 02:21:38 +04:00
}
}
1996-05-04 11:50:46 +04:00
return ( error_packet ( inbuf , outbuf , eclass , ecode , line ) ) ;
}
/****************************************************************************
create an error packet . Normally called using the ERROR ( ) macro
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int error_packet ( char * inbuf , char * outbuf , int error_class , uint32 error_code , int line )
{
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
int cmd ;
1997-11-10 22:23:17 +03:00
cmd = CVAL ( inbuf , smb_com ) ;
1996-05-04 11:50:46 +04:00
1997-11-10 22:23:17 +03:00
CVAL ( outbuf , smb_rcls ) = error_class ;
SSVAL ( outbuf , smb_err , error_code ) ;
1997-11-09 20:30:10 +03:00
1997-11-10 22:23:17 +03:00
DEBUG ( 3 , ( " %s error packet at line %d cmd=%d (%s) eclass=%d ecode=%d \n " ,
timestring ( ) ,
line ,
( int ) CVAL ( inbuf , smb_com ) ,
smb_fn_name ( CVAL ( inbuf , smb_com ) ) ,
error_class ,
error_code ) ) ;
1996-05-04 11:50:46 +04:00
if ( errno ! = 0 )
1997-11-10 22:23:17 +03:00
DEBUG ( 3 , ( " error string = %s \n " , strerror ( errno ) ) ) ;
1996-05-04 11:50:46 +04:00
return ( outsize ) ;
}
# ifndef SIGCLD_IGNORE
/****************************************************************************
this prevents zombie child processes
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sig_cld ( )
{
static int depth = 0 ;
if ( depth ! = 0 )
{
DEBUG ( 0 , ( " ERROR: Recursion in sig_cld? Perhaps you need `#define USE_WAITPID'? \n " ) ) ;
depth = 0 ;
return ( 0 ) ;
}
depth + + ;
1996-08-15 19:11:34 +04:00
BlockSignals ( True , SIGCLD ) ;
1996-05-04 11:50:46 +04:00
DEBUG ( 5 , ( " got SIGCLD \n " ) ) ;
# ifdef USE_WAITPID
1996-10-05 06:54:37 +04:00
while ( sys_waitpid ( ( pid_t ) - 1 , ( int * ) NULL , WNOHANG ) > 0 ) ;
1996-05-04 11:50:46 +04:00
# endif
/* Stop zombies */
/* Stevens, Adv. Unix Prog. says that on system V you must call
wait before reinstalling the signal handler , because the kernel
calls the handler from within the signal - call when there is a
child that has exited . This would lead to an infinite recursion
if done vice versa . */
# ifndef DONT_REINSTALL_SIG
# ifdef SIGCLD_IGNORE
signal ( SIGCLD , SIG_IGN ) ;
# else
signal ( SIGCLD , SIGNAL_CAST sig_cld ) ;
# endif
# endif
# ifndef USE_WAITPID
while ( wait3 ( WAIT3_CAST1 NULL , WNOHANG , WAIT3_CAST2 NULL ) > 0 ) ;
# endif
depth - - ;
1996-08-15 19:11:34 +04:00
BlockSignals ( False , SIGCLD ) ;
1996-05-04 11:50:46 +04:00
return 0 ;
}
# endif
/****************************************************************************
this is called when the client exits abruptly
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sig_pipe ( )
{
1997-11-10 22:23:17 +03:00
struct cli_state * cli ;
1997-10-21 13:34:33 +04:00
BlockSignals ( True , SIGPIPE ) ;
1996-08-21 16:36:01 +04:00
1997-11-10 22:23:17 +03:00
if ( ( cli = server_client ( ) ) & & cli - > initialised ) {
1997-10-21 13:34:33 +04:00
DEBUG ( 3 , ( " lost connection to password server \n " ) ) ;
1997-11-10 22:23:17 +03:00
cli_shutdown ( cli ) ;
1996-08-21 16:36:01 +04:00
# ifndef DONT_REINSTALL_SIG
1997-10-21 13:34:33 +04:00
signal ( SIGPIPE , SIGNAL_CAST sig_pipe ) ;
1996-08-21 16:36:01 +04:00
# endif
1997-10-21 13:34:33 +04:00
BlockSignals ( False , SIGPIPE ) ;
return 0 ;
}
1996-08-21 16:36:01 +04:00
1997-10-21 13:34:33 +04:00
exit_server ( " Got sigpipe \n " ) ;
return ( 0 ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
open the socket communication
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL open_sockets ( BOOL is_daemon , int port )
{
extern int Client ;
if ( is_daemon )
1997-10-21 22:27:55 +04:00
{
int num_interfaces = iface_count ( ) ;
int fd_listenset [ FD_SETSIZE ] ;
fd_set listen_set ;
int s ;
int i ;
/* Stop zombies */
1996-05-04 11:50:46 +04:00
# ifdef SIGCLD_IGNORE
1997-10-21 22:27:55 +04:00
signal ( SIGCLD , SIG_IGN ) ;
1996-05-04 11:50:46 +04:00
# else
1997-10-21 22:27:55 +04:00
signal ( SIGCLD , SIGNAL_CAST sig_cld ) ;
1996-05-04 11:50:46 +04:00
# endif
1997-10-21 22:27:55 +04:00
if ( atexit_set = = 0 )
atexit ( killkids ) ;
FD_ZERO ( & listen_set ) ;
if ( lp_interfaces ( ) & & lp_bind_interfaces_only ( ) )
{
/* We have been given an interfaces line, and been
told to only bind to those interfaces . Create a
socket per interface and bind to only these .
*/
if ( num_interfaces > FD_SETSIZE )
{
DEBUG ( 0 , ( " open_sockets: Too many interfaces specified to bind to. Number was %d \
max can be % d \ n " , num_interfaces, FD_SETSIZE));
return False ;
}
/* Now open a listen socket for each of the interfaces. */
for ( i = 0 ; i < num_interfaces ; i + + )
{
struct in_addr * ifip = iface_n_ip ( i ) ;
if ( ifip = = NULL )
{
DEBUG ( 0 , ( " open_sockets: interface %d has NULL IP address ! \n " , i ) ) ;
continue ;
}
s = fd_listenset [ i ] = open_socket_in ( SOCK_STREAM , port , 0 , ifip - > s_addr ) ;
if ( s = = - 1 )
return False ;
/* ready to listen */
if ( listen ( s , 5 ) = = - 1 )
{
DEBUG ( 0 , ( " listen: %s \n " , strerror ( errno ) ) ) ;
close ( s ) ;
return False ;
}
FD_SET ( s , & listen_set ) ;
}
}
else
{
/* Just bind to 0.0.0.0 - accept connections from anywhere. */
num_interfaces = 1 ;
1996-05-04 11:50:46 +04:00
/* open an incoming socket */
1996-08-19 15:17:29 +04:00
s = open_socket_in ( SOCK_STREAM , port , 0 , interpret_addr ( lp_socket_address ( ) ) ) ;
1996-05-04 11:50:46 +04:00
if ( s = = - 1 )
1997-10-21 22:27:55 +04:00
return ( False ) ;
1996-05-04 11:50:46 +04:00
/* ready to listen */
if ( listen ( s , 5 ) = = - 1 )
1997-10-21 22:27:55 +04:00
{
DEBUG ( 0 , ( " open_sockets: listen: %s \n " , strerror ( errno ) ) ) ;
close ( s ) ;
return False ;
}
1996-12-10 21:00:22 +03:00
1997-10-21 22:27:55 +04:00
fd_listenset [ 0 ] = s ;
FD_SET ( s , & listen_set ) ;
}
/* now accept incoming connections - forking a new process
for each incoming connection */
DEBUG ( 2 , ( " waiting for a connection \n " ) ) ;
while ( 1 )
{
fd_set lfds ;
int num ;
1996-05-04 11:50:46 +04:00
1997-10-21 22:27:55 +04:00
memcpy ( ( char * ) & lfds , ( char * ) & listen_set , sizeof ( listen_set ) ) ;
1996-05-04 11:50:46 +04:00
1997-10-21 22:27:55 +04:00
num = sys_select ( & lfds , NULL ) ;
if ( num = = - 1 & & errno = = EINTR )
continue ;
/* Find the sockets that are read-ready - accept on these. */
for ( ; num > 0 ; num - - )
{
struct sockaddr addr ;
int in_addrlen = sizeof ( addr ) ;
s = - 1 ;
for ( i = 0 ; i < num_interfaces ; i + + )
{
if ( FD_ISSET ( fd_listenset [ i ] , & lfds ) )
{
s = fd_listenset [ i ] ;
1997-10-24 02:30:57 +04:00
/* Clear this so we don't look at it again. */
FD_CLR ( fd_listenset [ i ] , & lfds ) ;
1997-10-21 22:27:55 +04:00
break ;
}
}
Client = accept ( s , & addr , & in_addrlen ) ;
if ( Client = = - 1 & & errno = = EINTR )
continue ;
if ( Client = = - 1 )
{
DEBUG ( 0 , ( " open_sockets: accept: %s \n " , strerror ( errno ) ) ) ;
continue ;
}
1996-05-04 11:50:46 +04:00
# ifdef NO_FORK_DEBUG
1997-10-21 22:27:55 +04:00
# ifndef NO_SIGNAL_TEST
signal ( SIGPIPE , SIGNAL_CAST sig_pipe ) ;
signal ( SIGCLD , SIGNAL_CAST SIG_DFL ) ;
# endif /* NO_SIGNAL_TEST */
return True ;
# else /* NO_FORK_DEBUG */
if ( Client ! = - 1 & & fork ( ) = = 0 )
{
/* Child code ... */
1996-05-04 11:50:46 +04:00
# ifndef NO_SIGNAL_TEST
signal ( SIGPIPE , SIGNAL_CAST sig_pipe ) ;
signal ( SIGCLD , SIGNAL_CAST SIG_DFL ) ;
1997-10-21 22:27:55 +04:00
# endif /* NO_SIGNAL_TEST */
/* close the listening socket(s) */
for ( i = 0 ; i < num_interfaces ; i + + )
close ( fd_listenset [ i ] ) ;
/* close our standard file descriptors */
close_low_fds ( ) ;
am_parent = 0 ;
1996-05-04 11:50:46 +04:00
1997-10-21 22:27:55 +04:00
set_socket_options ( Client , " SO_KEEPALIVE " ) ;
set_socket_options ( Client , user_socket_options ) ;
/* Reset global variables in util.c so that
client substitutions will be done correctly
in the process .
*/
reset_globals_after_fork ( ) ;
return True ;
}
close ( Client ) ; /* The parent doesn't need this socket */
# endif / NO_FORK_DEBUG * /
} /* end for num */
} /* end while 1 */
} /* end if is_daemon */
1996-05-04 11:50:46 +04:00
else
1997-10-21 22:27:55 +04:00
{
/* Started from inetd. fd 0 is the socket. */
/* We will abort gracefully when the client or remote system
goes away */
1996-05-04 11:50:46 +04:00
# ifndef NO_SIGNAL_TEST
1997-10-21 22:27:55 +04:00
signal ( SIGPIPE , SIGNAL_CAST sig_pipe ) ;
1996-05-04 11:50:46 +04:00
# endif
1997-10-21 22:27:55 +04:00
Client = dup ( 0 ) ;
1996-05-04 11:50:46 +04:00
1997-10-21 22:27:55 +04:00
/* close our standard file descriptors */
close_low_fds ( ) ;
1996-05-04 11:50:46 +04:00
1997-10-21 22:27:55 +04:00
set_socket_options ( Client , " SO_KEEPALIVE " ) ;
set_socket_options ( Client , user_socket_options ) ;
}
1996-05-04 11:50:46 +04:00
return True ;
}
1997-09-30 06:38:19 +04:00
/****************************************************************************
process an smb from the client - split out from the process ( ) code so
it can be used by the oplock break code .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void process_smb ( char * inbuf , char * outbuf )
{
extern int Client ;
1997-10-02 07:14:32 +04:00
static int trans_num ;
1997-09-30 06:38:19 +04:00
int msg_type = CVAL ( inbuf , 0 ) ;
1997-10-02 07:14:32 +04:00
int32 len = smb_len ( inbuf ) ;
1997-09-30 06:38:19 +04:00
int nread = len + 4 ;
1997-10-02 07:14:32 +04:00
if ( trans_num = = 0 ) {
/* on the first packet, check the global hosts allow/ hosts
deny parameters before doing any parsing of the packet
passed to us by the client . This prevents attacks on our
parsing code from hosts not in the hosts allow list */
if ( ! check_access ( - 1 ) ) {
/* send a negative session response "not listining on calling
name " */
static unsigned char buf [ 5 ] = { 0x83 , 0 , 0 , 1 , 0x81 } ;
DEBUG ( 1 , ( " %s Connection denied from %s \n " ,
timestring ( ) , client_addr ( ) ) ) ;
1997-10-03 07:15:24 +04:00
send_smb ( Client , ( char * ) buf ) ;
1997-10-02 07:14:32 +04:00
exit_server ( " connection denied " ) ;
}
}
1997-09-30 06:38:19 +04:00
DEBUG ( 6 , ( " got message type 0x%x of len 0x%x \n " , msg_type , len ) ) ;
DEBUG ( 3 , ( " %s Transaction %d of length %d \n " , timestring ( ) , trans_num , nread ) ) ;
# ifdef WITH_VTP
if ( trans_num = = 1 & & VT_Check ( inbuf ) )
{
VT_Process ( ) ;
return ;
}
# endif
if ( msg_type = = 0 )
show_msg ( inbuf ) ;
nread = construct_reply ( inbuf , outbuf , nread , max_send ) ;
if ( nread > 0 )
{
if ( CVAL ( outbuf , 0 ) = = 0 )
show_msg ( outbuf ) ;
if ( nread ! = smb_len ( outbuf ) + 4 )
{
DEBUG ( 0 , ( " ERROR: Invalid message response size! %d %d \n " ,
nread , smb_len ( outbuf ) ) ) ;
}
else
send_smb ( Client , outbuf ) ;
}
trans_num + + ;
}
1997-09-23 23:19:06 +04:00
/****************************************************************************
open the oplock IPC socket communication
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL open_oplock_ipc ( )
{
struct sockaddr_in sock_name ;
1997-10-04 09:24:02 +04:00
int len = sizeof ( sock_name ) ;
1997-09-23 23:19:06 +04:00
DEBUG ( 3 , ( " open_oplock_ipc: opening loopback UDP socket. \n " ) ) ;
/* Open a lookback UDP socket on a random port. */
1997-09-25 04:25:44 +04:00
oplock_sock = open_socket_in ( SOCK_DGRAM , 0 , 0 , htonl ( INADDR_LOOPBACK ) ) ;
1997-09-23 23:19:06 +04:00
if ( oplock_sock = = - 1 )
1997-09-25 04:25:44 +04:00
{
DEBUG ( 0 , ( " open_oplock_ipc: Failed to get local UDP socket for \
1997-09-26 23:26:56 +04:00
address % x . Error was % s \ n " , htonl(INADDR_LOOPBACK), strerror(errno)));
oplock_port = 0 ;
1997-09-23 23:19:06 +04:00
return ( False ) ;
1997-09-25 04:25:44 +04:00
}
1997-09-23 23:19:06 +04:00
/* Find out the transient UDP port we have been allocated. */
1997-10-04 09:24:02 +04:00
if ( getsockname ( oplock_sock , ( struct sockaddr * ) & sock_name , & len ) < 0 )
1997-09-23 23:19:06 +04:00
{
DEBUG ( 0 , ( " open_oplock_ipc: Failed to get local UDP port. Error was %s \n " ,
strerror ( errno ) ) ) ;
close ( oplock_sock ) ;
oplock_sock = - 1 ;
1997-09-26 23:26:56 +04:00
oplock_port = 0 ;
1997-09-23 23:19:06 +04:00
return False ;
}
oplock_port = ntohs ( sock_name . sin_port ) ;
1997-10-07 22:46:19 +04:00
DEBUG ( 3 , ( " open_oplock ipc: pid = %d, oplock_port = %u \n " ,
getpid ( ) , oplock_port ) ) ;
1997-09-23 23:19:06 +04:00
return True ;
}
/****************************************************************************
process an oplock break message .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-04 09:24:02 +04:00
static BOOL process_local_message ( int sock , char * buffer , int buf_size )
1997-09-23 23:19:06 +04:00
{
int32 msg_len ;
1997-10-22 02:51:21 +04:00
uint16 from_port ;
1997-09-23 23:19:06 +04:00
char * msg_start ;
1997-09-30 06:38:19 +04:00
msg_len = IVAL ( buffer , UDP_CMD_LEN_OFFSET ) ;
from_port = SVAL ( buffer , UDP_CMD_PORT_OFFSET ) ;
msg_start = & buffer [ UDP_CMD_HEADER_LEN ] ;
DEBUG ( 5 , ( " process_local_message: Got a message of length %d from port (%d) \n " ,
msg_len , from_port ) ) ;
/* Switch on message command - currently OPLOCK_BREAK_CMD is the
only valid request . */
switch ( SVAL ( msg_start , UDP_MESSAGE_CMD_OFFSET ) )
{
case OPLOCK_BREAK_CMD :
/* Ensure that the msg length is correct. */
if ( msg_len ! = OPLOCK_BREAK_MSG_LEN )
{
DEBUG ( 0 , ( " process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, \
should be % d ) . \ n " , msg_len, OPLOCK_BREAK_MSG_LEN));
return False ;
}
{
uint32 remotepid = IVAL ( msg_start , OPLOCK_BREAK_PID_OFFSET ) ;
uint32 dev = IVAL ( msg_start , OPLOCK_BREAK_DEV_OFFSET ) ;
uint32 inode = IVAL ( msg_start , OPLOCK_BREAK_INODE_OFFSET ) ;
1997-10-03 07:15:24 +04:00
struct timeval tval ;
1997-09-30 06:38:19 +04:00
struct sockaddr_in toaddr ;
1997-10-03 07:15:24 +04:00
tval . tv_sec = IVAL ( msg_start , OPLOCK_BREAK_SEC_OFFSET ) ;
tval . tv_usec = IVAL ( msg_start , OPLOCK_BREAK_USEC_OFFSET ) ;
1997-09-30 06:38:19 +04:00
DEBUG ( 5 , ( " process_local_message: oplock break request from \
1997-10-02 03:32:22 +04:00
pid % d , port % d , dev = % x , inode = % x \ n " , remotepid, from_port, dev, inode));
1997-09-30 06:38:19 +04:00
/*
* If we have no record of any currently open oplocks ,
* it ' s not an error , as a close command may have
* just been issued on the file that was oplocked .
* Just return success in this case .
*/
if ( global_oplocks_open ! = 0 )
{
1997-10-03 07:15:24 +04:00
if ( oplock_break ( dev , inode , & tval ) = = False )
1997-09-30 06:38:19 +04:00
{
DEBUG ( 0 , ( " process_local_message: oplock break failed - \
not returning udp message . \ n " ));
return False ;
}
}
else
{
DEBUG ( 3 , ( " process_local_message: oplock break requested with no outstanding \
oplocks . Returning success . \ n " ));
}
/* Send the message back after OR'ing in the 'REPLY' bit. */
SSVAL ( msg_start , UDP_MESSAGE_CMD_OFFSET , OPLOCK_BREAK_CMD | CMD_REPLY ) ;
bzero ( ( char * ) & toaddr , sizeof ( toaddr ) ) ;
toaddr . sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ;
toaddr . sin_port = htons ( from_port ) ;
toaddr . sin_family = AF_INET ;
1997-10-04 09:24:02 +04:00
if ( sendto ( sock , msg_start , OPLOCK_BREAK_MSG_LEN , 0 ,
1997-09-30 06:38:19 +04:00
( struct sockaddr * ) & toaddr , sizeof ( toaddr ) ) < 0 )
{
DEBUG ( 0 , ( " process_local_message: sendto process %d failed. Errno was %s \n " ,
remotepid , strerror ( errno ) ) ) ;
return False ;
}
1997-10-02 03:32:22 +04:00
DEBUG ( 5 , ( " process_local_message: oplock break reply sent to \
pid % d , port % d , for file dev = % x , inode = % x \ n " , remotepid,
from_port , dev , inode ) ) ;
1997-09-30 06:38:19 +04:00
}
break ;
1997-10-07 22:46:19 +04:00
/*
* Keep this as a debug case - eventually we can remove it .
*/
case 0x8001 :
DEBUG ( 0 , ( " process_local_message: Received unsolicited break \
reply - dumping info . \ n " ));
if ( msg_len ! = OPLOCK_BREAK_MSG_LEN )
{
DEBUG ( 0 , ( " process_local_message: ubr: incorrect length for reply \
( was % d , should be % d ) . \ n " , msg_len, OPLOCK_BREAK_MSG_LEN));
return False ;
}
{
uint32 remotepid = IVAL ( msg_start , OPLOCK_BREAK_PID_OFFSET ) ;
uint32 dev = IVAL ( msg_start , OPLOCK_BREAK_DEV_OFFSET ) ;
uint32 inode = IVAL ( msg_start , OPLOCK_BREAK_INODE_OFFSET ) ;
DEBUG ( 0 , ( " process_local_message: unsolicited oplock break reply from \
pid % d , port % d , dev = % x , inode = % x \ n " , remotepid, from_port, dev, inode));
}
return False ;
1997-09-30 06:38:19 +04:00
default :
DEBUG ( 0 , ( " process_local_message: unknown UDP message command code (%x) - ignoring. \n " ,
( unsigned int ) SVAL ( msg_start , 0 ) ) ) ;
return False ;
}
return True ;
}
/****************************************************************************
Process an oplock break directly .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-03 07:15:24 +04:00
BOOL oplock_break ( uint32 dev , uint32 inode , struct timeval * tval )
1997-09-30 06:38:19 +04:00
{
extern int Client ;
static char * inbuf = NULL ;
static char * outbuf = NULL ;
files_struct * fsp = NULL ;
int fnum ;
1997-10-02 03:32:22 +04:00
time_t start_time ;
BOOL shutdown_server = False ;
1997-09-30 06:38:19 +04:00
1997-11-06 22:11:16 +03:00
DEBUG ( 3 , ( " %s oplock_break: called for dev = %x, inode = %x. Current \
global_oplocks_open = % d \ n " , timestring(), dev, inode, global_oplocks_open));
1997-10-02 07:26:07 +04:00
1997-09-30 06:38:19 +04:00
if ( inbuf = = NULL )
{
inbuf = ( char * ) malloc ( BUFFER_SIZE + SAFETY_MARGIN ) ;
if ( inbuf = = NULL ) {
DEBUG ( 0 , ( " oplock_break: malloc fail for input buffer. \n " ) ) ;
return False ;
}
outbuf = ( char * ) malloc ( BUFFER_SIZE + SAFETY_MARGIN ) ;
if ( outbuf = = NULL ) {
DEBUG ( 0 , ( " oplock_break: malloc fail for output buffer. \n " ) ) ;
free ( inbuf ) ;
inbuf = NULL ;
return False ;
}
}
/* We need to search the file open table for the
entry containing this dev and inode , and ensure
we have an oplock on it . */
for ( fnum = 0 ; fnum < MAX_OPEN_FILES ; fnum + + )
{
if ( OPEN_FNUM ( fnum ) )
{
fsp = & Files [ fnum ] ;
1997-10-03 07:15:24 +04:00
if ( ( fsp - > fd_ptr - > dev = = dev ) & & ( fsp - > fd_ptr - > inode = = inode ) & &
( fsp - > open_time . tv_sec = = tval - > tv_sec ) & &
( fsp - > open_time . tv_usec = = tval - > tv_usec ) )
1997-09-30 06:38:19 +04:00
break ;
}
}
if ( fsp = = NULL )
{
/* The file could have been closed in the meantime - return success. */
1997-11-06 22:11:16 +03:00
DEBUG ( 3 , ( " %s oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
allowing break to succeed . \ n " , timestring(), dev, inode, fnum));
1997-09-30 06:38:19 +04:00
return True ;
}
/* Ensure we have an oplock on the file */
1997-09-23 23:19:06 +04:00
1997-10-04 00:36:06 +04:00
/* There is a potential race condition in that an oplock could
have been broken due to another udp request , and yet there are
still oplock break messages being sent in the udp message
queue for this file . So return true if we don ' t have an oplock ,
1997-10-04 04:23:57 +04:00
as we may have just freed it .
1997-09-30 06:38:19 +04:00
*/
1997-09-23 23:19:06 +04:00
1997-09-30 06:38:19 +04:00
if ( ! fsp - > granted_oplock )
1997-09-23 23:19:06 +04:00
{
1997-11-06 22:11:16 +03:00
DEBUG ( 3 , ( " %s oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. \
Allowing break to succeed regardless . \ n " , timestring(), fsp->name, fnum, dev, inode));
1997-10-04 00:36:06 +04:00
return True ;
1997-09-23 23:19:06 +04:00
}
1997-09-30 06:38:19 +04:00
/* Now comes the horrid part. We must send an oplock break to the client,
and then process incoming messages until we get a close or oplock release .
*/
/* Prepare the SMBlockingX message. */
bzero ( outbuf , smb_size ) ;
set_message ( outbuf , 8 , 0 , True ) ;
SCVAL ( outbuf , smb_com , SMBlockingX ) ;
SSVAL ( outbuf , smb_tid , fsp - > cnum ) ;
SSVAL ( outbuf , smb_pid , 0xFFFF ) ;
SSVAL ( outbuf , smb_uid , 0 ) ;
SSVAL ( outbuf , smb_mid , 0xFFFF ) ;
SCVAL ( outbuf , smb_vwv0 , 0xFF ) ;
SSVAL ( outbuf , smb_vwv2 , fnum ) ;
SCVAL ( outbuf , smb_vwv3 , LOCKING_ANDX_OPLOCK_RELEASE ) ;
/* Change this when we have level II oplocks. */
SCVAL ( outbuf , smb_vwv3 + 1 , OPLOCKLEVEL_NONE ) ;
send_smb ( Client , outbuf ) ;
global_oplock_break = True ;
/* Process incoming messages. */
1997-10-02 03:32:22 +04:00
/* JRA - If we don't get a break from the client in OPLOCK_BREAK_TIMEOUT
seconds we should just die . . . . */
start_time = time ( NULL ) ;
while ( OPEN_FNUM ( fnum ) & & fsp - > granted_oplock )
1997-09-25 04:25:44 +04:00
{
1997-09-30 06:38:19 +04:00
if ( receive_smb ( Client , inbuf , OPLOCK_BREAK_TIMEOUT * 1000 ) = = False )
{
1997-10-02 03:32:22 +04:00
/*
* Die if we got an error .
*/
1997-09-30 06:38:19 +04:00
if ( smb_read_error = = READ_EOF )
1997-11-06 22:11:16 +03:00
DEBUG ( 0 , ( " %s oplock_break: end of file from client \n " , timestring ( ) ) ) ;
1997-09-30 06:38:19 +04:00
if ( smb_read_error = = READ_ERROR )
1997-11-06 22:11:16 +03:00
DEBUG ( 0 , ( " %s oplock_break: receive_smb error (%s) \n " ,
timestring ( ) , strerror ( errno ) ) ) ;
1997-10-02 03:32:22 +04:00
if ( smb_read_error = = READ_TIMEOUT )
1997-11-06 22:11:16 +03:00
DEBUG ( 0 , ( " %s oplock_break: receive_smb timed out after %d seconds. \n " ,
timestring ( ) , OPLOCK_BREAK_TIMEOUT ) ) ;
1997-10-02 03:32:22 +04:00
1997-11-06 22:11:16 +03:00
DEBUG ( 0 , ( " %s oplock_break failed for file %s (fnum = %d, dev = %x, \
inode = % x ) . \ n " , timestring(), fsp->name, fnum, dev, inode));
1997-10-02 03:32:22 +04:00
shutdown_server = True ;
break ;
1997-09-30 06:38:19 +04:00
}
process_smb ( inbuf , outbuf ) ;
1997-10-02 03:32:22 +04:00
/* We only need this in case a readraw crossed on the wire. */
1997-10-04 00:36:06 +04:00
if ( global_oplock_break )
global_oplock_break = False ;
1997-10-02 03:32:22 +04:00
/*
* Die if we go over the time limit .
*/
if ( ( time ( NULL ) - start_time ) > OPLOCK_BREAK_TIMEOUT )
{
1997-11-06 22:11:16 +03:00
DEBUG ( 0 , ( " %s oplock_break: no break received from client within \
% d seconds . \ n " , timestring(), OPLOCK_BREAK_TIMEOUT));
DEBUG ( 0 , ( " %s oplock_break failed for file %s (fnum = %d, dev = %x, \
inode = % x ) . \ n " , timestring(), fsp->name, fnum, dev, inode));
1997-10-02 03:32:22 +04:00
shutdown_server = True ;
break ;
}
}
/*
* If the client did not respond we must die .
*/
if ( shutdown_server )
{
1997-11-06 22:11:16 +03:00
DEBUG ( 0 , ( " %s oplock_break: client failure in break - shutting down this smbd. \n " ,
timestring ( ) ) ) ;
1997-10-02 03:32:22 +04:00
close_sockets ( ) ;
close ( oplock_sock ) ;
exit_server ( " oplock break failure " ) ;
}
if ( OPEN_FNUM ( fnum ) )
{
1997-10-04 00:36:06 +04:00
/* The lockingX reply will have removed the oplock flag
from the sharemode . */
/* Paranoia.... */
fsp - > granted_oplock = False ;
1997-10-02 03:32:22 +04:00
}
global_oplocks_open - - ;
/* Santity check - remove this later. JRA */
if ( global_oplocks_open < 0 )
{
DEBUG ( 0 , ( " oplock_break: global_oplocks_open < 0 (%d). PANIC ERROR \n " ,
global_oplocks_open ) ) ;
1997-10-09 22:40:52 +04:00
exit_server ( " oplock_break: global_oplocks_open < 0 " ) ;
1997-09-25 04:25:44 +04:00
}
1997-11-06 22:11:16 +03:00
DEBUG ( 3 , ( " %s oplock_break: returning success for fnum = %d, dev = %x, inode = %x. Current \
global_oplocks_open = % d \ n " , timestring(), fnum, dev, inode, global_oplocks_open));
1997-10-02 07:26:07 +04:00
1997-09-23 23:19:06 +04:00
return True ;
}
1997-09-30 06:38:19 +04:00
/****************************************************************************
Send an oplock break message to another smbd process . If the oplock is held
by the local smbd then call the oplock break function directly .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-20 12:46:00 +04:00
BOOL request_oplock_break ( share_mode_entry * share_entry ,
1997-09-30 06:38:19 +04:00
uint32 dev , uint32 inode )
{
char op_break_msg [ OPLOCK_BREAK_MSG_LEN ] ;
struct sockaddr_in addr_out ;
int pid = getpid ( ) ;
if ( pid = = share_entry - > pid )
{
/* We are breaking our own oplock, make sure it's us. */
if ( share_entry - > op_port ! = oplock_port )
{
1997-10-02 04:57:59 +04:00
DEBUG ( 0 , ( " request_oplock_break: corrupt share mode entry - pid = %d, port = %d \
1997-09-30 06:38:19 +04:00
should be % d \ n " , pid, share_entry->op_port, oplock_port));
return False ;
}
1997-10-03 07:15:24 +04:00
DEBUG ( 5 , ( " request_oplock_break: breaking our own oplock \n " ) ) ;
1997-09-30 06:38:19 +04:00
/* Call oplock break direct. */
1997-10-03 07:15:24 +04:00
return oplock_break ( dev , inode , & share_entry - > time ) ;
1997-09-30 06:38:19 +04:00
}
/* We need to send a OPLOCK_BREAK_CMD message to the
port in the share mode entry . */
SSVAL ( op_break_msg , UDP_MESSAGE_CMD_OFFSET , OPLOCK_BREAK_CMD ) ;
SIVAL ( op_break_msg , OPLOCK_BREAK_PID_OFFSET , pid ) ;
SIVAL ( op_break_msg , OPLOCK_BREAK_DEV_OFFSET , dev ) ;
SIVAL ( op_break_msg , OPLOCK_BREAK_INODE_OFFSET , inode ) ;
1997-10-03 07:15:24 +04:00
SIVAL ( op_break_msg , OPLOCK_BREAK_SEC_OFFSET , ( uint32 ) share_entry - > time . tv_sec ) ;
SIVAL ( op_break_msg , OPLOCK_BREAK_USEC_OFFSET , ( uint32 ) share_entry - > time . tv_usec ) ;
1997-09-30 06:38:19 +04:00
/* set the address and port */
bzero ( ( char * ) & addr_out , sizeof ( addr_out ) ) ;
addr_out . sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ;
addr_out . sin_port = htons ( share_entry - > op_port ) ;
addr_out . sin_family = AF_INET ;
1997-11-06 22:11:16 +03:00
DEBUG ( 3 , ( " %s request_oplock_break: sending a oplock break message to pid %d on port %d \
for dev = % x , inode = % x \ n " , timestring(), share_entry->pid, share_entry->op_port, dev, inode));
1997-09-30 06:38:19 +04:00
if ( sendto ( oplock_sock , op_break_msg , OPLOCK_BREAK_MSG_LEN , 0 ,
( struct sockaddr * ) & addr_out , sizeof ( addr_out ) ) < 0 )
{
1997-11-06 22:11:16 +03:00
DEBUG ( 0 , ( " %s request_oplock_break: failed when sending a oplock break message \
1997-09-30 06:38:19 +04:00
to pid % d on port % d for dev = % x , inode = % x . Error was % s \ n " ,
1997-11-06 22:11:16 +03:00
timestring ( ) , share_entry - > pid , share_entry - > op_port , dev , inode ,
1997-09-30 06:38:19 +04:00
strerror ( errno ) ) ) ;
return False ;
}
/*
* Now we must await the oplock broken message coming back
* from the target smbd process . Timeout if it fails to
1997-11-06 22:11:16 +03:00
* return in ( OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR ) seconds .
1997-09-30 06:38:19 +04:00
* While we get messages that aren ' t ours , loop .
*/
while ( 1 )
{
char op_break_reply [ UDP_CMD_HEADER_LEN + OPLOCK_BREAK_MSG_LEN ] ;
int32 reply_msg_len ;
1997-10-22 02:51:21 +04:00
uint16 reply_from_port ;
1997-09-30 06:38:19 +04:00
char * reply_msg_start ;
if ( receive_local_message ( oplock_sock , op_break_reply , sizeof ( op_break_reply ) ,
1997-11-06 22:11:16 +03:00
( OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR ) * 1000 ) = = False )
1997-09-30 06:38:19 +04:00
{
if ( smb_read_error = = READ_TIMEOUT )
1997-11-06 22:11:16 +03:00
{
DEBUG ( 0 , ( " %s request_oplock_break: no response received to oplock break request to \
pid % d on port % d for dev = % x , inode = % x \ n " , timestring(), share_entry->pid,
1997-09-30 06:38:19 +04:00
share_entry - > op_port , dev , inode ) ) ;
1997-11-06 22:11:16 +03:00
/*
* This is a hack to make handling of failing clients more robust .
* If a oplock break response message is not received in the timeout
* period we may assume that the smbd servicing that client holding
* the oplock has died and the client changes were lost anyway , so
* we should continue to try and open the file .
*/
break ;
}
1997-09-30 06:38:19 +04:00
else
1997-11-06 22:11:16 +03:00
DEBUG ( 0 , ( " %s request_oplock_break: error in response received to oplock break request to \
pid % d on port % d for dev = % x , inode = % x . Error was ( % s ) . \ n " , timestring, share_entry->pid,
1997-09-30 06:38:19 +04:00
share_entry - > op_port , dev , inode , strerror ( errno ) ) ) ;
return False ;
}
/*
* If the response we got was not an answer to our message , but
* was a completely different request , push it onto the pending
* udp message stack so that we can deal with it in the main loop .
* It may be another oplock break request to us .
*/
/*
* Local note from JRA . There exists the possibility of a denial
* of service attack here by allowing non - root processes running
* on a local machine sending many of these pending messages to
* a smbd port . Currently I ' m not sure how to restrict the messages
* I will queue ( although I could add a limit to the queue ) to
* those received by root processes only . There should be a
* way to make this bulletproof . . . .
*/
reply_msg_len = IVAL ( op_break_reply , UDP_CMD_LEN_OFFSET ) ;
reply_from_port = SVAL ( op_break_reply , UDP_CMD_PORT_OFFSET ) ;
reply_msg_start = & op_break_reply [ UDP_CMD_HEADER_LEN ] ;
if ( reply_msg_len ! = OPLOCK_BREAK_MSG_LEN )
{
/* Ignore it. */
1997-11-06 22:11:16 +03:00
DEBUG ( 0 , ( " %s request_oplock_break: invalid message length received. Ignoring \n " ,
timestring ( ) ) ) ;
1997-09-30 06:38:19 +04:00
continue ;
}
if ( ( ( SVAL ( reply_msg_start , UDP_MESSAGE_CMD_OFFSET ) & CMD_REPLY ) = = 0 ) | |
( reply_from_port ! = share_entry - > op_port ) | |
( memcmp ( & reply_msg_start [ OPLOCK_BREAK_PID_OFFSET ] ,
& op_break_msg [ OPLOCK_BREAK_PID_OFFSET ] ,
OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET ) ! = 0 ) )
{
1997-11-06 22:11:16 +03:00
DEBUG ( 3 , ( " %s request_oplock_break: received other message whilst awaiting \
1997-09-30 06:38:19 +04:00
oplock break response from pid % d on port % d for dev = % x , inode = % x . \ n " ,
1997-11-06 22:11:16 +03:00
timestring ( ) , share_entry - > pid , share_entry - > op_port , dev , inode ) ) ;
1997-09-30 06:38:19 +04:00
if ( push_local_message ( op_break_reply , sizeof ( op_break_reply ) ) = = False )
return False ;
1997-10-07 22:46:19 +04:00
continue ;
1997-09-30 06:38:19 +04:00
}
break ;
}
1997-11-06 22:11:16 +03:00
DEBUG ( 3 , ( " %s request_oplock_break: broke oplock. \n " , timestring ( ) ) ) ;
1997-09-30 06:38:19 +04:00
return True ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
check if a snum is in use
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL snum_used ( int snum )
{
int i ;
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
if ( OPEN_CNUM ( i ) & & ( SNUM ( i ) = = snum ) )
return ( True ) ;
return ( False ) ;
}
/****************************************************************************
reload the services file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL reload_services ( BOOL test )
{
BOOL ret ;
if ( lp_loaded ( ) )
{
pstring fname ;
1997-09-26 22:55:29 +04:00
pstrcpy ( fname , lp_configfile ( ) ) ;
1996-05-04 11:50:46 +04:00
if ( file_exist ( fname , NULL ) & & ! strcsequal ( fname , servicesf ) )
{
1997-09-26 22:55:29 +04:00
pstrcpy ( servicesf , fname ) ;
1996-05-04 11:50:46 +04:00
test = False ;
}
}
reopen_logs ( ) ;
if ( test & & ! lp_file_list_changed ( ) )
return ( True ) ;
lp_killunused ( snum_used ) ;
ret = lp_load ( servicesf , False ) ;
/* perhaps the config filename is now set */
if ( ! test )
reload_services ( True ) ;
reopen_logs ( ) ;
1996-06-06 15:43:09 +04:00
load_interfaces ( ) ;
1996-05-04 11:50:46 +04:00
{
extern int Client ;
if ( Client ! = - 1 ) {
set_socket_options ( Client , " SO_KEEPALIVE " ) ;
set_socket_options ( Client , user_socket_options ) ;
}
}
1997-11-07 06:06:24 +03:00
reset_mangled_stack ( lp_mangledstack ( ) ) ;
1996-05-04 11:50:46 +04:00
/* this forces service parameters to be flushed */
become_service ( - 1 , True ) ;
return ( ret ) ;
}
/****************************************************************************
this prevents zombie child processes
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sig_hup ( )
{
1996-08-15 19:11:34 +04:00
BlockSignals ( True , SIGHUP ) ;
1996-05-04 11:50:46 +04:00
DEBUG ( 0 , ( " Got SIGHUP \n " ) ) ;
reload_services ( False ) ;
# ifndef DONT_REINSTALL_SIG
signal ( SIGHUP , SIGNAL_CAST sig_hup ) ;
# endif
1996-08-15 19:11:34 +04:00
BlockSignals ( False , SIGHUP ) ;
1996-05-04 11:50:46 +04:00
return ( 0 ) ;
}
/****************************************************************************
Setup the groups a user belongs to .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int setup_groups ( char * user , int uid , int gid , int * p_ngroups ,
1997-10-10 18:48:05 +04:00
int * * p_igroups , gid_t * * p_groups ,
int * * p_attrs )
1996-05-04 11:50:46 +04:00
{
if ( - 1 = = initgroups ( user , gid ) )
{
if ( getuid ( ) = = 0 )
{
DEBUG ( 0 , ( " Unable to initgroups! \n " ) ) ;
if ( gid < 0 | | gid > 16000 | | uid < 0 | | uid > 16000 )
DEBUG ( 0 , ( " This is probably a problem with the account %s \n " , user ) ) ;
}
}
else
{
int i , ngroups ;
int * igroups ;
1997-10-10 18:48:05 +04:00
int * attrs ;
1996-05-04 11:50:46 +04:00
gid_t grp = 0 ;
ngroups = getgroups ( 0 , & grp ) ;
if ( ngroups < = 0 )
ngroups = 32 ;
igroups = ( int * ) malloc ( sizeof ( int ) * ngroups ) ;
1997-10-10 18:48:05 +04:00
attrs = ( int * ) malloc ( sizeof ( int ) * ngroups ) ;
1996-05-04 11:50:46 +04:00
for ( i = 0 ; i < ngroups ; i + + )
1997-10-10 18:48:05 +04:00
{
attrs [ i ] = 0x7 ; /* XXXX don't know what NT user attributes are yet! */
1996-05-04 11:50:46 +04:00
igroups [ i ] = 0x42424242 ;
1997-10-10 18:48:05 +04:00
}
1996-05-04 11:50:46 +04:00
ngroups = getgroups ( ngroups , ( gid_t * ) igroups ) ;
if ( igroups [ 0 ] = = 0x42424242 )
ngroups = 0 ;
* p_ngroups = ngroups ;
1997-10-10 18:48:05 +04:00
* p_attrs = attrs ;
1996-05-04 11:50:46 +04:00
/* The following bit of code is very strange. It is due to the
fact that some OSes use int * and some use gid_t * for
getgroups , and some ( like SunOS ) use both , one in prototypes ,
and one in man pages and the actual code . Thus we detect it
dynamically using some very ugly code */
if ( ngroups > 0 )
{
/* does getgroups return ints or gid_t ?? */
static BOOL groups_use_ints = True ;
if ( groups_use_ints & &
ngroups = = 1 & &
SVAL ( igroups , 2 ) = = 0x4242 )
groups_use_ints = False ;
for ( i = 0 ; groups_use_ints & & i < ngroups ; i + + )
if ( igroups [ i ] = = 0x42424242 )
groups_use_ints = False ;
if ( groups_use_ints )
1997-10-10 18:48:05 +04:00
{
1996-05-04 11:50:46 +04:00
* p_igroups = igroups ;
* p_groups = ( gid_t * ) igroups ;
1997-10-10 18:48:05 +04:00
}
1996-05-04 11:50:46 +04:00
else
1997-10-10 18:48:05 +04:00
{
1996-05-04 11:50:46 +04:00
gid_t * groups = ( gid_t * ) igroups ;
igroups = ( int * ) malloc ( sizeof ( int ) * ngroups ) ;
for ( i = 0 ; i < ngroups ; i + + )
1997-10-10 18:48:05 +04:00
{
1996-05-04 11:50:46 +04:00
igroups [ i ] = groups [ i ] ;
1997-10-10 18:48:05 +04:00
}
1996-05-04 11:50:46 +04:00
* p_igroups = igroups ;
* p_groups = ( gid_t * ) groups ;
}
}
DEBUG ( 3 , ( " %s is in %d groups \n " , user , ngroups ) ) ;
for ( i = 0 ; i < ngroups ; i + + )
DEBUG ( 3 , ( " %d " , igroups [ i ] ) ) ;
DEBUG ( 3 , ( " \n " ) ) ;
}
return 0 ;
}
/****************************************************************************
make a connection to a service
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-10-26 00:42:46 +04:00
int make_connection ( char * service , char * user , char * password , int pwlen , char * dev , uint16 vuid )
1996-05-04 11:50:46 +04:00
{
int cnum ;
int snum ;
struct passwd * pass = NULL ;
connection_struct * pcon ;
BOOL guest = False ;
BOOL force = False ;
static BOOL first_connection = True ;
strlower ( service ) ;
snum = find_service ( service ) ;
if ( snum < 0 )
{
if ( strequal ( service , " IPC$ " ) )
{
DEBUG ( 3 , ( " %s refusing IPC connection \n " , timestring ( ) ) ) ;
return ( - 3 ) ;
}
DEBUG ( 0 , ( " %s couldn't find service %s \n " , timestring ( ) , service ) ) ;
return ( - 2 ) ;
}
if ( strequal ( service , HOMES_NAME ) )
{
if ( * user & & Get_Pwnam ( user , True ) )
return ( make_connection ( user , user , password , pwlen , dev , vuid ) ) ;
if ( validated_username ( vuid ) )
{
strcpy ( user , validated_username ( vuid ) ) ;
return ( make_connection ( user , user , password , pwlen , dev , vuid ) ) ;
}
}
if ( ! lp_snum_ok ( snum ) | | ! check_access ( snum ) ) {
return ( - 4 ) ;
}
/* you can only connect to the IPC$ service as an ipc device */
if ( strequal ( service , " IPC$ " ) )
strcpy ( dev , " IPC " ) ;
if ( * dev = = ' ? ' | | ! * dev )
{
if ( lp_print_ok ( snum ) )
strcpy ( dev , " LPT1: " ) ;
else
strcpy ( dev , " A: " ) ;
}
/* if the request is as a printer and you can't print then refuse */
strupper ( dev ) ;
if ( ! lp_print_ok ( snum ) & & ( strncmp ( dev , " LPT " , 3 ) = = 0 ) ) {
DEBUG ( 1 , ( " Attempt to connect to non-printer as a printer \n " ) ) ;
return ( - 6 ) ;
}
/* lowercase the user name */
strlower ( user ) ;
/* add it as a possible user name */
add_session_user ( service ) ;
/* shall we let them in? */
if ( ! authorise_login ( snum , user , password , pwlen , & guest , & force , vuid ) )
{
DEBUG ( 2 , ( " %s invalid username/password for %s \n " , timestring ( ) , service ) ) ;
return ( - 1 ) ;
}
cnum = find_free_connection ( str_checksum ( service ) + str_checksum ( user ) ) ;
if ( cnum < 0 )
{
DEBUG ( 0 , ( " %s couldn't find free connection \n " , timestring ( ) ) ) ;
return ( - 1 ) ;
}
pcon = & Connections [ cnum ] ;
bzero ( ( char * ) pcon , sizeof ( * pcon ) ) ;
/* find out some info about the user */
pass = Get_Pwnam ( user , True ) ;
if ( pass = = NULL )
{
DEBUG ( 0 , ( " %s couldn't find account %s \n " , timestring ( ) , user ) ) ;
return ( - 7 ) ;
}
pcon - > read_only = lp_readonly ( snum ) ;
{
pstring list ;
StrnCpy ( list , lp_readlist ( snum ) , sizeof ( pstring ) - 1 ) ;
string_sub ( list , " %S " , service ) ;
if ( user_in_list ( user , list ) )
pcon - > read_only = True ;
StrnCpy ( list , lp_writelist ( snum ) , sizeof ( pstring ) - 1 ) ;
string_sub ( list , " %S " , service ) ;
if ( user_in_list ( user , list ) )
pcon - > read_only = False ;
}
/* admin user check */
1997-10-08 04:21:39 +04:00
/* JRA - original code denied admin user if the share was
marked read_only . Changed as I don ' t think this is needed ,
but old code left in case there is a problem here .
*/
if ( user_in_list ( user , lp_admin_users ( snum ) )
#if 0
& & ! pcon - > read_only )
# else
)
# endif
1996-05-04 11:50:46 +04:00
{
pcon - > admin_user = True ;
DEBUG ( 0 , ( " %s logged in as admin user (root privileges) \n " , user ) ) ;
}
else
pcon - > admin_user = False ;
pcon - > force_user = force ;
1996-10-26 00:42:46 +04:00
pcon - > vuid = vuid ;
1996-05-04 11:50:46 +04:00
pcon - > uid = pass - > pw_uid ;
pcon - > gid = pass - > pw_gid ;
pcon - > num_files_open = 0 ;
pcon - > lastused = time ( NULL ) ;
pcon - > service = snum ;
pcon - > used = True ;
pcon - > printer = ( strncmp ( dev , " LPT " , 3 ) = = 0 ) ;
pcon - > ipc = ( strncmp ( dev , " IPC " , 3 ) = = 0 ) ;
pcon - > dirptr = NULL ;
1997-07-24 21:25:11 +04:00
pcon - > veto_list = NULL ;
pcon - > hide_list = NULL ;
1996-05-04 11:50:46 +04:00
string_set ( & pcon - > dirpath , " " ) ;
string_set ( & pcon - > user , user ) ;
# if HAVE_GETGRNAM
if ( * lp_force_group ( snum ) )
{
1997-01-09 21:02:17 +03:00
struct group * gptr ;
pstring gname ;
StrnCpy ( gname , lp_force_group ( snum ) , sizeof ( pstring ) - 1 ) ;
/* default service may be a group name */
string_sub ( gname , " %S " , service ) ;
gptr = ( struct group * ) getgrnam ( gname ) ;
1996-05-04 11:50:46 +04:00
if ( gptr )
{
pcon - > gid = gptr - > gr_gid ;
1997-01-09 21:02:17 +03:00
DEBUG ( 3 , ( " Forced group %s \n " , gname ) ) ;
1996-05-04 11:50:46 +04:00
}
else
1997-01-09 21:02:17 +03:00
DEBUG ( 1 , ( " Couldn't find group %s \n " , gname ) ) ;
1996-05-04 11:50:46 +04:00
}
# endif
if ( * lp_force_user ( snum ) )
{
struct passwd * pass2 ;
fstring fuser ;
1997-09-26 22:55:29 +04:00
fstrcpy ( fuser , lp_force_user ( snum ) ) ;
1996-05-04 11:50:46 +04:00
pass2 = ( struct passwd * ) Get_Pwnam ( fuser , True ) ;
if ( pass2 )
{
pcon - > uid = pass2 - > pw_uid ;
string_set ( & pcon - > user , fuser ) ;
1997-09-26 22:55:29 +04:00
fstrcpy ( user , fuser ) ;
1996-05-04 11:50:46 +04:00
pcon - > force_user = True ;
DEBUG ( 3 , ( " Forced user %s \n " , fuser ) ) ;
}
else
DEBUG ( 1 , ( " Couldn't find user %s \n " , fuser ) ) ;
}
{
pstring s ;
1997-09-26 22:55:29 +04:00
pstrcpy ( s , lp_pathname ( snum ) ) ;
1996-05-04 11:50:46 +04:00
standard_sub ( cnum , s ) ;
string_set ( & pcon - > connectpath , s ) ;
DEBUG ( 3 , ( " Connect path is %s \n " , s ) ) ;
}
/* groups stuff added by ih */
pcon - > ngroups = 0 ;
1997-10-10 18:48:05 +04:00
pcon - > igroups = NULL ;
1996-05-04 11:50:46 +04:00
pcon - > groups = NULL ;
1997-10-10 18:48:05 +04:00
pcon - > attrs = NULL ;
1996-05-04 11:50:46 +04:00
1997-08-19 23:22:26 +04:00
if ( ! IS_IPC ( cnum ) )
{
/* Find all the groups this uid is in and store them. Used by become_user() */
1997-10-10 18:48:05 +04:00
setup_groups ( pcon - > user , pcon - > uid , pcon - > gid ,
& pcon - > ngroups , & pcon - > igroups , & pcon - > groups , & pcon - > attrs ) ;
1996-05-04 11:50:46 +04:00
1997-08-19 23:22:26 +04:00
/* check number of connections */
if ( ! claim_connection ( cnum ,
1996-05-04 11:50:46 +04:00
lp_servicename ( SNUM ( cnum ) ) ,
lp_max_connections ( SNUM ( cnum ) ) , False ) )
1997-08-19 23:22:26 +04:00
{
DEBUG ( 1 , ( " too many connections - rejected \n " ) ) ;
return ( - 8 ) ;
}
1996-05-04 11:50:46 +04:00
1997-08-19 23:22:26 +04:00
if ( lp_status ( SNUM ( cnum ) ) )
claim_connection ( cnum , " STATUS. " , MAXSTATUS , first_connection ) ;
1996-05-04 11:50:46 +04:00
1997-08-19 23:22:26 +04:00
first_connection = False ;
} /* IS_IPC */
1996-05-04 11:50:46 +04:00
pcon - > open = True ;
/* execute any "root preexec = " line */
if ( * lp_rootpreexec ( SNUM ( cnum ) ) )
{
pstring cmd ;
1997-09-26 22:55:29 +04:00
pstrcpy ( cmd , lp_rootpreexec ( SNUM ( cnum ) ) ) ;
1996-05-04 11:50:46 +04:00
standard_sub ( cnum , cmd ) ;
DEBUG ( 5 , ( " cmd=%s \n " , cmd ) ) ;
1996-10-04 13:31:07 +04:00
smbrun ( cmd , NULL , False ) ;
1996-05-04 11:50:46 +04:00
}
1997-10-25 14:58:18 +04:00
if ( ! become_user ( & Connections [ cnum ] , cnum , pcon - > vuid ) )
1996-05-04 11:50:46 +04:00
{
DEBUG ( 0 , ( " Can't become connected user! \n " ) ) ;
pcon - > open = False ;
1997-08-19 23:22:26 +04:00
if ( ! IS_IPC ( cnum ) ) {
yield_connection ( cnum ,
1996-05-04 11:50:46 +04:00
lp_servicename ( SNUM ( cnum ) ) ,
lp_max_connections ( SNUM ( cnum ) ) ) ;
1997-08-19 23:22:26 +04:00
if ( lp_status ( SNUM ( cnum ) ) ) yield_connection ( cnum , " STATUS. " , MAXSTATUS ) ;
1996-05-04 11:50:46 +04:00
}
1997-08-19 23:22:26 +04:00
return ( - 1 ) ;
1996-05-04 11:50:46 +04:00
}
if ( ChDir ( pcon - > connectpath ) ! = 0 )
{
1996-05-29 11:54:01 +04:00
DEBUG ( 0 , ( " Can't change directory to %s (%s) \n " ,
pcon - > connectpath , strerror ( errno ) ) ) ;
1996-05-04 11:50:46 +04:00
pcon - > open = False ;
unbecome_user ( ) ;
1997-08-19 23:22:26 +04:00
if ( ! IS_IPC ( cnum ) ) {
yield_connection ( cnum ,
1996-05-04 11:50:46 +04:00
lp_servicename ( SNUM ( cnum ) ) ,
lp_max_connections ( SNUM ( cnum ) ) ) ;
1997-08-19 23:22:26 +04:00
if ( lp_status ( SNUM ( cnum ) ) ) yield_connection ( cnum , " STATUS. " , MAXSTATUS ) ;
1996-05-04 11:50:46 +04:00
}
1997-08-19 23:22:26 +04:00
return ( - 5 ) ;
1996-05-04 11:50:46 +04:00
}
string_set ( & pcon - > origpath , pcon - > connectpath ) ;
# if SOFTLINK_OPTIMISATION
/* resolve any soft links early */
{
pstring s ;
1997-09-26 22:55:29 +04:00
pstrcpy ( s , pcon - > connectpath ) ;
1996-05-04 11:50:46 +04:00
GetWd ( s ) ;
string_set ( & pcon - > connectpath , s ) ;
ChDir ( pcon - > connectpath ) ;
}
# endif
num_connections_open + + ;
add_session_user ( user ) ;
/* execute any "preexec = " line */
if ( * lp_preexec ( SNUM ( cnum ) ) )
{
pstring cmd ;
1997-09-26 22:55:29 +04:00
pstrcpy ( cmd , lp_preexec ( SNUM ( cnum ) ) ) ;
1996-05-04 11:50:46 +04:00
standard_sub ( cnum , cmd ) ;
1996-10-04 13:31:07 +04:00
smbrun ( cmd , NULL , False ) ;
1996-05-04 11:50:46 +04:00
}
/* we've finished with the sensitive stuff */
unbecome_user ( ) ;
1997-07-24 21:25:11 +04:00
/* Add veto/hide lists */
if ( ! IS_IPC ( cnum ) & & ! IS_PRINT ( cnum ) )
{
set_namearray ( & pcon - > veto_list , lp_veto_files ( SNUM ( cnum ) ) ) ;
set_namearray ( & pcon - > hide_list , lp_hide_files ( SNUM ( cnum ) ) ) ;
}
1996-05-04 11:50:46 +04:00
{
DEBUG ( IS_IPC ( cnum ) ? 3 : 1 , ( " %s %s (%s) connect to service %s as user %s (uid=%d,gid=%d) (pid %d) \n " ,
timestring ( ) ,
1996-10-05 14:41:13 +04:00
remote_machine ,
client_addr ( ) ,
1996-05-04 11:50:46 +04:00
lp_servicename ( SNUM ( cnum ) ) , user ,
pcon - > uid ,
pcon - > gid ,
( int ) getpid ( ) ) ) ;
}
return ( cnum ) ;
}
/****************************************************************************
find first available file slot
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int find_free_file ( void )
{
int i ;
1996-05-31 19:13:29 +04:00
/* we start at 1 here for an obscure reason I can't now remember,
but I think is important : - ) */
1996-05-04 11:50:46 +04:00
for ( i = 1 ; i < MAX_OPEN_FILES ; i + + )
if ( ! Files [ i ] . open )
return ( i ) ;
DEBUG ( 1 , ( " ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES? \n " ) ) ;
return ( - 1 ) ;
}
/****************************************************************************
find first available connection slot , starting from a random position .
The randomisation stops problems with the server dieing and clients
thinking the server is still available .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int find_free_connection ( int hash )
{
int i ;
BOOL used = False ;
hash = ( hash % ( MAX_CONNECTIONS - 2 ) ) + 1 ;
again :
for ( i = hash + 1 ; i ! = hash ; )
{
if ( ! Connections [ i ] . open & & Connections [ i ] . used = = used )
{
DEBUG ( 3 , ( " found free connection number %d \n " , i ) ) ;
return ( i ) ;
}
i + + ;
if ( i = = MAX_CONNECTIONS )
i = 1 ;
}
if ( ! used )
{
used = ! used ;
goto again ;
}
DEBUG ( 1 , ( " ERROR! Out of connection structures \n " ) ) ;
return ( - 1 ) ;
}
/****************************************************************************
reply for the core protocol
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_corep ( char * outbuf )
{
int outsize = set_message ( outbuf , 1 , 0 , True ) ;
Protocol = PROTOCOL_CORE ;
return outsize ;
}
/****************************************************************************
reply for the coreplus protocol
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_coreplus ( char * outbuf )
{
int raw = ( lp_readraw ( ) ? 1 : 0 ) | ( lp_writeraw ( ) ? 2 : 0 ) ;
int outsize = set_message ( outbuf , 13 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv5 , raw ) ; /* tell redirector we support
readbraw and writebraw ( possibly ) */
CVAL ( outbuf , smb_flg ) = 0x81 ; /* Reply, SMBlockread, SMBwritelock supported */
SSVAL ( outbuf , smb_vwv1 , 0x1 ) ; /* user level security, don't encrypt */
Protocol = PROTOCOL_COREPLUS ;
return outsize ;
}
/****************************************************************************
reply for the lanman 1.0 protocol
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_lanman1 ( char * outbuf )
{
int raw = ( lp_readraw ( ) ? 1 : 0 ) | ( lp_writeraw ( ) ? 2 : 0 ) ;
int secword = 0 ;
BOOL doencrypt = SMBENCRYPT ( ) ;
time_t t = time ( NULL ) ;
if ( lp_security ( ) > = SEC_USER ) secword | = 1 ;
if ( doencrypt ) secword | = 2 ;
set_message ( outbuf , 13 , doencrypt ? 8 : 0 , True ) ;
SSVAL ( outbuf , smb_vwv1 , secword ) ;
/* Create a token value and add it to the outgoing packet. */
if ( doencrypt )
generate_next_challenge ( smb_buf ( outbuf ) ) ;
Protocol = PROTOCOL_LANMAN1 ;
CVAL ( outbuf , smb_flg ) = 0x81 ; /* Reply, SMBlockread, SMBwritelock supported */
1997-02-28 23:39:36 +03:00
SSVAL ( outbuf , smb_vwv2 , max_recv ) ;
1996-05-04 11:50:46 +04:00
SSVAL ( outbuf , smb_vwv3 , lp_maxmux ( ) ) ; /* maxmux */
SSVAL ( outbuf , smb_vwv4 , 1 ) ;
SSVAL ( outbuf , smb_vwv5 , raw ) ; /* tell redirector we support
readbraw writebraw ( possibly ) */
SIVAL ( outbuf , smb_vwv6 , getpid ( ) ) ;
SSVAL ( outbuf , smb_vwv10 , TimeDiff ( t ) / 60 ) ;
put_dos_date ( outbuf , smb_vwv8 , t ) ;
return ( smb_len ( outbuf ) + 4 ) ;
}
/****************************************************************************
reply for the lanman 2.0 protocol
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_lanman2 ( char * outbuf )
{
int raw = ( lp_readraw ( ) ? 1 : 0 ) | ( lp_writeraw ( ) ? 2 : 0 ) ;
int secword = 0 ;
BOOL doencrypt = SMBENCRYPT ( ) ;
time_t t = time ( NULL ) ;
1997-11-10 22:23:17 +03:00
struct cli_state * cli = NULL ;
1997-10-21 13:34:33 +04:00
char cryptkey [ 8 ] ;
char crypt_len = 0 ;
1997-11-10 22:23:17 +03:00
if ( lp_security ( ) = = SEC_SERVER ) {
cli = server_cryptkey ( ) ;
}
if ( cli ) {
1997-10-21 13:34:33 +04:00
DEBUG ( 3 , ( " using password server validation \n " ) ) ;
1997-11-10 22:23:17 +03:00
doencrypt = ( ( cli - > sec_mode & 2 ) ! = 0 ) ;
1997-10-21 13:34:33 +04:00
}
1996-05-04 11:50:46 +04:00
if ( lp_security ( ) > = SEC_USER ) secword | = 1 ;
if ( doencrypt ) secword | = 2 ;
1997-11-10 22:23:17 +03:00
if ( doencrypt ) {
1997-10-21 13:34:33 +04:00
crypt_len = 8 ;
1997-11-10 22:23:17 +03:00
if ( ! cli ) {
1997-10-21 13:34:33 +04:00
generate_next_challenge ( cryptkey ) ;
} else {
1997-11-10 22:23:17 +03:00
memcpy ( cryptkey , cli - > cryptkey , 8 ) ;
set_challenge ( cli - > cryptkey ) ;
1997-10-21 13:34:33 +04:00
}
}
set_message ( outbuf , 13 , crypt_len , True ) ;
1996-05-04 11:50:46 +04:00
SSVAL ( outbuf , smb_vwv1 , secword ) ;
1997-10-21 15:54:57 +04:00
SIVAL ( outbuf , smb_vwv6 , getpid ( ) ) ;
1996-05-04 11:50:46 +04:00
if ( doencrypt )
1997-10-21 13:34:33 +04:00
memcpy ( smb_buf ( outbuf ) , cryptkey , 8 ) ;
1996-05-04 11:50:46 +04:00
Protocol = PROTOCOL_LANMAN2 ;
CVAL ( outbuf , smb_flg ) = 0x81 ; /* Reply, SMBlockread, SMBwritelock supported */
1997-02-28 23:39:36 +03:00
SSVAL ( outbuf , smb_vwv2 , max_recv ) ;
1996-05-04 11:50:46 +04:00
SSVAL ( outbuf , smb_vwv3 , lp_maxmux ( ) ) ;
SSVAL ( outbuf , smb_vwv4 , 1 ) ;
SSVAL ( outbuf , smb_vwv5 , raw ) ; /* readbraw and/or writebraw */
SSVAL ( outbuf , smb_vwv10 , TimeDiff ( t ) / 60 ) ;
put_dos_date ( outbuf , smb_vwv8 , t ) ;
return ( smb_len ( outbuf ) + 4 ) ;
}
1997-03-09 17:58:22 +03:00
1996-05-04 11:50:46 +04:00
/****************************************************************************
reply for the nt protocol
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_nt1 ( char * outbuf )
{
1997-03-09 17:58:22 +03:00
/* dual names + lock_and_read + nt SMBs + remote API calls */
int capabilities = CAP_NT_FIND | CAP_LOCK_AND_READ ;
/*
other valid capabilities which we may support at some time . . .
CAP_LARGE_FILES | CAP_NT_SMBS | CAP_RPC_REMOTE_APIS ;
1997-10-21 13:34:33 +04:00
CAP_LARGE_READX | CAP_STATUS32 | CAP_LEVEL_II_OPLOCKS ;
1997-03-09 17:58:22 +03:00
*/
1996-05-04 11:50:46 +04:00
int secword = 0 ;
BOOL doencrypt = SMBENCRYPT ( ) ;
1996-05-30 07:16:17 +04:00
time_t t = time ( NULL ) ;
1997-03-09 17:58:22 +03:00
int data_len ;
1997-10-21 13:34:33 +04:00
struct cli_state * cli = NULL ;
char cryptkey [ 8 ] ;
char crypt_len = 0 ;
1997-03-09 17:58:22 +03:00
1997-11-10 22:23:17 +03:00
if ( lp_security ( ) = = SEC_SERVER ) {
cli = server_cryptkey ( ) ;
}
if ( cli ) {
1997-10-21 13:34:33 +04:00
DEBUG ( 3 , ( " using password server validation \n " ) ) ;
1997-11-10 22:23:17 +03:00
doencrypt = ( ( cli - > sec_mode & 2 ) ! = 0 ) ;
1997-10-21 13:34:33 +04:00
}
1997-11-10 22:23:17 +03:00
if ( doencrypt ) {
1997-10-21 13:34:33 +04:00
crypt_len = 8 ;
if ( ! cli ) {
generate_next_challenge ( cryptkey ) ;
} else {
memcpy ( cryptkey , cli - > cryptkey , 8 ) ;
set_challenge ( cli - > cryptkey ) ;
}
}
if ( lp_readraw ( ) & & lp_writeraw ( ) ) {
capabilities | = CAP_RAW_MODE ;
}
if ( lp_security ( ) > = SEC_USER ) secword | = 1 ;
1996-05-04 11:50:46 +04:00
if ( doencrypt ) secword | = 2 ;
1997-03-09 17:58:22 +03:00
/* decide where (if) to put the encryption challenge, and
follow it with the OEM ' d domain name
*/
1997-10-21 13:34:33 +04:00
data_len = crypt_len + strlen ( myworkgroup ) + 1 ;
1997-03-09 17:58:22 +03:00
set_message ( outbuf , 17 , data_len , True ) ;
1997-10-21 13:34:33 +04:00
strcpy ( smb_buf ( outbuf ) + crypt_len , myworkgroup ) ;
1997-03-09 17:58:22 +03:00
1996-05-04 11:50:46 +04:00
CVAL ( outbuf , smb_vwv1 ) = secword ;
1997-10-21 13:34:33 +04:00
SSVALS ( outbuf , smb_vwv16 + 1 , crypt_len ) ;
if ( doencrypt )
memcpy ( smb_buf ( outbuf ) , cryptkey , 8 ) ;
1996-05-04 11:50:46 +04:00
Protocol = PROTOCOL_NT1 ;
SSVAL ( outbuf , smb_vwv1 + 1 , lp_maxmux ( ) ) ; /* maxmpx */
SSVAL ( outbuf , smb_vwv2 + 1 , 1 ) ; /* num vcs */
1997-03-09 17:58:22 +03:00
SIVAL ( outbuf , smb_vwv3 + 1 , 0xffff ) ; /* max buffer. LOTS! */
SIVAL ( outbuf , smb_vwv5 + 1 , 0xffff ) ; /* raw size. LOTS! */
SIVAL ( outbuf , smb_vwv7 + 1 , getpid ( ) ) ; /* session key */
1996-05-04 11:50:46 +04:00
SIVAL ( outbuf , smb_vwv9 + 1 , capabilities ) ; /* capabilities */
1996-05-30 07:16:17 +04:00
put_long_date ( outbuf + smb_vwv11 + 1 , t ) ;
SSVALS ( outbuf , smb_vwv15 + 1 , TimeDiff ( t ) / 60 ) ;
1997-03-09 17:58:22 +03:00
SSVAL ( outbuf , smb_vwv17 , data_len ) ; /* length of challenge+domain strings */
1996-05-04 11:50:46 +04:00
return ( smb_len ( outbuf ) + 4 ) ;
}
/* these are the protocol lists used for auto architecture detection:
WinNT 3.51 :
protocol [ PC NETWORK PROGRAM 1.0 ]
protocol [ XENIX CORE ]
protocol [ MICROSOFT NETWORKS 1.03 ]
protocol [ LANMAN1 .0 ]
protocol [ Windows for Workgroups 3.1 a ]
protocol [ LM1 .2 X002 ]
protocol [ LANMAN2 .1 ]
protocol [ NT LM 0.12 ]
Win95 :
protocol [ PC NETWORK PROGRAM 1.0 ]
protocol [ XENIX CORE ]
protocol [ MICROSOFT NETWORKS 1.03 ]
protocol [ LANMAN1 .0 ]
protocol [ Windows for Workgroups 3.1 a ]
protocol [ LM1 .2 X002 ]
protocol [ LANMAN2 .1 ]
protocol [ NT LM 0.12 ]
OS / 2 :
protocol [ PC NETWORK PROGRAM 1.0 ]
protocol [ XENIX CORE ]
protocol [ LANMAN1 .0 ]
protocol [ LM1 .2 X002 ]
protocol [ LANMAN2 .1 ]
*/
/*
* Modified to recognize the architecture of the remote machine better .
*
* This appears to be the matrix of which protocol is used by which
* MS product .
Protocol WfWg Win95 WinNT OS / 2
PC NETWORK PROGRAM 1.0 1 1 1 1
XENIX CORE 2 2
MICROSOFT NETWORKS 3.0 2 2
DOS LM1 .2 X002 3 3
MICROSOFT NETWORKS 1.03 3
DOS LANMAN2 .1 4 4
LANMAN1 .0 4 3
Windows for Workgroups 3.1 a 5 5 5
LM1 .2 X002 6 4
LANMAN2 .1 7 5
NT LM 0.12 6 8
*
* tim @ fsg . com 09 / 29 / 95
*/
# define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */
# define ARCH_WIN95 0x2
# define ARCH_OS2 0xC /* Again OS/2 is like NT */
# define ARCH_WINNT 0x8
# define ARCH_SAMBA 0x10
# define ARCH_ALL 0x1F
/* List of supported protocols, most desired first */
struct {
char * proto_name ;
char * short_name ;
int ( * proto_reply_fn ) ( char * ) ;
int protocol_level ;
} supported_protocols [ ] = {
{ " NT LANMAN 1.0 " , " NT1 " , reply_nt1 , PROTOCOL_NT1 } ,
{ " NT LM 0.12 " , " NT1 " , reply_nt1 , PROTOCOL_NT1 } ,
{ " LM1.2X002 " , " LANMAN2 " , reply_lanman2 , PROTOCOL_LANMAN2 } ,
{ " Samba " , " LANMAN2 " , reply_lanman2 , PROTOCOL_LANMAN2 } ,
{ " DOS LM1.2X002 " , " LANMAN2 " , reply_lanman2 , PROTOCOL_LANMAN2 } ,
{ " LANMAN1.0 " , " LANMAN1 " , reply_lanman1 , PROTOCOL_LANMAN1 } ,
{ " MICROSOFT NETWORKS 3.0 " , " LANMAN1 " , reply_lanman1 , PROTOCOL_LANMAN1 } ,
{ " MICROSOFT NETWORKS 1.03 " , " COREPLUS " , reply_coreplus , PROTOCOL_COREPLUS } ,
{ " PC NETWORK PROGRAM 1.0 " , " CORE " , reply_corep , PROTOCOL_CORE } ,
{ NULL , NULL } ,
} ;
/****************************************************************************
reply to a negprot
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int reply_negprot ( char * inbuf , char * outbuf )
{
int outsize = set_message ( outbuf , 1 , 0 , True ) ;
int Index = 0 ;
int choice = - 1 ;
int protocol ;
char * p ;
int bcc = SVAL ( smb_buf ( inbuf ) , - 2 ) ;
int arch = ARCH_ALL ;
p = smb_buf ( inbuf ) + 1 ;
while ( p < ( smb_buf ( inbuf ) + bcc ) )
{
Index + + ;
DEBUG ( 3 , ( " Requested protocol [%s] \n " , p ) ) ;
if ( strcsequal ( p , " Windows for Workgroups 3.1a " ) )
arch & = ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT ) ;
else if ( strcsequal ( p , " DOS LM1.2X002 " ) )
arch & = ( ARCH_WFWG | ARCH_WIN95 ) ;
else if ( strcsequal ( p , " DOS LANMAN2.1 " ) )
arch & = ( ARCH_WFWG | ARCH_WIN95 ) ;
else if ( strcsequal ( p , " NT LM 0.12 " ) )
arch & = ( ARCH_WIN95 | ARCH_WINNT ) ;
else if ( strcsequal ( p , " LANMAN2.1 " ) )
arch & = ( ARCH_WINNT | ARCH_OS2 ) ;
else if ( strcsequal ( p , " LM1.2X002 " ) )
arch & = ( ARCH_WINNT | ARCH_OS2 ) ;
else if ( strcsequal ( p , " MICROSOFT NETWORKS 1.03 " ) )
arch & = ARCH_WINNT ;
else if ( strcsequal ( p , " XENIX CORE " ) )
arch & = ( ARCH_WINNT | ARCH_OS2 ) ;
else if ( strcsequal ( p , " Samba " ) ) {
arch = ARCH_SAMBA ;
break ;
}
p + = strlen ( p ) + 2 ;
}
switch ( arch ) {
case ARCH_SAMBA :
1997-09-05 00:26:07 +04:00
set_remote_arch ( RA_SAMBA ) ;
1996-05-04 11:50:46 +04:00
break ;
case ARCH_WFWG :
1997-09-05 00:26:07 +04:00
set_remote_arch ( RA_WFWG ) ;
1996-05-04 11:50:46 +04:00
break ;
case ARCH_WIN95 :
1997-09-05 00:26:07 +04:00
set_remote_arch ( RA_WIN95 ) ;
1996-05-04 11:50:46 +04:00
break ;
case ARCH_WINNT :
1997-09-05 00:26:07 +04:00
set_remote_arch ( RA_WINNT ) ;
1996-05-04 11:50:46 +04:00
break ;
case ARCH_OS2 :
1997-09-05 00:26:07 +04:00
set_remote_arch ( RA_OS2 ) ;
1996-05-04 11:50:46 +04:00
break ;
default :
1997-09-05 00:26:07 +04:00
set_remote_arch ( RA_UNKNOWN ) ;
1996-05-04 11:50:46 +04:00
break ;
}
/* possibly reload - change of architecture */
reload_services ( True ) ;
/* a special case to stop password server loops */
if ( Index = = 1 & & strequal ( remote_machine , myhostname ) & &
lp_security ( ) = = SEC_SERVER )
exit_server ( " Password server loop! " ) ;
/* Check for protocols, most desirable first */
for ( protocol = 0 ; supported_protocols [ protocol ] . proto_name ; protocol + + )
{
p = smb_buf ( inbuf ) + 1 ;
Index = 0 ;
if ( lp_maxprotocol ( ) > = supported_protocols [ protocol ] . protocol_level )
while ( p < ( smb_buf ( inbuf ) + bcc ) )
{
if ( strequal ( p , supported_protocols [ protocol ] . proto_name ) )
choice = Index ;
Index + + ;
p + = strlen ( p ) + 2 ;
}
if ( choice ! = - 1 )
break ;
}
SSVAL ( outbuf , smb_vwv0 , choice ) ;
if ( choice ! = - 1 ) {
extern fstring remote_proto ;
1997-09-26 22:55:29 +04:00
fstrcpy ( remote_proto , supported_protocols [ protocol ] . short_name ) ;
1996-05-04 11:50:46 +04:00
reload_services ( True ) ;
outsize = supported_protocols [ protocol ] . proto_reply_fn ( outbuf ) ;
DEBUG ( 3 , ( " Selected protocol %s \n " , supported_protocols [ protocol ] . proto_name ) ) ;
}
else {
DEBUG ( 0 , ( " No protocol supported ! \n " ) ) ;
}
SSVAL ( outbuf , smb_vwv0 , choice ) ;
DEBUG ( 5 , ( " %s negprot index=%d \n " , timestring ( ) , choice ) ) ;
return ( outsize ) ;
}
/****************************************************************************
close all open files for a connection
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void close_open_files ( int cnum )
{
int i ;
for ( i = 0 ; i < MAX_OPEN_FILES ; i + + )
if ( Files [ i ] . cnum = = cnum & & Files [ i ] . open ) {
1997-10-16 01:53:59 +04:00
close_file ( i , False ) ;
1996-05-04 11:50:46 +04:00
}
}
/****************************************************************************
close a cnum
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-10-26 00:42:46 +04:00
void close_cnum ( int cnum , uint16 vuid )
1996-05-04 11:50:46 +04:00
{
DirCacheFlush ( SNUM ( cnum ) ) ;
unbecome_user ( ) ;
if ( ! OPEN_CNUM ( cnum ) )
{
DEBUG ( 0 , ( " Can't close cnum %d \n " , cnum ) ) ;
return ;
}
DEBUG ( IS_IPC ( cnum ) ? 3 : 1 , ( " %s %s (%s) closed connection to service %s \n " ,
timestring ( ) ,
1996-10-05 14:41:13 +04:00
remote_machine , client_addr ( ) ,
1996-05-04 11:50:46 +04:00
lp_servicename ( SNUM ( cnum ) ) ) ) ;
yield_connection ( cnum ,
lp_servicename ( SNUM ( cnum ) ) ,
lp_max_connections ( SNUM ( cnum ) ) ) ;
if ( lp_status ( SNUM ( cnum ) ) )
yield_connection ( cnum , " STATUS. " , MAXSTATUS ) ;
close_open_files ( cnum ) ;
dptr_closecnum ( cnum ) ;
/* execute any "postexec = " line */
1997-10-25 14:58:18 +04:00
if ( * lp_postexec ( SNUM ( cnum ) ) & & become_user ( & Connections [ cnum ] , cnum , vuid ) )
1996-05-04 11:50:46 +04:00
{
pstring cmd ;
strcpy ( cmd , lp_postexec ( SNUM ( cnum ) ) ) ;
standard_sub ( cnum , cmd ) ;
1996-10-04 13:31:07 +04:00
smbrun ( cmd , NULL , False ) ;
1996-05-04 11:50:46 +04:00
unbecome_user ( ) ;
}
unbecome_user ( ) ;
/* execute any "root postexec = " line */
if ( * lp_rootpostexec ( SNUM ( cnum ) ) )
{
pstring cmd ;
strcpy ( cmd , lp_rootpostexec ( SNUM ( cnum ) ) ) ;
standard_sub ( cnum , cmd ) ;
1996-10-04 13:31:07 +04:00
smbrun ( cmd , NULL , False ) ;
1996-05-04 11:50:46 +04:00
}
Connections [ cnum ] . open = False ;
num_connections_open - - ;
if ( Connections [ cnum ] . ngroups & & Connections [ cnum ] . groups )
{
if ( Connections [ cnum ] . igroups ! = ( int * ) Connections [ cnum ] . groups )
free ( Connections [ cnum ] . groups ) ;
free ( Connections [ cnum ] . igroups ) ;
Connections [ cnum ] . groups = NULL ;
Connections [ cnum ] . igroups = NULL ;
Connections [ cnum ] . ngroups = 0 ;
}
1997-07-24 21:25:11 +04:00
free_namearray ( Connections [ cnum ] . veto_list ) ;
free_namearray ( Connections [ cnum ] . hide_list ) ;
1996-05-04 11:50:46 +04:00
string_set ( & Connections [ cnum ] . user , " " ) ;
string_set ( & Connections [ cnum ] . dirpath , " " ) ;
string_set ( & Connections [ cnum ] . connectpath , " " ) ;
}
/****************************************************************************
simple routines to do connection counting
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL yield_connection ( int cnum , char * name , int max_connections )
{
struct connect_record crec ;
pstring fname ;
FILE * f ;
int mypid = getpid ( ) ;
int i ;
DEBUG ( 3 , ( " Yielding connection to %d %s \n " , cnum , name ) ) ;
if ( max_connections < = 0 )
return ( True ) ;
bzero ( & crec , sizeof ( crec ) ) ;
1997-09-26 22:55:29 +04:00
pstrcpy ( fname , lp_lockdir ( ) ) ;
1996-05-04 11:50:46 +04:00
standard_sub ( cnum , fname ) ;
trim_string ( fname , " " , " / " ) ;
strcat ( fname , " / " ) ;
strcat ( fname , name ) ;
strcat ( fname , " .LCK " ) ;
f = fopen ( fname , " r+ " ) ;
if ( ! f )
{
1997-06-06 20:14:17 +04:00
DEBUG ( 2 , ( " Couldn't open lock file %s (%s) \n " , fname , strerror ( errno ) ) ) ;
1996-05-04 11:50:46 +04:00
return ( False ) ;
}
fseek ( f , 0 , SEEK_SET ) ;
/* find a free spot */
for ( i = 0 ; i < max_connections ; i + + )
{
if ( fread ( & crec , sizeof ( crec ) , 1 , f ) ! = 1 )
{
DEBUG ( 2 , ( " Entry not found in lock file %s \n " , fname ) ) ;
fclose ( f ) ;
return ( False ) ;
}
if ( crec . pid = = mypid & & crec . cnum = = cnum )
break ;
}
if ( crec . pid ! = mypid | | crec . cnum ! = cnum )
{
fclose ( f ) ;
DEBUG ( 2 , ( " Entry not found in lock file %s \n " , fname ) ) ;
return ( False ) ;
}
bzero ( ( void * ) & crec , sizeof ( crec ) ) ;
/* remove our mark */
if ( fseek ( f , i * sizeof ( crec ) , SEEK_SET ) ! = 0 | |
fwrite ( & crec , sizeof ( crec ) , 1 , f ) ! = 1 )
{
DEBUG ( 2 , ( " Couldn't update lock file %s (%s) \n " , fname , strerror ( errno ) ) ) ;
fclose ( f ) ;
return ( False ) ;
}
DEBUG ( 3 , ( " Yield successful \n " ) ) ;
fclose ( f ) ;
return ( True ) ;
}
/****************************************************************************
simple routines to do connection counting
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL claim_connection ( int cnum , char * name , int max_connections , BOOL Clear )
{
struct connect_record crec ;
pstring fname ;
FILE * f ;
int snum = SNUM ( cnum ) ;
int i , foundi = - 1 ;
int total_recs ;
if ( max_connections < = 0 )
return ( True ) ;
DEBUG ( 5 , ( " trying claim %s %s %d \n " , lp_lockdir ( ) , name , max_connections ) ) ;
1997-09-26 22:55:29 +04:00
pstrcpy ( fname , lp_lockdir ( ) ) ;
1996-05-04 11:50:46 +04:00
standard_sub ( cnum , fname ) ;
trim_string ( fname , " " , " / " ) ;
if ( ! directory_exist ( fname , NULL ) )
mkdir ( fname , 0755 ) ;
strcat ( fname , " / " ) ;
strcat ( fname , name ) ;
strcat ( fname , " .LCK " ) ;
if ( ! file_exist ( fname , NULL ) )
{
1996-10-04 13:31:07 +04:00
int oldmask = umask ( 022 ) ;
1996-05-04 11:50:46 +04:00
f = fopen ( fname , " w " ) ;
if ( f ) fclose ( f ) ;
1996-10-04 13:31:07 +04:00
umask ( oldmask ) ;
1996-05-04 11:50:46 +04:00
}
total_recs = file_size ( fname ) / sizeof ( crec ) ;
f = fopen ( fname , " r+ " ) ;
if ( ! f )
{
DEBUG ( 1 , ( " couldn't open lock file %s \n " , fname ) ) ;
return ( False ) ;
}
/* find a free spot */
for ( i = 0 ; i < max_connections ; i + + )
{
if ( i > = total_recs | |
fseek ( f , i * sizeof ( crec ) , SEEK_SET ) ! = 0 | |
fread ( & crec , sizeof ( crec ) , 1 , f ) ! = 1 )
{
if ( foundi < 0 ) foundi = i ;
break ;
}
if ( Clear & & crec . pid & & ! process_exists ( crec . pid ) )
{
fseek ( f , i * sizeof ( crec ) , SEEK_SET ) ;
bzero ( ( void * ) & crec , sizeof ( crec ) ) ;
fwrite ( & crec , sizeof ( crec ) , 1 , f ) ;
if ( foundi < 0 ) foundi = i ;
continue ;
}
if ( foundi < 0 & & ( ! crec . pid | | ! process_exists ( crec . pid ) ) )
{
foundi = i ;
if ( ! Clear ) break ;
}
}
if ( foundi < 0 )
{
DEBUG ( 3 , ( " no free locks in %s \n " , fname ) ) ;
fclose ( f ) ;
return ( False ) ;
}
/* fill in the crec */
bzero ( ( void * ) & crec , sizeof ( crec ) ) ;
crec . magic = 0x280267 ;
crec . pid = getpid ( ) ;
crec . cnum = cnum ;
crec . uid = Connections [ cnum ] . uid ;
crec . gid = Connections [ cnum ] . gid ;
StrnCpy ( crec . name , lp_servicename ( snum ) , sizeof ( crec . name ) - 1 ) ;
crec . start = time ( NULL ) ;
1996-10-05 14:41:13 +04:00
StrnCpy ( crec . machine , remote_machine , sizeof ( crec . machine ) - 1 ) ;
StrnCpy ( crec . addr , client_addr ( ) , sizeof ( crec . addr ) - 1 ) ;
1996-05-04 11:50:46 +04:00
/* make our mark */
if ( fseek ( f , foundi * sizeof ( crec ) , SEEK_SET ) ! = 0 | |
fwrite ( & crec , sizeof ( crec ) , 1 , f ) ! = 1 )
{
fclose ( f ) ;
return ( False ) ;
}
fclose ( f ) ;
return ( True ) ;
}
# if DUMP_CORE
/*******************************************************************
prepare to dump a core file - carefully !
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL dump_core ( void )
{
char * p ;
pstring dname ;
1997-09-26 22:55:29 +04:00
pstrcpy ( dname , debugf ) ;
1996-05-04 11:50:46 +04:00
if ( ( p = strrchr ( dname , ' / ' ) ) ) * p = 0 ;
strcat ( dname , " /corefiles " ) ;
mkdir ( dname , 0700 ) ;
sys_chown ( dname , getuid ( ) , getgid ( ) ) ;
chmod ( dname , 0700 ) ;
if ( chdir ( dname ) ) return ( False ) ;
umask ( ~ ( 0700 ) ) ;
# ifndef NO_GETRLIMIT
# ifdef RLIMIT_CORE
{
struct rlimit rlp ;
getrlimit ( RLIMIT_CORE , & rlp ) ;
rlp . rlim_cur = MAX ( 4 * 1024 * 1024 , rlp . rlim_cur ) ;
setrlimit ( RLIMIT_CORE , & rlp ) ;
getrlimit ( RLIMIT_CORE , & rlp ) ;
DEBUG ( 3 , ( " Core limits now %d %d \n " , rlp . rlim_cur , rlp . rlim_max ) ) ;
}
# endif
# endif
DEBUG ( 0 , ( " Dumping core in %s \n " , dname ) ) ;
return ( True ) ;
}
# endif
/****************************************************************************
exit the server
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void exit_server ( char * reason )
{
static int firsttime = 1 ;
int i ;
if ( ! firsttime ) exit ( 0 ) ;
firsttime = 0 ;
unbecome_user ( ) ;
DEBUG ( 2 , ( " Closing connections \n " ) ) ;
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
if ( Connections [ i ] . open )
1997-08-19 23:22:26 +04:00
close_cnum ( i , ( uint16 ) - 1 ) ;
1996-05-04 11:50:46 +04:00
# ifdef DFS_AUTH
if ( dcelogin_atmost_once )
dfs_unlogin ( ) ;
# endif
if ( ! reason ) {
int oldlevel = DEBUGLEVEL ;
DEBUGLEVEL = 10 ;
DEBUG ( 0 , ( " Last message was %s \n " , smb_fn_name ( last_message ) ) ) ;
if ( last_inbuf )
show_msg ( last_inbuf ) ;
DEBUGLEVEL = oldlevel ;
DEBUG ( 0 , ( " =============================================================== \n " ) ) ;
# if DUMP_CORE
if ( dump_core ( ) ) return ;
# endif
}
1997-01-09 21:02:17 +03:00
1997-10-20 12:46:00 +04:00
locking_end ( ) ;
1997-01-09 21:02:17 +03:00
1996-05-04 11:50:46 +04:00
DEBUG ( 3 , ( " %s Server exit (%s) \n " , timestring ( ) , reason ? reason : " " ) ) ;
exit ( 0 ) ;
}
/****************************************************************************
do some standard substitutions in a string
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-08-27 23:27:25 +04:00
void standard_sub ( int cnum , char * str )
1996-05-04 11:50:46 +04:00
{
1997-07-24 21:25:11 +04:00
if ( VALID_CNUM ( cnum ) ) {
char * p , * s , * home ;
1997-08-27 23:27:25 +04:00
for ( s = str ; ( p = strchr ( s , ' % ' ) ) ! = NULL ; s = p ) {
1997-07-24 21:25:11 +04:00
switch ( * ( p + 1 ) ) {
case ' H ' : if ( ( home = get_home_dir ( Connections [ cnum ] . user ) ) ! = NULL )
string_sub ( p , " %H " , home ) ;
else
p + = 2 ;
break ;
case ' P ' : string_sub ( p , " %P " , Connections [ cnum ] . connectpath ) ; break ;
case ' S ' : string_sub ( p , " %S " , lp_servicename ( Connections [ cnum ] . service ) ) ; break ;
case ' g ' : string_sub ( p , " %g " , gidtoname ( Connections [ cnum ] . gid ) ) ; break ;
case ' u ' : string_sub ( p , " %u " , Connections [ cnum ] . user ) ; break ;
case ' \0 ' : p + + ; break ; /* don't run off the end of the string */
default : p + = 2 ; break ;
1996-05-04 11:50:46 +04:00
}
}
1997-07-24 21:25:11 +04:00
}
1997-08-27 23:27:25 +04:00
standard_sub_basic ( str ) ;
1996-05-04 11:50:46 +04:00
}
/*
These flags determine some of the permissions required to do an operation
Note that I don ' t set NEED_WRITE on some write operations because they
are used by some brain - dead clients when printing , and I don ' t want to
force write permissions on print services .
*/
# define AS_USER (1<<0)
# define NEED_WRITE (1<<1)
# define TIME_INIT (1<<2)
# define CAN_IPC (1<<3)
# define AS_GUEST (1<<5)
/*
define a list of possible SMB messages and their corresponding
functions . Any message that has a NULL function is unimplemented -
please feel free to contribute implementations !
*/
struct smb_message_struct
{
int code ;
char * name ;
int ( * fn ) ( ) ;
int flags ;
# if PROFILING
unsigned long time ;
# endif
}
smb_messages [ ] = {
/* CORE PROTOCOL */
1997-11-03 22:24:45 +03:00
{ SMBnegprot , " SMBnegprot " , reply_negprot , 0 } ,
{ SMBtcon , " SMBtcon " , reply_tcon , 0 } ,
{ SMBtdis , " SMBtdis " , reply_tdis , 0 } ,
{ SMBexit , " SMBexit " , reply_exit , 0 } ,
{ SMBioctl , " SMBioctl " , reply_ioctl , 0 } ,
{ SMBecho , " SMBecho " , reply_echo , 0 } ,
{ SMBsesssetupX , " SMBsesssetupX " , reply_sesssetup_and_X , 0 } ,
{ SMBtconX , " SMBtconX " , reply_tcon_and_X , 0 } ,
{ SMBulogoffX , " SMBulogoffX " , reply_ulogoffX , 0 } , /* ulogoff doesn't give a valid TID */
1996-05-04 11:50:46 +04:00
{ SMBgetatr , " SMBgetatr " , reply_getatr , AS_USER } ,
{ SMBsetatr , " SMBsetatr " , reply_setatr , AS_USER | NEED_WRITE } ,
{ SMBchkpth , " SMBchkpth " , reply_chkpth , AS_USER } ,
{ SMBsearch , " SMBsearch " , reply_search , AS_USER } ,
{ SMBopen , " SMBopen " , reply_open , AS_USER } ,
/* note that SMBmknew and SMBcreate are deliberately overloaded */
{ SMBcreate , " SMBcreate " , reply_mknew , AS_USER } ,
{ SMBmknew , " SMBmknew " , reply_mknew , AS_USER } ,
{ SMBunlink , " SMBunlink " , reply_unlink , AS_USER | NEED_WRITE } ,
{ SMBread , " SMBread " , reply_read , AS_USER } ,
{ SMBwrite , " SMBwrite " , reply_write , AS_USER } ,
1996-08-15 19:11:34 +04:00
{ SMBclose , " SMBclose " , reply_close , AS_USER | CAN_IPC } ,
1996-05-04 11:50:46 +04:00
{ SMBmkdir , " SMBmkdir " , reply_mkdir , AS_USER | NEED_WRITE } ,
{ SMBrmdir , " SMBrmdir " , reply_rmdir , AS_USER | NEED_WRITE } ,
{ SMBdskattr , " SMBdskattr " , reply_dskattr , AS_USER } ,
{ SMBmv , " SMBmv " , reply_mv , AS_USER | NEED_WRITE } ,
/* this is a Pathworks specific call, allowing the
changing of the root path */
{ pSETDIR , " pSETDIR " , reply_setdir , AS_USER } ,
{ SMBlseek , " SMBlseek " , reply_lseek , AS_USER } ,
{ SMBflush , " SMBflush " , reply_flush , AS_USER } ,
{ SMBctemp , " SMBctemp " , reply_ctemp , AS_USER } ,
{ SMBsplopen , " SMBsplopen " , reply_printopen , AS_USER } ,
{ SMBsplclose , " SMBsplclose " , reply_printclose , AS_USER } ,
1996-08-17 18:27:12 +04:00
{ SMBsplretq , " SMBsplretq " , reply_printqueue , AS_USER | AS_GUEST } ,
1996-05-04 11:50:46 +04:00
{ SMBsplwr , " SMBsplwr " , reply_printwrite , AS_USER } ,
{ SMBlock , " SMBlock " , reply_lock , AS_USER } ,
{ SMBunlock , " SMBunlock " , reply_unlock , AS_USER } ,
/* CORE+ PROTOCOL FOLLOWS */
{ SMBreadbraw , " SMBreadbraw " , reply_readbraw , AS_USER } ,
{ SMBwritebraw , " SMBwritebraw " , reply_writebraw , AS_USER } ,
{ SMBwriteclose , " SMBwriteclose " , reply_writeclose , AS_USER } ,
{ SMBlockread , " SMBlockread " , reply_lockread , AS_USER } ,
{ SMBwriteunlock , " SMBwriteunlock " , reply_writeunlock , AS_USER } ,
/* LANMAN1.0 PROTOCOL FOLLOWS */
{ SMBreadBmpx , " SMBreadBmpx " , reply_readbmpx , AS_USER } ,
{ SMBreadBs , " SMBreadBs " , NULL , AS_USER } ,
{ SMBwriteBmpx , " SMBwriteBmpx " , reply_writebmpx , AS_USER } ,
{ SMBwriteBs , " SMBwriteBs " , reply_writebs , AS_USER } ,
{ SMBwritec , " SMBwritec " , NULL , AS_USER } ,
{ SMBsetattrE , " SMBsetattrE " , reply_setattrE , AS_USER | NEED_WRITE } ,
{ SMBgetattrE , " SMBgetattrE " , reply_getattrE , AS_USER } ,
{ SMBtrans , " SMBtrans " , reply_trans , AS_USER | CAN_IPC } ,
{ SMBtranss , " SMBtranss " , NULL , AS_USER | CAN_IPC } ,
{ SMBioctls , " SMBioctls " , NULL , AS_USER } ,
{ SMBcopy , " SMBcopy " , reply_copy , AS_USER | NEED_WRITE } ,
{ SMBmove , " SMBmove " , NULL , AS_USER | NEED_WRITE } ,
1996-08-15 19:11:34 +04:00
{ SMBopenX , " SMBopenX " , reply_open_and_X , AS_USER | CAN_IPC } ,
1996-05-04 11:50:46 +04:00
{ SMBreadX , " SMBreadX " , reply_read_and_X , AS_USER } ,
{ SMBwriteX , " SMBwriteX " , reply_write_and_X , AS_USER } ,
{ SMBlockingX , " SMBlockingX " , reply_lockingX , AS_USER } ,
{ SMBffirst , " SMBffirst " , reply_search , AS_USER } ,
{ SMBfunique , " SMBfunique " , reply_search , AS_USER } ,
{ SMBfclose , " SMBfclose " , reply_fclose , AS_USER } ,
/* LANMAN2.0 PROTOCOL FOLLOWS */
{ SMBfindnclose , " SMBfindnclose " , reply_findnclose , AS_USER } ,
{ SMBfindclose , " SMBfindclose " , reply_findclose , AS_USER } ,
{ SMBtrans2 , " SMBtrans2 " , reply_trans2 , AS_USER } ,
{ SMBtranss2 , " SMBtranss2 " , reply_transs2 , AS_USER } ,
/* messaging routines */
{ SMBsends , " SMBsends " , reply_sends , AS_GUEST } ,
{ SMBsendstrt , " SMBsendstrt " , reply_sendstrt , AS_GUEST } ,
{ SMBsendend , " SMBsendend " , reply_sendend , AS_GUEST } ,
{ SMBsendtxt , " SMBsendtxt " , reply_sendtxt , AS_GUEST } ,
/* NON-IMPLEMENTED PARTS OF THE CORE PROTOCOL */
{ SMBsendb , " SMBsendb " , NULL , AS_GUEST } ,
{ SMBfwdname , " SMBfwdname " , NULL , AS_GUEST } ,
{ SMBcancelf , " SMBcancelf " , NULL , AS_GUEST } ,
{ SMBgetmac , " SMBgetmac " , NULL , AS_GUEST }
} ;
/****************************************************************************
return a string containing the function name of a SMB command
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * smb_fn_name ( int type )
{
static char * unknown_name = " SMBunknown " ;
static int num_smb_messages =
sizeof ( smb_messages ) / sizeof ( struct smb_message_struct ) ;
int match ;
for ( match = 0 ; match < num_smb_messages ; match + + )
if ( smb_messages [ match ] . code = = type )
break ;
if ( match = = num_smb_messages )
return ( unknown_name ) ;
return ( smb_messages [ match ] . name ) ;
}
/****************************************************************************
do a switch on the message type , and return the response size
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int switch_message ( int type , char * inbuf , char * outbuf , int size , int bufsize )
{
static int pid = - 1 ;
int outsize = 0 ;
static int num_smb_messages =
sizeof ( smb_messages ) / sizeof ( struct smb_message_struct ) ;
int match ;
# if PROFILING
struct timeval msg_start_time ;
struct timeval msg_end_time ;
static unsigned long total_time = 0 ;
GetTimeOfDay ( & msg_start_time ) ;
# endif
if ( pid = = - 1 )
pid = getpid ( ) ;
errno = 0 ;
last_message = type ;
/* make sure this is an SMB packet */
if ( strncmp ( smb_base ( inbuf ) , " \377 SMB " , 4 ) ! = 0 )
{
DEBUG ( 2 , ( " Non-SMB packet of length %d \n " , smb_len ( inbuf ) ) ) ;
return ( - 1 ) ;
}
for ( match = 0 ; match < num_smb_messages ; match + + )
if ( smb_messages [ match ] . code = = type )
break ;
if ( match = = num_smb_messages )
{
DEBUG ( 0 , ( " Unknown message type %d! \n " , type ) ) ;
outsize = reply_unknown ( inbuf , outbuf ) ;
}
else
{
DEBUG ( 3 , ( " switch message %s (pid %d) \n " , smb_messages [ match ] . name , pid ) ) ;
if ( smb_messages [ match ] . fn )
{
int cnum = SVAL ( inbuf , smb_tid ) ;
int flags = smb_messages [ match ] . flags ;
1996-10-26 00:42:46 +04:00
uint16 session_tag = SVAL ( inbuf , smb_uid ) ;
1996-05-04 11:50:46 +04:00
/* does this protocol need to be run as root? */
if ( ! ( flags & AS_USER ) )
unbecome_user ( ) ;
/* does this protocol need to be run as the connected user? */
1997-10-25 14:58:18 +04:00
if ( ( flags & AS_USER ) & & ! become_user ( & Connections [ cnum ] , cnum , session_tag ) ) {
1996-08-17 18:27:12 +04:00
if ( flags & AS_GUEST )
flags & = ~ AS_USER ;
else
return ( ERROR ( ERRSRV , ERRinvnid ) ) ;
}
/* this code is to work around a bug is MS client 3 without
introducing a security hole - it needs to be able to do
print queue checks as guest if it isn ' t logged in properly */
if ( flags & AS_USER )
flags & = ~ AS_GUEST ;
1996-05-04 11:50:46 +04:00
/* does it need write permission? */
if ( ( flags & NEED_WRITE ) & & ! CAN_WRITE ( cnum ) )
return ( ERROR ( ERRSRV , ERRaccess ) ) ;
/* ipc services are limited */
if ( IS_IPC ( cnum ) & & ( flags & AS_USER ) & & ! ( flags & CAN_IPC ) )
return ( ERROR ( ERRSRV , ERRaccess ) ) ;
/* load service specific parameters */
if ( OPEN_CNUM ( cnum ) & & ! become_service ( cnum , ( flags & AS_USER ) ? True : False ) )
return ( ERROR ( ERRSRV , ERRaccess ) ) ;
/* does this protocol need to be run as guest? */
if ( ( flags & AS_GUEST ) & & ( ! become_guest ( ) | | ! check_access ( - 1 ) ) )
return ( ERROR ( ERRSRV , ERRaccess ) ) ;
last_inbuf = inbuf ;
outsize = smb_messages [ match ] . fn ( inbuf , outbuf , size , bufsize ) ;
}
else
{
outsize = reply_unknown ( inbuf , outbuf ) ;
}
}
# if PROFILING
GetTimeOfDay ( & msg_end_time ) ;
if ( ! ( smb_messages [ match ] . flags & TIME_INIT ) )
{
smb_messages [ match ] . time = 0 ;
smb_messages [ match ] . flags | = TIME_INIT ;
}
{
unsigned long this_time =
( msg_end_time . tv_sec - msg_start_time . tv_sec ) * 1e6 +
( msg_end_time . tv_usec - msg_start_time . tv_usec ) ;
smb_messages [ match ] . time + = this_time ;
total_time + = this_time ;
}
DEBUG ( 2 , ( " TIME %s %d usecs %g pct \n " ,
smb_fn_name ( type ) , smb_messages [ match ] . time ,
( 100.0 * smb_messages [ match ] . time ) / total_time ) ) ;
# endif
return ( outsize ) ;
}
/****************************************************************************
1996-08-19 15:17:29 +04:00
construct a chained reply and add it to the already made reply
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int chain_reply ( char * inbuf , char * outbuf , int size , int bufsize )
1996-05-04 11:50:46 +04:00
{
1996-08-19 15:17:29 +04:00
static char * orig_inbuf ;
static char * orig_outbuf ;
1996-08-19 17:54:58 +04:00
int smb_com1 , smb_com2 = CVAL ( inbuf , smb_vwv0 ) ;
1996-08-19 15:17:29 +04:00
unsigned smb_off2 = SVAL ( inbuf , smb_vwv1 ) ;
char * inbuf2 , * outbuf2 ;
int outsize2 ;
char inbuf_saved [ smb_wct ] ;
char outbuf_saved [ smb_wct ] ;
extern int chain_size ;
int wct = CVAL ( outbuf , smb_wct ) ;
int outsize = smb_size + 2 * wct + SVAL ( outbuf , smb_vwv0 + 2 * wct ) ;
/* maybe its not chained */
if ( smb_com2 = = 0xFF ) {
CVAL ( outbuf , smb_vwv0 ) = 0xFF ;
return outsize ;
}
1996-05-04 11:50:46 +04:00
1996-08-19 15:17:29 +04:00
if ( chain_size = = 0 ) {
/* this is the first part of the chain */
orig_inbuf = inbuf ;
orig_outbuf = outbuf ;
}
1996-05-04 11:50:46 +04:00
1996-08-19 15:17:29 +04:00
/* we need to tell the client where the next part of the reply will be */
SSVAL ( outbuf , smb_vwv1 , smb_offset ( outbuf + outsize , outbuf ) ) ;
CVAL ( outbuf , smb_vwv0 ) = smb_com2 ;
1996-05-04 11:50:46 +04:00
1996-08-19 15:17:29 +04:00
/* remember how much the caller added to the chain, only counting stuff
after the parameter words */
chain_size + = outsize - smb_wct ;
1996-05-04 11:50:46 +04:00
1996-08-19 15:17:29 +04:00
/* work out pointers into the original packets. The
headers on these need to be filled in */
inbuf2 = orig_inbuf + smb_off2 + 4 - smb_wct ;
outbuf2 = orig_outbuf + SVAL ( outbuf , smb_vwv1 ) + 4 - smb_wct ;
1996-05-04 11:50:46 +04:00
1996-08-19 17:54:58 +04:00
/* remember the original command type */
1996-08-20 19:45:16 +04:00
smb_com1 = CVAL ( orig_inbuf , smb_com ) ;
1996-08-19 17:54:58 +04:00
1996-08-19 15:17:29 +04:00
/* save the data which will be overwritten by the new headers */
memcpy ( inbuf_saved , inbuf2 , smb_wct ) ;
memcpy ( outbuf_saved , outbuf2 , smb_wct ) ;
1996-05-04 11:50:46 +04:00
1996-08-20 19:45:16 +04:00
/* give the new packet the same header as the last part of the SMB */
memmove ( inbuf2 , inbuf , smb_wct ) ;
1996-05-04 11:50:46 +04:00
/* create the in buffer */
1996-08-19 17:54:58 +04:00
CVAL ( inbuf2 , smb_com ) = smb_com2 ;
1996-05-04 11:50:46 +04:00
/* create the out buffer */
1996-08-19 15:17:29 +04:00
bzero ( outbuf2 , smb_size ) ;
set_message ( outbuf2 , 0 , 0 , True ) ;
CVAL ( outbuf2 , smb_com ) = CVAL ( inbuf2 , smb_com ) ;
1996-05-04 11:50:46 +04:00
1996-08-19 15:17:29 +04:00
memcpy ( outbuf2 + 4 , inbuf2 + 4 , 4 ) ;
CVAL ( outbuf2 , smb_rcls ) = SUCCESS ;
CVAL ( outbuf2 , smb_reh ) = 0 ;
CVAL ( outbuf2 , smb_flg ) = 0x80 | ( CVAL ( inbuf2 , smb_flg ) & 0x8 ) ; /* bit 7 set
means a reply */
SSVAL ( outbuf2 , smb_flg2 , 1 ) ; /* say we support long filenames */
SSVAL ( outbuf2 , smb_err , SUCCESS ) ;
SSVAL ( outbuf2 , smb_tid , SVAL ( inbuf2 , smb_tid ) ) ;
SSVAL ( outbuf2 , smb_pid , SVAL ( inbuf2 , smb_pid ) ) ;
SSVAL ( outbuf2 , smb_uid , SVAL ( inbuf2 , smb_uid ) ) ;
SSVAL ( outbuf2 , smb_mid , SVAL ( inbuf2 , smb_mid ) ) ;
1996-05-04 11:50:46 +04:00
DEBUG ( 3 , ( " Chained message \n " ) ) ;
1996-08-19 15:17:29 +04:00
show_msg ( inbuf2 ) ;
1996-05-04 11:50:46 +04:00
/* process the request */
1996-08-19 15:17:29 +04:00
outsize2 = switch_message ( smb_com2 , inbuf2 , outbuf2 , size - chain_size ,
bufsize - chain_size ) ;
1996-05-04 11:50:46 +04:00
1996-08-20 19:45:16 +04:00
/* copy the new reply and request headers over the old ones, but
preserve the smb_com field */
1996-08-19 15:17:29 +04:00
memmove ( orig_outbuf , outbuf2 , smb_wct ) ;
1996-08-19 17:54:58 +04:00
CVAL ( orig_outbuf , smb_com ) = smb_com1 ;
1996-05-04 11:50:46 +04:00
1996-08-19 15:17:29 +04:00
/* restore the saved data, being careful not to overwrite any
data from the reply header */
memcpy ( inbuf2 , inbuf_saved , smb_wct ) ;
{
int ofs = smb_wct - PTR_DIFF ( outbuf2 , orig_outbuf ) ;
if ( ofs < 0 ) ofs = 0 ;
memmove ( outbuf2 + ofs , outbuf_saved + ofs , smb_wct - ofs ) ;
}
1996-05-04 11:50:46 +04:00
1996-08-19 17:54:58 +04:00
return outsize2 ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
construct a reply to the incoming packet
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int construct_reply ( char * inbuf , char * outbuf , int size , int bufsize )
{
int type = CVAL ( inbuf , smb_com ) ;
int outsize = 0 ;
int msg_type = CVAL ( inbuf , 0 ) ;
1996-08-19 15:17:29 +04:00
extern int chain_size ;
1996-05-04 11:50:46 +04:00
smb_last_time = time ( NULL ) ;
chain_size = 0 ;
1996-08-19 15:17:29 +04:00
chain_fnum = - 1 ;
following a cvs error, i am rewriting this monster-commit. with bad grace.
Modified Files:
---------------
Makefile:
adding extra files
ipc.c :
send_trans_reply() - alignment issue. this makes the alignment
the same as that in NT. this should be looked at by people who
understand the SMB stuff better than i.
api_fd_commands[] - added samr and wkssvc pipes.
loadparm.c :
lp_domain_controller() changed to mean "samba is a domain controller".
it's a "yes/no" parameter, now. no, it isn't used _anywhere_.
namedbwork.c nameelect.c :
if "domain controller = yes" then add SV_TYPE_DOMAIN_CTRL to the
host _and_ workgroup announcements. yes, you must do both: nt does.
namelogon.c :
important NETLOGON bug in SAMLOGON request parsing, which may be
the source of some people's problems with logging on to the Samba PDC.
password.c :
get_smbpwnam() renamed to get_smbpwd_entry().
pipes.c :
added samr and wkssvc pipes.
proto.h :
usual. can we actually _remove_ proto.h from the cvs tree, and
have it as one of the Makefile dependencies, or something?
reply.c :
get_smbpwnam() renamed to get_smbpwd_entry() - also changed response
error code when logging in from a WORKSTATION$ account. yes, paul
is right: we need to know when to return the right error code, and why.
server.c :
added call to reset_chain_pnum().
#ifdef NTDOMAIN added call to init_lsa_policy_hnd() #endif. jeremy,
you'd be proud: i did a compile without NTDOMAIN, and caught a link
error for this function.
smb.h :
defines and structures for samr and wkssvc pipes.
smbpass.c :
modified get_smbpwnam() to get_smbpwd_entry() and it now takes
two arguments. one for the name; if this is null, it looks up
by smb_userid instead.
oh, by the way, smb_userids are actually domain relative ids
(RIDs). concatenate a RID with the domain SID, and you have
an internet globally unique way of identifying a user.
we're using RIDs in the wrong way....
added mod_smbpwnam() function. this was based on code in smbpasswd.c
rpc_pipes/lsaparse.c :
added enum trusted domain parsing. this is incomplete: i need
a packet trace to write it properly.
rpc_pipes/pipe_hnd.c :
added reset_chain_pnum() function.
rpc_pipes/pipenetlog.c :
get_smbpwnam() function renamed to get_smbpwd_entry().
arcfour() issues.
removed capability of get_md4pw() function to automatically add
workstation accounts. this should either be done using
smbpasswd -add MACHINE$, or by using \PIPE\samr.
rpc_pipes/pipe_util.c :
create_pol_hnd() - creates a unique LSA Policy Handle. overkill
function: uses a 64 bit sequence number; current unix time and
the smbd pid.
rpc_pipes/smbparse.c :
arcfour() issues.
smb_io_unistr2() should advance by uni_str_len not uni_max_len.
smb_io_smb_hdr_rb() - request bind uses uint16 for the context
id, and uint8 for the num_syntaxes. oops, i put these both as
uint32s.
Added Files:
------------
rpc_pipes/lsa_hnd.c :
on the samr pipe, allocate and associate an LSA Policy Handle
with a SID. you receive queries with the LSA Policy Handle,
and have to turn this back into a SID in order to answer the
query...
rpc_pipes/pipesamr.c rpc_pipes/samrparse.c
\PIPE\samr processing. samr i presume is the SAM Replication pipe.
rpc_pipes/pipewkssvc.c rpc_pipes/wksparse.c
\PIPE\wkssvc processing. the Workstation Service pipe?
holy cow.
(This used to be commit 1bd084b3e690eb26a1006d616075e53d711ecd2f)
1997-11-07 02:03:58 +03:00
reset_chain_pnum ( ) ;
1996-05-04 11:50:46 +04:00
bzero ( outbuf , smb_size ) ;
if ( msg_type ! = 0 )
return ( reply_special ( inbuf , outbuf ) ) ;
CVAL ( outbuf , smb_com ) = CVAL ( inbuf , smb_com ) ;
set_message ( outbuf , 0 , 0 , True ) ;
memcpy ( outbuf + 4 , inbuf + 4 , 4 ) ;
CVAL ( outbuf , smb_rcls ) = SUCCESS ;
CVAL ( outbuf , smb_reh ) = 0 ;
CVAL ( outbuf , smb_flg ) = 0x80 | ( CVAL ( inbuf , smb_flg ) & 0x8 ) ; /* bit 7 set
means a reply */
SSVAL ( outbuf , smb_flg2 , 1 ) ; /* say we support long filenames */
SSVAL ( outbuf , smb_err , SUCCESS ) ;
SSVAL ( outbuf , smb_tid , SVAL ( inbuf , smb_tid ) ) ;
SSVAL ( outbuf , smb_pid , SVAL ( inbuf , smb_pid ) ) ;
SSVAL ( outbuf , smb_uid , SVAL ( inbuf , smb_uid ) ) ;
SSVAL ( outbuf , smb_mid , SVAL ( inbuf , smb_mid ) ) ;
outsize = switch_message ( type , inbuf , outbuf , size , bufsize ) ;
1996-08-19 17:54:58 +04:00
outsize + = chain_size ;
1996-05-04 11:50:46 +04:00
if ( outsize > 4 )
smb_setlen ( outbuf , outsize - 4 ) ;
return ( outsize ) ;
}
/****************************************************************************
process commands from the client
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 10:42:03 +04:00
static void process ( void )
1996-05-04 11:50:46 +04:00
{
extern int Client ;
InBuffer = ( char * ) malloc ( BUFFER_SIZE + SAFETY_MARGIN ) ;
OutBuffer = ( char * ) malloc ( BUFFER_SIZE + SAFETY_MARGIN ) ;
if ( ( InBuffer = = NULL ) | | ( OutBuffer = = NULL ) )
return ;
InBuffer + = SMB_ALIGNMENT ;
OutBuffer + = SMB_ALIGNMENT ;
# if PRIME_NMBD
DEBUG ( 3 , ( " priming nmbd \n " ) ) ;
{
struct in_addr ip ;
ip = * interpret_addr2 ( " localhost " ) ;
if ( zero_ip ( ip ) ) ip = * interpret_addr2 ( " 127.0.0.1 " ) ;
* OutBuffer = 0 ;
1996-06-04 10:42:03 +04:00
send_one_packet ( OutBuffer , 1 , ip , NMB_PORT , SOCK_DGRAM ) ;
1996-05-04 11:50:46 +04:00
}
# endif
1997-11-01 10:22:18 +03:00
/* re-initialise the timezone */
TimeInit ( ) ;
1996-05-04 11:50:46 +04:00
while ( True )
1997-09-23 23:19:06 +04:00
{
int deadtime = lp_deadtime ( ) * 60 ;
int counter ;
int last_keepalive = 0 ;
int service_load_counter = 0 ;
BOOL got_smb = False ;
if ( deadtime < = 0 )
deadtime = DEFAULT_SMBD_TIMEOUT ;
1997-10-27 16:38:07 +03:00
# if USE_READ_PREDICTION
1997-09-23 23:19:06 +04:00
if ( lp_readprediction ( ) )
do_read_prediction ( ) ;
1997-10-27 16:38:07 +03:00
# endif
1997-09-23 23:19:06 +04:00
errno = 0 ;
for ( counter = SMBD_SELECT_LOOP ;
! receive_message_or_smb ( Client , oplock_sock ,
1997-09-25 04:25:44 +04:00
InBuffer , BUFFER_SIZE , SMBD_SELECT_LOOP * 1000 , & got_smb ) ;
1997-09-23 23:19:06 +04:00
counter + = SMBD_SELECT_LOOP )
1996-05-04 11:50:46 +04:00
{
1997-09-23 23:19:06 +04:00
int i ;
time_t t ;
BOOL allidle = True ;
extern int keepalive ;
1996-05-04 11:50:46 +04:00
1997-07-13 18:05:01 +04:00
if ( counter > 365 * 3600 ) /* big number of seconds. */
{
counter = 0 ;
service_load_counter = 0 ;
}
1997-09-23 23:19:06 +04:00
if ( smb_read_error = = READ_EOF )
{
DEBUG ( 3 , ( " end of file from client \n " ) ) ;
return ;
}
1996-07-30 19:47:30 +04:00
1997-09-23 23:19:06 +04:00
if ( smb_read_error = = READ_ERROR )
{
DEBUG ( 3 , ( " receive_smb error (%s) exiting \n " ,
strerror ( errno ) ) ) ;
return ;
}
1996-05-04 11:50:46 +04:00
1997-09-23 23:19:06 +04:00
t = time ( NULL ) ;
1996-05-04 11:50:46 +04:00
1997-09-23 23:19:06 +04:00
/* become root again if waiting */
unbecome_user ( ) ;
1996-05-04 11:50:46 +04:00
1997-09-23 23:19:06 +04:00
/* check for smb.conf reload */
if ( counter > = service_load_counter + SMBD_RELOAD_CHECK )
1997-07-13 18:05:01 +04:00
{
service_load_counter = counter ;
/* reload services, if files have changed. */
1997-09-23 23:19:06 +04:00
reload_services ( True ) ;
1997-07-13 18:05:01 +04:00
}
1996-05-04 11:50:46 +04:00
1997-09-23 23:19:06 +04:00
/* automatic timeout if all connections are closed */
if ( num_connections_open = = 0 & & counter > = IDLE_CLOSED_TIMEOUT )
{
DEBUG ( 2 , ( " %s Closing idle connection \n " , timestring ( ) ) ) ;
return ;
}
1996-05-04 11:50:46 +04:00
1997-09-23 23:19:06 +04:00
if ( keepalive & & ( counter - last_keepalive ) > keepalive )
{
1997-11-10 22:23:17 +03:00
struct cli_state * cli = server_client ( ) ;
1997-10-21 13:34:33 +04:00
if ( ! send_keepalive ( Client ) ) {
DEBUG ( 2 , ( " %s Keepalive failed - exiting \n " , timestring ( ) ) ) ;
return ;
}
/* also send a keepalive to the password server if its still
connected */
1997-11-10 22:23:17 +03:00
if ( cli & & cli - > initialised )
send_keepalive ( cli - > fd ) ;
1997-10-21 13:34:33 +04:00
last_keepalive = counter ;
1997-09-23 23:19:06 +04:00
}
1996-05-04 11:50:46 +04:00
1997-09-23 23:19:06 +04:00
/* check for connection timeouts */
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
if ( Connections [ i ] . open )
{
/* close dirptrs on connections that are idle */
if ( ( t - Connections [ i ] . lastused ) > DPTR_IDLE_TIMEOUT )
dptr_idlecnum ( i ) ;
if ( Connections [ i ] . num_files_open > 0 | |
( t - Connections [ i ] . lastused ) < deadtime )
allidle = False ;
}
if ( allidle & & num_connections_open > 0 )
{
DEBUG ( 2 , ( " %s Closing idle connection 2 \n " , timestring ( ) ) ) ;
return ;
}
}
1996-05-04 11:50:46 +04:00
1997-09-23 23:19:06 +04:00
if ( got_smb )
1997-09-25 04:25:44 +04:00
process_smb ( InBuffer , OutBuffer ) ;
1997-09-23 23:19:06 +04:00
else
process_local_message ( oplock_sock , InBuffer , BUFFER_SIZE ) ;
}
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
initialise connect , service and file structs
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void init_structs ( void )
{
int i ;
1996-06-06 15:43:09 +04:00
get_myname ( myhostname , NULL ) ;
1996-05-04 11:50:46 +04:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
Connections [ i ] . open = False ;
Connections [ i ] . num_files_open = 0 ;
Connections [ i ] . lastused = 0 ;
Connections [ i ] . used = False ;
string_init ( & Connections [ i ] . user , " " ) ;
string_init ( & Connections [ i ] . dirpath , " " ) ;
string_init ( & Connections [ i ] . connectpath , " " ) ;
string_init ( & Connections [ i ] . origpath , " " ) ;
}
for ( i = 0 ; i < MAX_OPEN_FILES ; i + + )
{
Files [ i ] . open = False ;
string_init ( & Files [ i ] . name , " " ) ;
1997-01-09 21:02:17 +03:00
}
for ( i = 0 ; i < MAX_OPEN_FILES ; i + + )
{
file_fd_struct * fd_ptr = & FileFd [ i ] ;
fd_ptr - > ref_count = 0 ;
fd_ptr - > dev = ( int32 ) - 1 ;
fd_ptr - > inode = ( int32 ) - 1 ;
fd_ptr - > fd = - 1 ;
fd_ptr - > fd_readonly = - 1 ;
fd_ptr - > fd_writeonly = - 1 ;
fd_ptr - > real_open_flags = - 1 ;
1996-05-04 11:50:46 +04:00
}
1997-10-30 20:08:42 +03:00
/* for RPC pipes */
init_rpc_pipe_hnd ( ) ;
following a cvs error, i am rewriting this monster-commit. with bad grace.
Modified Files:
---------------
Makefile:
adding extra files
ipc.c :
send_trans_reply() - alignment issue. this makes the alignment
the same as that in NT. this should be looked at by people who
understand the SMB stuff better than i.
api_fd_commands[] - added samr and wkssvc pipes.
loadparm.c :
lp_domain_controller() changed to mean "samba is a domain controller".
it's a "yes/no" parameter, now. no, it isn't used _anywhere_.
namedbwork.c nameelect.c :
if "domain controller = yes" then add SV_TYPE_DOMAIN_CTRL to the
host _and_ workgroup announcements. yes, you must do both: nt does.
namelogon.c :
important NETLOGON bug in SAMLOGON request parsing, which may be
the source of some people's problems with logging on to the Samba PDC.
password.c :
get_smbpwnam() renamed to get_smbpwd_entry().
pipes.c :
added samr and wkssvc pipes.
proto.h :
usual. can we actually _remove_ proto.h from the cvs tree, and
have it as one of the Makefile dependencies, or something?
reply.c :
get_smbpwnam() renamed to get_smbpwd_entry() - also changed response
error code when logging in from a WORKSTATION$ account. yes, paul
is right: we need to know when to return the right error code, and why.
server.c :
added call to reset_chain_pnum().
#ifdef NTDOMAIN added call to init_lsa_policy_hnd() #endif. jeremy,
you'd be proud: i did a compile without NTDOMAIN, and caught a link
error for this function.
smb.h :
defines and structures for samr and wkssvc pipes.
smbpass.c :
modified get_smbpwnam() to get_smbpwd_entry() and it now takes
two arguments. one for the name; if this is null, it looks up
by smb_userid instead.
oh, by the way, smb_userids are actually domain relative ids
(RIDs). concatenate a RID with the domain SID, and you have
an internet globally unique way of identifying a user.
we're using RIDs in the wrong way....
added mod_smbpwnam() function. this was based on code in smbpasswd.c
rpc_pipes/lsaparse.c :
added enum trusted domain parsing. this is incomplete: i need
a packet trace to write it properly.
rpc_pipes/pipe_hnd.c :
added reset_chain_pnum() function.
rpc_pipes/pipenetlog.c :
get_smbpwnam() function renamed to get_smbpwd_entry().
arcfour() issues.
removed capability of get_md4pw() function to automatically add
workstation accounts. this should either be done using
smbpasswd -add MACHINE$, or by using \PIPE\samr.
rpc_pipes/pipe_util.c :
create_pol_hnd() - creates a unique LSA Policy Handle. overkill
function: uses a 64 bit sequence number; current unix time and
the smbd pid.
rpc_pipes/smbparse.c :
arcfour() issues.
smb_io_unistr2() should advance by uni_str_len not uni_max_len.
smb_io_smb_hdr_rb() - request bind uses uint16 for the context
id, and uint8 for the num_syntaxes. oops, i put these both as
uint32s.
Added Files:
------------
rpc_pipes/lsa_hnd.c :
on the samr pipe, allocate and associate an LSA Policy Handle
with a SID. you receive queries with the LSA Policy Handle,
and have to turn this back into a SID in order to answer the
query...
rpc_pipes/pipesamr.c rpc_pipes/samrparse.c
\PIPE\samr processing. samr i presume is the SAM Replication pipe.
rpc_pipes/pipewkssvc.c rpc_pipes/wksparse.c
\PIPE\wkssvc processing. the Workstation Service pipe?
holy cow.
(This used to be commit 1bd084b3e690eb26a1006d616075e53d711ecd2f)
1997-11-07 02:03:58 +03:00
# ifdef NTDOMAIN
/* for LSA handles */
init_lsa_policy_hnd ( ) ;
# endif
1996-05-04 11:50:46 +04:00
init_dptrs ( ) ;
}
/****************************************************************************
usage on the program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 10:42:03 +04:00
static void usage ( char * pname )
1996-05-04 11:50:46 +04:00
{
DEBUG ( 0 , ( " Incorrect program usage - are you sure the command line is correct? \n " ) ) ;
printf ( " Usage: %s [-D] [-p port] [-d debuglevel] [-l log basename] [-s services file] \n " , pname ) ;
printf ( " Version %s \n " , VERSION ) ;
printf ( " \t -D become a daemon \n " ) ;
printf ( " \t -p port listen on the specified port \n " ) ;
printf ( " \t -d debuglevel set the debuglevel \n " ) ;
printf ( " \t -l log basename. Basename for log/debug files \n " ) ;
printf ( " \t -s services file. Filename of services file \n " ) ;
printf ( " \t -P passive only \n " ) ;
printf ( " \t -a overwrite log file, don't append \n " ) ;
printf ( " \n " ) ;
}
/****************************************************************************
main program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 10:42:03 +04:00
int main ( int argc , char * argv [ ] )
1996-05-04 11:50:46 +04:00
{
extern BOOL append_log ;
/* shall I run as a daemon */
BOOL is_daemon = False ;
1996-06-04 10:42:03 +04:00
int port = SMB_PORT ;
1996-05-04 11:50:46 +04:00
int opt ;
extern char * optarg ;
1996-12-10 21:00:22 +03:00
char pidFile [ 100 ] = { 0 } ;
1996-05-04 11:50:46 +04:00
# ifdef NEED_AUTH_PARAMETERS
set_auth_parameters ( argc , argv ) ;
# endif
# ifdef SecureWare
setluid ( 0 ) ;
# endif
append_log = True ;
TimeInit ( ) ;
strcpy ( debugf , SMBLOGFILE ) ;
setup_logging ( argv [ 0 ] , False ) ;
1997-07-19 00:21:32 +04:00
charset_initialise ( ) ;
1996-05-04 11:50:46 +04:00
/* make absolutely sure we run as root - to handle cases whre people
are crazy enough to have it setuid */
# ifdef USE_SETRES
setresuid ( 0 , 0 , 0 ) ;
# else
setuid ( 0 ) ;
seteuid ( 0 ) ;
setuid ( 0 ) ;
seteuid ( 0 ) ;
# endif
fault_setup ( exit_server ) ;
1996-12-10 21:00:22 +03:00
signal ( SIGTERM , SIGNAL_CAST dflt_sig ) ;
1996-05-04 11:50:46 +04:00
1996-10-04 13:31:07 +04:00
/* we want total control over the permissions on created files,
so set our umask to 0 */
umask ( 0 ) ;
1996-05-04 11:50:46 +04:00
1996-10-07 19:04:48 +04:00
GetWd ( OriginalDir ) ;
1996-06-01 19:25:30 +04:00
init_uid ( ) ;
1996-05-04 11:50:46 +04:00
/* this is for people who can't start the program correctly */
while ( argc > 1 & & ( * argv [ 1 ] ! = ' - ' ) )
{
argv + + ;
argc - - ;
}
1996-12-10 21:00:22 +03:00
while ( ( opt = getopt ( argc , argv , " O:i:l:s:d:Dp:hPaf: " ) ) ! = EOF )
1996-05-04 11:50:46 +04:00
switch ( opt )
{
1996-12-10 21:00:22 +03:00
case ' f ' :
strncpy ( pidFile , optarg , sizeof ( pidFile ) ) ;
break ;
1996-05-04 11:50:46 +04:00
case ' O ' :
strcpy ( user_socket_options , optarg ) ;
break ;
case ' i ' :
strcpy ( scope , optarg ) ;
break ;
case ' P ' :
{
extern BOOL passive ;
passive = True ;
}
break ;
case ' s ' :
strcpy ( servicesf , optarg ) ;
break ;
case ' l ' :
strcpy ( debugf , optarg ) ;
break ;
case ' a ' :
{
extern BOOL append_log ;
append_log = ! append_log ;
}
break ;
case ' D ' :
is_daemon = True ;
break ;
case ' d ' :
if ( * optarg = = ' A ' )
DEBUGLEVEL = 10000 ;
else
DEBUGLEVEL = atoi ( optarg ) ;
break ;
case ' p ' :
port = atoi ( optarg ) ;
break ;
case ' h ' :
usage ( argv [ 0 ] ) ;
exit ( 0 ) ;
break ;
default :
usage ( argv [ 0 ] ) ;
exit ( 1 ) ;
}
reopen_logs ( ) ;
DEBUG ( 2 , ( " %s smbd version %s started \n " , timestring ( ) , VERSION ) ) ;
1997-07-08 20:54:44 +04:00
DEBUG ( 2 , ( " Copyright Andrew Tridgell 1992-1997 \n " ) ) ;
1996-05-04 11:50:46 +04:00
# ifndef NO_GETRLIMIT
# ifdef RLIMIT_NOFILE
{
struct rlimit rlp ;
getrlimit ( RLIMIT_NOFILE , & rlp ) ;
rlp . rlim_cur = ( MAX_OPEN_FILES > rlp . rlim_max ) ? rlp . rlim_max : MAX_OPEN_FILES ;
setrlimit ( RLIMIT_NOFILE , & rlp ) ;
getrlimit ( RLIMIT_NOFILE , & rlp ) ;
DEBUG ( 3 , ( " Maximum number of open files per session is %d \n " , rlp . rlim_cur ) ) ;
}
# endif
# endif
DEBUG ( 2 , ( " uid=%d gid=%d euid=%d egid=%d \n " ,
getuid ( ) , getgid ( ) , geteuid ( ) , getegid ( ) ) ) ;
if ( sizeof ( uint16 ) < 2 | | sizeof ( uint32 ) < 4 )
{
DEBUG ( 0 , ( " ERROR: Samba is not configured correctly for the word size on your machine \n " ) ) ;
exit ( 1 ) ;
}
init_structs ( ) ;
if ( ! reload_services ( False ) )
return ( - 1 ) ;
1997-07-19 00:21:32 +04:00
codepage_initialise ( lp_client_code_page ( ) ) ;
1997-06-11 05:03:06 +04:00
1997-05-20 04:32:51 +04:00
strcpy ( myworkgroup , lp_workgroup ( ) ) ;
1996-05-04 11:50:46 +04:00
# ifndef NO_SIGNAL_TEST
signal ( SIGHUP , SIGNAL_CAST sig_hup ) ;
# endif
DEBUG ( 3 , ( " %s loaded services \n " , timestring ( ) ) ) ;
if ( ! is_daemon & & ! is_a_socket ( 0 ) )
{
DEBUG ( 0 , ( " standard input is not a socket, assuming -D option \n " ) ) ;
is_daemon = True ;
}
if ( is_daemon )
{
DEBUG ( 3 , ( " %s becoming a daemon \n " , timestring ( ) ) ) ;
become_daemon ( ) ;
}
1996-12-10 21:00:22 +03:00
if ( * pidFile )
{
int fd ;
char buf [ 20 ] ;
if ( ( fd = open ( pidFile ,
1997-07-24 21:25:11 +04:00
# ifdef O_NONBLOCK
O_NONBLOCK |
# endif
O_CREAT | O_WRONLY | O_TRUNC , 0644 ) ) < 0 )
1996-12-10 21:00:22 +03:00
{
DEBUG ( 0 , ( " ERROR: can't open %s: %s \n " , pidFile , strerror ( errno ) ) ) ;
exit ( 1 ) ;
}
if ( fcntl_lock ( fd , F_SETLK , 0 , 1 , F_WRLCK ) = = False )
{
DEBUG ( 0 , ( " ERROR: smbd is already running \n " ) ) ;
exit ( 1 ) ;
}
sprintf ( buf , " %u \n " , ( unsigned int ) getpid ( ) ) ;
if ( write ( fd , buf , strlen ( buf ) ) < 0 )
{
DEBUG ( 0 , ( " ERROR: can't write to %s: %s \n " , pidFile , strerror ( errno ) ) ) ;
exit ( 1 ) ;
}
/* Leave pid file open & locked for the duration... */
}
1996-05-05 07:04:19 +04:00
if ( ! open_sockets ( is_daemon , port ) )
exit ( 1 ) ;
1996-05-04 11:50:46 +04:00
1997-10-27 17:27:17 +03:00
if ( ! locking_init ( 0 ) )
1996-08-15 19:11:34 +04:00
exit ( 1 ) ;
1996-05-05 07:04:19 +04:00
/* possibly reload the services file. */
reload_services ( True ) ;
1996-05-04 11:50:46 +04:00
1997-02-28 23:39:36 +03:00
max_recv = MIN ( lp_maxxmit ( ) , BUFFER_SIZE ) ;
1996-05-04 11:50:46 +04:00
1996-05-05 07:04:19 +04:00
if ( * lp_rootdir ( ) )
{
if ( sys_chroot ( lp_rootdir ( ) ) = = 0 )
DEBUG ( 2 , ( " %s changed root to %s \n " , timestring ( ) , lp_rootdir ( ) ) ) ;
1996-05-04 11:50:46 +04:00
}
1996-05-05 07:04:19 +04:00
1997-09-23 23:19:06 +04:00
/* Setup the oplock IPC socket. */
if ( ! open_oplock_ipc ( ) )
exit ( 1 ) ;
1996-05-05 07:04:19 +04:00
process ( ) ;
close_sockets ( ) ;
1996-05-04 11:50:46 +04:00
exit_server ( " normal exit " ) ;
return ( 0 ) ;
}