1996-05-04 11:50:46 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
Main SMB reply routines
Copyright ( C ) Andrew Tridgell 1992 - 1995
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 .
*/
/*
This file handles most of the reply_ calls that the server
makes to handle specific protocols
*/
# include "includes.h"
# include "trans2.h"
/* look in server.c for some explanation of these variables */
extern int Protocol ;
extern int DEBUGLEVEL ;
extern int chain_size ;
extern int maxxmit ;
extern int chain_fnum ;
extern char magic_char ;
extern connection_struct Connections [ ] ;
extern files_struct Files [ ] ;
extern BOOL case_sensitive ;
extern pstring sesssetup_user ;
extern int Client ;
/* this macro should always be used to extract an fnum (smb_fid) from
a packet to ensure chaining works correctly */
# define GETFNUM(buf,where) (chain_fnum!= -1?chain_fnum:SVAL(buf,where))
/****************************************************************************
reply to an special message
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_special ( char * inbuf , char * outbuf )
{
int outsize = 4 ;
int msg_type = CVAL ( inbuf , 0 ) ;
int msg_flags = CVAL ( inbuf , 1 ) ;
pstring name1 , name2 ;
extern fstring remote_machine ;
extern fstring local_machine ;
char * p ;
* name1 = * name2 = 0 ;
smb_setlen ( outbuf , 0 ) ;
switch ( msg_type )
{
case 0x81 : /* session request */
CVAL ( outbuf , 0 ) = 0x82 ;
CVAL ( outbuf , 3 ) = 0 ;
if ( name_len ( inbuf + 4 ) > 50 )
{
DEBUG ( 0 , ( " Invalid name length in session request \n " ) ) ;
return ( 0 ) ;
}
name_extract ( inbuf , 4 , name1 ) ;
name_extract ( inbuf , 4 + name_len ( inbuf + 4 ) , name2 ) ;
DEBUG ( 2 , ( " netbios connect: name1=%s name2=%s \n " , name1 , name2 ) ) ;
strcpy ( remote_machine , name2 ) ;
trim_string ( remote_machine , " " , " " ) ;
p = strchr ( remote_machine , ' ' ) ;
strlower ( remote_machine ) ;
if ( p ) * p = 0 ;
strcpy ( local_machine , name1 ) ;
trim_string ( local_machine , " " , " " ) ;
p = strchr ( local_machine , ' ' ) ;
strlower ( local_machine ) ;
if ( p ) * p = 0 ;
add_session_user ( remote_machine ) ;
reload_services ( True ) ;
reopen_logs ( ) ;
break ;
case 0x85 : /* session keepalive */
default :
return ( 0 ) ;
}
DEBUG ( 5 , ( " %s init msg_type=0x%x msg_flags=0x%x \n " , timestring ( ) , msg_type , msg_flags ) ) ;
return ( outsize ) ;
}
/*******************************************************************
work out what error to give to a failed connection
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int connection_error ( char * inbuf , char * outbuf , int connection_num )
{
switch ( connection_num )
{
case - 8 :
return ( ERROR ( ERRSRV , ERRnoresource ) ) ;
case - 7 :
return ( ERROR ( ERRSRV , ERRbaduid ) ) ;
case - 6 :
return ( ERROR ( ERRSRV , ERRinvdevice ) ) ;
case - 5 :
return ( ERROR ( ERRSRV , ERRinvnetname ) ) ;
case - 4 :
return ( ERROR ( ERRSRV , ERRaccess ) ) ;
case - 3 :
return ( ERROR ( ERRDOS , ERRnoipc ) ) ;
case - 2 :
return ( ERROR ( ERRSRV , ERRinvnetname ) ) ;
}
return ( ERROR ( ERRSRV , ERRbadpw ) ) ;
}
/****************************************************************************
reply to a tcon
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_tcon ( char * inbuf , char * outbuf )
{
pstring service ;
pstring user ;
pstring password ;
pstring dev ;
int connection_num ;
int outsize = 0 ;
int uid = SVAL ( inbuf , smb_uid ) ;
int vuid ;
int pwlen ;
* service = * user = * password = * dev = 0 ;
vuid = valid_uid ( uid ) ;
parse_connect ( inbuf , service , user , password , & pwlen , dev ) ;
connection_num = make_connection ( service , user , password , pwlen , dev , vuid ) ;
if ( connection_num < 0 )
return ( connection_error ( inbuf , outbuf , connection_num ) ) ;
outsize = set_message ( outbuf , 2 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , maxxmit ) ;
SSVAL ( outbuf , smb_vwv1 , connection_num ) ;
SSVAL ( outbuf , smb_tid , connection_num ) ;
DEBUG ( 3 , ( " %s tcon service=%s user=%s cnum=%d \n " , timestring ( ) , service , user , connection_num ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a tcon and X
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_tcon_and_X ( char * inbuf , char * outbuf , int length , int bufsize )
{
pstring service ;
pstring user ;
pstring password ;
pstring devicename ;
int connection_num ;
int outsize = 0 ;
int uid = SVAL ( inbuf , smb_uid ) ;
int vuid ;
int smb_com2 = SVAL ( inbuf , smb_vwv0 ) ;
int smb_off2 = SVAL ( inbuf , smb_vwv1 ) ;
int passlen = SVAL ( inbuf , smb_vwv3 ) ;
* service = * user = * password = * devicename = 0 ;
/* we might have to close an old one */
if ( ( SVAL ( inbuf , smb_vwv2 ) & 0x1 ) ! = 0 )
close_cnum ( SVAL ( inbuf , smb_tid ) , uid ) ;
vuid = valid_uid ( uid ) ;
{
char * path ;
char * p ;
memcpy ( password , smb_buf ( inbuf ) , passlen ) ;
password [ passlen ] = 0 ;
path = smb_buf ( inbuf ) + passlen ;
DEBUG ( 4 , ( " parsing net-path %s, passlen=%d \n " , path , passlen ) ) ;
strcpy ( service , path + 2 ) ;
p = strchr ( service , ' \\ ' ) ;
if ( ! p )
return ( ERROR ( ERRSRV , ERRinvnetname ) ) ;
* p = 0 ;
strcpy ( service , p + 1 ) ;
p = strchr ( service , ' % ' ) ;
if ( p )
{
* p + + = 0 ;
strcpy ( user , p ) ;
}
StrnCpy ( devicename , path + strlen ( path ) + 1 , 6 ) ;
DEBUG ( 4 , ( " Got device type %s \n " , devicename ) ) ;
}
connection_num = make_connection ( service , user , password , passlen , devicename , vuid ) ;
if ( connection_num < 0 )
return ( connection_error ( inbuf , outbuf , connection_num ) ) ;
outsize = set_message ( outbuf , 2 , strlen ( devicename ) + 1 , True ) ;
DEBUG ( 3 , ( " %s tconX service=%s user=%s cnum=%d \n " , timestring ( ) , service , user , connection_num ) ) ;
/* set the incoming and outgoing tid to the just created one */
SSVAL ( inbuf , smb_tid , connection_num ) ;
SSVAL ( outbuf , smb_tid , connection_num ) ;
CVAL ( outbuf , smb_vwv0 ) = smb_com2 ;
SSVAL ( outbuf , smb_vwv1 , ( chain_size + outsize ) - 4 ) ;
strcpy ( smb_buf ( outbuf ) , devicename ) ;
if ( smb_com2 ! = 0xFF )
outsize + = chain_reply ( smb_com2 , inbuf , inbuf + smb_off2 + 4 ,
outbuf , outbuf + outsize ,
length , bufsize ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to an unknown type
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_unknown ( char * inbuf , char * outbuf )
{
int cnum ;
int type ;
cnum = SVAL ( inbuf , smb_tid ) ;
type = CVAL ( inbuf , smb_com ) ;
DEBUG ( 0 , ( " %s unknown command type (%s): cnum=%d type=%d (0x%X) \n " ,
timestring ( ) ,
smb_fn_name ( type ) ,
cnum , type , type ) ) ;
return ( ERROR ( ERRSRV , ERRunknownsmb ) ) ;
}
/****************************************************************************
reply to an ioctl
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_ioctl ( char * inbuf , char * outbuf )
{
DEBUG ( 3 , ( " ignoring ioctl \n " ) ) ;
return ( ERROR ( ERRSRV , ERRnosupport ) ) ;
}
/****************************************************************************
reply to a session setup command
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_sesssetup_and_X ( char * inbuf , char * outbuf , int length , int bufsize )
{
int outsize = 0 ;
int sess_uid ;
int gid ;
int smb_com2 ;
int smb_off2 ;
int smb_bufsize ;
int smb_mpxmax ;
int smb_vc_num ;
uint32 smb_sesskey ;
int smb_apasslen ;
pstring smb_apasswd ;
int smb_ntpasslen = 0 ;
pstring smb_ntpasswd ;
BOOL valid_nt_password = False ;
pstring user ;
BOOL guest = False ;
* smb_apasswd = 0 ;
sess_uid = SVAL ( inbuf , smb_uid ) ;
smb_com2 = CVAL ( inbuf , smb_vwv0 ) ;
smb_off2 = SVAL ( inbuf , smb_vwv1 ) ;
smb_bufsize = SVAL ( inbuf , smb_vwv2 ) ;
smb_mpxmax = SVAL ( inbuf , smb_vwv3 ) ;
smb_vc_num = SVAL ( inbuf , smb_vwv4 ) ;
smb_sesskey = IVAL ( inbuf , smb_vwv5 ) ;
if ( Protocol < PROTOCOL_NT1 ) {
smb_apasslen = SVAL ( inbuf , smb_vwv7 ) ;
memcpy ( smb_apasswd , smb_buf ( inbuf ) , smb_apasslen ) ;
StrnCpy ( user , smb_buf ( inbuf ) + smb_apasslen , sizeof ( user ) - 1 ) ;
} else {
uint16 passlen1 = SVAL ( inbuf , smb_vwv7 ) ;
uint16 passlen2 = SVAL ( inbuf , smb_vwv8 ) ;
BOOL doencrypt = SMBENCRYPT ( ) ;
char * p = smb_buf ( inbuf ) ;
if ( passlen1 > 256 ) passlen1 = 0 ;
if ( passlen2 > 256 ) passlen2 = 0 ; /* I don't know why NT gives weird
lengths sometimes */
if ( doencrypt ) {
/* Save the lanman2 password and the NT md4 password. */
smb_apasslen = passlen1 ;
memcpy ( smb_apasswd , p , smb_apasslen ) ;
smb_ntpasslen = passlen2 ;
memcpy ( smb_ntpasswd , p + passlen1 , smb_ntpasslen ) ;
} else {
/* for Win95 */
if ( passlen1 > passlen2 ) {
smb_apasslen = passlen1 ;
StrnCpy ( smb_apasswd , p , smb_apasslen ) ;
} else {
smb_apasslen = passlen2 ;
StrnCpy ( smb_apasswd , p + passlen1 , smb_apasslen ) ;
}
}
1996-05-31 10:09:42 +04:00
# if NT_WORKAROUND
1996-05-04 11:50:46 +04:00
if ( passlen2 = = 1 ) {
/* apparently NT sometimes sets passlen2 to 1 when it means 0. This
tries to work around that problem */
passlen2 = 0 ;
}
1996-05-31 10:09:42 +04:00
# endif
1996-05-04 11:50:46 +04:00
p + = passlen1 + passlen2 ;
strcpy ( user , p ) ; p = skip_string ( p , 1 ) ;
DEBUG ( 3 , ( " Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] \n " ,
p , skip_string ( p , 1 ) , skip_string ( p , 2 ) ) ) ;
}
DEBUG ( 3 , ( " sesssetupX:name=[%s] \n " , user ) ) ;
if ( ! * user )
strcpy ( user , lp_guestaccount ( - 1 ) ) ;
strlower ( user ) ;
strcpy ( sesssetup_user , user ) ;
reload_services ( True ) ;
add_session_user ( user ) ;
if ( ! ( lp_security ( ) = = SEC_SERVER & & server_validate ( inbuf ) ) & &
! check_hosts_equiv ( user ) )
{
if ( strequal ( user , lp_guestaccount ( - 1 ) ) & & ( * smb_apasswd = = 0 ) )
guest = True ;
/* now check if it's a valid username/password */
/* If an NT password was supplied try and validate with that
first . This is superior as the passwords are mixed case 128 length unicode */
if ( smb_ntpasslen & & ! guest )
{
if ( ! password_ok ( user , smb_ntpasswd , smb_ntpasslen , NULL , True ) )
DEBUG ( 0 , ( " NT Password did not match ! Defaulting to Lanman \n " ) ) ;
else
valid_nt_password = True ;
}
if ( ! valid_nt_password & & ! guest & & ! password_ok ( user , smb_apasswd , smb_apasslen , NULL , False ) )
{
if ( lp_security ( ) > = SEC_USER ) {
# if (GUEST_SESSSETUP == 0)
return ( ERROR ( ERRSRV , ERRbadpw ) ) ;
# endif
# if (GUEST_SESSSETUP == 1)
if ( Get_Pwnam ( user , True ) )
return ( ERROR ( ERRSRV , ERRbadpw ) ) ;
# endif
}
if ( * smb_apasswd | | ! Get_Pwnam ( user , True ) )
strcpy ( user , lp_guestaccount ( - 1 ) ) ;
DEBUG ( 3 , ( " Registered username %s for guest access \n " , user ) ) ;
guest = True ;
}
}
if ( ! Get_Pwnam ( user , True ) ) {
DEBUG ( 3 , ( " No such user %s - using guest account \n " , user ) ) ;
strcpy ( user , lp_guestaccount ( - 1 ) ) ;
guest = True ;
}
if ( ! strequal ( user , lp_guestaccount ( - 1 ) ) & &
lp_servicenumber ( user ) < 0 )
{
int homes = lp_servicenumber ( HOMES_NAME ) ;
char * home = get_home_dir ( user ) ;
if ( homes > = 0 & & home )
lp_add_home ( user , homes , home ) ;
}
/* it's ok - setup a reply */
if ( Protocol < PROTOCOL_NT1 ) {
outsize = set_message ( outbuf , 3 , 0 , True ) ;
} else {
char * p ;
outsize = set_message ( outbuf , 3 , 3 , True ) ;
p = smb_buf ( outbuf ) ;
strcpy ( p , " Unix " ) ; p = skip_string ( p , 1 ) ;
strcpy ( p , " Samba " ) ; strcat ( p , VERSION ) ; p = skip_string ( p , 1 ) ;
strcpy ( p , my_workgroup ( ) ) ; p = skip_string ( p , 1 ) ;
outsize = set_message ( outbuf , 3 , PTR_DIFF ( p , smb_buf ( outbuf ) ) , False ) ;
/* perhaps grab OS version here?? */
}
/* Set the correct uid in the outgoing and incoming packets
We will use this on future requests to determine which
user we should become .
*/
{
struct passwd * pw = Get_Pwnam ( user , False ) ;
if ( ! pw ) {
DEBUG ( 1 , ( " Username %s is invalid on this system \n " , user ) ) ;
return ( ERROR ( ERRSRV , ERRbadpw ) ) ;
}
gid = pw - > pw_gid ;
SSVAL ( outbuf , smb_uid , ( uint16 ) pw - > pw_uid ) ;
SSVAL ( inbuf , smb_uid , ( uint16 ) pw - > pw_uid ) ;
}
CVAL ( outbuf , smb_vwv0 ) = smb_com2 ;
SSVAL ( outbuf , smb_vwv1 , ( chain_size + outsize ) - 4 ) ;
if ( guest )
SSVAL ( outbuf , smb_vwv2 , 1 ) ;
/* register the name and uid as being validated, so further connections
to a uid can get through without a password , on the same VC */
register_uid ( SVAL ( inbuf , smb_uid ) , gid , user , guest ) ;
maxxmit = MIN ( maxxmit , smb_bufsize ) ;
if ( smb_com2 ! = 0xFF )
outsize + = chain_reply ( smb_com2 , inbuf , inbuf + smb_off2 + 4 ,
outbuf , outbuf + outsize ,
length , bufsize ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a chkpth
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_chkpth ( char * inbuf , char * outbuf )
{
int outsize = 0 ;
int cnum , mode ;
pstring name ;
BOOL ok = False ;
cnum = SVAL ( inbuf , smb_tid ) ;
strcpy ( name , smb_buf ( inbuf ) + 1 ) ;
unix_convert ( name , cnum ) ;
mode = SVAL ( inbuf , smb_vwv0 ) ;
if ( check_name ( name , cnum ) )
ok = directory_exist ( name , NULL ) ;
if ( ! ok )
return ( ERROR ( ERRDOS , ERRbadpath ) ) ;
outsize = set_message ( outbuf , 0 , 0 , True ) ;
DEBUG ( 3 , ( " %s chkpth %s cnum=%d mode=%d \n " , timestring ( ) , name , cnum , mode ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a getatr
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_getatr ( char * inbuf , char * outbuf )
{
pstring fname ;
int cnum ;
int outsize = 0 ;
struct stat sbuf ;
BOOL ok = False ;
int mode = 0 ;
uint32 size = 0 ;
time_t mtime = 0 ;
cnum = SVAL ( inbuf , smb_tid ) ;
strcpy ( fname , smb_buf ( inbuf ) + 1 ) ;
unix_convert ( fname , cnum ) ;
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
under WfWg - weird ! */
if ( ! ( * fname ) )
{
mode = aHIDDEN | aDIR ;
if ( ! CAN_WRITE ( cnum ) ) mode | = aRONLY ;
size = 0 ;
mtime = 0 ;
ok = True ;
}
else
if ( check_name ( fname , cnum ) )
{
if ( sys_stat ( fname , & sbuf ) = = 0 )
{
mode = dos_mode ( cnum , fname , & sbuf ) ;
size = sbuf . st_size ;
mtime = sbuf . st_mtime ;
if ( mode & aDIR )
size = 0 ;
ok = True ;
}
else
DEBUG ( 3 , ( " stat of %s failed (%s) \n " , fname , strerror ( errno ) ) ) ;
}
if ( ! ok )
return ( UNIXERROR ( ERRDOS , ERRbadfile ) ) ;
outsize = set_message ( outbuf , 10 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , mode ) ;
put_dos_date3 ( outbuf , smb_vwv1 , mtime ) ;
SIVAL ( outbuf , smb_vwv3 , size ) ;
if ( Protocol > = PROTOCOL_NT1 ) {
char * p = strrchr ( fname , ' / ' ) ;
uint16 flg2 = SVAL ( outbuf , smb_flg2 ) ;
if ( ! p ) p = fname ;
if ( ! is_8_3 ( fname ) )
SSVAL ( outbuf , smb_flg2 , flg2 | 0x40 ) ; /* IS_LONG_NAME */
}
DEBUG ( 3 , ( " %s getatr name=%s mode=%d size=%d \n " , timestring ( ) , fname , mode , size ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a setatr
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_setatr ( char * inbuf , char * outbuf )
{
pstring fname ;
int cnum ;
int outsize = 0 ;
BOOL ok = False ;
int mode ;
time_t mtime ;
cnum = SVAL ( inbuf , smb_tid ) ;
strcpy ( fname , smb_buf ( inbuf ) + 1 ) ;
unix_convert ( fname , cnum ) ;
mode = SVAL ( inbuf , smb_vwv0 ) ;
mtime = make_unix_date3 ( inbuf + smb_vwv1 ) ;
if ( directory_exist ( fname , NULL ) )
mode | = aDIR ;
if ( check_name ( fname , cnum ) )
ok = ( dos_chmod ( cnum , fname , mode , NULL ) = = 0 ) ;
if ( ok )
ok = set_filetime ( fname , mtime ) ;
if ( ! ok )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
outsize = set_message ( outbuf , 0 , 0 , True ) ;
DEBUG ( 3 , ( " %s setatr name=%s mode=%d \n " , timestring ( ) , fname , mode ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a dskattr
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_dskattr ( char * inbuf , char * outbuf )
{
int cnum ;
int outsize = 0 ;
int dfree , dsize , bsize ;
cnum = SVAL ( inbuf , smb_tid ) ;
sys_disk_free ( " . " , & bsize , & dfree , & dsize ) ;
outsize = set_message ( outbuf , 5 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , dsize ) ;
SSVAL ( outbuf , smb_vwv1 , bsize / 512 ) ;
SSVAL ( outbuf , smb_vwv2 , 512 ) ;
SSVAL ( outbuf , smb_vwv3 , dfree ) ;
DEBUG ( 3 , ( " %s dskattr cnum=%d dfree=%d \n " , timestring ( ) , cnum , dfree ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a search
Can be called from SMBsearch , SMBffirst or SMBfunique .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_search ( char * inbuf , char * outbuf )
{
pstring mask ;
pstring directory ;
pstring fname ;
int size , mode ;
time_t date ;
int dirtype ;
int cnum ;
int outsize = 0 ;
int numentries = 0 ;
BOOL finished = False ;
int maxentries ;
int i ;
char * p ;
BOOL ok = False ;
int status_len ;
char * path ;
char status [ 21 ] ;
int dptr_num = - 1 ;
BOOL check_descend = False ;
BOOL expect_close = False ;
BOOL can_open = True ;
* mask = * directory = * fname = 0 ;
/* If we were called as SMBffirst then we must expect close. */
if ( CVAL ( inbuf , smb_com ) = = SMBffirst )
expect_close = True ;
cnum = SVAL ( inbuf , smb_tid ) ;
outsize = set_message ( outbuf , 1 , 3 , True ) ;
maxentries = SVAL ( inbuf , smb_vwv0 ) ;
dirtype = SVAL ( inbuf , smb_vwv1 ) ;
path = smb_buf ( inbuf ) + 1 ;
status_len = SVAL ( smb_buf ( inbuf ) , 3 + strlen ( path ) ) ;
/* dirtype &= ~aDIR; */
DEBUG ( 5 , ( " path=%s status_len=%d \n " , path , status_len ) ) ;
if ( status_len = = 0 )
{
pstring dir2 ;
strcpy ( directory , smb_buf ( inbuf ) + 1 ) ;
strcpy ( dir2 , smb_buf ( inbuf ) + 1 ) ;
unix_convert ( directory , cnum ) ;
unix_format ( dir2 ) ;
if ( ! check_name ( directory , cnum ) )
can_open = False ;
p = strrchr ( dir2 , ' / ' ) ;
if ( p = = NULL )
{ strcpy ( mask , dir2 ) ; * dir2 = 0 ; }
else
{ * p = 0 ; strcpy ( mask , p + 1 ) ; }
p = strrchr ( directory , ' / ' ) ;
if ( ! p )
* directory = 0 ;
else
* p = 0 ;
if ( strlen ( directory ) = = 0 )
strcpy ( directory , " ./ " ) ;
bzero ( status , 21 ) ;
CVAL ( status , 0 ) = dirtype ;
}
else
{
memcpy ( status , smb_buf ( inbuf ) + 1 + strlen ( path ) + 4 , 21 ) ;
memcpy ( mask , status + 1 , 11 ) ;
mask [ 11 ] = 0 ;
dirtype = CVAL ( status , 0 ) & 0x1F ;
Connections [ cnum ] . dirptr = dptr_fetch ( status + 12 , & dptr_num ) ;
if ( ! Connections [ cnum ] . dirptr )
goto SearchEmpty ;
string_set ( & Connections [ cnum ] . dirpath , dptr_path ( dptr_num ) ) ;
if ( ! case_sensitive )
strnorm ( mask ) ;
}
/* turn strings of spaces into a . */
{
trim_string ( mask , NULL , " " ) ;
if ( ( p = strrchr ( mask , ' ' ) ) )
{
fstring ext ;
strcpy ( ext , p + 1 ) ;
* p = 0 ;
trim_string ( mask , NULL , " " ) ;
strcat ( mask , " . " ) ;
strcat ( mask , ext ) ;
}
}
{
for ( p = mask ; * p ; p + + )
{
if ( * p ! = ' ? ' & & * p ! = ' * ' & & ! isdoschar ( * p ) )
{
DEBUG ( 5 , ( " Invalid char [%c] in search mask? \n " , * p ) ) ;
* p = ' ? ' ;
}
}
}
if ( ! strchr ( mask , ' . ' ) & & strlen ( mask ) > 8 )
{
fstring tmp ;
strcpy ( tmp , & mask [ 8 ] ) ;
mask [ 8 ] = ' . ' ;
mask [ 9 ] = 0 ;
strcat ( mask , tmp ) ;
}
DEBUG ( 5 , ( " mask=%s directory=%s \n " , mask , directory ) ) ;
if ( can_open )
{
p = smb_buf ( outbuf ) + 3 ;
ok = True ;
if ( status_len = = 0 )
{
dptr_num = dptr_create ( cnum , directory , expect_close , SVAL ( inbuf , smb_pid ) ) ;
if ( dptr_num < 0 )
return ( ERROR ( ERRDOS , ERRnofids ) ) ;
}
DEBUG ( 4 , ( " dptr_num is %d \n " , dptr_num ) ) ;
if ( ok )
{
if ( ( dirtype & 0x1F ) = = aVOLID )
{
memcpy ( p , status , 21 ) ;
make_dir_struct ( p , " ??????????? " , volume_label ( SNUM ( cnum ) ) , 0 , aVOLID , 0 ) ;
dptr_fill ( p + 12 , dptr_num ) ;
if ( dptr_zero ( p + 12 ) & & ( status_len = = 0 ) )
numentries = 1 ;
else
numentries = 0 ;
p + = DIR_STRUCT_SIZE ;
}
else
{
DEBUG ( 8 , ( " dirpath=<%s> dontdescend=<%s> \n " , Connections [ cnum ] . dirpath , lp_dontdescend ( SNUM ( cnum ) ) ) ) ;
if ( in_list ( Connections [ cnum ] . dirpath ,
lp_dontdescend ( SNUM ( cnum ) ) , True ) )
check_descend = True ;
for ( i = numentries ; ( i < maxentries ) & & ! finished ; i + + )
{
finished =
! get_dir_entry ( cnum , mask , dirtype , fname , & size , & mode , & date , check_descend ) ;
if ( ! finished )
{
memcpy ( p , status , 21 ) ;
make_dir_struct ( p , mask , fname , size , mode , date ) ;
dptr_fill ( p + 12 , dptr_num ) ;
numentries + + ;
}
p + = DIR_STRUCT_SIZE ;
}
}
}
}
SearchEmpty :
if ( numentries = = 0 | | ! ok )
{
CVAL ( outbuf , smb_rcls ) = ERRDOS ;
SSVAL ( outbuf , smb_err , ERRnofiles ) ;
}
/* If we were called as SMBffirst with smb_search_id == NULL
and no entries were found then return error and close dirptr
( X / Open spec ) */
if ( ok & & expect_close & & numentries = = 0 & & status_len = = 0 )
{
CVAL ( outbuf , smb_rcls ) = ERRDOS ;
SSVAL ( outbuf , smb_err , ERRnofiles ) ;
/* Also close the dptr - we know it's gone */
dptr_close ( dptr_num ) ;
}
/* If we were called as SMBfunique, then we can close the dirptr now ! */
if ( dptr_num > = 0 & & CVAL ( inbuf , smb_com ) = = SMBfunique )
dptr_close ( dptr_num ) ;
SSVAL ( outbuf , smb_vwv0 , numentries ) ;
SSVAL ( outbuf , smb_vwv1 , 3 + numentries * DIR_STRUCT_SIZE ) ;
CVAL ( smb_buf ( outbuf ) , 0 ) = 5 ;
SSVAL ( smb_buf ( outbuf ) , 1 , numentries * DIR_STRUCT_SIZE ) ;
if ( Protocol > = PROTOCOL_NT1 ) {
uint16 flg2 = SVAL ( outbuf , smb_flg2 ) ;
SSVAL ( outbuf , smb_flg2 , flg2 | 0x40 ) ; /* IS_LONG_NAME */
}
outsize + = DIR_STRUCT_SIZE * numentries ;
smb_setlen ( outbuf , outsize - 4 ) ;
if ( ( ! * directory ) & & dptr_path ( dptr_num ) )
sprintf ( directory , " (%s) " , dptr_path ( dptr_num ) ) ;
DEBUG ( 4 , ( " %s %s mask=%s path=%s cnum=%d dtype=%d nument=%d of %d \n " ,
timestring ( ) ,
smb_fn_name ( CVAL ( inbuf , smb_com ) ) ,
mask , directory , cnum , dirtype , numentries , maxentries ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a fclose ( stop directory search )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_fclose ( char * inbuf , char * outbuf )
{
int cnum ;
int outsize = 0 ;
int status_len ;
char * path ;
char status [ 21 ] ;
int dptr_num = - 1 ;
cnum = SVAL ( inbuf , smb_tid ) ;
outsize = set_message ( outbuf , 1 , 0 , True ) ;
path = smb_buf ( inbuf ) + 1 ;
status_len = SVAL ( smb_buf ( inbuf ) , 3 + strlen ( path ) ) ;
if ( status_len = = 0 )
return ( ERROR ( ERRSRV , ERRsrverror ) ) ;
memcpy ( status , smb_buf ( inbuf ) + 1 + strlen ( path ) + 4 , 21 ) ;
if ( dptr_fetch ( status + 12 , & dptr_num ) ) {
/* Close the dptr - we know it's gone */
dptr_close ( dptr_num ) ;
}
SSVAL ( outbuf , smb_vwv0 , 0 ) ;
DEBUG ( 3 , ( " %s search close cnum=%d \n " , timestring ( ) , cnum ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to an open
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_open ( char * inbuf , char * outbuf )
{
pstring fname ;
int cnum ;
int fnum = - 1 ;
int outsize = 0 ;
int fmode = 0 ;
int share_mode ;
int size = 0 ;
time_t mtime = 0 ;
int unixmode ;
int rmode = 0 ;
struct stat sbuf ;
cnum = SVAL ( inbuf , smb_tid ) ;
share_mode = SVAL ( inbuf , smb_vwv0 ) ;
strcpy ( fname , smb_buf ( inbuf ) + 1 ) ;
unix_convert ( fname , cnum ) ;
fnum = find_free_file ( ) ;
if ( fnum < 0 )
return ( ERROR ( ERRSRV , ERRnofids ) ) ;
if ( ! check_name ( fname , cnum ) )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
unixmode = unix_mode ( cnum , aARCH ) ;
open_file_shared ( fnum , cnum , fname , share_mode , 3 , unixmode , & rmode , NULL ) ;
if ( ! Files [ fnum ] . open )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
if ( fstat ( Files [ fnum ] . fd , & sbuf ) ! = 0 ) {
close_file ( fnum ) ;
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
}
size = sbuf . st_size ;
fmode = dos_mode ( cnum , fname , & sbuf ) ;
mtime = sbuf . st_mtime ;
if ( fmode & aDIR ) {
DEBUG ( 3 , ( " attempt to open a directory %s \n " , fname ) ) ;
close_file ( fnum ) ;
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
}
outsize = set_message ( outbuf , 7 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , fnum ) ;
SSVAL ( outbuf , smb_vwv1 , fmode ) ;
put_dos_date3 ( outbuf , smb_vwv2 , mtime ) ;
SIVAL ( outbuf , smb_vwv4 , size ) ;
SSVAL ( outbuf , smb_vwv6 , rmode ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to an open and X
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_open_and_X ( char * inbuf , char * outbuf , int length , int bufsize )
{
pstring fname ;
int cnum = SVAL ( inbuf , smb_tid ) ;
int fnum = - 1 ;
int outsize = 0 ;
int openmode = 0 ;
int smb_com2 = CVAL ( inbuf , smb_vwv0 ) ;
int smb_off2 = SVAL ( inbuf , smb_vwv1 ) ;
int smb_mode = SVAL ( inbuf , smb_vwv3 ) ;
int smb_attr = SVAL ( inbuf , smb_vwv5 ) ;
#if 0
int open_flags = SVAL ( inbuf , smb_vwv2 ) ;
int smb_sattr = SVAL ( inbuf , smb_vwv4 ) ;
uint32 smb_time = make_unix_date3 ( inbuf + smb_vwv6 ) ;
# endif
int smb_ofun = SVAL ( inbuf , smb_vwv8 ) ;
int unixmode ;
int size = 0 , fmode = 0 , mtime = 0 , rmode = 0 ;
struct stat sbuf ;
int smb_action = 0 ;
/* XXXX we need to handle passed times, sattr and flags */
strcpy ( fname , smb_buf ( inbuf ) ) ;
unix_convert ( fname , cnum ) ;
/* now add create and trunc bits */
if ( smb_ofun & 0x10 )
openmode | = O_CREAT ;
if ( ( smb_ofun & 0x3 ) = = 2 )
openmode | = O_TRUNC ;
fnum = find_free_file ( ) ;
if ( fnum < 0 )
return ( ERROR ( ERRSRV , ERRnofids ) ) ;
if ( ! check_name ( fname , cnum ) )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
unixmode = unix_mode ( cnum , smb_attr | aARCH ) ;
open_file_shared ( fnum , cnum , fname , smb_mode , smb_ofun , unixmode ,
& rmode , & smb_action ) ;
if ( ! Files [ fnum ] . open )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
if ( fstat ( Files [ fnum ] . fd , & sbuf ) ! = 0 ) {
close_file ( fnum ) ;
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
}
size = sbuf . st_size ;
fmode = dos_mode ( cnum , fname , & sbuf ) ;
mtime = sbuf . st_mtime ;
if ( fmode & aDIR ) {
close_file ( fnum ) ;
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
}
outsize = set_message ( outbuf , 15 , 0 , True ) ;
CVAL ( outbuf , smb_vwv0 ) = smb_com2 ;
SSVAL ( outbuf , smb_vwv1 , ( chain_size + outsize ) - 4 ) ;
SSVAL ( outbuf , smb_vwv2 , fnum ) ;
SSVAL ( outbuf , smb_vwv3 , fmode ) ;
put_dos_date3 ( outbuf , smb_vwv4 , mtime ) ;
SIVAL ( outbuf , smb_vwv6 , size ) ;
SSVAL ( outbuf , smb_vwv8 , rmode ) ;
SSVAL ( outbuf , smb_vwv11 , smb_action ) ;
chain_fnum = fnum ;
if ( smb_com2 ! = 0xFF )
outsize + = chain_reply ( smb_com2 , inbuf , inbuf + smb_off2 + 4 ,
outbuf , outbuf + outsize ,
length , bufsize ) ;
chain_fnum = - 1 ;
return ( outsize ) ;
}
/****************************************************************************
reply to a SMBulogoffX
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_ulogoffX ( char * inbuf , char * outbuf , int length , int bufsize )
{
int outsize = 0 ;
int smb_com2 = CVAL ( inbuf , smb_vwv0 ) ;
int smb_off2 = SVAL ( inbuf , smb_vwv1 ) ;
int uid = SVAL ( inbuf , smb_uid ) ;
invalidate_uid ( uid ) ;
outsize = set_message ( outbuf , 2 , 0 , True ) ;
CVAL ( outbuf , smb_vwv0 ) = smb_com2 ;
SSVAL ( outbuf , smb_vwv1 , ( chain_size + outsize ) - 4 ) ;
DEBUG ( 3 , ( " %s ulogoffX uid=%d \n " , timestring ( ) , uid ) ) ;
if ( smb_com2 ! = 0xFF )
outsize + = chain_reply ( smb_com2 , inbuf , inbuf + smb_off2 + 4 ,
outbuf , outbuf + outsize ,
length , bufsize ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a mknew
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_mknew ( char * inbuf , char * outbuf )
{
pstring fname ;
int cnum , com ;
int fnum = - 1 ;
int outsize = 0 ;
int createmode ;
mode_t unixmode ;
com = SVAL ( inbuf , smb_com ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
createmode = SVAL ( inbuf , smb_vwv0 ) ;
strcpy ( fname , smb_buf ( inbuf ) + 1 ) ;
unix_convert ( fname , cnum ) ;
if ( createmode & aVOLID )
{
DEBUG ( 0 , ( " Attempt to create file (%s) with volid set - please report this \n " , fname ) ) ;
}
unixmode = unix_mode ( cnum , createmode ) ;
if ( com = = SMBmknew & & file_exist ( fname , NULL ) )
return ( ERROR ( ERRDOS , ERRfilexists ) ) ;
fnum = find_free_file ( ) ;
if ( fnum < 0 )
return ( ERROR ( ERRSRV , ERRnofids ) ) ;
if ( ! check_name ( fname , cnum ) )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
open_file ( fnum , cnum , fname , O_RDWR | O_CREAT | O_TRUNC , unixmode ) ;
if ( ! Files [ fnum ] . open )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , fnum ) ;
DEBUG ( 2 , ( " new file %s \n " , fname ) ) ;
DEBUG ( 3 , ( " %s mknew %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o \n " , timestring ( ) , fname , Files [ fnum ] . fd , fnum , cnum , createmode , unixmode ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a create temporary file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_ctemp ( char * inbuf , char * outbuf )
{
pstring fname ;
pstring fname2 ;
int cnum ;
int fnum = - 1 ;
int outsize = 0 ;
int createmode ;
mode_t unixmode ;
cnum = SVAL ( inbuf , smb_tid ) ;
createmode = SVAL ( inbuf , smb_vwv0 ) ;
sprintf ( fname , " %s/TMXXXXXX " , smb_buf ( inbuf ) + 1 ) ;
unix_convert ( fname , cnum ) ;
unixmode = unix_mode ( cnum , createmode ) ;
fnum = find_free_file ( ) ;
if ( fnum < 0 )
return ( ERROR ( ERRSRV , ERRnofids ) ) ;
if ( ! check_name ( fname , cnum ) )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
strcpy ( fname2 , ( char * ) mktemp ( fname ) ) ;
open_file ( fnum , cnum , fname2 , O_RDWR | O_CREAT | O_TRUNC , unixmode ) ;
if ( ! Files [ fnum ] . open )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
outsize = set_message ( outbuf , 1 , 2 + strlen ( fname2 ) , True ) ;
SSVAL ( outbuf , smb_vwv0 , fnum ) ;
CVAL ( smb_buf ( outbuf ) , 0 ) = 4 ;
strcpy ( smb_buf ( outbuf ) + 1 , fname2 ) ;
DEBUG ( 2 , ( " created temp file %s \n " , fname2 ) ) ;
DEBUG ( 3 , ( " %s ctemp %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o \n " , timestring ( ) , fname2 , Files [ fnum ] . fd , fnum , cnum , createmode , unixmode ) ) ;
return ( outsize ) ;
}
/*******************************************************************
check if a user is allowed to delete a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL can_delete ( char * fname , int cnum , int dirtype )
{
struct stat sbuf ;
int fmode ;
if ( ! CAN_WRITE ( cnum ) ) return ( False ) ;
if ( sys_lstat ( fname , & sbuf ) ! = 0 ) return ( False ) ;
fmode = dos_mode ( cnum , fname , & sbuf ) ;
if ( fmode & aDIR ) return ( False ) ;
1996-05-31 19:13:29 +04:00
if ( ! lp_delete_readonly ( SNUM ( cnum ) ) ) {
if ( fmode & aRONLY ) return ( False ) ;
}
1996-05-04 11:50:46 +04:00
if ( ( fmode & ~ dirtype ) & ( aHIDDEN | aSYSTEM ) )
return ( False ) ;
if ( ! check_file_sharing ( cnum , fname ) ) return ( False ) ;
return ( True ) ;
}
/****************************************************************************
reply to a unlink
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_unlink ( char * inbuf , char * outbuf )
{
int outsize = 0 ;
pstring name ;
int cnum ;
int dirtype ;
pstring directory ;
pstring mask ;
char * p ;
int count = 0 ;
int error = ERRnoaccess ;
BOOL has_wild ;
BOOL exists = False ;
* directory = * mask = 0 ;
cnum = SVAL ( inbuf , smb_tid ) ;
dirtype = SVAL ( inbuf , smb_vwv0 ) ;
strcpy ( name , smb_buf ( inbuf ) + 1 ) ;
DEBUG ( 3 , ( " reply_unlink : %s \n " , name ) ) ;
unix_convert ( name , cnum ) ;
p = strrchr ( name , ' / ' ) ;
if ( ! p ) {
strcpy ( directory , " ./ " ) ;
strcpy ( mask , name ) ;
} else {
* p = 0 ;
strcpy ( directory , name ) ;
strcpy ( mask , p + 1 ) ;
}
if ( is_mangled ( mask ) )
check_mangled_stack ( mask ) ;
has_wild = strchr ( mask , ' * ' ) | | strchr ( mask , ' ? ' ) ;
if ( ! has_wild ) {
strcat ( directory , " / " ) ;
strcat ( directory , mask ) ;
if ( can_delete ( directory , cnum , dirtype ) & & ! sys_unlink ( directory ) ) count + + ;
if ( ! count ) exists = file_exist ( directory , NULL ) ;
} else {
void * dirptr = NULL ;
char * dname ;
if ( check_name ( directory , cnum ) )
dirptr = OpenDir ( directory ) ;
if ( dirptr )
{
error = ERRbadfile ;
if ( strequal ( mask , " ????????.??? " ) )
strcpy ( mask , " * " ) ;
while ( ( dname = ReadDirName ( dirptr ) ) )
{
pstring fname ;
strcpy ( fname , dname ) ;
if ( ! mask_match ( fname , mask , case_sensitive , False ) ) continue ;
error = ERRnoaccess ;
sprintf ( fname , " %s/%s " , directory , dname ) ;
if ( ! can_delete ( fname , cnum , dirtype ) ) continue ;
if ( ! sys_unlink ( fname ) ) count + + ;
DEBUG ( 3 , ( " reply_unlink : doing unlink on %s \n " , fname ) ) ;
}
CloseDir ( dirptr ) ;
}
}
if ( count = = 0 ) {
if ( exists )
return ( ERROR ( ERRDOS , error ) ) ;
else
return ( UNIXERROR ( ERRDOS , error ) ) ;
}
outsize = set_message ( outbuf , 0 , 0 , True ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a readbraw ( core + protocol )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_readbraw ( char * inbuf , char * outbuf )
{
int cnum , maxcount , mincount , fnum ;
int nread = 0 ;
int startpos ;
char * header = outbuf ;
int ret = 0 ;
int fd ;
char * fname ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
startpos = IVAL ( inbuf , smb_vwv1 ) ;
maxcount = SVAL ( inbuf , smb_vwv3 ) ;
mincount = SVAL ( inbuf , smb_vwv4 ) ;
/* ensure we don't overrun the packet size */
maxcount = MIN ( 65535 , maxcount ) ;
maxcount = MAX ( mincount , maxcount ) ;
if ( ! FNUM_OK ( fnum , cnum ) | | ! Files [ fnum ] . can_read )
{
DEBUG ( 3 , ( " fnum %d not open in readbraw - cache prime? \n " , fnum ) ) ;
_smb_setlen ( header , 0 ) ;
transfer_file ( 0 , Client , 0 , header , 4 , 0 ) ;
return ( - 1 ) ;
}
else
{
fd = Files [ fnum ] . fd ;
fname = Files [ fnum ] . name ;
}
if ( ! is_locked ( fnum , cnum , maxcount , startpos ) )
{
int size = Files [ fnum ] . size ;
int sizeneeded = startpos + maxcount ;
if ( size < sizeneeded ) {
struct stat st ;
if ( fstat ( Files [ fnum ] . fd , & st ) = = 0 )
size = st . st_size ;
if ( ! Files [ fnum ] . can_write )
Files [ fnum ] . size = size ;
}
nread = MIN ( maxcount , size - startpos ) ;
}
if ( nread < mincount )
nread = 0 ;
DEBUG ( 3 , ( " %s readbraw fnum=%d cnum=%d start=%d max=%d min=%d nread=%d \n " ,
timestring ( ) ,
fnum , cnum , startpos ,
maxcount , mincount , nread ) ) ;
# if UNSAFE_READRAW
{
int predict = 0 ;
_smb_setlen ( header , nread ) ;
if ( ! Files [ fnum ] . can_write )
predict = read_predict ( fd , startpos , header + 4 , NULL , nread ) ;
if ( ( nread - predict ) > 0 )
seek_file ( fnum , startpos + predict ) ;
ret = transfer_file ( fd , Client , nread - predict , header , 4 + predict ,
startpos + predict ) ;
}
if ( ret ! = nread + 4 )
DEBUG ( 0 , ( " ERROR: file read failure on %s at %d for %d bytes (%d) \n " ,
fname , startpos , nread , ret ) ) ;
# else
ret = read_file ( fnum , header + 4 , startpos , nread , nread , - 1 , False ) ;
if ( ret < mincount ) ret = 0 ;
_smb_setlen ( header , ret ) ;
transfer_file ( 0 , Client , 0 , header , 4 + ret , 0 ) ;
# endif
DEBUG ( 5 , ( " readbraw finished \n " ) ) ;
return - 1 ;
}
/****************************************************************************
reply to a lockread ( core + protocol )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_lockread ( char * inbuf , char * outbuf )
{
int cnum , fnum ;
int nread = - 1 ;
char * data ;
int outsize = 0 ;
uint32 startpos , numtoread ;
int eclass ;
uint32 ecode ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_READ ( fnum ) ;
CHECK_ERROR ( fnum ) ;
numtoread = SVAL ( inbuf , smb_vwv1 ) ;
startpos = IVAL ( inbuf , smb_vwv2 ) ;
outsize = set_message ( outbuf , 5 , 3 , True ) ;
numtoread = MIN ( BUFFER_SIZE - outsize , numtoread ) ;
data = smb_buf ( outbuf ) + 3 ;
if ( ! do_lock ( fnum , cnum , numtoread , startpos , & eclass , & ecode ) )
return ( ERROR ( eclass , ecode ) ) ;
nread = read_file ( fnum , data , startpos , numtoread , numtoread , - 1 , False ) ;
if ( nread < 0 )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
outsize + = nread ;
SSVAL ( outbuf , smb_vwv0 , nread ) ;
SSVAL ( outbuf , smb_vwv5 , nread + 3 ) ;
SSVAL ( smb_buf ( outbuf ) , 1 , nread ) ;
DEBUG ( 3 , ( " %s lockread fnum=%d cnum=%d num=%d nread=%d \n " , timestring ( ) , fnum , cnum , numtoread , nread ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a read
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_read ( char * inbuf , char * outbuf )
{
int cnum , numtoread , fnum ;
int nread = 0 ;
char * data ;
int startpos ;
int outsize = 0 ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_READ ( fnum ) ;
CHECK_ERROR ( fnum ) ;
numtoread = SVAL ( inbuf , smb_vwv1 ) ;
startpos = IVAL ( inbuf , smb_vwv2 ) ;
outsize = set_message ( outbuf , 5 , 3 , True ) ;
numtoread = MIN ( BUFFER_SIZE - outsize , numtoread ) ;
data = smb_buf ( outbuf ) + 3 ;
if ( is_locked ( fnum , cnum , numtoread , startpos ) )
return ( ERROR ( ERRDOS , ERRlock ) ) ;
if ( numtoread > 0 )
nread = read_file ( fnum , data , startpos , numtoread , numtoread , - 1 , False ) ;
if ( nread < 0 )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
outsize + = nread ;
SSVAL ( outbuf , smb_vwv0 , nread ) ;
SSVAL ( outbuf , smb_vwv5 , nread + 3 ) ;
CVAL ( smb_buf ( outbuf ) , 0 ) = 1 ;
SSVAL ( smb_buf ( outbuf ) , 1 , nread ) ;
DEBUG ( 3 , ( " %s read fnum=%d cnum=%d num=%d nread=%d \n " , timestring ( ) , fnum , cnum , numtoread , nread ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a read and X
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_read_and_X ( char * inbuf , char * outbuf , int length , int bufsize )
{
int smb_com2 = CVAL ( inbuf , smb_vwv0 ) ;
int smb_off2 = SVAL ( inbuf , smb_vwv1 ) ;
int fnum = GETFNUM ( inbuf , smb_vwv2 ) ;
uint32 smb_offs = IVAL ( inbuf , smb_vwv3 ) ;
int smb_maxcnt = SVAL ( inbuf , smb_vwv5 ) ;
int smb_mincnt = SVAL ( inbuf , smb_vwv6 ) ;
int cnum ;
int nread = - 1 ;
char * data ;
int outsize = 0 ;
BOOL ok = False ;
cnum = SVAL ( inbuf , smb_tid ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_READ ( fnum ) ;
CHECK_ERROR ( fnum ) ;
outsize = set_message ( outbuf , 12 , 0 , True ) ;
data = smb_buf ( outbuf ) ;
if ( is_locked ( fnum , cnum , smb_maxcnt , smb_offs ) )
return ( ERROR ( ERRDOS , ERRlock ) ) ;
nread = read_file ( fnum , data , smb_offs , smb_maxcnt , smb_maxcnt , - 1 , False ) ;
ok = True ;
if ( nread < 0 )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
outsize + = nread ;
CVAL ( outbuf , smb_vwv0 ) = smb_com2 ;
SSVAL ( outbuf , smb_vwv1 , ( outsize + chain_size ) - 4 ) ;
SSVAL ( outbuf , smb_vwv5 , nread ) ;
SSVAL ( outbuf , smb_vwv6 , smb_offset ( data , outbuf ) + chain_size ) ;
SSVAL ( smb_buf ( outbuf ) , - 2 , nread ) ;
DEBUG ( 3 , ( " %s readX fnum=%d cnum=%d min=%d max=%d nread=%d com2=%d off2=%d \n " ,
timestring ( ) , fnum , cnum ,
smb_mincnt , smb_maxcnt , nread , smb_com2 , smb_off2 ) ) ;
chain_fnum = fnum ;
if ( smb_com2 ! = 0xFF )
outsize + = chain_reply ( smb_com2 , inbuf , inbuf + smb_off2 + 4 ,
outbuf , outbuf + outsize ,
length , bufsize ) ;
chain_fnum = - 1 ;
return ( outsize ) ;
}
/****************************************************************************
reply to a writebraw ( core + or LANMAN1 .0 protocol )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_writebraw ( char * inbuf , char * outbuf )
{
int nwritten = 0 ;
int total_written = 0 ;
int numtowrite = 0 ;
int cnum , fnum ;
int outsize = 0 ;
long startpos ;
char * data = NULL ;
BOOL write_through ;
int tcount ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_WRITE ( fnum ) ;
CHECK_ERROR ( fnum ) ;
tcount = IVAL ( inbuf , smb_vwv1 ) ;
startpos = IVAL ( inbuf , smb_vwv3 ) ;
write_through = BITSETW ( inbuf + smb_vwv7 , 0 ) ;
/* We have to deal with slightly different formats depending
on whether we are using the core + or lanman1 .0 protocol */
if ( Protocol < = PROTOCOL_COREPLUS ) {
numtowrite = SVAL ( smb_buf ( inbuf ) , - 2 ) ;
data = smb_buf ( inbuf ) ;
} else {
numtowrite = SVAL ( inbuf , smb_vwv10 ) ;
data = smb_base ( inbuf ) + SVAL ( inbuf , smb_vwv11 ) ;
}
/* force the error type */
CVAL ( inbuf , smb_com ) = SMBwritec ;
CVAL ( outbuf , smb_com ) = SMBwritec ;
if ( is_locked ( fnum , cnum , tcount , startpos ) )
return ( ERROR ( ERRDOS , ERRlock ) ) ;
if ( seek_file ( fnum , startpos ) ! = startpos )
DEBUG ( 0 , ( " couldn't seek to %d in writebraw \n " , startpos ) ) ;
if ( numtowrite > 0 )
nwritten = write_file ( fnum , data , numtowrite ) ;
DEBUG ( 3 , ( " %s writebraw1 fnum=%d cnum=%d start=%d num=%d wrote=%d sync=%d \n " ,
timestring ( ) , fnum , cnum , startpos , numtowrite , nwritten , write_through ) ) ;
if ( nwritten < numtowrite )
return ( UNIXERROR ( ERRHRD , ERRdiskfull ) ) ;
total_written = nwritten ;
/* Return a message to the redirector to tell it
to send more bytes */
CVAL ( outbuf , smb_com ) = SMBwritebraw ;
SSVALS ( outbuf , smb_vwv0 , - 1 ) ;
outsize = set_message ( outbuf , Protocol > PROTOCOL_COREPLUS ? 1 : 0 , 0 , True ) ;
send_smb ( Client , outbuf ) ;
/* Now read the raw data into the buffer and write it */
1996-06-10 09:16:19 +04:00
if ( read_smb_length ( Client , inbuf , SMB_SECONDARY_WAIT ) = = - 1 ) {
1996-05-04 11:50:46 +04:00
exit_server ( " secondary writebraw failed " ) ;
}
/* Even though this is not an smb message, smb_len
returns the generic length of an smb message */
numtowrite = smb_len ( inbuf ) ;
if ( tcount > nwritten + numtowrite ) {
DEBUG ( 3 , ( " Client overestimated the write %d %d %d \n " ,
tcount , nwritten , numtowrite ) ) ;
}
nwritten = transfer_file ( Client , Files [ fnum ] . fd , numtowrite , NULL , 0 ,
startpos + nwritten ) ;
total_written + = nwritten ;
/* Set up outbuf to return the correct return */
outsize = set_message ( outbuf , 1 , 0 , True ) ;
CVAL ( outbuf , smb_com ) = SMBwritec ;
SSVAL ( outbuf , smb_vwv0 , total_written ) ;
if ( nwritten < numtowrite ) {
CVAL ( outbuf , smb_rcls ) = ERRHRD ;
SSVAL ( outbuf , smb_err , ERRdiskfull ) ;
}
if ( lp_syncalways ( SNUM ( cnum ) ) | | write_through )
sync_file ( fnum ) ;
DEBUG ( 3 , ( " %s writebraw2 fnum=%d cnum=%d start=%d num=%d wrote=%d \n " ,
timestring ( ) , fnum , cnum , startpos , numtowrite , total_written ) ) ;
/* we won't return a status if write through is not selected - this
follows what WfWg does */
if ( ! write_through & & total_written = = tcount )
return ( - 1 ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a writeunlock ( core + )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_writeunlock ( char * inbuf , char * outbuf )
{
int cnum , fnum ;
int nwritten = - 1 ;
int outsize = 0 ;
char * data ;
uint32 numtowrite , startpos ;
int eclass ;
uint32 ecode ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_WRITE ( fnum ) ;
CHECK_ERROR ( fnum ) ;
numtowrite = SVAL ( inbuf , smb_vwv1 ) ;
startpos = IVAL ( inbuf , smb_vwv2 ) ;
data = smb_buf ( inbuf ) + 3 ;
if ( is_locked ( fnum , cnum , numtowrite , startpos ) )
return ( ERROR ( ERRDOS , ERRlock ) ) ;
seek_file ( fnum , startpos ) ;
/* The special X/Open SMB protocol handling of
zero length writes is * NOT * done for
this call */
if ( numtowrite = = 0 )
nwritten = 0 ;
else
nwritten = write_file ( fnum , data , numtowrite ) ;
if ( lp_syncalways ( SNUM ( cnum ) ) )
sync_file ( fnum ) ;
if ( ( ( nwritten = = 0 ) & & ( numtowrite ! = 0 ) ) | | ( nwritten < 0 ) )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
if ( ! do_unlock ( fnum , cnum , numtowrite , startpos , & eclass , & ecode ) )
return ( ERROR ( eclass , ecode ) ) ;
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , nwritten ) ;
DEBUG ( 3 , ( " %s writeunlock fnum=%d cnum=%d num=%d wrote=%d \n " ,
timestring ( ) , fnum , cnum , numtowrite , nwritten ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a write
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_write ( char * inbuf , char * outbuf , int dum1 , int dum2 )
{
int cnum , numtowrite , fnum ;
int nwritten = - 1 ;
int outsize = 0 ;
int startpos ;
char * data ;
dum1 = dum2 = 0 ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_WRITE ( fnum ) ;
CHECK_ERROR ( fnum ) ;
numtowrite = SVAL ( inbuf , smb_vwv1 ) ;
startpos = IVAL ( inbuf , smb_vwv2 ) ;
data = smb_buf ( inbuf ) + 3 ;
if ( is_locked ( fnum , cnum , numtowrite , startpos ) )
return ( ERROR ( ERRDOS , ERRlock ) ) ;
seek_file ( fnum , startpos ) ;
/* X/Open SMB protocol says that if smb_vwv1 is
zero then the file size should be extended or
truncated to the size given in smb_vwv [ 2 - 3 ] */
if ( numtowrite = = 0 )
nwritten = set_filelen ( Files [ fnum ] . fd , startpos ) ;
else
nwritten = write_file ( fnum , data , numtowrite ) ;
if ( lp_syncalways ( SNUM ( cnum ) ) )
sync_file ( fnum ) ;
if ( ( ( nwritten = = 0 ) & & ( numtowrite ! = 0 ) ) | | ( nwritten < 0 ) )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , nwritten ) ;
if ( nwritten < numtowrite ) {
CVAL ( outbuf , smb_rcls ) = ERRHRD ;
SSVAL ( outbuf , smb_err , ERRdiskfull ) ;
}
DEBUG ( 3 , ( " %s write fnum=%d cnum=%d num=%d wrote=%d \n " , timestring ( ) , fnum , cnum , numtowrite , nwritten ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a write and X
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_write_and_X ( char * inbuf , char * outbuf , int length , int bufsize )
{
int smb_com2 = CVAL ( inbuf , smb_vwv0 ) ;
int smb_off2 = SVAL ( inbuf , smb_vwv1 ) ;
int fnum = GETFNUM ( inbuf , smb_vwv2 ) ;
uint32 smb_offs = IVAL ( inbuf , smb_vwv3 ) ;
int smb_dsize = SVAL ( inbuf , smb_vwv10 ) ;
int smb_doff = SVAL ( inbuf , smb_vwv11 ) ;
BOOL write_through = BITSETW ( inbuf + smb_vwv7 , 0 ) ;
int cnum ;
int nwritten = - 1 ;
int outsize = 0 ;
char * data ;
cnum = SVAL ( inbuf , smb_tid ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_WRITE ( fnum ) ;
CHECK_ERROR ( fnum ) ;
data = smb_base ( inbuf ) + smb_doff ;
if ( is_locked ( fnum , cnum , smb_dsize , smb_offs ) )
return ( ERROR ( ERRDOS , ERRlock ) ) ;
seek_file ( fnum , smb_offs ) ;
/* X/Open SMB protocol says that, unlike SMBwrite
if the length is zero then NO truncation is
done , just a write of zero . To truncate a file ,
use SMBwrite . */
if ( smb_dsize = = 0 )
nwritten = 0 ;
else
nwritten = write_file ( fnum , data , smb_dsize ) ;
if ( ( ( nwritten = = 0 ) & & ( smb_dsize ! = 0 ) ) | | ( nwritten < 0 ) )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
outsize = set_message ( outbuf , 6 , 0 , True ) ;
CVAL ( outbuf , smb_vwv0 ) = smb_com2 ;
SSVAL ( outbuf , smb_vwv1 , ( outsize + chain_size ) - 4 ) ;
SSVAL ( outbuf , smb_vwv2 , nwritten ) ;
if ( nwritten < smb_dsize ) {
CVAL ( outbuf , smb_rcls ) = ERRHRD ;
SSVAL ( outbuf , smb_err , ERRdiskfull ) ;
}
DEBUG ( 3 , ( " %s writeX fnum=%d cnum=%d num=%d wrote=%d \n " , timestring ( ) , fnum , cnum , smb_dsize , nwritten ) ) ;
chain_fnum = fnum ;
if ( lp_syncalways ( SNUM ( cnum ) ) | | write_through )
sync_file ( fnum ) ;
if ( smb_com2 ! = 0xFF )
outsize + = chain_reply ( smb_com2 , inbuf , inbuf + smb_off2 + 4 ,
outbuf , outbuf + outsize ,
length , bufsize ) ;
chain_fnum = - 1 ;
return ( outsize ) ;
}
/****************************************************************************
reply to a lseek
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_lseek ( char * inbuf , char * outbuf )
{
int cnum , fnum ;
uint32 startpos ;
int32 res = - 1 ;
int mode , umode ;
int outsize = 0 ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_ERROR ( fnum ) ;
mode = SVAL ( inbuf , smb_vwv1 ) & 3 ;
startpos = IVAL ( inbuf , smb_vwv2 ) ;
switch ( mode & 3 )
{
case 0 : umode = SEEK_SET ; break ;
case 1 : umode = SEEK_CUR ; break ;
case 2 : umode = SEEK_END ; break ;
default :
umode = SEEK_SET ; break ;
}
res = lseek ( Files [ fnum ] . fd , startpos , umode ) ;
Files [ fnum ] . pos = res ;
outsize = set_message ( outbuf , 2 , 0 , True ) ;
SIVALS ( outbuf , smb_vwv0 , res ) ;
DEBUG ( 3 , ( " %s lseek fnum=%d cnum=%d ofs=%d mode=%d \n " , timestring ( ) , fnum , cnum , startpos , mode ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a flush
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_flush ( char * inbuf , char * outbuf )
{
int cnum , fnum ;
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
if ( fnum ! = 0xFFFF ) {
CHECK_FNUM ( fnum , cnum ) ;
CHECK_ERROR ( fnum ) ;
}
if ( fnum = = 0xFFFF )
{
int i ;
for ( i = 0 ; i < MAX_OPEN_FILES ; i + + )
if ( OPEN_FNUM ( i ) )
sync_file ( i ) ;
}
else
sync_file ( fnum ) ;
DEBUG ( 3 , ( " %s flush fnum=%d \n " , timestring ( ) , fnum ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a exit
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_exit ( char * inbuf , char * outbuf )
{
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
DEBUG ( 3 , ( " %s exit \n " , timestring ( ) ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a close
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_close ( char * inbuf , char * outbuf )
{
int fnum , cnum ;
int outsize = 0 ;
time_t mtime ;
int32 eclass = 0 , err = 0 ;
outsize = set_message ( outbuf , 0 , 0 , True ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
if ( HAS_CACHED_ERROR ( fnum ) ) {
eclass = Files [ fnum ] . wbmpx_ptr - > wr_errclass ;
err = Files [ fnum ] . wbmpx_ptr - > wr_error ;
}
mtime = make_unix_date3 ( inbuf + smb_vwv1 ) ;
/* try and set the date */
set_filetime ( Files [ fnum ] . name , mtime ) ;
1996-06-04 10:42:03 +04:00
close_file ( fnum ) ;
1996-05-04 11:50:46 +04:00
/* We have a cached error */
if ( eclass | | err )
return ( ERROR ( eclass , err ) ) ;
DEBUG ( 3 , ( " %s close fd=%d fnum=%d cnum=%d (numopen=%d) \n " ,
timestring ( ) , Files [ fnum ] . fd , fnum , cnum ,
Connections [ cnum ] . num_files_open ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a writeclose ( Core + protocol )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_writeclose ( char * inbuf , char * outbuf )
{
int cnum , numtowrite , fnum ;
int nwritten = - 1 ;
int outsize = 0 ;
int startpos ;
char * data ;
time_t mtime ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_WRITE ( fnum ) ;
CHECK_ERROR ( fnum ) ;
numtowrite = SVAL ( inbuf , smb_vwv1 ) ;
startpos = IVAL ( inbuf , smb_vwv2 ) ;
mtime = make_unix_date3 ( inbuf + smb_vwv4 ) ;
data = smb_buf ( inbuf ) + 1 ;
if ( is_locked ( fnum , cnum , numtowrite , startpos ) )
return ( ERROR ( ERRDOS , ERRlock ) ) ;
seek_file ( fnum , startpos ) ;
nwritten = write_file ( fnum , data , numtowrite ) ;
set_filetime ( Files [ fnum ] . name , mtime ) ;
1996-06-04 10:42:03 +04:00
close_file ( fnum ) ;
1996-05-04 11:50:46 +04:00
DEBUG ( 3 , ( " %s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d) \n " ,
timestring ( ) , fnum , cnum , numtowrite , nwritten ,
Connections [ cnum ] . num_files_open ) ) ;
if ( nwritten < = 0 )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , nwritten ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a lock
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_lock ( char * inbuf , char * outbuf )
{
int fnum , cnum ;
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
uint32 count , offset ;
int eclass ;
uint32 ecode ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_ERROR ( fnum ) ;
count = IVAL ( inbuf , smb_vwv1 ) ;
offset = IVAL ( inbuf , smb_vwv3 ) ;
DEBUG ( 3 , ( " %s lock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d \n " , timestring ( ) , Files [ fnum ] . fd , fnum , cnum , offset , count ) ) ;
if ( ! do_lock ( fnum , cnum , count , offset , & eclass , & ecode ) )
return ( ERROR ( eclass , ecode ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a unlock
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_unlock ( char * inbuf , char * outbuf )
{
int fnum , cnum ;
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
uint32 count , offset ;
int eclass ;
uint32 ecode ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_ERROR ( fnum ) ;
count = IVAL ( inbuf , smb_vwv1 ) ;
offset = IVAL ( inbuf , smb_vwv3 ) ;
if ( ! do_unlock ( fnum , cnum , count , offset , & eclass , & ecode ) )
return ( ERROR ( eclass , ecode ) ) ;
DEBUG ( 3 , ( " %s unlock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d \n " , timestring ( ) , Files [ fnum ] . fd , fnum , cnum , offset , count ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a tdis
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_tdis ( char * inbuf , char * outbuf )
{
int cnum , uid ;
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
uid = SVAL ( inbuf , smb_uid ) ;
1996-07-03 05:58:27 +04:00
if ( ! OPEN_CNUM ( cnum ) ) {
DEBUG ( 4 , ( " Invalid cnum in tdis (%d) \n " , cnum ) ) ;
return ( ERROR ( ERRSRV , ERRinvnid ) ) ;
}
1996-05-04 11:50:46 +04:00
Connections [ cnum ] . used = False ;
close_cnum ( cnum , uid ) ;
DEBUG ( 3 , ( " %s tdis cnum=%d \n " , timestring ( ) , cnum ) ) ;
return outsize ;
}
/****************************************************************************
reply to a echo
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_echo ( char * inbuf , char * outbuf )
{
int cnum ;
int smb_reverb = SVAL ( inbuf , smb_vwv0 ) ;
int seq_num ;
int data_len = smb_buflen ( inbuf ) ;
int outsize = set_message ( outbuf , 1 , data_len , True ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
if ( cnum ! = 0xFFFF & & ! OPEN_CNUM ( cnum ) )
{
DEBUG ( 4 , ( " Invalid cnum in echo (%d) \n " , cnum ) ) ;
return ( ERROR ( ERRSRV , ERRinvnid ) ) ;
}
/* copy any incoming data back out */
if ( data_len > 0 )
memcpy ( smb_buf ( outbuf ) , smb_buf ( inbuf ) , data_len ) ;
if ( smb_reverb > 100 )
{
DEBUG ( 0 , ( " large reverb (%d)?? Setting to 100 \n " , smb_reverb ) ) ;
smb_reverb = 100 ;
}
for ( seq_num = 1 ; seq_num < = smb_reverb ; seq_num + + )
{
SSVAL ( outbuf , smb_vwv0 , seq_num ) ;
smb_setlen ( outbuf , outsize - 4 ) ;
send_smb ( Client , outbuf ) ;
}
DEBUG ( 3 , ( " %s echo %d times cnum=%d \n " , timestring ( ) , smb_reverb , cnum ) ) ;
return - 1 ;
}
/****************************************************************************
reply to a printopen
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_printopen ( char * inbuf , char * outbuf )
{
pstring fname ;
pstring fname2 ;
int cnum ;
int fnum = - 1 ;
int outsize = 0 ;
* fname = * fname2 = 0 ;
cnum = SVAL ( inbuf , smb_tid ) ;
if ( ! CAN_PRINT ( cnum ) )
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
{
pstring s ;
char * p ;
StrnCpy ( s , smb_buf ( inbuf ) + 1 , sizeof ( pstring ) - 1 ) ;
p = s ;
while ( * p )
{
if ( ! ( isalnum ( * p ) | | strchr ( " ._- " , * p ) ) )
* p = ' X ' ;
p + + ;
}
if ( strlen ( s ) > 10 ) s [ 10 ] = 0 ;
sprintf ( fname , " %s.XXXXXX " , s ) ;
}
fnum = find_free_file ( ) ;
if ( fnum < 0 )
return ( ERROR ( ERRSRV , ERRnofids ) ) ;
strcpy ( fname2 , ( char * ) mktemp ( fname ) ) ;
if ( ! check_name ( fname2 , cnum ) )
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
open_file ( fnum , cnum , fname2 , O_WRONLY | O_CREAT | O_TRUNC ,
unix_mode ( cnum , 0 ) ) ;
if ( ! Files [ fnum ] . open )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
/* force it to be a print file */
Files [ fnum ] . print_file = True ;
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , fnum ) ;
DEBUG ( 3 , ( " %s openprint %s fd=%d fnum=%d cnum=%d \n " , timestring ( ) , fname2 , Files [ fnum ] . fd , fnum , cnum ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a printclose
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_printclose ( char * inbuf , char * outbuf )
{
int fnum , cnum ;
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_ERROR ( fnum ) ;
if ( ! CAN_PRINT ( cnum ) )
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
close_file ( fnum ) ;
DEBUG ( 3 , ( " %s printclose fd=%d fnum=%d cnum=%d \n " , timestring ( ) , Files [ fnum ] . fd , fnum , cnum ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a printqueue
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_printqueue ( char * inbuf , char * outbuf )
{
int cnum , uid ;
int outsize = set_message ( outbuf , 2 , 3 , True ) ;
int max_count = SVAL ( inbuf , smb_vwv0 ) ;
int start_index = SVAL ( inbuf , smb_vwv1 ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
uid = SVAL ( inbuf , smb_uid ) ;
/* allow checking the queue for anyone */
#if 0
if ( ! CAN_PRINT ( cnum ) )
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
# endif
SSVAL ( outbuf , smb_vwv0 , 0 ) ;
SSVAL ( outbuf , smb_vwv1 , 0 ) ;
CVAL ( smb_buf ( outbuf ) , 0 ) = 1 ;
SSVAL ( smb_buf ( outbuf ) , 1 , 0 ) ;
DEBUG ( 3 , ( " %s printqueue cnum=%d start_index=%d max_count=%d \n " ,
timestring ( ) , cnum , start_index , max_count ) ) ;
if ( ! OPEN_CNUM ( cnum ) | | ! Connections [ cnum ] . printer )
{
int i ;
cnum = - 1 ;
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
if ( CAN_PRINT ( i ) & & Connections [ i ] . printer )
cnum = i ;
if ( cnum = = - 1 )
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
if ( OPEN_CNUM ( i ) )
cnum = i ;
if ( ! OPEN_CNUM ( cnum ) )
return ( ERROR ( ERRSRV , ERRinvnid ) ) ;
DEBUG ( 5 , ( " connection not open or not a printer, using cnum %d \n " , cnum ) ) ;
}
if ( ! become_user ( cnum , uid ) )
return ( ERROR ( ERRSRV , ERRinvnid ) ) ;
{
print_queue_struct * queue = NULL ;
char * p = smb_buf ( outbuf ) + 3 ;
int count = get_printqueue ( SNUM ( cnum ) , cnum , & queue , NULL ) ;
int num_to_get = ABS ( max_count ) ;
int first = ( max_count > 0 ? start_index : start_index + max_count + 1 ) ;
int i ;
if ( first > = count )
num_to_get = 0 ;
else
num_to_get = MIN ( num_to_get , count - first ) ;
for ( i = first ; i < first + num_to_get ; i + + )
{
put_dos_date2 ( p , 0 , queue [ i ] . time ) ;
CVAL ( p , 4 ) = ( queue [ i ] . status = = LPQ_PRINTING ? 2 : 3 ) ;
SSVAL ( p , 5 , queue [ i ] . job ) ;
SIVAL ( p , 7 , queue [ i ] . size ) ;
CVAL ( p , 11 ) = 0 ;
StrnCpy ( p + 12 , queue [ i ] . user , 16 ) ;
p + = 28 ;
}
if ( count > 0 )
{
outsize = set_message ( outbuf , 2 , 28 * count + 3 , False ) ;
SSVAL ( outbuf , smb_vwv0 , count ) ;
SSVAL ( outbuf , smb_vwv1 , ( max_count > 0 ? first + count : first - 1 ) ) ;
CVAL ( smb_buf ( outbuf ) , 0 ) = 1 ;
SSVAL ( smb_buf ( outbuf ) , 1 , 28 * count ) ;
}
if ( queue ) free ( queue ) ;
DEBUG ( 3 , ( " %d entries returned in queue \n " , count ) ) ;
}
return ( outsize ) ;
}
/****************************************************************************
reply to a printwrite
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_printwrite ( char * inbuf , char * outbuf )
{
int cnum , numtowrite , fnum ;
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
char * data ;
cnum = SVAL ( inbuf , smb_tid ) ;
if ( ! CAN_PRINT ( cnum ) )
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_WRITE ( fnum ) ;
CHECK_ERROR ( fnum ) ;
numtowrite = SVAL ( smb_buf ( inbuf ) , 1 ) ;
data = smb_buf ( inbuf ) + 3 ;
if ( write_file ( fnum , data , numtowrite ) ! = numtowrite )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
DEBUG ( 3 , ( " %s printwrite fnum=%d cnum=%d num=%d \n " , timestring ( ) , fnum , cnum , numtowrite ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a mkdir
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_mkdir ( char * inbuf , char * outbuf )
{
pstring directory ;
int cnum ;
int outsize , ret = - 1 ;
strcpy ( directory , smb_buf ( inbuf ) + 1 ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
unix_convert ( directory , cnum ) ;
if ( check_name ( directory , cnum ) )
ret = sys_mkdir ( directory , unix_mode ( cnum , aDIR ) ) ;
if ( ret < 0 )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
outsize = set_message ( outbuf , 0 , 0 , True ) ;
DEBUG ( 3 , ( " %s mkdir %s cnum=%d ret=%d \n " , timestring ( ) , directory , cnum , ret ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a rmdir
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_rmdir ( char * inbuf , char * outbuf )
{
pstring directory ;
int cnum ;
int outsize = 0 ;
BOOL ok = False ;
cnum = SVAL ( inbuf , smb_tid ) ;
strcpy ( directory , smb_buf ( inbuf ) + 1 ) ;
unix_convert ( directory , cnum ) ;
if ( check_name ( directory , cnum ) )
{
dptr_closepath ( directory , SVAL ( inbuf , smb_pid ) ) ;
ok = ( sys_rmdir ( directory ) = = 0 ) ;
if ( ! ok )
DEBUG ( 3 , ( " couldn't remove directory %s : %s \n " ,
directory , strerror ( errno ) ) ) ;
}
if ( ! ok )
return ( UNIXERROR ( ERRDOS , ERRbadpath ) ) ;
outsize = set_message ( outbuf , 0 , 0 , True ) ;
DEBUG ( 3 , ( " %s rmdir %s \n " , timestring ( ) , directory ) ) ;
return ( outsize ) ;
}
/*******************************************************************
resolve wildcards in a filename rename
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL resolve_wildcards ( char * name1 , char * name2 )
{
fstring root1 , root2 ;
fstring ext1 , ext2 ;
char * p , * p2 ;
name1 = strrchr ( name1 , ' / ' ) ;
name2 = strrchr ( name2 , ' / ' ) ;
if ( ! name1 | | ! name2 ) return ( False ) ;
strcpy ( root1 , name1 ) ;
strcpy ( root2 , name2 ) ;
p = strrchr ( root1 , ' . ' ) ;
if ( p ) {
* p = 0 ;
strcpy ( ext1 , p + 1 ) ;
} else {
strcpy ( ext1 , " " ) ;
}
p = strrchr ( root2 , ' . ' ) ;
if ( p ) {
* p = 0 ;
strcpy ( ext2 , p + 1 ) ;
} else {
strcpy ( ext2 , " " ) ;
}
p = root1 ;
p2 = root2 ;
while ( * p2 ) {
if ( * p2 = = ' ? ' ) {
* p2 = * p ;
p2 + + ;
} else {
p2 + + ;
}
if ( * p ) p + + ;
}
p = ext1 ;
p2 = ext2 ;
while ( * p2 ) {
if ( * p2 = = ' ? ' ) {
* p2 = * p ;
p2 + + ;
} else {
p2 + + ;
}
if ( * p ) p + + ;
}
strcpy ( name2 , root2 ) ;
if ( ext2 [ 0 ] ) {
strcat ( name2 , " . " ) ;
strcat ( name2 , ext2 ) ;
}
return ( True ) ;
}
/*******************************************************************
check if a user is allowed to rename a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL can_rename ( char * fname , int cnum )
{
struct stat sbuf ;
if ( ! CAN_WRITE ( cnum ) ) return ( False ) ;
if ( sys_lstat ( fname , & sbuf ) ! = 0 ) return ( False ) ;
if ( ! check_file_sharing ( cnum , fname ) ) return ( False ) ;
return ( True ) ;
}
/****************************************************************************
reply to a mv
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_mv ( char * inbuf , char * outbuf )
{
int outsize = 0 ;
pstring name ;
int cnum ;
pstring directory ;
pstring mask , newname ;
char * p ;
int count = 0 ;
int error = ERRnoaccess ;
BOOL has_wild ;
BOOL exists = False ;
* directory = * mask = 0 ;
cnum = SVAL ( inbuf , smb_tid ) ;
strcpy ( name , smb_buf ( inbuf ) + 1 ) ;
strcpy ( newname , smb_buf ( inbuf ) + 3 + strlen ( name ) ) ;
DEBUG ( 3 , ( " reply_mv : %s -> %s \n " , name , newname ) ) ;
unix_convert ( name , cnum ) ;
unix_convert ( newname , cnum ) ;
p = strrchr ( name , ' / ' ) ;
if ( ! p ) {
strcpy ( directory , " ./ " ) ;
strcpy ( mask , name ) ;
} else {
* p = 0 ;
strcpy ( directory , name ) ;
strcpy ( mask , p + 1 ) ;
}
if ( is_mangled ( mask ) )
check_mangled_stack ( mask ) ;
has_wild = strchr ( mask , ' * ' ) | | strchr ( mask , ' ? ' ) ;
if ( ! has_wild ) {
strcat ( directory , " / " ) ;
strcat ( directory , mask ) ;
if ( resolve_wildcards ( directory , newname ) & &
can_rename ( directory , cnum ) & &
! file_exist ( newname , NULL ) & &
! sys_rename ( directory , newname ) ) count + + ;
if ( ! count ) exists = file_exist ( directory , NULL ) ;
if ( ! count & & exists & & file_exist ( newname , NULL ) ) {
exists = True ;
error = 183 ;
}
} else {
void * dirptr = NULL ;
char * dname ;
pstring destname ;
if ( check_name ( directory , cnum ) )
dirptr = OpenDir ( directory ) ;
if ( dirptr )
{
error = ERRbadfile ;
if ( strequal ( mask , " ????????.??? " ) )
strcpy ( mask , " * " ) ;
while ( ( dname = ReadDirName ( dirptr ) ) )
{
pstring fname ;
strcpy ( fname , dname ) ;
if ( ! mask_match ( fname , mask , case_sensitive , False ) ) continue ;
error = ERRnoaccess ;
sprintf ( fname , " %s/%s " , directory , dname ) ;
if ( ! can_rename ( fname , cnum ) ) continue ;
strcpy ( destname , newname ) ;
if ( ! resolve_wildcards ( fname , destname ) ) continue ;
if ( file_exist ( destname , NULL ) ) {
error = 183 ;
continue ;
}
if ( ! sys_rename ( fname , destname ) ) count + + ;
DEBUG ( 3 , ( " reply_mv : doing rename on %s -> %s \n " , fname , destname ) ) ;
}
CloseDir ( dirptr ) ;
}
}
if ( count = = 0 ) {
if ( exists )
return ( ERROR ( ERRDOS , error ) ) ;
else
return ( UNIXERROR ( ERRDOS , error ) ) ;
}
outsize = set_message ( outbuf , 0 , 0 , True ) ;
return ( outsize ) ;
}
/*******************************************************************
copy a file as part of a reply_copy
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL copy_file ( char * src , char * dest1 , int cnum , int ofun ,
int count , BOOL target_is_directory )
{
int Access , action ;
struct stat st ;
int ret = 0 ;
int fnum1 , fnum2 ;
pstring dest ;
strcpy ( dest , dest1 ) ;
if ( target_is_directory ) {
char * p = strrchr ( src , ' / ' ) ;
if ( p )
p + + ;
else
p = src ;
strcat ( dest , " / " ) ;
strcat ( dest , p ) ;
}
if ( ! file_exist ( src , & st ) ) return ( False ) ;
fnum1 = find_free_file ( ) ;
if ( fnum1 < 0 ) return ( False ) ;
open_file_shared ( fnum1 , cnum , src , ( DENY_NONE < < 4 ) ,
1 , 0 , & Access , & action ) ;
if ( ! Files [ fnum1 ] . open ) return ( False ) ;
if ( ! target_is_directory & & count )
ofun = 1 ;
fnum2 = find_free_file ( ) ;
if ( fnum2 < 0 ) {
close_file ( fnum1 ) ;
return ( False ) ;
}
open_file_shared ( fnum2 , cnum , dest , ( DENY_NONE < < 4 ) | 1 ,
ofun , st . st_mode , & Access , & action ) ;
if ( ! Files [ fnum2 ] . open ) {
close_file ( fnum1 ) ;
return ( False ) ;
}
if ( ( ofun & 3 ) = = 1 ) {
lseek ( Files [ fnum2 ] . fd , 0 , SEEK_END ) ;
}
if ( st . st_size )
ret = transfer_file ( Files [ fnum1 ] . fd , Files [ fnum2 ] . fd , st . st_size , NULL , 0 , 0 ) ;
close_file ( fnum1 ) ;
close_file ( fnum2 ) ;
return ( ret = = st . st_size ) ;
}
/****************************************************************************
reply to a file copy .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_copy ( char * inbuf , char * outbuf )
{
int outsize = 0 ;
pstring name ;
int cnum ;
pstring directory ;
pstring mask , newname ;
char * p ;
int count = 0 ;
int error = ERRnoaccess ;
BOOL has_wild ;
BOOL exists = False ;
int tid2 = SVAL ( inbuf , smb_vwv0 ) ;
int ofun = SVAL ( inbuf , smb_vwv1 ) ;
int flags = SVAL ( inbuf , smb_vwv2 ) ;
BOOL target_is_directory = False ;
* directory = * mask = 0 ;
cnum = SVAL ( inbuf , smb_tid ) ;
strcpy ( name , smb_buf ( inbuf ) ) ;
strcpy ( newname , smb_buf ( inbuf ) + 1 + strlen ( name ) ) ;
DEBUG ( 3 , ( " reply_copy : %s -> %s \n " , name , newname ) ) ;
if ( tid2 ! = cnum ) {
/* can't currently handle inter share copies XXXX */
DEBUG ( 3 , ( " Rejecting inter-share copy \n " ) ) ;
return ( ERROR ( ERRSRV , ERRinvdevice ) ) ;
}
unix_convert ( name , cnum ) ;
unix_convert ( newname , cnum ) ;
target_is_directory = directory_exist ( newname , NULL ) ;
if ( ( flags & 1 ) & & target_is_directory ) {
return ( ERROR ( ERRDOS , ERRbadfile ) ) ;
}
if ( ( flags & 2 ) & & ! target_is_directory ) {
return ( ERROR ( ERRDOS , ERRbadpath ) ) ;
}
if ( ( flags & ( 1 < < 5 ) ) & & directory_exist ( name , NULL ) ) {
/* wants a tree copy! XXXX */
DEBUG ( 3 , ( " Rejecting tree copy \n " ) ) ;
return ( ERROR ( ERRSRV , ERRerror ) ) ;
}
p = strrchr ( name , ' / ' ) ;
if ( ! p ) {
strcpy ( directory , " ./ " ) ;
strcpy ( mask , name ) ;
} else {
* p = 0 ;
strcpy ( directory , name ) ;
strcpy ( mask , p + 1 ) ;
}
if ( is_mangled ( mask ) )
check_mangled_stack ( mask ) ;
has_wild = strchr ( mask , ' * ' ) | | strchr ( mask , ' ? ' ) ;
if ( ! has_wild ) {
strcat ( directory , " / " ) ;
strcat ( directory , mask ) ;
if ( resolve_wildcards ( directory , newname ) & &
copy_file ( directory , newname , cnum , ofun ,
count , target_is_directory ) ) count + + ;
if ( ! count ) exists = file_exist ( directory , NULL ) ;
} else {
void * dirptr = NULL ;
char * dname ;
pstring destname ;
if ( check_name ( directory , cnum ) )
dirptr = OpenDir ( directory ) ;
if ( dirptr )
{
error = ERRbadfile ;
if ( strequal ( mask , " ????????.??? " ) )
strcpy ( mask , " * " ) ;
while ( ( dname = ReadDirName ( dirptr ) ) )
{
pstring fname ;
strcpy ( fname , dname ) ;
if ( ! mask_match ( fname , mask , case_sensitive , False ) ) continue ;
error = ERRnoaccess ;
sprintf ( fname , " %s/%s " , directory , dname ) ;
strcpy ( destname , newname ) ;
if ( resolve_wildcards ( fname , destname ) & &
copy_file ( directory , newname , cnum , ofun ,
count , target_is_directory ) ) count + + ;
DEBUG ( 3 , ( " reply_copy : doing copy on %s -> %s \n " , fname , destname ) ) ;
}
CloseDir ( dirptr ) ;
}
}
if ( count = = 0 ) {
if ( exists )
return ( ERROR ( ERRDOS , error ) ) ;
else
return ( UNIXERROR ( ERRDOS , error ) ) ;
}
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , count ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a setdir
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_setdir ( char * inbuf , char * outbuf )
{
int cnum , snum ;
int outsize = 0 ;
BOOL ok = False ;
pstring newdir ;
cnum = SVAL ( inbuf , smb_tid ) ;
snum = Connections [ cnum ] . service ;
if ( ! CAN_SETDIR ( snum ) )
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
strcpy ( newdir , smb_buf ( inbuf ) + 1 ) ;
strlower ( newdir ) ;
if ( strlen ( newdir ) = = 0 )
ok = True ;
else
{
ok = directory_exist ( newdir , NULL ) ;
if ( ok )
string_set ( & Connections [ cnum ] . connectpath , newdir ) ;
}
if ( ! ok )
return ( ERROR ( ERRDOS , ERRbadpath ) ) ;
outsize = set_message ( outbuf , 0 , 0 , True ) ;
CVAL ( outbuf , smb_reh ) = CVAL ( inbuf , smb_reh ) ;
DEBUG ( 3 , ( " %s setdir %s cnum=%d \n " , timestring ( ) , newdir , cnum ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a lockingX request
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_lockingX ( char * inbuf , char * outbuf , int length , int bufsize )
{
int smb_com2 = CVAL ( inbuf , smb_vwv0 ) ;
int smb_off2 = SVAL ( inbuf , smb_vwv1 ) ;
int fnum = GETFNUM ( inbuf , smb_vwv2 ) ;
uint16 locktype = SVAL ( inbuf , smb_vwv3 ) ;
uint16 num_ulocks = SVAL ( inbuf , smb_vwv6 ) ;
uint16 num_locks = SVAL ( inbuf , smb_vwv7 ) ;
uint32 count , offset ;
int cnum ;
int i ;
char * data ;
uint32 ecode = 0 , dummy2 ;
int outsize , eclass = 0 , dummy1 ;
cnum = SVAL ( inbuf , smb_tid ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_ERROR ( fnum ) ;
data = smb_buf ( inbuf ) ;
/* Data now points at the beginning of the list
of smb_unlkrng structs */
for ( i = 0 ; i < ( int ) num_ulocks ; i + + ) {
count = IVAL ( data , SMB_LKLEN_OFFSET ( i ) ) ;
offset = IVAL ( data , SMB_LKOFF_OFFSET ( i ) ) ;
if ( ! do_unlock ( fnum , cnum , count , offset , & eclass , & ecode ) )
return ERROR ( eclass , ecode ) ;
}
/* Now do any requested locks */
data + = 10 * num_ulocks ;
/* Data now points at the beginning of the list
of smb_lkrng structs */
for ( i = 0 ; i < ( int ) num_locks ; i + + ) {
count = IVAL ( data , SMB_LKLEN_OFFSET ( i ) ) ;
offset = IVAL ( data , SMB_LKOFF_OFFSET ( i ) ) ;
if ( ! do_lock ( fnum , cnum , count , offset , & eclass , & ecode ) )
break ;
}
/* If any of the above locks failed, then we must unlock
all of the previous locks ( X / Open spec ) . */
if ( i ! = num_locks & & num_locks ! = 0 ) {
for ( ; i > = 0 ; i - - ) {
count = IVAL ( data , SMB_LKLEN_OFFSET ( i ) ) ;
offset = IVAL ( data , SMB_LKOFF_OFFSET ( i ) ) ;
do_unlock ( fnum , cnum , count , offset , & dummy1 , & dummy2 ) ;
}
return ERROR ( eclass , ecode ) ;
}
outsize = set_message ( outbuf , 2 , 0 , True ) ;
CVAL ( outbuf , smb_vwv0 ) = smb_com2 ;
SSVAL ( outbuf , smb_vwv1 , ( outsize + chain_size ) - 4 ) ;
DEBUG ( 3 , ( " %s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d \n " ,
timestring ( ) , fnum , cnum , locktype , num_locks , num_ulocks ) ) ;
chain_fnum = fnum ;
if ( smb_com2 ! = 0xFF )
outsize + = chain_reply ( smb_com2 , inbuf , inbuf + smb_off2 + 4 ,
outbuf , outbuf + outsize ,
length , bufsize ) ;
chain_fnum = - 1 ;
return ( outsize ) ;
}
/****************************************************************************
reply to a SMBreadbmpx ( read block multiplex ) request
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_readbmpx ( char * inbuf , char * outbuf , int length , int bufsize )
{
int cnum , fnum ;
int nread = - 1 ;
int total_read ;
char * data ;
int32 startpos ;
int outsize , mincount , maxcount ;
int max_per_packet ;
int tcount ;
int pad ;
/* this function doesn't seem to work - disable by default */
if ( ! lp_readbmpx ( ) )
return ( ERROR ( ERRSRV , ERRuseSTD ) ) ;
outsize = set_message ( outbuf , 8 , 0 , True ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_READ ( fnum ) ;
CHECK_ERROR ( fnum ) ;
startpos = IVAL ( inbuf , smb_vwv1 ) ;
maxcount = SVAL ( inbuf , smb_vwv3 ) ;
mincount = SVAL ( inbuf , smb_vwv4 ) ;
data = smb_buf ( outbuf ) ;
pad = ( ( int ) data ) % 4 ;
if ( pad ) pad = 4 - pad ;
data + = pad ;
max_per_packet = bufsize - ( outsize + pad ) ;
tcount = maxcount ;
total_read = 0 ;
if ( is_locked ( fnum , cnum , maxcount , startpos ) )
return ( ERROR ( ERRDOS , ERRlock ) ) ;
do
{
int N = MIN ( max_per_packet , tcount - total_read ) ;
nread = read_file ( fnum , data , startpos , N , N , - 1 , False ) ;
if ( nread < = 0 ) nread = 0 ;
if ( nread < N )
tcount = total_read + nread ;
set_message ( outbuf , 8 , nread , False ) ;
SIVAL ( outbuf , smb_vwv0 , startpos ) ;
SSVAL ( outbuf , smb_vwv2 , tcount ) ;
SSVAL ( outbuf , smb_vwv6 , nread ) ;
SSVAL ( outbuf , smb_vwv7 , smb_offset ( data , outbuf ) ) ;
send_smb ( Client , outbuf ) ;
total_read + = nread ;
startpos + = nread ;
}
while ( total_read < tcount ) ;
return ( - 1 ) ;
}
/****************************************************************************
reply to a SMBwritebmpx ( write block multiplex primary ) request
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_writebmpx ( char * inbuf , char * outbuf )
{
int cnum , numtowrite , fnum ;
int nwritten = - 1 ;
int outsize = 0 ;
int32 startpos ;
int tcount , write_through , smb_doff ;
char * data ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_WRITE ( fnum ) ;
CHECK_ERROR ( fnum ) ;
tcount = SVAL ( inbuf , smb_vwv1 ) ;
startpos = IVAL ( inbuf , smb_vwv3 ) ;
write_through = BITSETW ( inbuf + smb_vwv7 , 0 ) ;
numtowrite = SVAL ( inbuf , smb_vwv10 ) ;
smb_doff = SVAL ( inbuf , smb_vwv11 ) ;
data = smb_base ( inbuf ) + smb_doff ;
/* If this fails we need to send an SMBwriteC response,
not an SMBwritebmpx - set this up now so we don ' t forget */
CVAL ( outbuf , smb_com ) = SMBwritec ;
if ( is_locked ( fnum , cnum , tcount , startpos ) )
return ( ERROR ( ERRDOS , ERRlock ) ) ;
seek_file ( fnum , startpos ) ;
nwritten = write_file ( fnum , data , numtowrite ) ;
if ( lp_syncalways ( SNUM ( cnum ) ) | | write_through )
sync_file ( fnum ) ;
if ( nwritten < numtowrite )
return ( UNIXERROR ( ERRHRD , ERRdiskfull ) ) ;
/* If the maximum to be written to this file
is greater than what we just wrote then set
up a secondary struct to be attached to this
fd , we will use this to cache error messages etc . */
if ( tcount > nwritten )
{
write_bmpx_struct * wbms ;
if ( Files [ fnum ] . wbmpx_ptr ! = NULL )
wbms = Files [ fnum ] . wbmpx_ptr ; /* Use an existing struct */
else
wbms = ( write_bmpx_struct * ) malloc ( sizeof ( write_bmpx_struct ) ) ;
if ( ! wbms )
{
DEBUG ( 0 , ( " Out of memory in reply_readmpx \n " ) ) ;
return ( ERROR ( ERRSRV , ERRnoresource ) ) ;
}
wbms - > wr_mode = write_through ;
wbms - > wr_discard = False ; /* No errors yet */
wbms - > wr_total_written = nwritten ;
wbms - > wr_errclass = 0 ;
wbms - > wr_error = 0 ;
Files [ fnum ] . wbmpx_ptr = wbms ;
}
/* We are returning successfully, set the message type back to
SMBwritebmpx */
CVAL ( outbuf , smb_com ) = SMBwriteBmpx ;
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVALS ( outbuf , smb_vwv0 , - 1 ) ; /* We don't support smb_remaining */
DEBUG ( 3 , ( " %s writebmpx fnum=%d cnum=%d num=%d wrote=%d \n " ,
timestring ( ) , fnum , cnum , numtowrite , nwritten ) ) ;
if ( write_through & & tcount = = nwritten ) {
/* we need to send both a primary and a secondary response */
smb_setlen ( outbuf , outsize - 4 ) ;
send_smb ( Client , outbuf ) ;
/* now the secondary */
outsize = set_message ( outbuf , 1 , 0 , True ) ;
CVAL ( outbuf , smb_com ) = SMBwritec ;
SSVAL ( outbuf , smb_vwv0 , nwritten ) ;
}
return ( outsize ) ;
}
/****************************************************************************
reply to a SMBwritebs ( write block multiplex secondary ) request
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_writebs ( char * inbuf , char * outbuf )
{
int cnum , numtowrite , fnum ;
int nwritten = - 1 ;
int outsize = 0 ;
int32 startpos ;
int tcount , write_through , smb_doff ;
char * data ;
write_bmpx_struct * wbms ;
BOOL send_response = False ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_WRITE ( fnum ) ;
tcount = SVAL ( inbuf , smb_vwv1 ) ;
startpos = IVAL ( inbuf , smb_vwv2 ) ;
numtowrite = SVAL ( inbuf , smb_vwv6 ) ;
smb_doff = SVAL ( inbuf , smb_vwv7 ) ;
data = smb_base ( inbuf ) + smb_doff ;
/* We need to send an SMBwriteC response, not an SMBwritebs */
CVAL ( outbuf , smb_com ) = SMBwritec ;
/* This fd should have an auxiliary struct attached,
check that it does */
wbms = Files [ fnum ] . wbmpx_ptr ;
if ( ! wbms ) return ( - 1 ) ;
/* If write through is set we can return errors, else we must
cache them */
write_through = wbms - > wr_mode ;
/* Check for an earlier error */
if ( wbms - > wr_discard )
return - 1 ; /* Just discard the packet */
seek_file ( fnum , startpos ) ;
nwritten = write_file ( fnum , data , numtowrite ) ;
if ( lp_syncalways ( SNUM ( cnum ) ) | | write_through )
sync_file ( fnum ) ;
if ( nwritten < numtowrite )
{
if ( write_through ) {
/* We are returning an error - we can delete the aux struct */
if ( wbms ) free ( ( char * ) wbms ) ;
Files [ fnum ] . wbmpx_ptr = NULL ;
return ( ERROR ( ERRHRD , ERRdiskfull ) ) ;
}
return ( CACHE_ERROR ( wbms , ERRHRD , ERRdiskfull ) ) ;
}
/* Increment the total written, if this matches tcount
we can discard the auxiliary struct ( hurrah ! ) and return a writeC */
wbms - > wr_total_written + = nwritten ;
if ( wbms - > wr_total_written > = tcount )
{
if ( write_through ) {
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , wbms - > wr_total_written ) ;
send_response = True ;
}
free ( ( char * ) wbms ) ;
Files [ fnum ] . wbmpx_ptr = NULL ;
}
if ( send_response )
return ( outsize ) ;
return ( - 1 ) ;
}
/****************************************************************************
reply to a SMBsetattrE
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_setattrE ( char * inbuf , char * outbuf )
{
int cnum , fnum ;
struct utimbuf unix_times ;
int outsize = 0 ;
outsize = set_message ( outbuf , 0 , 0 , True ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_ERROR ( fnum ) ;
/* Convert the DOS times into unix times. Ignore create
time as UNIX can ' t set this .
*/
unix_times . actime = make_unix_date2 ( inbuf + smb_vwv3 ) ;
unix_times . modtime = make_unix_date2 ( inbuf + smb_vwv5 ) ;
/* Set the date on this file */
if ( sys_utime ( Files [ fnum ] . name , & unix_times ) )
return ( ERROR ( ERRDOS , ERRnoaccess ) ) ;
DEBUG ( 3 , ( " %s reply_setattrE fnum=%d cnum=%d \n " , timestring ( ) , fnum , cnum ) ) ;
return ( outsize ) ;
}
/****************************************************************************
reply to a SMBgetattrE
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_getattrE ( char * inbuf , char * outbuf )
{
int cnum , fnum ;
struct stat sbuf ;
int outsize = 0 ;
int mode ;
outsize = set_message ( outbuf , 11 , 0 , True ) ;
cnum = SVAL ( inbuf , smb_tid ) ;
fnum = GETFNUM ( inbuf , smb_vwv0 ) ;
CHECK_FNUM ( fnum , cnum ) ;
CHECK_ERROR ( fnum ) ;
/* Do an fstat on this file */
if ( fstat ( Files [ fnum ] . fd , & sbuf ) )
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
mode = dos_mode ( cnum , Files [ fnum ] . name , & sbuf ) ;
/* Convert the times into dos times. Set create
date to be last modify date as UNIX doesn ' t save
this */
put_dos_date2 ( outbuf , smb_vwv0 , sbuf . st_mtime ) ;
put_dos_date2 ( outbuf , smb_vwv2 , sbuf . st_atime ) ;
put_dos_date2 ( outbuf , smb_vwv4 , sbuf . st_mtime ) ;
if ( mode & aDIR )
{
SIVAL ( outbuf , smb_vwv6 , 0 ) ;
SIVAL ( outbuf , smb_vwv8 , 0 ) ;
}
else
{
SIVAL ( outbuf , smb_vwv6 , sbuf . st_size ) ;
SIVAL ( outbuf , smb_vwv8 , ROUNDUP ( sbuf . st_size , 1024 ) ) ;
}
SSVAL ( outbuf , smb_vwv10 , mode ) ;
DEBUG ( 3 , ( " %s reply_getattrE fnum=%d cnum=%d \n " , timestring ( ) , fnum , cnum ) ) ;
return ( outsize ) ;
}