2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
transaction2 handling
Copyright ( C ) Andrew Tridgell 2003
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 the parsing of transact2 requests
*/
# include "includes.h"
2004-12-16 15:31:34 +03:00
# include "dlinklist.h"
2004-11-02 10:18:24 +03:00
# include "smb_server/smb_server.h"
2003-08-13 05:53:07 +04:00
# define CHECK_MIN_BLOB_SIZE(blob, size) do { \
if ( ( blob ) - > length < ( size ) ) { \
return NT_STATUS_INFO_LENGTH_MISMATCH ; \
} } while ( 0 )
/* grow the data allocation size of a trans2 reply - this guarantees
that requests to grow the data size later will not change the
pointer */
2004-06-28 12:39:00 +04:00
static void trans2_grow_data_allocation ( struct smbsrv_request * req ,
2003-08-13 05:53:07 +04:00
struct smb_trans2 * trans ,
2004-05-25 21:24:24 +04:00
uint16_t new_size )
2003-08-13 05:53:07 +04:00
{
if ( new_size < = trans - > out . data . length ) {
return ;
}
2004-09-27 05:36:19 +04:00
trans - > out . data . data = talloc_realloc ( req , trans - > out . data . data , new_size ) ;
2003-08-13 05:53:07 +04:00
}
/* grow the data size of a trans2 reply */
2004-06-28 12:39:00 +04:00
static void trans2_grow_data ( struct smbsrv_request * req ,
2003-08-13 05:53:07 +04:00
struct smb_trans2 * trans ,
2004-05-25 21:24:24 +04:00
uint16_t new_size )
2003-08-13 05:53:07 +04:00
{
trans2_grow_data_allocation ( req , trans , new_size ) ;
trans - > out . data . length = new_size ;
}
/* grow the data, zero filling any new bytes */
2004-06-28 12:39:00 +04:00
static void trans2_grow_data_fill ( struct smbsrv_request * req ,
2003-08-13 05:53:07 +04:00
struct smb_trans2 * trans ,
2004-05-25 21:24:24 +04:00
uint16_t new_size )
2003-08-13 05:53:07 +04:00
{
2004-05-25 21:24:24 +04:00
uint16_t old_size = trans - > out . data . length ;
2003-08-13 05:53:07 +04:00
trans2_grow_data ( req , trans , new_size ) ;
if ( new_size > old_size ) {
memset ( trans - > out . data . data + old_size , 0 , new_size - old_size ) ;
}
}
/* setup a trans2 reply, given the data and params sizes */
2004-06-28 12:39:00 +04:00
static void trans2_setup_reply ( struct smbsrv_request * req ,
2003-08-13 05:53:07 +04:00
struct smb_trans2 * trans ,
2004-05-25 21:24:24 +04:00
uint16_t param_size , uint16_t data_size ,
uint16_t setup_count )
2003-08-13 05:53:07 +04:00
{
trans - > out . setup_count = setup_count ;
if ( setup_count ! = 0 ) {
2004-10-19 10:31:37 +04:00
trans - > out . setup = talloc_zero_array_p ( req , uint16_t , setup_count ) ;
2003-08-13 05:53:07 +04:00
}
2004-09-08 09:39:06 +04:00
trans - > out . params = data_blob_talloc ( req , NULL , param_size ) ;
trans - > out . data = data_blob_talloc ( req , NULL , data_size ) ;
2003-08-13 05:53:07 +04:00
}
/*
pull a string from a blob in a trans2 request
*/
2004-06-28 12:39:00 +04:00
static size_t trans2_pull_blob_string ( struct smbsrv_request * req ,
2003-08-13 05:53:07 +04:00
const DATA_BLOB * blob ,
2004-05-25 21:24:24 +04:00
uint16_t offset ,
2003-08-13 05:53:07 +04:00
const char * * str ,
int flags )
{
/* we use STR_NO_RANGE_CHECK because the params are allocated
separately in a DATA_BLOB , so we need to do our own range
checking */
if ( offset > = blob - > length ) {
* str = NULL ;
return 0 ;
}
return req_pull_string ( req , str ,
blob - > data + offset ,
blob - > length - offset ,
STR_NO_RANGE_CHECK | flags ) ;
}
/*
push a string into the data section of a trans2 request
return the number of bytes consumed in the output
*/
2004-06-28 12:39:00 +04:00
static size_t trans2_push_data_string ( struct smbsrv_request * req ,
2003-08-13 05:53:07 +04:00
struct smb_trans2 * trans ,
2004-05-25 21:24:24 +04:00
uint16_t len_offset ,
uint16_t offset ,
2003-08-13 05:53:07 +04:00
const WIRE_STRING * str ,
int dest_len ,
int flags )
{
int alignment = 0 , ret = 0 , pkt_len ;
/* we use STR_NO_RANGE_CHECK because the params are allocated
separately in a DATA_BLOB , so we need to do our own range
checking */
if ( ! str - > s | | offset > = trans - > out . data . length ) {
if ( flags & STR_LEN8BIT ) {
SCVAL ( trans - > out . data . data , len_offset , 0 ) ;
} else {
SIVAL ( trans - > out . data . data , len_offset , 0 ) ;
}
return 0 ;
}
flags | = STR_NO_RANGE_CHECK ;
if ( dest_len = = - 1 | | ( dest_len > trans - > out . data . length - offset ) ) {
dest_len = trans - > out . data . length - offset ;
}
if ( ! ( flags & ( STR_ASCII | STR_UNICODE ) ) ) {
2003-08-16 00:19:30 +04:00
flags | = ( req - > flags2 & FLAGS2_UNICODE_STRINGS ) ? STR_UNICODE : STR_ASCII ;
2003-08-13 05:53:07 +04:00
}
if ( ( offset & 1 ) & & ( flags & STR_UNICODE ) & & ! ( flags & STR_NOALIGN ) ) {
alignment = 1 ;
if ( dest_len > 0 ) {
SCVAL ( trans - > out . data . data + offset , 0 , 0 ) ;
r2552: Character set conversion and string handling updates.
The intial motivation for this commit was to merge in some of the
bugfixes present in Samba3's chrcnv and string handling code into
Samba4. However, along the way I found a lot of unused functions, and
decided to do a bit more...
The strlen_m code now does not use a fixed buffer, but more work is
needed to finish off other functions in str_util.c. These fixed
length buffers hav caused very nasty, hard to chase down bugs at some
sites.
The strupper_m() function has a strupper_talloc() to replace it (we
need to go around and fix more uses, but it's a start). Use of these
new functions will avoid bugs where the upper or lowercase version of
a string is a different length.
I have removed the push_*_allocate functions, which are replaced by
calls to push_*_talloc. Likewise, pstring and other 'fixed length'
wrappers are removed, where possible.
I have removed the first ('base pointer') argument, used by push_ucs2,
as the Samba4 way of doing things ensures that this is always on an
even boundary anyway. (It was used in only one place, in any case).
(This used to be commit dfecb0150627b500cb026b8a4932fe87902ca392)
2004-09-23 04:51:45 +04:00
ret = push_string ( trans - > out . data . data + offset + 1 , str - > s , dest_len - 1 , flags ) ;
2003-08-13 05:53:07 +04:00
}
} else {
r2552: Character set conversion and string handling updates.
The intial motivation for this commit was to merge in some of the
bugfixes present in Samba3's chrcnv and string handling code into
Samba4. However, along the way I found a lot of unused functions, and
decided to do a bit more...
The strlen_m code now does not use a fixed buffer, but more work is
needed to finish off other functions in str_util.c. These fixed
length buffers hav caused very nasty, hard to chase down bugs at some
sites.
The strupper_m() function has a strupper_talloc() to replace it (we
need to go around and fix more uses, but it's a start). Use of these
new functions will avoid bugs where the upper or lowercase version of
a string is a different length.
I have removed the push_*_allocate functions, which are replaced by
calls to push_*_talloc. Likewise, pstring and other 'fixed length'
wrappers are removed, where possible.
I have removed the first ('base pointer') argument, used by push_ucs2,
as the Samba4 way of doing things ensures that this is always on an
even boundary anyway. (It was used in only one place, in any case).
(This used to be commit dfecb0150627b500cb026b8a4932fe87902ca392)
2004-09-23 04:51:45 +04:00
ret = push_string ( trans - > out . data . data + offset , str - > s , dest_len , flags ) ;
2003-08-13 05:53:07 +04:00
}
/* sometimes the string needs to be terminated, but the length
on the wire must not include the termination ! */
pkt_len = ret ;
if ( ( flags & STR_LEN_NOTERM ) & & ( flags & STR_TERMINATE ) ) {
if ( ( flags & STR_UNICODE ) & & ret > = 2 ) {
pkt_len = ret - 2 ;
}
if ( ( flags & STR_ASCII ) & & ret > = 1 ) {
pkt_len = ret - 1 ;
}
}
if ( flags & STR_LEN8BIT ) {
SCVAL ( trans - > out . data . data , len_offset , pkt_len ) ;
} else {
SIVAL ( trans - > out . data . data , len_offset , pkt_len ) ;
}
return ret + alignment ;
}
/*
append a string to the data section of a trans2 reply
len_offset points to the place in the packet where the length field
should go
*/
2004-06-28 12:39:00 +04:00
static void trans2_append_data_string ( struct smbsrv_request * req ,
2003-08-13 05:53:07 +04:00
struct smb_trans2 * trans ,
const WIRE_STRING * str ,
uint_t len_offset ,
int flags )
{
size_t ret ;
2004-05-25 21:24:24 +04:00
uint16_t offset ;
2003-08-13 05:53:07 +04:00
const int max_bytes_per_char = 3 ;
offset = trans - > out . data . length ;
2004-03-26 05:41:20 +03:00
trans2_grow_data ( req , trans , offset + ( 2 + strlen_m ( str - > s ) ) * max_bytes_per_char ) ;
2003-08-13 05:53:07 +04:00
ret = trans2_push_data_string ( req , trans , len_offset , offset , str , - 1 , flags ) ;
trans2_grow_data ( req , trans , offset + ret ) ;
}
2004-10-02 16:16:46 +04:00
/*
align the end of the data section of a trans reply on an even boundary
*/
static void trans2_align_data ( struct smbsrv_request * req , struct smb_trans2 * trans )
{
if ( ( trans - > out . data . length & 1 ) = = 0 ) {
return ;
}
trans2_grow_data ( req , trans , trans - > out . data . length + 1 ) ;
SCVAL ( trans - > out . data . data , trans - > out . data . length - 1 , 0 ) ;
}
2003-08-13 05:53:07 +04:00
/*
trans2 qfsinfo implementation
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS trans2_qfsinfo ( struct smbsrv_request * req , struct smb_trans2 * trans )
2003-08-13 05:53:07 +04:00
{
union smb_fsinfo fsinfo ;
NTSTATUS status ;
2004-05-25 21:24:24 +04:00
uint16_t level ;
2003-08-13 05:53:07 +04:00
uint_t i ;
2003-12-16 12:02:58 +03:00
DATA_BLOB guid_blob ;
2003-08-13 05:53:07 +04:00
/* make sure we got enough parameters */
if ( trans - > in . params . length ! = 2 ) {
return NT_STATUS_FOOBAR ;
}
level = SVAL ( trans - > in . params . data , 0 ) ;
switch ( level ) {
case SMB_QFS_ALLOCATION :
fsinfo . allocation . level = RAW_QFS_ALLOCATION ;
2004-09-29 17:17:09 +04:00
status = ntvfs_fsinfo ( req , & fsinfo ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 0 , 18 , 0 ) ;
SIVAL ( trans - > out . data . data , 0 , fsinfo . allocation . out . fs_id ) ;
SIVAL ( trans - > out . data . data , 4 , fsinfo . allocation . out . sectors_per_unit ) ;
SIVAL ( trans - > out . data . data , 8 , fsinfo . allocation . out . total_alloc_units ) ;
SIVAL ( trans - > out . data . data , 12 , fsinfo . allocation . out . avail_alloc_units ) ;
SSVAL ( trans - > out . data . data , 16 , fsinfo . allocation . out . bytes_per_sector ) ;
return NT_STATUS_OK ;
case SMB_QFS_VOLUME :
fsinfo . volume . level = RAW_QFS_VOLUME ;
2004-09-29 17:17:09 +04:00
status = ntvfs_fsinfo ( req , & fsinfo ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 0 , 5 , 0 ) ;
SIVAL ( trans - > out . data . data , 0 , fsinfo . volume . out . serial_number ) ;
/* w2k3 implements this incorrectly for unicode - it
* leaves the last byte off the string */
trans2_append_data_string ( req , trans ,
& fsinfo . volume . out . volume_name ,
4 , STR_LEN8BIT | STR_NOALIGN ) ;
return NT_STATUS_OK ;
case SMB_QFS_VOLUME_INFO :
case SMB_QFS_VOLUME_INFORMATION :
fsinfo . volume_info . level = RAW_QFS_VOLUME_INFO ;
2004-09-29 17:17:09 +04:00
status = ntvfs_fsinfo ( req , & fsinfo ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 0 , 18 , 0 ) ;
2004-05-25 17:57:39 +04:00
push_nttime ( trans - > out . data . data , 0 , fsinfo . volume_info . out . create_time ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( trans - > out . data . data , 8 , fsinfo . volume_info . out . serial_number ) ;
2004-08-25 08:03:28 +04:00
SSVAL ( trans - > out . data . data , 16 , 0 ) ; /* padding */
2003-08-13 05:53:07 +04:00
trans2_append_data_string ( req , trans ,
& fsinfo . volume_info . out . volume_name ,
12 , STR_UNICODE ) ;
return NT_STATUS_OK ;
case SMB_QFS_SIZE_INFO :
case SMB_QFS_SIZE_INFORMATION :
fsinfo . size_info . level = RAW_QFS_SIZE_INFO ;
2004-09-29 17:17:09 +04:00
status = ntvfs_fsinfo ( req , & fsinfo ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 0 , 24 , 0 ) ;
SBVAL ( trans - > out . data . data , 0 , fsinfo . size_info . out . total_alloc_units ) ;
SBVAL ( trans - > out . data . data , 8 , fsinfo . size_info . out . avail_alloc_units ) ;
SIVAL ( trans - > out . data . data , 16 , fsinfo . size_info . out . sectors_per_unit ) ;
SIVAL ( trans - > out . data . data , 20 , fsinfo . size_info . out . bytes_per_sector ) ;
return NT_STATUS_OK ;
case SMB_QFS_DEVICE_INFO :
case SMB_QFS_DEVICE_INFORMATION :
fsinfo . device_info . level = RAW_QFS_DEVICE_INFO ;
2004-09-29 17:17:09 +04:00
status = ntvfs_fsinfo ( req , & fsinfo ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 0 , 8 , 0 ) ;
SIVAL ( trans - > out . data . data , 0 , fsinfo . device_info . out . device_type ) ;
SIVAL ( trans - > out . data . data , 4 , fsinfo . device_info . out . characteristics ) ;
return NT_STATUS_OK ;
case SMB_QFS_ATTRIBUTE_INFO :
case SMB_QFS_ATTRIBUTE_INFORMATION :
fsinfo . attribute_info . level = RAW_QFS_ATTRIBUTE_INFO ;
2004-09-29 17:17:09 +04:00
status = ntvfs_fsinfo ( req , & fsinfo ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 0 , 12 , 0 ) ;
SIVAL ( trans - > out . data . data , 0 , fsinfo . attribute_info . out . fs_attr ) ;
SIVAL ( trans - > out . data . data , 4 , fsinfo . attribute_info . out . max_file_component_length ) ;
/* this must not be null terminated or win98 gets
confused ! also note that w2k3 returns this as
unicode even when ascii is negotiated */
trans2_append_data_string ( req , trans ,
& fsinfo . attribute_info . out . fs_type ,
8 , STR_UNICODE ) ;
return NT_STATUS_OK ;
case SMB_QFS_QUOTA_INFORMATION :
fsinfo . quota_information . level = RAW_QFS_QUOTA_INFORMATION ;
2004-09-29 17:17:09 +04:00
status = ntvfs_fsinfo ( req , & fsinfo ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 0 , 48 , 0 ) ;
SBVAL ( trans - > out . data . data , 0 , fsinfo . quota_information . out . unknown [ 0 ] ) ;
SBVAL ( trans - > out . data . data , 8 , fsinfo . quota_information . out . unknown [ 1 ] ) ;
SBVAL ( trans - > out . data . data , 16 , fsinfo . quota_information . out . unknown [ 2 ] ) ;
SBVAL ( trans - > out . data . data , 24 , fsinfo . quota_information . out . quota_soft ) ;
SBVAL ( trans - > out . data . data , 32 , fsinfo . quota_information . out . quota_hard ) ;
SBVAL ( trans - > out . data . data , 40 , fsinfo . quota_information . out . quota_flags ) ;
return NT_STATUS_OK ;
case SMB_QFS_FULL_SIZE_INFORMATION :
fsinfo . full_size_information . level = RAW_QFS_FULL_SIZE_INFORMATION ;
2004-09-29 17:17:09 +04:00
status = ntvfs_fsinfo ( req , & fsinfo ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 0 , 32 , 0 ) ;
SBVAL ( trans - > out . data . data , 0 , fsinfo . full_size_information . out . total_alloc_units ) ;
SBVAL ( trans - > out . data . data , 8 , fsinfo . full_size_information . out . call_avail_alloc_units ) ;
SBVAL ( trans - > out . data . data , 16 , fsinfo . full_size_information . out . actual_avail_alloc_units ) ;
SIVAL ( trans - > out . data . data , 24 , fsinfo . full_size_information . out . sectors_per_unit ) ;
SIVAL ( trans - > out . data . data , 28 , fsinfo . full_size_information . out . bytes_per_sector ) ;
return NT_STATUS_OK ;
case SMB_QFS_OBJECTID_INFORMATION :
fsinfo . objectid_information . level = RAW_QFS_OBJECTID_INFORMATION ;
2004-09-29 17:17:09 +04:00
status = ntvfs_fsinfo ( req , & fsinfo ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 0 , 64 , 0 ) ;
2004-09-08 09:39:06 +04:00
status = ndr_push_struct_blob ( & guid_blob , req ,
2003-12-16 12:02:58 +03:00
& fsinfo . objectid_information . out . guid ,
( ndr_push_flags_fn_t ) ndr_push_GUID ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-11-01 08:46:52 +03:00
memcpy ( trans - > out . data . data , guid_blob . data , guid_blob . length ) ;
2003-12-16 12:02:58 +03:00
2003-08-13 05:53:07 +04:00
for ( i = 0 ; i < 6 ; i + + ) {
SBVAL ( trans - > out . data . data , 16 + 8 * i , fsinfo . objectid_information . out . unknown [ i ] ) ;
}
return NT_STATUS_OK ;
}
return NT_STATUS_INVALID_LEVEL ;
}
2004-11-06 10:58:45 +03:00
/*
trans2 open implementation
*/
static NTSTATUS trans2_open ( struct smbsrv_request * req , struct smb_trans2 * trans )
{
union smb_open * io ;
NTSTATUS status ;
/* make sure we got enough parameters */
if ( trans - > in . params . length < 29 ) {
return NT_STATUS_FOOBAR ;
}
io = talloc_p ( req , union smb_open ) ;
if ( io = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
io - > t2open . level = RAW_OPEN_T2OPEN ;
io - > t2open . in . flags = SVAL ( trans - > in . params . data , VWV ( 0 ) ) ;
io - > t2open . in . open_mode = SVAL ( trans - > in . params . data , VWV ( 1 ) ) ;
io - > t2open . in . file_attrs = SVAL ( trans - > in . params . data , VWV ( 3 ) ) ;
io - > t2open . in . write_time = srv_pull_dos_date ( req - > smb_conn ,
trans - > in . params . data + VWV ( 4 ) ) ; ;
io - > t2open . in . open_func = SVAL ( trans - > in . params . data , VWV ( 6 ) ) ;
io - > t2open . in . size = IVAL ( trans - > in . params . data , VWV ( 7 ) ) ;
io - > t2open . in . timeout = IVAL ( trans - > in . params . data , VWV ( 9 ) ) ;
io - > t2open . in . num_eas = 0 ;
io - > t2open . in . eas = NULL ;
trans2_pull_blob_string ( req , & trans - > in . params , 28 , & io - > t2open . in . fname , 0 ) ;
status = ea_pull_list ( & trans - > in . data , io , & io - > t2open . in . num_eas , & io - > t2open . in . eas ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = ntvfs_openfile ( req , io ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 30 , 0 , 0 ) ;
SSVAL ( trans - > out . params . data , VWV ( 0 ) , io - > t2open . out . fnum ) ;
SSVAL ( trans - > out . params . data , VWV ( 1 ) , io - > t2open . out . attrib ) ;
srv_push_dos_date3 ( req - > smb_conn , trans - > out . params . data ,
VWV ( 2 ) , io - > t2open . out . write_time ) ;
SIVAL ( trans - > out . params . data , VWV ( 4 ) , io - > t2open . out . size ) ;
SSVAL ( trans - > out . params . data , VWV ( 6 ) , io - > t2open . out . access ) ;
2004-11-07 13:03:17 +03:00
SSVAL ( trans - > out . params . data , VWV ( 7 ) , io - > t2open . out . ftype ) ;
SSVAL ( trans - > out . params . data , VWV ( 8 ) , io - > t2open . out . devstate ) ;
SSVAL ( trans - > out . params . data , VWV ( 9 ) , io - > t2open . out . action ) ;
SIVAL ( trans - > out . params . data , VWV ( 10 ) , 0 ) ; /* reserved */
SSVAL ( trans - > out . params . data , VWV ( 12 ) , 0 ) ; /* EaErrorOffset */
SIVAL ( trans - > out . params . data , VWV ( 13 ) , 0 ) ; /* EaLength */
2004-11-06 10:58:45 +03:00
return status ;
}
2004-12-14 02:57:59 +03:00
/*
trans2 mkdir implementation
*/
static NTSTATUS trans2_mkdir ( struct smbsrv_request * req , struct smb_trans2 * trans )
{
union smb_mkdir * io ;
NTSTATUS status ;
/* make sure we got enough parameters */
if ( trans - > in . params . length < 5 ) {
return NT_STATUS_FOOBAR ;
}
io = talloc_p ( req , union smb_mkdir ) ;
if ( io = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
io - > t2mkdir . level = RAW_MKDIR_T2MKDIR ;
trans2_pull_blob_string ( req , & trans - > in . params , 4 , & io - > t2mkdir . in . path , 0 ) ;
status = ea_pull_list ( & trans - > in . data , io ,
& io - > t2mkdir . in . num_eas ,
& io - > t2mkdir . in . eas ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = ntvfs_mkdir ( req , io ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 2 , 0 , 0 ) ;
SSVAL ( trans - > out . params . data , VWV ( 0 ) , 0 ) ;
return status ;
}
2003-08-13 05:53:07 +04:00
/*
fill in the reply from a qpathinfo or qfileinfo call
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS trans2_fileinfo_fill ( struct smbsrv_request * req , struct smb_trans2 * trans ,
2003-08-13 05:53:07 +04:00
union smb_fileinfo * st )
{
uint_t i ;
2004-12-15 06:53:05 +03:00
uint32_t list_size ;
2003-08-13 05:53:07 +04:00
switch ( st - > generic . level ) {
case RAW_FILEINFO_GENERIC :
case RAW_FILEINFO_GETATTR :
case RAW_FILEINFO_GETATTRE :
2004-11-18 04:41:43 +03:00
case RAW_FILEINFO_SEC_DESC :
2003-08-13 05:53:07 +04:00
/* handled elsewhere */
return NT_STATUS_INVALID_LEVEL ;
case RAW_FILEINFO_BASIC_INFO :
case RAW_FILEINFO_BASIC_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 40 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
2004-05-25 17:57:39 +04:00
push_nttime ( trans - > out . data . data , 0 , st - > basic_info . out . create_time ) ;
push_nttime ( trans - > out . data . data , 8 , st - > basic_info . out . access_time ) ;
push_nttime ( trans - > out . data . data , 16 , st - > basic_info . out . write_time ) ;
push_nttime ( trans - > out . data . data , 24 , st - > basic_info . out . change_time ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( trans - > out . data . data , 32 , st - > basic_info . out . attrib ) ;
SIVAL ( trans - > out . data . data , 36 , 0 ) ; /* padding */
return NT_STATUS_OK ;
case RAW_FILEINFO_STANDARD :
trans2_setup_reply ( req , trans , 2 , 22 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
2004-06-29 11:40:14 +04:00
srv_push_dos_date2 ( req - > smb_conn , trans - > out . data . data , 0 , st - > standard . out . create_time ) ;
srv_push_dos_date2 ( req - > smb_conn , trans - > out . data . data , 4 , st - > standard . out . access_time ) ;
srv_push_dos_date2 ( req - > smb_conn , trans - > out . data . data , 8 , st - > standard . out . write_time ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( trans - > out . data . data , 12 , st - > standard . out . size ) ;
SIVAL ( trans - > out . data . data , 16 , st - > standard . out . alloc_size ) ;
SSVAL ( trans - > out . data . data , 20 , st - > standard . out . attrib ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_EA_SIZE :
trans2_setup_reply ( req , trans , 2 , 26 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
2004-06-29 11:40:14 +04:00
srv_push_dos_date2 ( req - > smb_conn , trans - > out . data . data , 0 , st - > ea_size . out . create_time ) ;
srv_push_dos_date2 ( req - > smb_conn , trans - > out . data . data , 4 , st - > ea_size . out . access_time ) ;
srv_push_dos_date2 ( req - > smb_conn , trans - > out . data . data , 8 , st - > ea_size . out . write_time ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( trans - > out . data . data , 12 , st - > ea_size . out . size ) ;
SIVAL ( trans - > out . data . data , 16 , st - > ea_size . out . alloc_size ) ;
SSVAL ( trans - > out . data . data , 20 , st - > ea_size . out . attrib ) ;
SIVAL ( trans - > out . data . data , 22 , st - > ea_size . out . ea_size ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_NETWORK_OPEN_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 56 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
2004-05-25 17:57:39 +04:00
push_nttime ( trans - > out . data . data , 0 , st - > network_open_information . out . create_time ) ;
push_nttime ( trans - > out . data . data , 8 , st - > network_open_information . out . access_time ) ;
push_nttime ( trans - > out . data . data , 16 , st - > network_open_information . out . write_time ) ;
push_nttime ( trans - > out . data . data , 24 , st - > network_open_information . out . change_time ) ;
2003-08-13 05:53:07 +04:00
SBVAL ( trans - > out . data . data , 32 , st - > network_open_information . out . alloc_size ) ;
SBVAL ( trans - > out . data . data , 40 , st - > network_open_information . out . size ) ;
SIVAL ( trans - > out . data . data , 48 , st - > network_open_information . out . attrib ) ;
SIVAL ( trans - > out . data . data , 52 , 0 ) ; /* padding */
return NT_STATUS_OK ;
case RAW_FILEINFO_STANDARD_INFO :
case RAW_FILEINFO_STANDARD_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 24 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
SBVAL ( trans - > out . data . data , 0 , st - > standard_info . out . alloc_size ) ;
SBVAL ( trans - > out . data . data , 8 , st - > standard_info . out . size ) ;
SIVAL ( trans - > out . data . data , 16 , st - > standard_info . out . nlink ) ;
SCVAL ( trans - > out . data . data , 20 , st - > standard_info . out . delete_pending ) ;
SCVAL ( trans - > out . data . data , 21 , st - > standard_info . out . directory ) ;
SSVAL ( trans - > out . data . data , 22 , 0 ) ; /* padding */
return NT_STATUS_OK ;
case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 8 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
SIVAL ( trans - > out . data . data , 0 , st - > attribute_tag_information . out . attrib ) ;
SIVAL ( trans - > out . data . data , 4 , st - > attribute_tag_information . out . reparse_tag ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_EA_INFO :
case RAW_FILEINFO_EA_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 4 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
SIVAL ( trans - > out . data . data , 0 , st - > ea_info . out . ea_size ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_MODE_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 4 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
SIVAL ( trans - > out . data . data , 0 , st - > mode_information . out . mode ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_ALIGNMENT_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 4 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
SIVAL ( trans - > out . data . data , 0 ,
st - > alignment_information . out . alignment_requirement ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_ALL_EAS :
2004-12-15 06:53:05 +03:00
list_size = ea_list_size ( st - > all_eas . out . num_eas ,
2004-12-16 15:31:34 +03:00
st - > all_eas . out . eas ) ;
trans2_setup_reply ( req , trans , 2 , list_size , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
ea_put_list ( trans - > out . data . data ,
st - > all_eas . out . num_eas , st - > all_eas . out . eas ) ;
2003-08-13 05:53:07 +04:00
return NT_STATUS_OK ;
case RAW_FILEINFO_ACCESS_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 4 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
SIVAL ( trans - > out . data . data , 0 , st - > access_information . out . access_flags ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_POSITION_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 8 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
SBVAL ( trans - > out . data . data , 0 , st - > position_information . out . position ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_COMPRESSION_INFO :
case RAW_FILEINFO_COMPRESSION_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 16 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
SBVAL ( trans - > out . data . data , 0 , st - > compression_info . out . compressed_size ) ;
SSVAL ( trans - > out . data . data , 8 , st - > compression_info . out . format ) ;
SCVAL ( trans - > out . data . data , 10 , st - > compression_info . out . unit_shift ) ;
SCVAL ( trans - > out . data . data , 11 , st - > compression_info . out . chunk_shift ) ;
SCVAL ( trans - > out . data . data , 12 , st - > compression_info . out . cluster_shift ) ;
SSVAL ( trans - > out . data . data , 13 , 0 ) ; /* 3 bytes padding */
SCVAL ( trans - > out . data . data , 15 , 0 ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_IS_NAME_VALID :
trans2_setup_reply ( req , trans , 2 , 0 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
return NT_STATUS_OK ;
case RAW_FILEINFO_INTERNAL_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 8 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
2003-09-02 08:37:33 +04:00
SBVAL ( trans - > out . data . data , 0 , st - > internal_information . out . file_id ) ;
2003-08-13 05:53:07 +04:00
return NT_STATUS_OK ;
case RAW_FILEINFO_ALL_INFO :
case RAW_FILEINFO_ALL_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 72 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
2004-05-25 17:57:39 +04:00
push_nttime ( trans - > out . data . data , 0 , st - > all_info . out . create_time ) ;
push_nttime ( trans - > out . data . data , 8 , st - > all_info . out . access_time ) ;
push_nttime ( trans - > out . data . data , 16 , st - > all_info . out . write_time ) ;
push_nttime ( trans - > out . data . data , 24 , st - > all_info . out . change_time ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( trans - > out . data . data , 32 , st - > all_info . out . attrib ) ;
2004-08-25 08:03:28 +04:00
SIVAL ( trans - > out . data . data , 36 , 0 ) ;
2003-08-13 05:53:07 +04:00
SBVAL ( trans - > out . data . data , 40 , st - > all_info . out . alloc_size ) ;
SBVAL ( trans - > out . data . data , 48 , st - > all_info . out . size ) ;
SIVAL ( trans - > out . data . data , 56 , st - > all_info . out . nlink ) ;
SCVAL ( trans - > out . data . data , 60 , st - > all_info . out . delete_pending ) ;
SCVAL ( trans - > out . data . data , 61 , st - > all_info . out . directory ) ;
SSVAL ( trans - > out . data . data , 62 , 0 ) ; /* padding */
SIVAL ( trans - > out . data . data , 64 , st - > all_info . out . ea_size ) ;
trans2_append_data_string ( req , trans , & st - > all_info . out . fname ,
2003-08-16 00:19:30 +04:00
68 , STR_UNICODE ) ;
2003-08-13 05:53:07 +04:00
return NT_STATUS_OK ;
case RAW_FILEINFO_NAME_INFO :
case RAW_FILEINFO_NAME_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 4 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
2003-08-16 00:19:30 +04:00
trans2_append_data_string ( req , trans , & st - > name_info . out . fname , 0 , STR_UNICODE ) ;
2003-08-13 05:53:07 +04:00
return NT_STATUS_OK ;
case RAW_FILEINFO_ALT_NAME_INFO :
case RAW_FILEINFO_ALT_NAME_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 4 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
2003-08-16 00:19:30 +04:00
trans2_append_data_string ( req , trans , & st - > alt_name_info . out . fname , 0 , STR_UNICODE ) ;
2003-08-13 05:53:07 +04:00
return NT_STATUS_OK ;
case RAW_FILEINFO_STREAM_INFO :
case RAW_FILEINFO_STREAM_INFORMATION :
trans2_setup_reply ( req , trans , 2 , 0 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
for ( i = 0 ; i < st - > stream_info . out . num_streams ; i + + ) {
2004-05-25 21:24:24 +04:00
uint16_t data_size = trans - > out . data . length ;
2004-11-25 23:01:47 +03:00
uint8_t * data ;
2003-08-13 05:53:07 +04:00
trans2_grow_data ( req , trans , data_size + 24 ) ;
data = trans - > out . data . data + data_size ;
SBVAL ( data , 8 , st - > stream_info . out . streams [ i ] . size ) ;
SBVAL ( data , 16 , st - > stream_info . out . streams [ i ] . alloc_size ) ;
trans2_append_data_string ( req , trans ,
& st - > stream_info . out . streams [ i ] . stream_name ,
data_size + 4 , STR_UNICODE ) ;
if ( i = = st - > stream_info . out . num_streams - 1 ) {
SIVAL ( trans - > out . data . data , data_size , 0 ) ;
} else {
trans2_grow_data_fill ( req , trans , ( trans - > out . data . length + 7 ) & ~ 7 ) ;
SIVAL ( trans - > out . data . data , data_size ,
trans - > out . data . length - data_size ) ;
}
}
return NT_STATUS_OK ;
}
return NT_STATUS_INVALID_LEVEL ;
}
/*
trans2 qpathinfo implementation
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS trans2_qpathinfo ( struct smbsrv_request * req , struct smb_trans2 * trans )
2003-08-13 05:53:07 +04:00
{
union smb_fileinfo st ;
NTSTATUS status ;
2004-05-25 21:24:24 +04:00
uint16_t level ;
2003-08-13 05:53:07 +04:00
/* make sure we got enough parameters */
2004-10-02 16:16:46 +04:00
if ( trans - > in . params . length < 2 ) {
2003-08-13 05:53:07 +04:00
return NT_STATUS_FOOBAR ;
}
level = SVAL ( trans - > in . params . data , 0 ) ;
trans2_pull_blob_string ( req , & trans - > in . params , 6 , & st . generic . in . fname , 0 ) ;
if ( st . generic . in . fname = = NULL ) {
return NT_STATUS_FOOBAR ;
}
/* work out the backend level - we make it 1-1 in the header */
2004-07-19 14:35:05 +04:00
st . generic . level = ( enum smb_fileinfo_level ) level ;
2003-08-13 05:53:07 +04:00
if ( st . generic . level > = RAW_FILEINFO_GENERIC ) {
return NT_STATUS_INVALID_LEVEL ;
}
/* call the backend */
2004-09-29 17:17:09 +04:00
status = ntvfs_qpathinfo ( req , & st ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* fill in the reply parameters */
status = trans2_fileinfo_fill ( req , trans , & st ) ;
return status ;
}
/*
trans2 qpathinfo implementation
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS trans2_qfileinfo ( struct smbsrv_request * req , struct smb_trans2 * trans )
2003-08-13 05:53:07 +04:00
{
union smb_fileinfo st ;
NTSTATUS status ;
2004-05-25 21:24:24 +04:00
uint16_t level ;
2003-08-13 05:53:07 +04:00
/* make sure we got enough parameters */
if ( trans - > in . params . length < 4 ) {
return NT_STATUS_FOOBAR ;
}
st . generic . in . fnum = SVAL ( trans - > in . params . data , 0 ) ;
level = SVAL ( trans - > in . params . data , 2 ) ;
/* work out the backend level - we make it 1-1 in the header */
2004-07-19 14:35:05 +04:00
st . generic . level = ( enum smb_fileinfo_level ) level ;
2003-08-13 05:53:07 +04:00
if ( st . generic . level > = RAW_FILEINFO_GENERIC ) {
return NT_STATUS_INVALID_LEVEL ;
}
/* call the backend */
2004-09-29 17:17:09 +04:00
status = ntvfs_qfileinfo ( req , & st ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* fill in the reply parameters */
status = trans2_fileinfo_fill ( req , trans , & st ) ;
return status ;
}
/*
parse a trans2 setfileinfo / setpathinfo data blob
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS trans2_parse_sfileinfo ( struct smbsrv_request * req ,
2003-08-13 05:53:07 +04:00
union smb_setfileinfo * st ,
const DATA_BLOB * blob )
{
2004-05-25 20:24:13 +04:00
uint32_t len ;
2003-08-13 05:53:07 +04:00
switch ( st - > generic . level ) {
case RAW_SFILEINFO_GENERIC :
case RAW_SFILEINFO_SETATTR :
case RAW_SFILEINFO_SETATTRE :
2004-11-18 04:41:43 +03:00
case RAW_SFILEINFO_SEC_DESC :
2003-08-13 05:53:07 +04:00
/* handled elsewhere */
return NT_STATUS_INVALID_LEVEL ;
case RAW_SFILEINFO_STANDARD :
CHECK_MIN_BLOB_SIZE ( blob , 12 ) ;
2004-06-29 11:40:14 +04:00
st - > standard . in . create_time = srv_pull_dos_date2 ( req - > smb_conn , blob - > data + 0 ) ;
st - > standard . in . access_time = srv_pull_dos_date2 ( req - > smb_conn , blob - > data + 4 ) ;
st - > standard . in . write_time = srv_pull_dos_date2 ( req - > smb_conn , blob - > data + 8 ) ;
2003-08-13 05:53:07 +04:00
return NT_STATUS_OK ;
case RAW_SFILEINFO_EA_SET :
CHECK_MIN_BLOB_SIZE ( blob , 4 ) ;
len = IVAL ( blob - > data , 0 ) ;
if ( len > blob - > length | | len < 4 ) {
return NT_STATUS_INFO_LENGTH_MISMATCH ;
}
{
DATA_BLOB blob2 ;
blob2 . data = blob - > data + 4 ;
blob2 . length = len - 4 ;
2004-09-08 09:39:06 +04:00
len = ea_pull_struct ( & blob2 , req , & st - > ea_set . in . ea ) ;
2003-08-13 05:53:07 +04:00
}
if ( len = = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
return NT_STATUS_OK ;
case SMB_SFILEINFO_BASIC_INFO :
case SMB_SFILEINFO_BASIC_INFORMATION :
CHECK_MIN_BLOB_SIZE ( blob , 36 ) ;
st - > basic_info . in . create_time = pull_nttime ( blob - > data , 0 ) ;
st - > basic_info . in . access_time = pull_nttime ( blob - > data , 8 ) ;
st - > basic_info . in . write_time = pull_nttime ( blob - > data , 16 ) ;
st - > basic_info . in . change_time = pull_nttime ( blob - > data , 24 ) ;
st - > basic_info . in . attrib = IVAL ( blob - > data , 32 ) ;
return NT_STATUS_OK ;
case SMB_SFILEINFO_DISPOSITION_INFO :
case SMB_SFILEINFO_DISPOSITION_INFORMATION :
CHECK_MIN_BLOB_SIZE ( blob , 1 ) ;
st - > disposition_info . in . delete_on_close = CVAL ( blob - > data , 0 ) ;
return NT_STATUS_OK ;
case SMB_SFILEINFO_ALLOCATION_INFO :
case SMB_SFILEINFO_ALLOCATION_INFORMATION :
CHECK_MIN_BLOB_SIZE ( blob , 8 ) ;
st - > allocation_info . in . alloc_size = BVAL ( blob - > data , 0 ) ;
return NT_STATUS_OK ;
case RAW_SFILEINFO_END_OF_FILE_INFO :
case RAW_SFILEINFO_END_OF_FILE_INFORMATION :
CHECK_MIN_BLOB_SIZE ( blob , 8 ) ;
st - > end_of_file_info . in . size = BVAL ( blob - > data , 0 ) ;
return NT_STATUS_OK ;
case RAW_SFILEINFO_RENAME_INFORMATION : {
DATA_BLOB blob2 ;
CHECK_MIN_BLOB_SIZE ( blob , 12 ) ;
st - > rename_information . in . overwrite = CVAL ( blob - > data , 0 ) ;
st - > rename_information . in . root_fid = IVAL ( blob - > data , 4 ) ;
len = IVAL ( blob - > data , 8 ) ;
blob2 . data = blob - > data + 12 ;
blob2 . length = MIN ( blob - > length , len ) ;
trans2_pull_blob_string ( req , & blob2 , 0 ,
2003-08-31 07:16:52 +04:00
& st - > rename_information . in . new_name , STR_UNICODE ) ;
2003-08-13 05:53:07 +04:00
return NT_STATUS_OK ;
}
case RAW_SFILEINFO_POSITION_INFORMATION :
CHECK_MIN_BLOB_SIZE ( blob , 8 ) ;
st - > position_information . in . position = BVAL ( blob - > data , 0 ) ;
return NT_STATUS_OK ;
case RAW_SFILEINFO_MODE_INFORMATION :
CHECK_MIN_BLOB_SIZE ( blob , 4 ) ;
st - > mode_information . in . mode = IVAL ( blob - > data , 0 ) ;
return NT_STATUS_OK ;
}
return NT_STATUS_INVALID_LEVEL ;
}
/*
trans2 setfileinfo implementation
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS trans2_setfileinfo ( struct smbsrv_request * req , struct smb_trans2 * trans )
2003-08-13 05:53:07 +04:00
{
union smb_setfileinfo st ;
NTSTATUS status ;
2004-05-25 21:24:24 +04:00
uint16_t level , fnum ;
2003-08-13 05:53:07 +04:00
DATA_BLOB * blob ;
/* make sure we got enough parameters */
if ( trans - > in . params . length < 4 ) {
return NT_STATUS_FOOBAR ;
}
fnum = SVAL ( trans - > in . params . data , 0 ) ;
level = SVAL ( trans - > in . params . data , 2 ) ;
blob = & trans - > in . data ;
st . generic . file . fnum = fnum ;
2004-07-19 14:35:05 +04:00
st . generic . level = ( enum smb_setfileinfo_level ) level ;
2003-08-13 05:53:07 +04:00
status = trans2_parse_sfileinfo ( req , & st , blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-09-29 17:17:09 +04:00
status = ntvfs_setfileinfo ( req , & st ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 2 , 0 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
return NT_STATUS_OK ;
}
/*
trans2 setpathinfo implementation
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS trans2_setpathinfo ( struct smbsrv_request * req , struct smb_trans2 * trans )
2003-08-13 05:53:07 +04:00
{
union smb_setfileinfo st ;
NTSTATUS status ;
2004-05-25 21:24:24 +04:00
uint16_t level ;
2003-08-13 05:53:07 +04:00
DATA_BLOB * blob ;
/* make sure we got enough parameters */
if ( trans - > in . params . length < 4 ) {
return NT_STATUS_FOOBAR ;
}
level = SVAL ( trans - > in . params . data , 0 ) ;
blob = & trans - > in . data ;
2004-07-19 14:35:05 +04:00
st . generic . level = ( enum smb_setfileinfo_level ) level ;
2003-08-13 05:53:07 +04:00
2004-08-12 01:22:27 +04:00
trans2_pull_blob_string ( req , & trans - > in . params , 6 , & st . generic . file . fname , 0 ) ;
2003-08-13 05:53:07 +04:00
if ( st . generic . file . fname = = NULL ) {
return NT_STATUS_FOOBAR ;
}
status = trans2_parse_sfileinfo ( req , & st , blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2004-09-29 17:17:09 +04:00
status = ntvfs_setpathinfo ( req , & st ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
trans2_setup_reply ( req , trans , 2 , 0 , 0 ) ;
SSVAL ( trans - > out . params . data , 0 , 0 ) ;
return NT_STATUS_OK ;
}
/* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
struct find_state {
2004-06-28 12:39:00 +04:00
struct smbsrv_request * req ;
2003-08-13 05:53:07 +04:00
struct smb_trans2 * trans ;
2004-07-19 14:35:05 +04:00
enum smb_search_level level ;
2004-05-25 21:24:24 +04:00
uint16_t last_entry_offset ;
uint16_t flags ;
2003-08-13 05:53:07 +04:00
} ;
/*
fill a single entry in a trans2 find reply
*/
2004-06-28 12:39:00 +04:00
static void find_fill_info ( struct smbsrv_request * req ,
2003-08-13 05:53:07 +04:00
struct smb_trans2 * trans ,
2003-08-31 07:16:52 +04:00
struct find_state * state ,
2003-08-13 05:53:07 +04:00
union smb_search_data * file )
{
2004-11-25 23:01:47 +03:00
uint8_t * data ;
2003-08-13 05:53:07 +04:00
uint_t ofs = trans - > out . data . length ;
2003-08-31 07:16:52 +04:00
switch ( state - > level ) {
2003-08-13 05:53:07 +04:00
case RAW_SEARCH_SEARCH :
2004-09-21 12:46:47 +04:00
case RAW_SEARCH_FFIRST :
case RAW_SEARCH_FUNIQUE :
2003-08-13 05:53:07 +04:00
case RAW_SEARCH_GENERIC :
/* handled elsewhere */
break ;
case RAW_SEARCH_STANDARD :
2003-08-31 07:16:52 +04:00
if ( state - > flags & FLAG_TRANS2_FIND_REQUIRE_RESUME ) {
trans2_grow_data ( req , trans , ofs + 27 ) ;
SIVAL ( trans - > out . data . data , ofs , file - > standard . resume_key ) ;
ofs + = 4 ;
} else {
trans2_grow_data ( req , trans , ofs + 23 ) ;
}
2003-08-13 05:53:07 +04:00
data = trans - > out . data . data + ofs ;
2004-06-29 11:40:14 +04:00
srv_push_dos_date2 ( req - > smb_conn , data , 0 , file - > standard . create_time ) ;
srv_push_dos_date2 ( req - > smb_conn , data , 4 , file - > standard . access_time ) ;
srv_push_dos_date2 ( req - > smb_conn , data , 8 , file - > standard . write_time ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( data , 12 , file - > standard . size ) ;
SIVAL ( data , 16 , file - > standard . alloc_size ) ;
SSVAL ( data , 20 , file - > standard . attrib ) ;
trans2_append_data_string ( req , trans , & file - > standard . name ,
ofs + 22 , STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM ) ;
break ;
case RAW_SEARCH_EA_SIZE :
2003-08-31 07:16:52 +04:00
if ( state - > flags & FLAG_TRANS2_FIND_REQUIRE_RESUME ) {
trans2_grow_data ( req , trans , ofs + 31 ) ;
SIVAL ( trans - > out . data . data , ofs , file - > ea_size . resume_key ) ;
ofs + = 4 ;
} else {
trans2_grow_data ( req , trans , ofs + 27 ) ;
}
2003-08-13 05:53:07 +04:00
data = trans - > out . data . data + ofs ;
2004-06-29 11:40:14 +04:00
srv_push_dos_date2 ( req - > smb_conn , data , 0 , file - > ea_size . create_time ) ;
srv_push_dos_date2 ( req - > smb_conn , data , 4 , file - > ea_size . access_time ) ;
srv_push_dos_date2 ( req - > smb_conn , data , 8 , file - > ea_size . write_time ) ;
2003-08-13 05:53:07 +04:00
SIVAL ( data , 12 , file - > ea_size . size ) ;
SIVAL ( data , 16 , file - > ea_size . alloc_size ) ;
SSVAL ( data , 20 , file - > ea_size . attrib ) ;
SIVAL ( data , 22 , file - > ea_size . ea_size ) ;
trans2_append_data_string ( req , trans , & file - > ea_size . name ,
2004-08-25 08:16:48 +04:00
ofs + 26 , STR_LEN8BIT | STR_NOALIGN ) ;
2004-09-21 12:46:47 +04:00
trans2_grow_data ( req , trans , trans - > out . data . length + 1 ) ;
trans - > out . data . data [ trans - > out . data . length - 1 ] = 0 ;
2003-08-13 05:53:07 +04:00
break ;
case RAW_SEARCH_DIRECTORY_INFO :
trans2_grow_data ( req , trans , ofs + 64 ) ;
data = trans - > out . data . data + ofs ;
SIVAL ( data , 4 , file - > directory_info . file_index ) ;
2004-05-25 17:57:39 +04:00
push_nttime ( data , 8 , file - > directory_info . create_time ) ;
push_nttime ( data , 16 , file - > directory_info . access_time ) ;
push_nttime ( data , 24 , file - > directory_info . write_time ) ;
push_nttime ( data , 32 , file - > directory_info . change_time ) ;
2003-08-13 05:53:07 +04:00
SBVAL ( data , 40 , file - > directory_info . size ) ;
SBVAL ( data , 48 , file - > directory_info . alloc_size ) ;
SIVAL ( data , 56 , file - > directory_info . attrib ) ;
trans2_append_data_string ( req , trans , & file - > directory_info . name ,
2003-08-16 01:11:13 +04:00
ofs + 60 , STR_TERMINATE_ASCII ) ;
2003-08-13 05:53:07 +04:00
data = trans - > out . data . data + ofs ;
SIVAL ( data , 0 , trans - > out . data . length - ofs ) ;
break ;
case RAW_SEARCH_FULL_DIRECTORY_INFO :
trans2_grow_data ( req , trans , ofs + 68 ) ;
data = trans - > out . data . data + ofs ;
SIVAL ( data , 4 , file - > full_directory_info . file_index ) ;
2004-05-25 17:57:39 +04:00
push_nttime ( data , 8 , file - > full_directory_info . create_time ) ;
push_nttime ( data , 16 , file - > full_directory_info . access_time ) ;
push_nttime ( data , 24 , file - > full_directory_info . write_time ) ;
push_nttime ( data , 32 , file - > full_directory_info . change_time ) ;
2003-08-13 05:53:07 +04:00
SBVAL ( data , 40 , file - > full_directory_info . size ) ;
SBVAL ( data , 48 , file - > full_directory_info . alloc_size ) ;
SIVAL ( data , 56 , file - > full_directory_info . attrib ) ;
SIVAL ( data , 64 , file - > full_directory_info . ea_size ) ;
trans2_append_data_string ( req , trans , & file - > full_directory_info . name ,
2003-08-16 01:11:13 +04:00
ofs + 60 , STR_TERMINATE_ASCII ) ;
2003-08-13 05:53:07 +04:00
data = trans - > out . data . data + ofs ;
SIVAL ( data , 0 , trans - > out . data . length - ofs ) ;
break ;
case RAW_SEARCH_NAME_INFO :
trans2_grow_data ( req , trans , ofs + 12 ) ;
data = trans - > out . data . data + ofs ;
SIVAL ( data , 4 , file - > name_info . file_index ) ;
trans2_append_data_string ( req , trans , & file - > name_info . name ,
2003-08-16 01:11:13 +04:00
ofs + 8 , STR_TERMINATE_ASCII ) ;
2003-08-13 05:53:07 +04:00
data = trans - > out . data . data + ofs ;
SIVAL ( data , 0 , trans - > out . data . length - ofs ) ;
break ;
case RAW_SEARCH_BOTH_DIRECTORY_INFO :
trans2_grow_data ( req , trans , ofs + 94 ) ;
data = trans - > out . data . data + ofs ;
SIVAL ( data , 4 , file - > both_directory_info . file_index ) ;
2004-05-25 17:57:39 +04:00
push_nttime ( data , 8 , file - > both_directory_info . create_time ) ;
push_nttime ( data , 16 , file - > both_directory_info . access_time ) ;
push_nttime ( data , 24 , file - > both_directory_info . write_time ) ;
push_nttime ( data , 32 , file - > both_directory_info . change_time ) ;
2003-08-13 05:53:07 +04:00
SBVAL ( data , 40 , file - > both_directory_info . size ) ;
SBVAL ( data , 48 , file - > both_directory_info . alloc_size ) ;
SIVAL ( data , 56 , file - > both_directory_info . attrib ) ;
SIVAL ( data , 64 , file - > both_directory_info . ea_size ) ;
SCVAL ( data , 69 , 0 ) ; /* reserved */
memset ( data + 70 , 0 , 24 ) ;
trans2_push_data_string ( req , trans ,
68 + ofs , 70 + ofs ,
& file - > both_directory_info . short_name ,
24 , STR_UNICODE | STR_LEN8BIT ) ;
trans2_append_data_string ( req , trans , & file - > both_directory_info . name ,
2003-08-16 01:11:13 +04:00
ofs + 60 , STR_TERMINATE_ASCII ) ;
2004-10-02 16:16:46 +04:00
trans2_align_data ( req , trans ) ;
2003-08-13 05:53:07 +04:00
data = trans - > out . data . data + ofs ;
SIVAL ( data , 0 , trans - > out . data . length - ofs ) ;
break ;
2003-09-02 08:37:33 +04:00
case RAW_SEARCH_ID_FULL_DIRECTORY_INFO :
2003-08-13 05:53:07 +04:00
trans2_grow_data ( req , trans , ofs + 80 ) ;
data = trans - > out . data . data + ofs ;
2003-09-02 08:37:33 +04:00
SIVAL ( data , 4 , file - > id_full_directory_info . file_index ) ;
2004-05-25 17:57:39 +04:00
push_nttime ( data , 8 , file - > id_full_directory_info . create_time ) ;
push_nttime ( data , 16 , file - > id_full_directory_info . access_time ) ;
push_nttime ( data , 24 , file - > id_full_directory_info . write_time ) ;
push_nttime ( data , 32 , file - > id_full_directory_info . change_time ) ;
2003-09-02 08:37:33 +04:00
SBVAL ( data , 40 , file - > id_full_directory_info . size ) ;
SBVAL ( data , 48 , file - > id_full_directory_info . alloc_size ) ;
SIVAL ( data , 56 , file - > id_full_directory_info . attrib ) ;
SIVAL ( data , 64 , file - > id_full_directory_info . ea_size ) ;
SIVAL ( data , 68 , 0 ) ; /* padding */
SBVAL ( data , 72 , file - > id_full_directory_info . file_id ) ;
trans2_append_data_string ( req , trans , & file - > id_full_directory_info . name ,
2003-08-16 01:11:13 +04:00
ofs + 60 , STR_TERMINATE_ASCII ) ;
2003-08-13 05:53:07 +04:00
data = trans - > out . data . data + ofs ;
SIVAL ( data , 0 , trans - > out . data . length - ofs ) ;
break ;
2003-09-02 08:37:33 +04:00
case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO :
2003-08-13 05:53:07 +04:00
trans2_grow_data ( req , trans , ofs + 104 ) ;
data = trans - > out . data . data + ofs ;
2003-09-02 08:37:33 +04:00
SIVAL ( data , 4 , file - > id_both_directory_info . file_index ) ;
2004-05-25 17:57:39 +04:00
push_nttime ( data , 8 , file - > id_both_directory_info . create_time ) ;
push_nttime ( data , 16 , file - > id_both_directory_info . access_time ) ;
push_nttime ( data , 24 , file - > id_both_directory_info . write_time ) ;
push_nttime ( data , 32 , file - > id_both_directory_info . change_time ) ;
2003-09-02 08:37:33 +04:00
SBVAL ( data , 40 , file - > id_both_directory_info . size ) ;
SBVAL ( data , 48 , file - > id_both_directory_info . alloc_size ) ;
SIVAL ( data , 56 , file - > id_both_directory_info . attrib ) ;
SIVAL ( data , 64 , file - > id_both_directory_info . ea_size ) ;
2003-08-13 05:53:07 +04:00
SCVAL ( data , 69 , 0 ) ; /* reserved */
2004-08-25 08:16:48 +04:00
memset ( data + 70 , 0 , 26 ) ;
2003-08-13 05:53:07 +04:00
trans2_push_data_string ( req , trans ,
68 + ofs , 70 + ofs ,
2003-09-02 08:37:33 +04:00
& file - > id_both_directory_info . short_name ,
2003-08-13 05:53:07 +04:00
24 , STR_UNICODE | STR_LEN8BIT ) ;
2004-08-25 08:16:48 +04:00
SBVAL ( data , 96 , file - > id_both_directory_info . file_id ) ;
2003-09-02 08:37:33 +04:00
trans2_append_data_string ( req , trans , & file - > id_both_directory_info . name ,
2003-08-16 01:11:13 +04:00
ofs + 60 , STR_TERMINATE_ASCII ) ;
2003-08-13 05:53:07 +04:00
data = trans - > out . data . data + ofs ;
SIVAL ( data , 0 , trans - > out . data . length - ofs ) ;
break ;
}
}
/* callback function for trans2 findfirst/findnext */
static BOOL find_callback ( void * private , union smb_search_data * file )
{
struct find_state * state = ( struct find_state * ) private ;
struct smb_trans2 * trans = state - > trans ;
uint_t old_length ;
old_length = trans - > out . data . length ;
2003-08-31 07:16:52 +04:00
find_fill_info ( state - > req , trans , state , file ) ;
2003-08-13 05:53:07 +04:00
/* see if we have gone beyond the user specified maximum */
if ( trans - > out . data . length > trans - > in . max_data ) {
/* restore the old length and tell the backend to stop */
trans2_grow_data ( state - > req , trans , old_length ) ;
return False ;
}
state - > last_entry_offset = old_length ;
return True ;
}
/*
trans2 findfirst implementation
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS trans2_findfirst ( struct smbsrv_request * req , struct smb_trans2 * trans )
2003-08-13 05:53:07 +04:00
{
union smb_search_first search ;
NTSTATUS status ;
2004-05-25 21:24:24 +04:00
uint16_t level ;
2004-11-25 23:01:47 +03:00
uint8_t * param ;
2003-08-13 05:53:07 +04:00
struct find_state state ;
/* make sure we got all the parameters */
if ( trans - > in . params . length < 14 ) {
return NT_STATUS_FOOBAR ;
}
search . t2ffirst . in . search_attrib = SVAL ( trans - > in . params . data , 0 ) ;
search . t2ffirst . in . max_count = SVAL ( trans - > in . params . data , 2 ) ;
search . t2ffirst . in . flags = SVAL ( trans - > in . params . data , 4 ) ;
level = SVAL ( trans - > in . params . data , 6 ) ;
search . t2ffirst . in . storage_type = IVAL ( trans - > in . params . data , 8 ) ;
trans2_pull_blob_string ( req , & trans - > in . params , 12 , & search . t2ffirst . in . pattern , 0 ) ;
if ( search . t2ffirst . in . pattern = = NULL ) {
return NT_STATUS_FOOBAR ;
}
2004-07-19 14:35:05 +04:00
search . t2ffirst . level = ( enum smb_search_level ) level ;
2003-08-13 05:53:07 +04:00
if ( search . t2ffirst . level > = RAW_SEARCH_GENERIC ) {
return NT_STATUS_INVALID_LEVEL ;
}
/* setup the private state structure that the backend will give us in the callback */
state . req = req ;
state . trans = trans ;
state . level = search . t2ffirst . level ;
state . last_entry_offset = 0 ;
2003-08-31 07:16:52 +04:00
state . flags = search . t2ffirst . in . flags ;
2003-08-13 05:53:07 +04:00
/* setup for just a header in the reply */
trans2_setup_reply ( req , trans , 10 , 0 , 0 ) ;
/* call the backend */
2004-09-29 17:17:09 +04:00
status = ntvfs_search_first ( req , & search , & state , find_callback ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2004-09-22 12:17:26 +04:00
trans2_setup_reply ( req , trans , 0 , 0 , 0 ) ;
2003-08-13 05:53:07 +04:00
return status ;
}
/* fill in the findfirst reply header */
param = trans - > out . params . data ;
SSVAL ( param , VWV ( 0 ) , search . t2ffirst . out . handle ) ;
SSVAL ( param , VWV ( 1 ) , search . t2ffirst . out . count ) ;
SSVAL ( param , VWV ( 2 ) , search . t2ffirst . out . end_of_search ) ;
SSVAL ( param , VWV ( 3 ) , 0 ) ;
SSVAL ( param , VWV ( 4 ) , state . last_entry_offset ) ;
2004-09-22 12:17:26 +04:00
2003-08-13 05:53:07 +04:00
return NT_STATUS_OK ;
}
/*
trans2 findnext implementation
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS trans2_findnext ( struct smbsrv_request * req , struct smb_trans2 * trans )
2003-08-13 05:53:07 +04:00
{
union smb_search_next search ;
NTSTATUS status ;
2004-05-25 21:24:24 +04:00
uint16_t level ;
2004-11-25 23:01:47 +03:00
uint8_t * param ;
2003-08-13 05:53:07 +04:00
struct find_state state ;
/* make sure we got all the parameters */
if ( trans - > in . params . length < 12 ) {
return NT_STATUS_FOOBAR ;
}
search . t2fnext . in . handle = SVAL ( trans - > in . params . data , 0 ) ;
search . t2fnext . in . max_count = SVAL ( trans - > in . params . data , 2 ) ;
level = SVAL ( trans - > in . params . data , 4 ) ;
search . t2fnext . in . resume_key = IVAL ( trans - > in . params . data , 6 ) ;
search . t2fnext . in . flags = SVAL ( trans - > in . params . data , 10 ) ;
trans2_pull_blob_string ( req , & trans - > in . params , 12 , & search . t2fnext . in . last_name , 0 ) ;
if ( search . t2fnext . in . last_name = = NULL ) {
return NT_STATUS_FOOBAR ;
}
2004-07-19 14:35:05 +04:00
search . t2fnext . level = ( enum smb_search_level ) level ;
2003-08-13 05:53:07 +04:00
if ( search . t2fnext . level > = RAW_SEARCH_GENERIC ) {
return NT_STATUS_INVALID_LEVEL ;
}
/* setup the private state structure that the backend will give us in the callback */
state . req = req ;
state . trans = trans ;
state . level = search . t2fnext . level ;
state . last_entry_offset = 0 ;
2003-08-31 07:16:52 +04:00
state . flags = search . t2fnext . in . flags ;
2003-08-13 05:53:07 +04:00
/* setup for just a header in the reply */
trans2_setup_reply ( req , trans , 8 , 0 , 0 ) ;
/* call the backend */
2004-09-29 17:17:09 +04:00
status = ntvfs_search_next ( req , & search , & state , find_callback ) ;
2003-08-13 05:53:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* fill in the findfirst reply header */
param = trans - > out . params . data ;
SSVAL ( param , VWV ( 0 ) , search . t2fnext . out . count ) ;
SSVAL ( param , VWV ( 1 ) , search . t2fnext . out . end_of_search ) ;
SSVAL ( param , VWV ( 2 ) , 0 ) ;
SSVAL ( param , VWV ( 3 ) , state . last_entry_offset ) ;
return NT_STATUS_OK ;
}
/*
backend for trans2 requests
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS trans2_backend ( struct smbsrv_request * req , struct smb_trans2 * trans )
2003-08-13 05:53:07 +04:00
{
2004-09-29 17:17:09 +04:00
NTSTATUS status ;
/* direct trans2 pass thru */
status = ntvfs_trans2 ( req , trans ) ;
if ( ! NT_STATUS_EQUAL ( NT_STATUS_NOT_IMPLEMENTED , status ) ) {
return status ;
2003-08-13 05:53:07 +04:00
}
/* must have at least one setup word */
if ( trans - > in . setup_count < 1 ) {
return NT_STATUS_FOOBAR ;
}
/* the trans2 command is in setup[0] */
switch ( trans - > in . setup [ 0 ] ) {
case TRANSACT2_FINDFIRST :
return trans2_findfirst ( req , trans ) ;
case TRANSACT2_FINDNEXT :
return trans2_findnext ( req , trans ) ;
case TRANSACT2_QPATHINFO :
return trans2_qpathinfo ( req , trans ) ;
case TRANSACT2_QFILEINFO :
return trans2_qfileinfo ( req , trans ) ;
case TRANSACT2_SETFILEINFO :
return trans2_setfileinfo ( req , trans ) ;
case TRANSACT2_SETPATHINFO :
return trans2_setpathinfo ( req , trans ) ;
case TRANSACT2_QFSINFO :
return trans2_qfsinfo ( req , trans ) ;
2004-11-06 10:58:45 +03:00
case TRANSACT2_OPEN :
return trans2_open ( req , trans ) ;
2004-12-14 02:57:59 +03:00
case TRANSACT2_MKDIR :
return trans2_mkdir ( req , trans ) ;
2003-08-13 05:53:07 +04:00
}
/* an unknown trans2 command */
return NT_STATUS_FOOBAR ;
}
2004-12-16 15:31:34 +03:00
/*
send a continue request
*/
static void reply_trans_continue ( struct smbsrv_request * req , uint8_t command ,
struct smb_trans2 * trans )
2003-08-13 05:53:07 +04:00
{
2004-12-16 15:31:34 +03:00
struct smbsrv_trans_partial * tp ;
int count ;
2003-08-13 05:53:07 +04:00
2004-12-16 15:31:34 +03:00
/* make sure they don't flood us */
for ( count = 0 , tp = req - > smb_conn - > trans_partial ; tp ; tp = tp - > next ) count + + ;
if ( count > 100 ) {
req_reply_error ( req , NT_STATUS_INSUFFICIENT_RESOURCES ) ;
2003-08-13 05:53:07 +04:00
return ;
}
2004-12-16 15:31:34 +03:00
tp = talloc_p ( req , struct smbsrv_trans_partial ) ;
2003-08-13 05:53:07 +04:00
2004-12-16 15:31:34 +03:00
tp - > req = talloc_reference ( tp , req ) ;
tp - > trans = trans ;
tp - > command = command ;
2003-08-13 05:53:07 +04:00
2004-12-16 15:31:34 +03:00
DLIST_ADD ( req - > smb_conn - > trans_partial , tp ) ;
2003-12-11 12:07:45 +03:00
2004-12-16 15:31:34 +03:00
/* send a 'please continue' reply */
req_setup_reply ( req , 0 , 0 ) ;
req_send_reply ( req ) ;
}
2003-08-13 05:53:07 +04:00
2004-12-16 15:31:34 +03:00
/*
answer a reconstructed trans request
*/
static void reply_trans_complete ( struct smbsrv_request * req , uint8_t command ,
struct smb_trans2 * trans )
{
uint16_t params_left , data_left ;
uint8_t * params , * data ;
NTSTATUS status ;
int i ;
2003-08-13 05:53:07 +04:00
/* its a full request, give it to the backend */
2003-12-11 12:07:45 +03:00
if ( command = = SMBtrans ) {
2004-12-16 15:31:34 +03:00
status = ntvfs_trans ( req , trans ) ;
2003-12-11 12:07:45 +03:00
} else {
2004-12-16 15:31:34 +03:00
status = trans2_backend ( req , trans ) ;
2003-12-11 12:07:45 +03:00
}
2003-08-13 05:53:07 +04:00
2004-06-16 10:49:24 +04:00
if ( NT_STATUS_IS_ERR ( status ) ) {
2003-08-13 05:53:07 +04:00
req_reply_error ( req , status ) ;
return ;
}
2004-12-16 15:31:34 +03:00
params_left = trans - > out . params . length ;
data_left = trans - > out . data . length ;
params = trans - > out . params . data ;
data = trans - > out . data . data ;
2004-10-29 07:48:49 +04:00
2004-12-16 15:31:34 +03:00
req_setup_reply ( req , 10 + trans - > out . setup_count , 0 ) ;
2004-10-29 07:48:49 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
req_setup_error ( req , status ) ;
}
2003-08-13 05:53:07 +04:00
/* we need to divide up the reply into chunks that fit into
the negotiated buffer size */
do {
2004-05-25 21:24:24 +04:00
uint16_t this_data , this_param , max_bytes ;
2003-08-13 05:53:07 +04:00
uint_t align1 = 1 , align2 = ( params_left ? 2 : 0 ) ;
2004-10-29 07:48:49 +04:00
struct smbsrv_request * this_req ;
2003-08-13 05:53:07 +04:00
max_bytes = req_max_data ( req ) - ( align1 + align2 ) ;
this_param = params_left ;
if ( this_param > max_bytes ) {
this_param = max_bytes ;
}
max_bytes - = this_param ;
this_data = data_left ;
if ( this_data > max_bytes ) {
this_data = max_bytes ;
}
2004-10-29 07:48:49 +04:00
/* don't destroy unless this is the last chunk */
if ( params_left - this_param ! = 0 | |
data_left - this_data ! = 0 ) {
this_req = req_setup_secondary ( req ) ;
} else {
this_req = req ;
}
req_grow_data ( this_req , this_param + this_data + ( align1 + align2 ) ) ;
2003-08-13 05:53:07 +04:00
2004-12-16 15:31:34 +03:00
SSVAL ( this_req - > out . vwv , VWV ( 0 ) , trans - > out . params . length ) ;
SSVAL ( this_req - > out . vwv , VWV ( 1 ) , trans - > out . data . length ) ;
2004-10-29 07:48:49 +04:00
SSVAL ( this_req - > out . vwv , VWV ( 2 ) , 0 ) ;
2003-08-13 05:53:07 +04:00
2004-10-29 07:48:49 +04:00
SSVAL ( this_req - > out . vwv , VWV ( 3 ) , this_param ) ;
SSVAL ( this_req - > out . vwv , VWV ( 4 ) , align1 + PTR_DIFF ( this_req - > out . data , this_req - > out . hdr ) ) ;
2004-12-16 15:31:34 +03:00
SSVAL ( this_req - > out . vwv , VWV ( 5 ) , PTR_DIFF ( params , trans - > out . params . data ) ) ;
2003-08-13 05:53:07 +04:00
2004-10-29 07:48:49 +04:00
SSVAL ( this_req - > out . vwv , VWV ( 6 ) , this_data ) ;
SSVAL ( this_req - > out . vwv , VWV ( 7 ) , align1 + align2 +
PTR_DIFF ( this_req - > out . data + this_param , this_req - > out . hdr ) ) ;
2004-12-16 15:31:34 +03:00
SSVAL ( this_req - > out . vwv , VWV ( 8 ) , PTR_DIFF ( data , trans - > out . data . data ) ) ;
2003-08-13 05:53:07 +04:00
2004-12-16 15:31:34 +03:00
SSVAL ( this_req - > out . vwv , VWV ( 9 ) , trans - > out . setup_count ) ;
for ( i = 0 ; i < trans - > out . setup_count ; i + + ) {
SSVAL ( this_req - > out . vwv , VWV ( 10 + i ) , trans - > out . setup [ i ] ) ;
2003-08-13 05:53:07 +04:00
}
2004-10-29 07:48:49 +04:00
memset ( this_req - > out . data , 0 , align1 ) ;
2003-08-13 05:53:07 +04:00
if ( this_param ! = 0 ) {
2004-10-29 07:48:49 +04:00
memcpy ( this_req - > out . data + align1 , params , this_param ) ;
2003-08-13 05:53:07 +04:00
}
2004-10-29 07:48:49 +04:00
memset ( this_req - > out . data + this_param + align1 , 0 , align2 ) ;
2003-08-13 05:53:07 +04:00
if ( this_data ! = 0 ) {
2004-10-29 07:48:49 +04:00
memcpy ( this_req - > out . data + this_param + align1 + align2 , data , this_data ) ;
2003-08-13 05:53:07 +04:00
}
params_left - = this_param ;
data_left - = this_data ;
params + = this_param ;
data + = this_data ;
2004-10-29 07:48:49 +04:00
req_send_reply ( this_req ) ;
2003-08-13 05:53:07 +04:00
} while ( params_left ! = 0 | | data_left ! = 0 ) ;
}
2003-12-11 12:07:45 +03:00
2004-12-16 15:31:34 +03:00
/*
Reply to an SMBtrans or SMBtrans2 request
*/
void reply_trans_generic ( struct smbsrv_request * req , uint8_t command )
{
struct smb_trans2 * trans ;
int i ;
uint16_t param_ofs , data_ofs ;
uint16_t param_count , data_count ;
uint16_t param_total , data_total ;
trans = talloc_p ( req , struct smb_trans2 ) ;
if ( trans = = NULL ) {
req_reply_error ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
/* parse request */
if ( req - > in . wct < 14 ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
param_total = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
data_total = SVAL ( req - > in . vwv , VWV ( 1 ) ) ;
trans - > in . max_param = SVAL ( req - > in . vwv , VWV ( 2 ) ) ;
trans - > in . max_data = SVAL ( req - > in . vwv , VWV ( 3 ) ) ;
trans - > in . max_setup = CVAL ( req - > in . vwv , VWV ( 4 ) ) ;
trans - > in . flags = SVAL ( req - > in . vwv , VWV ( 5 ) ) ;
trans - > in . timeout = IVAL ( req - > in . vwv , VWV ( 6 ) ) ;
param_count = SVAL ( req - > in . vwv , VWV ( 9 ) ) ;
param_ofs = SVAL ( req - > in . vwv , VWV ( 10 ) ) ;
data_count = SVAL ( req - > in . vwv , VWV ( 11 ) ) ;
data_ofs = SVAL ( req - > in . vwv , VWV ( 12 ) ) ;
trans - > in . setup_count = CVAL ( req - > in . vwv , VWV ( 13 ) ) ;
if ( req - > in . wct ! = 14 + trans - > in . setup_count ) {
req_reply_dos_error ( req , ERRSRV , ERRerror ) ;
return ;
}
/* parse out the setup words */
trans - > in . setup = talloc_array_p ( req , uint16_t , trans - > in . setup_count ) ;
if ( trans - > in . setup_count & & ! trans - > in . setup ) {
req_reply_error ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
for ( i = 0 ; i < trans - > in . setup_count ; i + + ) {
trans - > in . setup [ i ] = SVAL ( req - > in . vwv , VWV ( 14 + i ) ) ;
}
if ( command = = SMBtrans ) {
req_pull_string ( req , & trans - > in . trans_name , req - > in . data , - 1 , STR_TERMINATE ) ;
}
if ( ! req_pull_blob ( req , req - > in . hdr + param_ofs , param_count , & trans - > in . params ) | |
! req_pull_blob ( req , req - > in . hdr + data_ofs , data_count , & trans - > in . data ) ) {
req_reply_error ( req , NT_STATUS_FOOBAR ) ;
return ;
}
/* is it a partial request? if so, then send a 'send more' message */
if ( param_total > param_count | | data_total > data_count ) {
reply_trans_continue ( req , command , trans ) ;
return ;
}
reply_trans_complete ( req , command , trans ) ;
}
/*
Reply to an SMBtranss2 request
*/
static void reply_transs_generic ( struct smbsrv_request * req , uint8_t command )
{
struct smbsrv_trans_partial * tp ;
struct smb_trans2 * trans = NULL ;
uint16_t param_ofs , data_ofs ;
uint16_t param_count , data_count ;
uint16_t param_disp , data_disp ;
uint16_t param_total , data_total ;
DATA_BLOB params , data ;
for ( tp = req - > smb_conn - > trans_partial ; tp ; tp = tp - > next ) {
if ( tp - > command = = command & &
SVAL ( tp - > req - > in . hdr , HDR_MID ) = = SVAL ( req - > in . hdr , HDR_MID ) ) {
break ;
}
}
if ( tp = = NULL ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
trans = tp - > trans ;
/* parse request */
if ( req - > in . wct < 8 ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
param_total = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
data_total = SVAL ( req - > in . vwv , VWV ( 1 ) ) ;
param_count = SVAL ( req - > in . vwv , VWV ( 2 ) ) ;
param_ofs = SVAL ( req - > in . vwv , VWV ( 3 ) ) ;
param_disp = SVAL ( req - > in . vwv , VWV ( 4 ) ) ;
data_count = SVAL ( req - > in . vwv , VWV ( 5 ) ) ;
data_ofs = SVAL ( req - > in . vwv , VWV ( 6 ) ) ;
data_disp = SVAL ( req - > in . vwv , VWV ( 7 ) ) ;
if ( ! req_pull_blob ( req , req - > in . hdr + param_ofs , param_count , & params ) | |
! req_pull_blob ( req , req - > in . hdr + data_ofs , data_count , & data ) ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
/* only allow contiguous requests */
if ( ( param_count ! = 0 & &
param_disp ! = trans - > in . params . length ) | |
( data_count ! = 0 & &
data_disp ! = trans - > in . data . length ) ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
/* add to the existing request */
if ( param_count ! = 0 ) {
trans - > in . params . data = talloc_realloc_p ( trans ,
trans - > in . params . data ,
uint8_t ,
param_disp + param_count ) ;
if ( trans - > in . params . data = = NULL ) {
goto failed ;
}
trans - > in . params . length = param_disp + param_count ;
}
if ( data_count ! = 0 ) {
trans - > in . data . data = talloc_realloc_p ( trans ,
trans - > in . data . data ,
uint8_t ,
data_disp + data_count ) ;
if ( trans - > in . data . data = = NULL ) {
goto failed ;
}
trans - > in . data . length = data_disp + data_count ;
}
memcpy ( trans - > in . params . data + param_disp , params . data , params . length ) ;
memcpy ( trans - > in . data . data + data_disp , data . data , data . length ) ;
/* the sequence number of the reply is taken from the last secondary
response */
tp - > req - > seq_num = req - > seq_num ;
/* we don't reply to Transs2 requests */
talloc_free ( req ) ;
if ( trans - > in . params . length = = param_total & &
trans - > in . data . length = = data_total ) {
/* its now complete */
reply_trans_complete ( tp - > req , command , trans ) ;
DLIST_REMOVE ( tp - > req - > smb_conn - > trans_partial , tp ) ;
talloc_free ( tp ) ;
}
return ;
failed :
req_reply_error ( tp - > req , NT_STATUS_NO_MEMORY ) ;
DLIST_REMOVE ( req - > smb_conn - > trans_partial , tp ) ;
talloc_free ( req ) ;
talloc_free ( tp ) ;
}
/*
Reply to an SMBtrans2
*/
2004-06-28 12:39:00 +04:00
void reply_trans2 ( struct smbsrv_request * req )
2003-12-11 12:07:45 +03:00
{
reply_trans_generic ( req , SMBtrans2 ) ;
}
2004-12-16 15:31:34 +03:00
/*
Reply to an SMBtrans
*/
2004-06-28 12:39:00 +04:00
void reply_trans ( struct smbsrv_request * req )
2003-12-11 12:07:45 +03:00
{
reply_trans_generic ( req , SMBtrans ) ;
}
2004-12-16 15:31:34 +03:00
/*
Reply to an SMBtranss request
*/
void reply_transs ( struct smbsrv_request * req )
2003-12-11 12:07:45 +03:00
{
2004-12-16 15:31:34 +03:00
reply_transs_generic ( req , SMBtrans ) ;
2003-12-11 12:07:45 +03:00
}
2004-12-16 15:31:34 +03:00
/*
Reply to an SMBtranss2 request
*/
void reply_transs2 ( struct smbsrv_request * req )
{
reply_transs_generic ( req , SMBtrans2 ) ;
}
2003-12-11 12:07:45 +03:00