2003-12-04 14:01:58 +03:00
/*
Unix SMB / CIFS implementation .
NT transaction handling
Copyright ( C ) Andrew Tridgell 2003
Copyright ( C ) James J Myers 2003 < myersjj @ samba . org >
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-11-02 10:18:24 +03:00
# include "smb_server/smb_server.h"
2005-12-28 01:51:30 +03:00
# include "ntvfs/ntvfs.h"
2005-12-28 18:38:36 +03:00
# include "libcli/raw/libcliraw.h"
2006-03-16 03:23:11 +03:00
# include "librpc/gen_ndr/ndr_security.h"
2004-11-02 10:18:24 +03:00
2006-03-08 06:54:24 +03:00
/*
hold the state of a nttrans op while in progress . Needed to allow for async backend
functions .
*/
struct nttrans_op {
struct smb_nttrans * trans ;
NTSTATUS ( * send_fn ) ( struct nttrans_op * ) ;
void * op_info ;
} ;
2003-12-04 14:01:58 +03:00
/* setup a nttrans reply, given the data and params sizes */
2006-03-08 08:47:51 +03:00
static NTSTATUS nttrans_setup_reply ( struct nttrans_op * op ,
struct smb_nttrans * trans ,
uint16_t param_size , uint16_t data_size ,
uint16_t setup_count )
2003-12-04 14:01:58 +03:00
{
trans - > out . setup_count = setup_count ;
if ( setup_count ! = 0 ) {
2006-03-08 08:47:51 +03:00
trans - > out . setup = talloc_zero_array ( op , uint16_t , setup_count ) ;
NT_STATUS_HAVE_NO_MEMORY ( trans - > out . setup ) ;
2003-12-04 14:01:58 +03:00
}
2006-03-08 08:47:51 +03:00
trans - > out . params = data_blob_talloc ( op , NULL , param_size ) ;
if ( param_size ! = 0 ) {
NT_STATUS_HAVE_NO_MEMORY ( trans - > out . params . data ) ;
}
trans - > out . data = data_blob_talloc ( op , NULL , data_size ) ;
if ( data_size ! = 0 ) {
NT_STATUS_HAVE_NO_MEMORY ( trans - > out . data . data ) ;
}
return NT_STATUS_OK ;
2003-12-04 14:01:58 +03:00
}
2006-03-08 06:54:24 +03:00
/*
send a nttrans create reply
*/
static NTSTATUS nttrans_create_send ( struct nttrans_op * op )
{
union smb_open * io = talloc_get_type ( op - > op_info , union smb_open ) ;
uint8_t * params ;
op - > trans - > out . setup_count = 0 ;
op - > trans - > out . setup = NULL ;
op - > trans - > out . params = data_blob_talloc ( op , NULL , 69 ) ;
op - > trans - > out . data = data_blob ( NULL , 0 ) ;
params = op - > trans - > out . params . data ;
NT_STATUS_HAVE_NO_MEMORY ( params ) ;
SSVAL ( params , 0 , io - > ntcreatex . out . oplock_level ) ;
2006-03-13 01:48:25 +03:00
SSVAL ( params , 2 , io - > ntcreatex . out . file . fnum ) ;
2006-03-08 06:54:24 +03:00
SIVAL ( params , 4 , io - > ntcreatex . out . create_action ) ;
SIVAL ( params , 8 , 0 ) ; /* ea error offset */
push_nttime ( params , 12 , io - > ntcreatex . out . create_time ) ;
push_nttime ( params , 20 , io - > ntcreatex . out . access_time ) ;
push_nttime ( params , 28 , io - > ntcreatex . out . write_time ) ;
push_nttime ( params , 36 , io - > ntcreatex . out . change_time ) ;
SIVAL ( params , 44 , io - > ntcreatex . out . attrib ) ;
SBVAL ( params , 48 , io - > ntcreatex . out . alloc_size ) ;
SBVAL ( params , 56 , io - > ntcreatex . out . size ) ;
SSVAL ( params , 64 , io - > ntcreatex . out . file_type ) ;
SSVAL ( params , 66 , io - > ntcreatex . out . ipc_state ) ;
SCVAL ( params , 68 , io - > ntcreatex . out . is_directory ) ;
return NT_STATUS_OK ;
}
2003-12-04 14:01:58 +03:00
2004-11-18 05:06:11 +03:00
/*
parse NTTRANS_CREATE request
2003-12-04 14:01:58 +03:00
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS nttrans_create ( struct smbsrv_request * req ,
2006-03-08 06:54:24 +03:00
struct nttrans_op * op )
2003-12-04 14:01:58 +03:00
{
2006-03-08 06:54:24 +03:00
struct smb_nttrans * trans = op - > trans ;
2004-11-17 15:36:14 +03:00
union smb_open * io ;
uint16_t fname_len ;
uint32_t sd_length , ea_length ;
NTSTATUS status ;
uint8_t * params ;
if ( trans - > in . params . length < 54 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/* parse the request */
2006-03-08 06:54:24 +03:00
io = talloc ( op , union smb_open ) ;
NT_STATUS_HAVE_NO_MEMORY ( io ) ;
2004-11-17 15:36:14 +03:00
io - > ntcreatex . level = RAW_OPEN_NTTRANS_CREATE ;
params = trans - > in . params . data ;
io - > ntcreatex . in . flags = IVAL ( params , 0 ) ;
io - > ntcreatex . in . root_fid = IVAL ( params , 4 ) ;
io - > ntcreatex . in . access_mask = IVAL ( params , 8 ) ;
io - > ntcreatex . in . alloc_size = BVAL ( params , 12 ) ;
io - > ntcreatex . in . file_attr = IVAL ( params , 20 ) ;
io - > ntcreatex . in . share_access = IVAL ( params , 24 ) ;
io - > ntcreatex . in . open_disposition = IVAL ( params , 28 ) ;
io - > ntcreatex . in . create_options = IVAL ( params , 32 ) ;
sd_length = IVAL ( params , 36 ) ;
ea_length = IVAL ( params , 40 ) ;
fname_len = IVAL ( params , 44 ) ;
io - > ntcreatex . in . impersonation = IVAL ( params , 48 ) ;
io - > ntcreatex . in . security_flags = CVAL ( params , 52 ) ;
io - > ntcreatex . in . sec_desc = NULL ;
io - > ntcreatex . in . ea_list = NULL ;
req_pull_string ( req , & io - > ntcreatex . in . fname ,
2006-03-10 14:49:38 +03:00
params + 53 ,
MIN ( fname_len + 1 , trans - > in . params . length - 53 ) ,
2004-11-17 15:36:14 +03:00
STR_NO_RANGE_CHECK | STR_TERMINATE ) ;
if ( ! io - > ntcreatex . in . fname ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( sd_length > trans - > in . data . length | |
ea_length > trans - > in . data . length | |
( sd_length + ea_length ) > trans - > in . data . length ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/* this call has an optional security descriptor */
if ( sd_length ! = 0 ) {
DATA_BLOB blob ;
blob . data = trans - > in . data . data ;
blob . length = sd_length ;
2005-01-27 10:08:20 +03:00
io - > ntcreatex . in . sec_desc = talloc ( io , struct security_descriptor ) ;
2004-11-17 15:36:14 +03:00
if ( io - > ntcreatex . in . sec_desc = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = ndr_pull_struct_blob ( & blob , io ,
io - > ntcreatex . in . sec_desc ,
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
}
/* and an optional ea_list */
if ( ea_length > 4 ) {
DATA_BLOB blob ;
blob . data = trans - > in . data . data + sd_length ;
blob . length = ea_length ;
2005-01-27 10:08:20 +03:00
io - > ntcreatex . in . ea_list = talloc ( io , struct smb_ea_list ) ;
2004-11-17 15:36:14 +03:00
if ( io - > ntcreatex . in . ea_list = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2004-11-18 01:00:15 +03:00
status = ea_pull_list_chained ( & blob , io ,
& io - > ntcreatex . in . ea_list - > num_eas ,
& io - > ntcreatex . in . ea_list - > eas ) ;
2004-11-17 15:36:14 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
}
2006-03-08 06:54:24 +03:00
op - > send_fn = nttrans_create_send ;
op - > op_info = io ;
2006-03-18 14:10:21 +03:00
return ntvfs_open ( req - > ntvfs , io ) ;
2006-03-08 06:54:24 +03:00
}
/*
send NTTRANS_QUERY_SEC_DESC reply
*/
static NTSTATUS nttrans_query_sec_desc_send ( struct nttrans_op * op )
{
struct smb_nttrans * trans = op - > trans ;
union smb_fileinfo * io = talloc_get_type ( op - > op_info , union smb_fileinfo ) ;
NTSTATUS status ;
2004-11-17 15:36:14 +03:00
trans - > out . setup_count = 0 ;
trans - > out . setup = NULL ;
2006-03-08 06:54:24 +03:00
trans - > out . params = data_blob_talloc ( op , NULL , 4 ) ;
2004-11-17 15:36:14 +03:00
trans - > out . data = data_blob ( NULL , 0 ) ;
2006-03-08 06:54:24 +03:00
NT_STATUS_HAVE_NO_MEMORY ( trans - > out . params . data ) ;
2004-11-17 15:36:14 +03:00
2006-03-08 06:54:24 +03:00
status = ndr_push_struct_blob ( & trans - > out . data , op ,
io - > query_secdesc . out . sd ,
( ndr_push_flags_fn_t ) ndr_push_security_descriptor ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-11-17 15:36:14 +03:00
2006-03-08 06:54:24 +03:00
SIVAL ( trans - > out . params . data , 0 , trans - > out . data . length ) ;
2004-11-17 15:36:14 +03:00
return NT_STATUS_OK ;
2003-12-04 14:01:58 +03:00
}
2004-11-18 05:06:11 +03:00
/*
parse NTTRANS_QUERY_SEC_DESC request
*/
static NTSTATUS nttrans_query_sec_desc ( struct smbsrv_request * req ,
2006-03-08 06:54:24 +03:00
struct nttrans_op * op )
2004-11-18 05:06:11 +03:00
{
2006-03-08 06:54:24 +03:00
struct smb_nttrans * trans = op - > trans ;
2004-11-18 05:06:11 +03:00
union smb_fileinfo * io ;
if ( trans - > in . params . length < 8 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/* parse the request */
2006-03-08 06:54:24 +03:00
io = talloc ( op , union smb_fileinfo ) ;
NT_STATUS_HAVE_NO_MEMORY ( io ) ;
2004-11-18 05:06:11 +03:00
io - > query_secdesc . level = RAW_FILEINFO_SEC_DESC ;
2006-03-13 01:48:25 +03:00
io - > query_secdesc . in . file . fnum = SVAL ( trans - > in . params . data , 0 ) ;
2006-03-10 23:49:20 +03:00
io - > query_secdesc . in . secinfo_flags = IVAL ( trans - > in . params . data , 4 ) ;
2004-11-18 05:06:11 +03:00
2006-03-08 06:54:24 +03:00
op - > op_info = io ;
op - > send_fn = nttrans_query_sec_desc_send ;
2004-11-18 05:06:11 +03:00
2006-03-18 14:10:21 +03:00
return ntvfs_qfileinfo ( req - > ntvfs , io ) ;
2004-11-18 05:06:11 +03:00
}
/*
parse NTTRANS_SET_SEC_DESC request
*/
static NTSTATUS nttrans_set_sec_desc ( struct smbsrv_request * req ,
2006-03-08 06:54:24 +03:00
struct nttrans_op * op )
2004-11-18 05:06:11 +03:00
{
2006-03-08 06:54:24 +03:00
struct smb_nttrans * trans = op - > trans ;
2004-11-18 05:06:11 +03:00
union smb_setfileinfo * io ;
NTSTATUS status ;
if ( trans - > in . params . length < 8 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/* parse the request */
2005-01-27 10:08:20 +03:00
io = talloc ( req , union smb_setfileinfo ) ;
2006-03-08 06:54:24 +03:00
NT_STATUS_HAVE_NO_MEMORY ( io ) ;
2004-11-18 05:06:11 +03:00
io - > set_secdesc . level = RAW_SFILEINFO_SEC_DESC ;
2006-03-13 01:48:25 +03:00
io - > set_secdesc . in . file . fnum = SVAL ( trans - > in . params . data , 0 ) ;
2004-11-18 05:06:11 +03:00
io - > set_secdesc . in . secinfo_flags = IVAL ( trans - > in . params . data , 4 ) ;
2005-01-27 10:08:20 +03:00
io - > set_secdesc . in . sd = talloc ( io , struct security_descriptor ) ;
2006-03-08 06:54:24 +03:00
NT_STATUS_HAVE_NO_MEMORY ( io - > set_secdesc . in . sd ) ;
2004-11-18 05:06:11 +03:00
status = ndr_pull_struct_blob ( & trans - > in . data , req ,
io - > set_secdesc . in . sd ,
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ;
2006-03-08 06:54:24 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-11-18 05:06:11 +03:00
trans - > out . setup_count = 0 ;
trans - > out . setup = NULL ;
trans - > out . params = data_blob ( NULL , 0 ) ;
trans - > out . data = data_blob ( NULL , 0 ) ;
2006-03-18 14:10:21 +03:00
return ntvfs_setfileinfo ( req - > ntvfs , io ) ;
2004-11-18 05:06:11 +03:00
}
2003-12-04 14:01:58 +03:00
/* parse NTTRANS_RENAME request
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS nttrans_rename ( struct smbsrv_request * req ,
2006-03-08 06:54:24 +03:00
struct nttrans_op * op )
2003-12-04 14:01:58 +03:00
{
2006-03-08 06:54:24 +03:00
return NT_STATUS_NOT_IMPLEMENTED ;
2003-12-04 14:01:58 +03:00
}
2004-11-17 15:36:14 +03:00
/*
parse NTTRANS_IOCTL request
2003-12-04 14:01:58 +03:00
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS nttrans_ioctl ( struct smbsrv_request * req ,
2006-03-08 06:54:24 +03:00
struct nttrans_op * op )
2003-12-04 14:01:58 +03:00
{
2006-03-08 06:54:24 +03:00
struct smb_nttrans * trans = op - > trans ;
union smb_ioctl * nt ;
2004-05-25 20:24:13 +04:00
uint32_t function ;
2004-05-25 21:24:24 +04:00
uint16_t fnum ;
2004-05-25 21:50:17 +04:00
uint8_t filter ;
2003-12-04 14:01:58 +03:00
BOOL fsctl ;
DATA_BLOB * blob ;
2006-03-08 08:47:51 +03:00
NTSTATUS status ;
2003-12-04 14:01:58 +03:00
/* should have at least 4 setup words */
if ( trans - > in . setup_count ! = 4 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2006-03-08 06:54:24 +03:00
nt = talloc ( op , union smb_ioctl ) ;
NT_STATUS_HAVE_NO_MEMORY ( nt ) ;
2003-12-04 14:01:58 +03:00
function = IVAL ( trans - > in . setup , 0 ) ;
fnum = SVAL ( trans - > in . setup , 4 ) ;
fsctl = CVAL ( trans - > in . setup , 6 ) ;
filter = CVAL ( trans - > in . setup , 7 ) ;
blob = & trans - > in . data ;
2006-03-08 06:54:24 +03:00
nt - > ntioctl . level = RAW_IOCTL_NTIOCTL ;
2006-03-13 01:48:25 +03:00
nt - > ntioctl . in . file . fnum = fnum ;
2006-03-08 06:54:24 +03:00
nt - > ntioctl . in . function = function ;
nt - > ntioctl . in . fsctl = fsctl ;
nt - > ntioctl . in . filter = filter ;
2003-12-04 14:01:58 +03:00
2006-03-08 08:47:51 +03:00
status = nttrans_setup_reply ( op , trans , 0 , 0 , 1 ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2003-12-04 14:01:58 +03:00
trans - > out . setup [ 0 ] = 0 ;
2006-03-18 14:10:21 +03:00
return ntvfs_ioctl ( req - > ntvfs , nt ) ;
2006-03-08 06:54:24 +03:00
}
/*
send NTTRANS_NOTIFY_CHANGE reply
*/
static NTSTATUS nttrans_notify_change_send ( struct nttrans_op * op )
{
2006-03-18 12:07:47 +03:00
struct smb_notify * info = talloc_get_type ( op - > op_info , struct smb_notify ) ;
2006-03-08 08:47:51 +03:00
size_t size = 0 ;
int i ;
NTSTATUS status ;
uint8_t * p ;
# define MAX_BYTES_PER_CHAR 3
/* work out how big the reply buffer could be */
2006-03-18 12:07:47 +03:00
for ( i = 0 ; i < info - > out . num_changes ; i + + ) {
size + = 12 + 3 + ( 1 + strlen ( info - > out . changes [ i ] . name . s ) ) * MAX_BYTES_PER_CHAR ;
2006-03-08 08:47:51 +03:00
}
status = nttrans_setup_reply ( op , op - > trans , size , 0 , 0 ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
p = op - > trans - > out . params . data ;
/* construct the changes buffer */
2006-03-18 12:07:47 +03:00
for ( i = 0 ; i < info - > out . num_changes ; i + + ) {
2006-03-30 12:44:28 +04:00
uint32_t ofs ;
2006-03-08 08:47:51 +03:00
ssize_t len ;
2006-03-18 12:07:47 +03:00
SIVAL ( p , 4 , info - > out . changes [ i ] . action ) ;
len = push_string ( p + 12 , info - > out . changes [ i ] . name . s ,
2006-03-30 12:44:28 +04:00
op - > trans - > out . params . length -
( p + 12 - op - > trans - > out . params . data ) , STR_UNICODE ) ;
2006-03-08 08:47:51 +03:00
SIVAL ( p , 8 , len ) ;
2006-03-30 12:44:28 +04:00
ofs = len + 12 ;
2006-03-08 08:47:51 +03:00
if ( ofs & 3 ) {
int pad = 4 - ( ofs & 3 ) ;
memset ( p + ofs , 0 , pad ) ;
ofs + = pad ;
}
2006-03-30 12:44:28 +04:00
if ( i = = info - > out . num_changes - 1 ) {
SIVAL ( p , 0 , 0 ) ;
} else {
SIVAL ( p , 0 , ofs ) ;
}
2006-03-08 08:47:51 +03:00
2006-03-30 12:44:28 +04:00
p + = ofs ;
2006-03-08 08:47:51 +03:00
}
2006-03-30 12:44:28 +04:00
op - > trans - > out . params . length = p - op - > trans - > out . params . data ;
2006-03-08 08:47:51 +03:00
return NT_STATUS_OK ;
2006-03-08 06:54:24 +03:00
}
/*
parse NTTRANS_NOTIFY_CHANGE request
*/
static NTSTATUS nttrans_notify_change ( struct smbsrv_request * req ,
struct nttrans_op * op )
{
struct smb_nttrans * trans = op - > trans ;
2006-03-18 12:07:47 +03:00
struct smb_notify * info ;
2006-03-08 06:54:24 +03:00
/* should have at least 4 setup words */
if ( trans - > in . setup_count ! = 4 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2006-03-18 12:07:47 +03:00
info = talloc ( op , struct smb_notify ) ;
2006-03-08 06:54:24 +03:00
NT_STATUS_HAVE_NO_MEMORY ( info ) ;
2006-03-18 12:07:47 +03:00
info - > in . completion_filter = IVAL ( trans - > in . setup , 0 ) ;
info - > in . file . fnum = SVAL ( trans - > in . setup , 4 ) ;
info - > in . recursive = SVAL ( trans - > in . setup , 6 ) ;
info - > in . buffer_size = trans - > in . max_param ;
2006-03-08 06:54:24 +03:00
op - > op_info = info ;
op - > send_fn = nttrans_notify_change_send ;
2006-03-18 14:10:21 +03:00
return ntvfs_notify ( req - > ntvfs , info ) ;
2003-12-04 14:01:58 +03:00
}
/*
backend for nttrans requests
*/
2004-06-28 12:39:00 +04:00
static NTSTATUS nttrans_backend ( struct smbsrv_request * req ,
2006-03-08 06:54:24 +03:00
struct nttrans_op * op )
2003-12-04 14:01:58 +03:00
{
/* the nttrans command is in function */
2006-03-08 06:54:24 +03:00
switch ( op - > trans - > in . function ) {
2003-12-04 14:01:58 +03:00
case NT_TRANSACT_CREATE :
2006-03-08 06:54:24 +03:00
return nttrans_create ( req , op ) ;
2003-12-04 14:01:58 +03:00
case NT_TRANSACT_IOCTL :
2006-03-08 06:54:24 +03:00
return nttrans_ioctl ( req , op ) ;
2003-12-04 14:01:58 +03:00
case NT_TRANSACT_RENAME :
2006-03-08 06:54:24 +03:00
return nttrans_rename ( req , op ) ;
2004-11-18 05:06:11 +03:00
case NT_TRANSACT_QUERY_SECURITY_DESC :
2006-03-08 06:54:24 +03:00
return nttrans_query_sec_desc ( req , op ) ;
2004-11-18 05:06:11 +03:00
case NT_TRANSACT_SET_SECURITY_DESC :
2006-03-08 06:54:24 +03:00
return nttrans_set_sec_desc ( req , op ) ;
case NT_TRANSACT_NOTIFY_CHANGE :
return nttrans_notify_change ( req , op ) ;
2003-12-04 14:01:58 +03:00
}
/* an unknown nttrans command */
2006-03-08 06:54:24 +03:00
return NT_STATUS_DOS ( ERRSRV , ERRerror ) ;
2003-12-04 14:01:58 +03:00
}
2006-03-18 14:10:21 +03:00
static void reply_nttrans_send ( struct ntvfs_request * ntvfs )
2003-12-04 14:01:58 +03:00
{
2006-03-18 14:10:21 +03:00
struct smbsrv_request * req ;
2004-05-25 21:24:24 +04:00
uint16_t params_left , data_left ;
2004-11-25 23:01:47 +03:00
uint8_t * params , * data ;
2006-03-08 06:54:24 +03:00
struct smb_nttrans * trans ;
struct nttrans_op * op ;
2003-12-04 14:01:58 +03:00
2006-03-18 14:10:21 +03:00
SMBSRV_CHECK_ASYNC_STATUS ( op , struct nttrans_op ) ;
2003-12-04 14:01:58 +03:00
2006-03-08 06:54:24 +03:00
trans = op - > trans ;
2003-12-04 14:01:58 +03:00
2006-03-08 06:54:24 +03:00
/* if this function needs work to form the nttrans reply buffer, then
call that now */
if ( op - > send_fn ! = NULL ) {
NTSTATUS status ;
status = op - > send_fn ( op ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
smbsrv_send_error ( req , status ) ;
return ;
}
2003-12-04 14:01:58 +03:00
}
2006-03-22 14:49:24 +03:00
smbsrv_setup_reply ( req , 18 + trans - > out . setup_count , 0 ) ;
2006-03-08 06:54:24 +03:00
/* note that we don't check the max_setup count (matching w2k3
behaviour ) */
2003-12-04 14:01:58 +03:00
2006-03-08 06:54:24 +03:00
if ( trans - > out . params . length > trans - > in . max_param ) {
smbsrv_setup_error ( req , NT_STATUS_BUFFER_TOO_SMALL ) ;
trans - > out . params . length = trans - > in . max_param ;
2004-11-18 07:19:26 +03:00
}
2006-03-08 06:54:24 +03:00
if ( trans - > out . data . length > trans - > in . max_data ) {
smbsrv_setup_error ( req , NT_STATUS_BUFFER_TOO_SMALL ) ;
trans - > out . data . length = trans - > in . max_data ;
2004-11-18 07:19:26 +03:00
}
2003-12-04 14:01:58 +03:00
2006-03-08 06:54:24 +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
2003-12-04 14:01:58 +03: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-12-04 14:01:58 +03:00
uint_t align1 = 1 , align2 = ( params_left ? 2 : 0 ) ;
2004-10-29 07:48:49 +04:00
struct smbsrv_request * this_req ;
2006-03-08 06:54:24 +03:00
int i ;
2003-12-04 14:01:58 +03: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 ) {
2006-03-06 19:19:27 +03:00
this_req = smbsrv_setup_secondary_request ( req ) ;
2004-10-29 07:48:49 +04:00
} else {
this_req = req ;
}
2003-12-04 14:01:58 +03:00
req_grow_data ( req , this_param + this_data + ( align1 + align2 ) ) ;
2004-10-29 07:48:49 +04:00
SSVAL ( this_req - > out . vwv , 0 , 0 ) ; /* reserved */
SCVAL ( this_req - > out . vwv , 2 , 0 ) ; /* reserved */
2006-03-08 06:54:24 +03:00
SIVAL ( this_req - > out . vwv , 3 , trans - > out . params . length ) ;
SIVAL ( this_req - > out . vwv , 7 , trans - > out . data . length ) ;
2003-12-04 14:01:58 +03:00
2004-10-29 07:48:49 +04:00
SIVAL ( this_req - > out . vwv , 11 , this_param ) ;
SIVAL ( this_req - > out . vwv , 15 , align1 + PTR_DIFF ( this_req - > out . data , this_req - > out . hdr ) ) ;
2006-03-08 06:54:24 +03:00
SIVAL ( this_req - > out . vwv , 19 , PTR_DIFF ( params , trans - > out . params . data ) ) ;
2003-12-04 14:01:58 +03:00
2004-10-29 07:48:49 +04:00
SIVAL ( this_req - > out . vwv , 23 , this_data ) ;
SIVAL ( this_req - > out . vwv , 27 , align1 + align2 +
PTR_DIFF ( this_req - > out . data + this_param , this_req - > out . hdr ) ) ;
2006-03-08 06:54:24 +03:00
SIVAL ( this_req - > out . vwv , 31 , PTR_DIFF ( data , trans - > out . data . data ) ) ;
2003-12-04 14:01:58 +03:00
2006-03-08 06:54:24 +03:00
SCVAL ( this_req - > out . vwv , 35 , trans - > out . setup_count ) ;
for ( i = 0 ; i < trans - > out . setup_count ; i + + ) {
SSVAL ( this_req - > out . vwv , VWV ( 18 + i ) , trans - > out . setup [ i ] ) ;
2003-12-04 14:01:58 +03:00
}
2004-10-29 07:48:49 +04:00
memset ( this_req - > out . data , 0 , align1 ) ;
2003-12-04 14:01:58 +03:00
if ( this_param ! = 0 ) {
2004-10-29 07:48:49 +04:00
memcpy ( this_req - > out . data + align1 , params , this_param ) ;
2003-12-04 14:01:58 +03:00
}
2004-10-29 07:48:49 +04:00
memset ( this_req - > out . data + this_param + align1 , 0 , align2 ) ;
2003-12-04 14:01:58 +03: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-12-04 14:01:58 +03:00
}
params_left - = this_param ;
data_left - = this_data ;
params + = this_param ;
data + = this_data ;
2006-03-06 19:19:27 +03:00
smbsrv_send_reply ( this_req ) ;
2003-12-04 14:01:58 +03:00
} while ( params_left ! = 0 | | data_left ! = 0 ) ;
}
2006-03-08 06:54:24 +03:00
/****************************************************************************
Reply to an SMBnttrans request
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void smbsrv_reply_nttrans ( struct smbsrv_request * req )
{
struct nttrans_op * op ;
struct smb_nttrans * trans ;
int i ;
uint16_t param_ofs , data_ofs ;
uint16_t param_count , data_count ;
uint16_t param_total , data_total ;
/* parse request */
if ( req - > in . wct < 19 ) {
smbsrv_send_error ( req , NT_STATUS_FOOBAR ) ;
return ;
}
2006-03-18 14:10:21 +03:00
SMBSRV_TALLOC_IO_PTR ( op , struct nttrans_op ) ;
SMBSRV_SETUP_NTVFS_REQUEST ( reply_nttrans_send , NTVFS_ASYNC_STATE_MAY_ASYNC ) ;
2006-03-08 06:54:24 +03:00
trans = talloc ( op , struct smb_nttrans ) ;
if ( trans = = NULL ) {
smbsrv_send_error ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
op - > trans = trans ;
op - > op_info = NULL ;
op - > send_fn = NULL ;
trans - > in . max_setup = CVAL ( req - > in . vwv , 0 ) ;
param_total = IVAL ( req - > in . vwv , 3 ) ;
data_total = IVAL ( req - > in . vwv , 7 ) ;
trans - > in . max_param = IVAL ( req - > in . vwv , 11 ) ;
trans - > in . max_data = IVAL ( req - > in . vwv , 15 ) ;
param_count = IVAL ( req - > in . vwv , 19 ) ;
param_ofs = IVAL ( req - > in . vwv , 23 ) ;
data_count = IVAL ( req - > in . vwv , 27 ) ;
data_ofs = IVAL ( req - > in . vwv , 31 ) ;
trans - > in . setup_count = CVAL ( req - > in . vwv , 35 ) ;
trans - > in . function = SVAL ( req - > in . vwv , 36 ) ;
if ( req - > in . wct ! = 19 + trans - > in . setup_count ) {
smbsrv_send_error ( req , NT_STATUS_DOS ( ERRSRV , ERRerror ) ) ;
return ;
}
/* parse out the setup words */
trans - > in . setup = talloc_array ( req , uint16_t , trans - > in . setup_count ) ;
if ( ! trans - > in . setup ) {
smbsrv_send_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 ( 19 + i ) ) ;
}
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 ) ) {
smbsrv_send_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 ) {
DEBUG ( 0 , ( " REWRITE: not handling partial nttrans requests! \n " ) ) ;
return ;
}
2006-03-18 14:10:21 +03:00
SMBSRV_CALL_NTVFS_BACKEND ( nttrans_backend ( req , op ) ) ;
2006-03-08 06:54:24 +03:00
}
2003-12-04 14:01:58 +03:00
/****************************************************************************
Reply to an SMBnttranss request
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-03-06 18:31:01 +03:00
void smbsrv_reply_nttranss ( struct smbsrv_request * req )
2003-12-04 14:01:58 +03:00
{
2006-03-06 19:19:27 +03:00
smbsrv_send_error ( req , NT_STATUS_FOOBAR ) ;
2003-12-04 14:01:58 +03:00
}