2003-12-04 14:01:58 +03:00
/*
Unix SMB / CIFS implementation .
SMBsearch 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"
2003-12-04 14:01:58 +03:00
/* check req->async.status and if not OK then send an error reply */
# define CHECK_ASYNC_STATUS do { \
2004-10-29 01:48:53 +04:00
if ( ! NT_STATUS_IS_OK ( req - > async_states - > status ) ) { \
req_reply_error ( req , req - > async_states - > status ) ; \
2003-12-04 14:01:58 +03:00
return ; \
} } while ( 0 )
/*
check if the backend wants to handle the request asynchronously .
if it wants it handled synchronously then call the send function
immediately
*/
# define REQ_ASYNC_TAIL do { \
2004-10-29 01:48:53 +04:00
if ( ! ( req - > async_states - > state & NTVFS_ASYNC_STATE_ASYNC ) ) { \
req - > async_states - > send_fn ( req ) ; \
2003-12-04 14:01:58 +03:00
} } while ( 0 )
/* useful wrapper for talloc with NO_MEMORY reply */
2004-09-21 12:46:47 +04:00
# define REQ_TALLOC(ptr) do { \
ptr = talloc ( req , sizeof ( * ( ptr ) ) ) ; \
2003-12-04 14:01:58 +03:00
if ( ! ptr ) { \
req_reply_error ( req , NT_STATUS_NO_MEMORY ) ; \
return ; \
} } while ( 0 )
# define CHECK_MIN_BLOB_SIZE(blob, size) do { \
if ( ( blob ) - > length < ( size ) ) { \
return NT_STATUS_INFO_LENGTH_MISMATCH ; \
} } while ( 0 )
/* a structure to encapsulate the state information about
* an in - progress search first / next operation */
struct search_state {
2004-06-28 12:39:00 +04:00
struct smbsrv_request * req ;
2003-12-04 14:01:58 +03:00
union smb_search_data * file ;
2004-05-25 21:24:24 +04:00
uint16_t last_entry_offset ;
2003-12-04 14:01:58 +03:00
} ;
/*
fill a single entry in a search find reply
*/
2004-10-29 10:01:51 +04:00
static BOOL find_fill_info ( struct smbsrv_request * req ,
2003-12-04 14:01:58 +03:00
union smb_search_data * file )
{
2004-09-21 12:46:47 +04:00
char * p ;
2004-10-29 10:01:51 +04:00
if ( req - > out . data_size + 43 > req_max_data ( req ) ) {
return False ;
}
2003-12-04 14:01:58 +03:00
2004-09-21 12:46:47 +04:00
req_grow_data ( req , req - > out . data_size + 43 ) ;
p = req - > out . data + req - > out . data_size - 43 ;
SCVAL ( p , 0 , file - > search . id . reserved ) ;
memcpy ( p + 1 , file - > search . id . name , 11 ) ;
SCVAL ( p , 12 , file - > search . id . handle ) ;
SIVAL ( p , 13 , file - > search . id . server_cookie ) ;
SIVAL ( p , 17 , file - > search . id . client_cookie ) ;
SCVAL ( p , 21 , file - > search . attrib ) ;
srv_push_dos_date ( req - > smb_conn , p , 22 , file - > search . write_time ) ;
SIVAL ( p , 26 , file - > search . size ) ;
2004-09-22 16:38:19 +04:00
memset ( p + 30 , ' ' , 12 ) ;
memcpy ( p + 30 , file - > search . name , MIN ( strlen ( file - > search . name ) + 1 , 12 ) ) ;
SCVAL ( p , 42 , 0 ) ;
2004-10-29 10:01:51 +04:00
return True ;
2003-12-04 14:01:58 +03:00
}
/* callback function for search first/next */
static BOOL find_callback ( void * private , union smb_search_data * file )
{
struct search_state * state = ( struct search_state * ) private ;
2004-10-29 10:01:51 +04:00
return find_fill_info ( state - > req , file ) ;
2003-12-04 14:01:58 +03:00
}
/****************************************************************************
Reply to a search .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-28 12:39:00 +04:00
void reply_search ( struct smbsrv_request * req )
2003-12-04 14:01:58 +03:00
{
union smb_search_first * sf ;
union smb_search_next * sn ;
2004-05-25 21:24:24 +04:00
uint16_t resume_key_length ;
2003-12-04 14:01:58 +03:00
struct search_state state ;
char * p ;
2004-09-21 12:46:47 +04:00
NTSTATUS status ;
enum smb_search_level level = RAW_SEARCH_SEARCH ;
uint8_t op = CVAL ( req - > in . hdr , HDR_COM ) ;
if ( op = = SMBffirst ) {
level = RAW_SEARCH_FFIRST ;
} else if ( op = = SMBfunique ) {
level = RAW_SEARCH_FUNIQUE ;
}
2003-12-04 14:01:58 +03:00
2004-09-21 12:46:47 +04:00
REQ_TALLOC ( sf ) ;
2003-12-04 14:01:58 +03:00
/* parse request */
if ( req - > in . wct ! = 2 ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
p = req - > in . data ;
p + = req_pull_ascii4 ( req , & sf - > search_first . in . pattern ,
2004-09-21 12:46:47 +04:00
p , STR_TERMINATE ) ;
2003-12-04 14:01:58 +03:00
if ( ! sf - > search_first . in . pattern ) {
req_reply_error ( req , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
return ;
}
2004-09-21 12:46:47 +04:00
if ( req_data_oob ( req , p , 3 ) ) {
2003-12-04 14:01:58 +03:00
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
2004-09-21 12:46:47 +04:00
return ;
}
if ( * p ! = 5 ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
resume_key_length = SVAL ( p , 1 ) ;
2003-12-04 14:01:58 +03:00
p + = 3 ;
/* setup state for callback */
state . req = req ;
state . file = NULL ;
state . last_entry_offset = 0 ;
/* construct reply */
req_setup_reply ( req , 1 , 0 ) ;
req_append_var_block ( req , NULL , 0 ) ;
2004-09-21 12:46:47 +04:00
if ( resume_key_length ! = 0 ) {
if ( resume_key_length ! = 21 | |
req_data_oob ( req , p , 21 ) | |
level = = RAW_SEARCH_FUNIQUE ) {
2003-12-04 14:01:58 +03:00
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
2004-09-21 12:46:47 +04:00
return ;
}
/* do a search next operation */
REQ_TALLOC ( sn ) ;
sn - > search_next . in . id . reserved = CVAL ( p , 0 ) ;
memcpy ( sn - > search_next . in . id . name , p + 1 , 11 ) ;
sn - > search_next . in . id . handle = CVAL ( p , 12 ) ;
sn - > search_next . in . id . server_cookie = IVAL ( p , 13 ) ;
sn - > search_next . in . id . client_cookie = IVAL ( p , 17 ) ;
sn - > search_next . level = level ;
2003-12-04 14:01:58 +03:00
sn - > search_next . in . max_count = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
2004-09-21 12:46:47 +04:00
sn - > search_next . in . search_attrib = SVAL ( req - > in . vwv , VWV ( 1 ) ) ;
2003-12-04 14:01:58 +03:00
/* call backend */
2004-09-29 17:17:09 +04:00
status = ntvfs_search_next ( req , sn , & state , find_callback ) ;
2003-12-04 14:01:58 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , sn - > search_next . out . count ) ;
} else {
/* do a search first operation */
2004-09-21 12:46:47 +04:00
sf - > search_first . level = level ;
2003-12-04 14:01:58 +03:00
sf - > search_first . in . search_attrib = SVAL ( req - > in . vwv , VWV ( 1 ) ) ;
sf - > search_first . in . max_count = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
/* call backend */
2004-09-29 17:17:09 +04:00
status = ntvfs_search_first ( req , sf , & state , find_callback ) ;
2003-12-04 14:01:58 +03:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , sf - > search_first . out . count ) ;
}
2004-09-21 12:46:47 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
req_reply_error ( req , status ) ;
return ;
}
2003-12-04 14:01:58 +03:00
req_send_reply ( req ) ;
}
/****************************************************************************
Reply to a fclose ( async reply )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-28 12:39:00 +04:00
static void reply_fclose_send ( struct smbsrv_request * req )
2003-12-04 14:01:58 +03:00
{
CHECK_ASYNC_STATUS ;
/* construct reply */
req_setup_reply ( req , 1 , 0 ) ;
2004-09-21 12:46:47 +04:00
SSVAL ( req - > out . vwv , VWV ( 0 ) , 0 ) ;
2003-12-04 14:01:58 +03:00
req_send_reply ( req ) ;
}
/****************************************************************************
Reply to fclose ( stop directory search ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-28 12:39:00 +04:00
void reply_fclose ( struct smbsrv_request * req )
2003-12-04 14:01:58 +03:00
{
2004-09-21 12:46:47 +04:00
union smb_search_close * sc ;
2004-05-25 21:24:24 +04:00
uint16_t resume_key_length ;
2004-09-21 12:46:47 +04:00
char * p ;
const char * pattern ;
2003-12-04 14:01:58 +03:00
2004-09-21 12:46:47 +04:00
REQ_TALLOC ( sc ) ;
2003-12-04 14:01:58 +03:00
/* parse request */
if ( req - > in . wct ! = 2 ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
2004-09-21 12:46:47 +04:00
p = req - > in . data ;
p + = req_pull_ascii4 ( req , & pattern , p , STR_TERMINATE ) ;
if ( pattern & & * pattern ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
2003-12-04 14:01:58 +03:00
2004-09-21 12:46:47 +04:00
if ( req_data_oob ( req , p , 3 ) ) {
2003-12-04 14:01:58 +03:00
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
2004-09-21 12:46:47 +04:00
return ;
}
if ( * p ! = 5 ) {
2003-12-04 14:01:58 +03:00
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
2004-09-21 12:46:47 +04:00
return ;
}
resume_key_length = SVAL ( p , 1 ) ;
p + = 3 ;
if ( resume_key_length ! = 21 ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
if ( req_data_oob ( req , p , 21 ) ) {
req_reply_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
sc - > fclose . level = RAW_FINDCLOSE_FCLOSE ;
sc - > fclose . in . max_count = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
sc - > fclose . in . search_attrib = SVAL ( req - > in . vwv , VWV ( 1 ) ) ;
sc - > fclose . in . id . reserved = CVAL ( p , 0 ) ;
memcpy ( sc - > fclose . in . id . name , p + 1 , 11 ) ;
sc - > fclose . in . id . handle = CVAL ( p , 12 ) ;
sc - > fclose . in . id . server_cookie = IVAL ( p , 13 ) ;
sc - > fclose . in . id . client_cookie = IVAL ( p , 17 ) ;
2003-12-04 14:01:58 +03:00
2004-09-21 12:46:47 +04:00
/* do a search close operation */
2004-10-29 01:48:53 +04:00
req - > async_states - > state | = NTVFS_ASYNC_STATE_MAY_ASYNC ;
req - > async_states - > send_fn = reply_fclose_send ;
req - > async_states - > private_data = sc ;
2003-12-04 14:01:58 +03:00
/* call backend */
2004-10-29 01:48:53 +04:00
req - > async_states - > status = ntvfs_search_close ( req , sc ) ;
2003-12-04 14:01:58 +03:00
REQ_ASYNC_TAIL ;
}