2005-01-12 10:03:29 +03:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Andrew Tridgell 2005
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 .
*/
/*
a composite API for loading a whole file into memory
*/
# include "includes.h"
# include "libcli/raw/libcliraw.h"
# include "libcli/composite/composite.h"
# include "librpc/gen_ndr/ndr_security.h"
/* the stages of this call */
enum loadfile_stage { LOADFILE_OPEN , LOADFILE_READ , LOADFILE_CLOSE } ;
static void loadfile_handler ( struct smbcli_request * req ) ;
2005-01-17 00:58:28 +03:00
struct loadfile_state {
2005-01-22 05:51:39 +03:00
enum loadfile_stage stage ;
2005-01-17 00:58:28 +03:00
struct smb_composite_loadfile * io ;
2005-01-17 01:22:13 +03:00
struct smbcli_request * req ;
2005-01-17 00:58:28 +03:00
union smb_open * io_open ;
union smb_read * io_read ;
} ;
2005-01-12 10:03:29 +03:00
/*
setup for the close
*/
static NTSTATUS setup_close ( struct smbcli_composite * c ,
struct smbcli_tree * tree , uint16_t fnum )
{
2005-01-17 02:23:45 +03:00
struct loadfile_state * state = talloc_get_type ( c - > private , struct loadfile_state ) ;
2005-01-17 00:58:28 +03:00
union smb_close * io_close ;
2005-01-12 10:03:29 +03:00
/* nothing to read, setup the close */
io_close = talloc ( c , union smb_close ) ;
NT_STATUS_HAVE_NO_MEMORY ( io_close ) ;
io_close - > close . level = RAW_CLOSE_CLOSE ;
io_close - > close . in . fnum = fnum ;
io_close - > close . in . write_time = 0 ;
2005-01-17 01:22:13 +03:00
state - > req = smb_raw_close_send ( tree , io_close ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > req ) ;
2005-01-12 10:03:29 +03:00
/* call the handler again when the close is done */
2005-01-17 01:22:13 +03:00
state - > req - > async . fn = loadfile_handler ;
state - > req - > async . private = c ;
2005-01-22 05:51:39 +03:00
state - > stage = LOADFILE_CLOSE ;
2005-01-12 10:03:29 +03:00
return NT_STATUS_OK ;
}
/*
called when the open is done - pull the results and setup for the
first readx , or close if the file is zero size
*/
static NTSTATUS loadfile_open ( struct smbcli_composite * c ,
struct smb_composite_loadfile * io )
{
2005-01-17 02:23:45 +03:00
struct loadfile_state * state = talloc_get_type ( c - > private , struct loadfile_state ) ;
2005-01-17 01:22:13 +03:00
struct smbcli_tree * tree = state - > req - > tree ;
2005-01-12 10:03:29 +03:00
NTSTATUS status ;
2005-01-17 01:22:13 +03:00
status = smb_raw_open_recv ( state - > req , c , state - > io_open ) ;
2005-01-12 10:03:29 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
/* don't allow stupidly large loads */
2005-01-17 00:58:28 +03:00
if ( state - > io_open - > ntcreatex . out . size > 100 * 1000 * 1000 ) {
2005-01-12 10:03:29 +03:00
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
/* allocate space for the file data */
2005-01-17 00:58:28 +03:00
io - > out . size = state - > io_open - > ntcreatex . out . size ;
2005-01-12 10:03:29 +03:00
io - > out . data = talloc_array ( c , uint8_t , io - > out . size ) ;
NT_STATUS_HAVE_NO_MEMORY ( io - > out . data ) ;
if ( io - > out . size = = 0 ) {
2005-01-17 00:58:28 +03:00
return setup_close ( c , tree , state - > io_open - > ntcreatex . out . fnum ) ;
2005-01-12 10:03:29 +03:00
}
/* setup for the read */
2005-01-17 00:58:28 +03:00
state - > io_read = talloc ( c , union smb_read ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > io_read ) ;
2005-01-12 10:03:29 +03:00
2005-01-17 00:58:28 +03:00
state - > io_read - > readx . level = RAW_READ_READX ;
state - > io_read - > readx . in . fnum = state - > io_open - > ntcreatex . out . fnum ;
state - > io_read - > readx . in . offset = 0 ;
state - > io_read - > readx . in . mincnt = MIN ( 32768 , io - > out . size ) ;
state - > io_read - > readx . in . maxcnt = state - > io_read - > readx . in . mincnt ;
state - > io_read - > readx . in . remaining = 0 ;
state - > io_read - > readx . out . data = io - > out . data ;
2005-01-17 01:22:13 +03:00
state - > req = smb_raw_read_send ( tree , state - > io_read ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > req ) ;
2005-01-12 10:03:29 +03:00
/* call the handler again when the first read is done */
2005-01-17 01:22:13 +03:00
state - > req - > async . fn = loadfile_handler ;
state - > req - > async . private = c ;
2005-01-22 05:51:39 +03:00
state - > stage = LOADFILE_READ ;
2005-01-15 13:29:43 +03:00
2005-01-17 00:58:28 +03:00
talloc_free ( state - > io_open ) ;
2005-01-12 10:03:29 +03:00
return NT_STATUS_OK ;
}
/*
called when a read is done - pull the results and setup for the
next read , or close if the file is all done
*/
static NTSTATUS loadfile_read ( struct smbcli_composite * c ,
struct smb_composite_loadfile * io )
{
2005-01-17 02:23:45 +03:00
struct loadfile_state * state = talloc_get_type ( c - > private , struct loadfile_state ) ;
2005-01-17 01:22:13 +03:00
struct smbcli_tree * tree = state - > req - > tree ;
2005-01-12 10:03:29 +03:00
NTSTATUS status ;
2005-01-17 01:22:13 +03:00
status = smb_raw_read_recv ( state - > req , state - > io_read ) ;
2005-01-12 10:03:29 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
/* we might be done */
2005-01-17 00:58:28 +03:00
if ( state - > io_read - > readx . in . offset +
state - > io_read - > readx . out . nread = = io - > out . size ) {
return setup_close ( c , tree , state - > io_read - > readx . in . fnum ) ;
2005-01-12 10:03:29 +03:00
}
/* setup for the next read */
2005-01-17 00:58:28 +03:00
state - > io_read - > readx . in . offset + = state - > io_read - > readx . out . nread ;
state - > io_read - > readx . in . mincnt = MIN ( 32768 , io - > out . size - state - > io_read - > readx . in . offset ) ;
state - > io_read - > readx . out . data = io - > out . data + state - > io_read - > readx . in . offset ;
2005-01-12 10:03:29 +03:00
2005-01-17 01:22:13 +03:00
state - > req = smb_raw_read_send ( tree , state - > io_read ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > req ) ;
2005-01-12 10:03:29 +03:00
/* call the handler again when the read is done */
2005-01-17 01:22:13 +03:00
state - > req - > async . fn = loadfile_handler ;
state - > req - > async . private = c ;
2005-01-12 10:03:29 +03:00
return NT_STATUS_OK ;
}
/*
called when the close is done , check the status and cleanup
*/
static NTSTATUS loadfile_close ( struct smbcli_composite * c ,
struct smb_composite_loadfile * io )
{
2005-01-17 02:23:45 +03:00
struct loadfile_state * state = talloc_get_type ( c - > private , struct loadfile_state ) ;
2005-01-12 10:03:29 +03:00
NTSTATUS status ;
2005-01-17 01:22:13 +03:00
status = smbcli_request_simple_recv ( state - > req ) ;
2005-01-12 10:03:29 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
c - > state = SMBCLI_REQUEST_DONE ;
if ( c - > async . fn ) {
c - > async . fn ( c ) ;
}
return NT_STATUS_OK ;
}
/*
handler for completion of a sub - request in loadfile
*/
static void loadfile_handler ( struct smbcli_request * req )
{
struct smbcli_composite * c = req - > async . private ;
2005-01-17 02:23:45 +03:00
struct loadfile_state * state = talloc_get_type ( c - > private , struct loadfile_state ) ;
2005-01-12 10:03:29 +03:00
/* when this handler is called, the stage indicates what
call has just finished */
2005-01-22 05:51:39 +03:00
switch ( state - > stage ) {
2005-01-12 10:03:29 +03:00
case LOADFILE_OPEN :
2005-01-17 00:58:28 +03:00
c - > status = loadfile_open ( c , state - > io ) ;
2005-01-12 10:03:29 +03:00
break ;
case LOADFILE_READ :
2005-01-17 00:58:28 +03:00
c - > status = loadfile_read ( c , state - > io ) ;
2005-01-12 10:03:29 +03:00
break ;
case LOADFILE_CLOSE :
2005-01-17 00:58:28 +03:00
c - > status = loadfile_close ( c , state - > io ) ;
2005-01-12 10:03:29 +03:00
break ;
}
if ( ! NT_STATUS_IS_OK ( c - > status ) ) {
c - > state = SMBCLI_REQUEST_ERROR ;
if ( c - > async . fn ) {
c - > async . fn ( c ) ;
}
}
}
/*
composite loadfile call - does an openx followed by a number of readx calls ,
followed by a close
*/
struct smbcli_composite * smb_composite_loadfile_send ( struct smbcli_tree * tree ,
struct smb_composite_loadfile * io )
{
struct smbcli_composite * c ;
2005-01-17 00:58:28 +03:00
struct loadfile_state * state ;
2005-01-12 10:03:29 +03:00
c = talloc_zero ( tree , struct smbcli_composite ) ;
if ( c = = NULL ) goto failed ;
2005-01-17 00:58:28 +03:00
state = talloc ( c , struct loadfile_state ) ;
if ( state = = NULL ) goto failed ;
state - > io = io ;
c - > private = state ;
2005-01-12 10:03:29 +03:00
c - > state = SMBCLI_REQUEST_SEND ;
2005-01-15 13:29:43 +03:00
c - > event_ctx = tree - > session - > transport - > socket - > event . ctx ;
2005-01-12 10:03:29 +03:00
/* setup for the open */
2005-01-17 00:58:28 +03:00
state - > io_open = talloc_zero ( c , union smb_open ) ;
if ( state - > io_open = = NULL ) goto failed ;
2005-01-12 10:03:29 +03:00
2005-01-17 00:58:28 +03:00
state - > io_open - > ntcreatex . level = RAW_OPEN_NTCREATEX ;
state - > io_open - > ntcreatex . in . flags = NTCREATEX_FLAGS_EXTENDED ;
state - > io_open - > ntcreatex . in . access_mask = SEC_FILE_READ_DATA ;
state - > io_open - > ntcreatex . in . file_attr = FILE_ATTRIBUTE_NORMAL ;
state - > io_open - > ntcreatex . in . share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE ;
state - > io_open - > ntcreatex . in . open_disposition = NTCREATEX_DISP_OPEN ;
state - > io_open - > ntcreatex . in . impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS ;
state - > io_open - > ntcreatex . in . fname = io - > in . fname ;
2005-01-12 10:03:29 +03:00
/* send the open on its way */
2005-01-17 01:22:13 +03:00
state - > req = smb_raw_open_send ( tree , state - > io_open ) ;
if ( state - > req = = NULL ) goto failed ;
2005-01-12 10:03:29 +03:00
/* setup the callback handler */
2005-01-17 01:22:13 +03:00
state - > req - > async . fn = loadfile_handler ;
state - > req - > async . private = c ;
2005-01-22 05:51:39 +03:00
state - > stage = LOADFILE_OPEN ;
2005-01-12 10:03:29 +03:00
return c ;
failed :
talloc_free ( c ) ;
return NULL ;
}
/*
composite loadfile call - recv side
*/
NTSTATUS smb_composite_loadfile_recv ( struct smbcli_composite * c , TALLOC_CTX * mem_ctx )
{
NTSTATUS status ;
2005-01-12 14:43:18 +03:00
status = smb_composite_wait ( c ) ;
2005-01-12 10:03:29 +03:00
2005-01-12 14:43:18 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
2005-01-17 02:23:45 +03:00
struct loadfile_state * state = talloc_get_type ( c - > private , struct loadfile_state ) ;
2005-01-17 00:58:28 +03:00
talloc_steal ( mem_ctx , state - > io - > out . data ) ;
2005-01-12 10:03:29 +03:00
}
talloc_free ( c ) ;
return status ;
}
/*
composite loadfile call - sync interface
*/
NTSTATUS smb_composite_loadfile ( struct smbcli_tree * tree ,
TALLOC_CTX * mem_ctx ,
struct smb_composite_loadfile * io )
{
struct smbcli_composite * c = smb_composite_loadfile_send ( tree , io ) ;
return smb_composite_loadfile_recv ( c , mem_ctx ) ;
}