2006-06-20 11:05:51 +04:00
/*
Unix SMB2 implementation .
Copyright ( C ) Stefan Metzmacher 2006
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-06-20 11:05:51 +04:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-06-20 11:05:51 +04:00
*/
# include "includes.h"
# include "libcli/smb2/smb2.h"
# include "libcli/smb2/smb2_calls.h"
# include "smb_server/smb_server.h"
# include "smb_server/service_smb_proto.h"
# include "smb_server/smb2/smb2_server.h"
# include "ntvfs/ntvfs.h"
2006-06-22 21:35:04 +04:00
# include "librpc/gen_ndr/ndr_security.h"
struct smb2srv_getinfo_op {
struct smb2srv_request * req ;
struct smb2_getinfo * info ;
void * io_ptr ;
NTSTATUS ( * send_fn ) ( struct smb2srv_getinfo_op * op ) ;
} ;
2006-06-20 11:05:51 +04:00
static void smb2srv_getinfo_send ( struct ntvfs_request * ntvfs )
{
2006-06-22 21:35:04 +04:00
struct smb2srv_getinfo_op * op ;
2006-06-20 11:05:51 +04:00
struct smb2srv_request * req ;
2006-06-22 21:35:04 +04:00
/*
* SMB2 uses NT_STATUS_INVALID_INFO_CLASS
* so we need to translated it here
*/
if ( NT_STATUS_EQUAL ( NT_STATUS_INVALID_LEVEL , ntvfs - > async_states - > status ) ) {
ntvfs - > async_states - > status = NT_STATUS_INVALID_INFO_CLASS ;
}
SMB2SRV_CHECK_ASYNC_STATUS ( op , struct smb2srv_getinfo_op ) ;
ZERO_STRUCT ( op - > info - > out ) ;
if ( op - > send_fn ) {
SMB2SRV_CHECK ( op - > send_fn ( op ) ) ;
}
2007-10-07 02:10:49 +04:00
SMB2SRV_CHECK ( smb2srv_setup_reply ( req , 0x08 , true , op - > info - > out . blob . length ) ) ;
2006-06-20 11:05:51 +04:00
2008-05-30 01:28:53 +04:00
SMB2SRV_CHECK ( smb2_push_o16s32_blob ( & req - > out , 0x02 , op - > info - > out . blob ) ) ;
2006-06-20 11:05:51 +04:00
SSVAL ( req - > out . body , 0x06 , 0 ) ;
smb2srv_send_reply ( req ) ;
}
2006-06-22 21:35:04 +04:00
static NTSTATUS smb2srv_getinfo_file_send ( struct smb2srv_getinfo_op * op )
{
union smb_fileinfo * io = talloc_get_type ( op - > io_ptr , union smb_fileinfo ) ;
NTSTATUS status ;
status = smbsrv_push_passthru_fileinfo ( op - > req ,
& op - > info - > out . blob ,
io - > generic . level , io ,
STR_UNICODE ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
return NT_STATUS_OK ;
}
static NTSTATUS smb2srv_getinfo_file ( struct smb2srv_getinfo_op * op , uint8_t smb2_level )
{
union smb_fileinfo * io ;
2008-02-14 09:11:36 +03:00
uint16_t level ;
2006-06-22 21:35:04 +04:00
io = talloc ( op , union smb_fileinfo ) ;
NT_STATUS_HAVE_NO_MEMORY ( io ) ;
2008-02-14 09:11:36 +03:00
level = op - > info - > in . info_type | ( op - > info - > in . info_class < < 8 ) ;
switch ( level ) {
2006-06-22 21:35:04 +04:00
case RAW_FILEINFO_SMB2_ALL_EAS :
2008-02-14 09:11:36 +03:00
io - > all_eas . level = level ;
2006-06-22 21:35:04 +04:00
io - > all_eas . in . file . ntvfs = op - > info - > in . file . ntvfs ;
2008-02-14 09:11:36 +03:00
io - > all_eas . in . continue_flags = op - > info - > in . getinfo_flags ;
2006-06-22 21:35:04 +04:00
break ;
case RAW_FILEINFO_SMB2_ALL_INFORMATION :
2008-02-14 09:11:36 +03:00
io - > all_info2 . level = level ;
2006-06-22 21:35:04 +04:00
io - > all_info2 . in . file . ntvfs = op - > info - > in . file . ntvfs ;
break ;
default :
/* the rest directly maps to the passthru levels */
io - > generic . level = smb2_level + 1000 ;
io - > generic . in . file . ntvfs = op - > info - > in . file . ntvfs ;
break ;
}
op - > io_ptr = io ;
op - > send_fn = smb2srv_getinfo_file_send ;
return ntvfs_qfileinfo ( op - > req - > ntvfs , io ) ;
}
static NTSTATUS smb2srv_getinfo_fs_send ( struct smb2srv_getinfo_op * op )
{
union smb_fsinfo * io = talloc_get_type ( op - > io_ptr , union smb_fsinfo ) ;
NTSTATUS status ;
status = smbsrv_push_passthru_fsinfo ( op - > req ,
& op - > info - > out . blob ,
io - > generic . level , io ,
STR_UNICODE ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
return NT_STATUS_OK ;
}
static NTSTATUS smb2srv_getinfo_fs ( struct smb2srv_getinfo_op * op , uint8_t smb2_level )
2006-06-20 11:05:51 +04:00
{
2006-06-22 21:35:04 +04:00
union smb_fsinfo * io ;
io = talloc ( op , union smb_fsinfo ) ;
NT_STATUS_HAVE_NO_MEMORY ( io ) ;
/* the rest directly maps to the passthru levels */
io - > generic . level = smb2_level + 1000 ;
/* TODO: allow qfsinfo only the share root directory handle */
op - > io_ptr = io ;
op - > send_fn = smb2srv_getinfo_fs_send ;
return ntvfs_fsinfo ( op - > req - > ntvfs , io ) ;
}
static NTSTATUS smb2srv_getinfo_security_send ( struct smb2srv_getinfo_op * op )
{
union smb_fileinfo * io = talloc_get_type ( op - > io_ptr , union smb_fileinfo ) ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2006-06-22 21:35:04 +04:00
2008-01-02 07:05:05 +03:00
ndr_err = ndr_push_struct_blob ( & op - > info - > out . blob , op - > req , NULL ,
2007-11-09 21:24:51 +03:00
io - > query_secdesc . out . sd ,
( ndr_push_flags_fn_t ) ndr_push_security_descriptor ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
2006-06-22 21:35:04 +04:00
return NT_STATUS_OK ;
}
static NTSTATUS smb2srv_getinfo_security ( struct smb2srv_getinfo_op * op , uint8_t smb2_level )
{
union smb_fileinfo * io ;
switch ( smb2_level ) {
case 0x00 :
io = talloc ( op , union smb_fileinfo ) ;
NT_STATUS_HAVE_NO_MEMORY ( io ) ;
io - > query_secdesc . level = RAW_FILEINFO_SEC_DESC ;
io - > query_secdesc . in . file . ntvfs = op - > info - > in . file . ntvfs ;
2008-02-14 09:11:36 +03:00
io - > query_secdesc . in . secinfo_flags = op - > info - > in . additional_information ;
2006-06-22 21:35:04 +04:00
op - > io_ptr = io ;
op - > send_fn = smb2srv_getinfo_security_send ;
return ntvfs_qfileinfo ( op - > req - > ntvfs , io ) ;
}
2006-06-29 15:17:37 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2006-06-22 21:35:04 +04:00
}
static NTSTATUS smb2srv_getinfo_backend ( struct smb2srv_getinfo_op * op )
{
2008-02-14 09:11:36 +03:00
switch ( op - > info - > in . info_type ) {
2006-06-22 21:35:04 +04:00
case SMB2_GETINFO_FILE :
2008-02-14 09:11:36 +03:00
return smb2srv_getinfo_file ( op , op - > info - > in . info_class ) ;
2006-06-22 21:35:04 +04:00
case SMB2_GETINFO_FS :
2008-02-14 09:11:36 +03:00
return smb2srv_getinfo_fs ( op , op - > info - > in . info_class ) ;
2006-06-22 21:35:04 +04:00
case SMB2_GETINFO_SECURITY :
2008-02-14 09:11:36 +03:00
return smb2srv_getinfo_security ( op , op - > info - > in . info_class ) ;
2006-06-29 15:17:37 +04:00
2008-02-14 09:11:36 +03:00
case SMB2_GETINFO_QUOTA :
2006-06-29 15:17:37 +04:00
return NT_STATUS_NOT_SUPPORTED ;
2006-06-22 21:35:04 +04:00
}
2006-06-29 15:17:37 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2006-06-20 11:05:51 +04:00
}
void smb2srv_getinfo_recv ( struct smb2srv_request * req )
{
struct smb2_getinfo * info ;
2006-06-22 21:35:04 +04:00
struct smb2srv_getinfo_op * op ;
2006-06-20 11:05:51 +04:00
2007-10-07 02:10:49 +04:00
SMB2SRV_CHECK_BODY_SIZE ( req , 0x28 , true ) ;
2006-06-20 11:05:51 +04:00
SMB2SRV_TALLOC_IO_PTR ( info , struct smb2_getinfo ) ;
2006-06-22 21:35:04 +04:00
/* this overwrites req->io_ptr !*/
SMB2SRV_TALLOC_IO_PTR ( op , struct smb2srv_getinfo_op ) ;
op - > req = req ;
op - > info = info ;
op - > io_ptr = NULL ;
op - > send_fn = NULL ;
2006-06-20 11:05:51 +04:00
SMB2SRV_SETUP_NTVFS_REQUEST ( smb2srv_getinfo_send , NTVFS_ASYNC_STATE_MAY_ASYNC ) ;
2008-02-14 09:11:36 +03:00
info - > in . info_type = CVAL ( req - > in . body , 0x02 ) ;
info - > in . info_class = CVAL ( req - > in . body , 0x03 ) ;
info - > in . output_buffer_length = IVAL ( req - > in . body , 0x04 ) ;
info - > in . reserved = IVAL ( req - > in . body , 0x0C ) ;
info - > in . additional_information = IVAL ( req - > in . body , 0x10 ) ;
info - > in . getinfo_flags = IVAL ( req - > in . body , 0x14 ) ;
2006-06-20 11:05:51 +04:00
info - > in . file . ntvfs = smb2srv_pull_handle ( req , req - > in . body , 0x18 ) ;
2008-02-14 09:11:36 +03:00
SMB2SRV_CHECK ( smb2_pull_o16As32_blob ( & req - > in , op ,
req - > in . body + 0x08 , & info - > in . blob ) ) ;
2006-06-20 11:05:51 +04:00
SMB2SRV_CHECK_FILE_HANDLE ( info - > in . file . ntvfs ) ;
2006-06-22 21:35:04 +04:00
SMB2SRV_CALL_NTVFS_BACKEND ( smb2srv_getinfo_backend ( op ) ) ;
2006-06-20 11:05:51 +04:00
}
2006-06-27 21:46:57 +04:00
struct smb2srv_setinfo_op {
struct smb2srv_request * req ;
struct smb2_setinfo * info ;
} ;
static void smb2srv_setinfo_send ( struct ntvfs_request * ntvfs )
{
struct smb2srv_setinfo_op * op ;
struct smb2srv_request * req ;
/*
* SMB2 uses NT_STATUS_INVALID_INFO_CLASS
* so we need to translated it here
*/
if ( NT_STATUS_EQUAL ( NT_STATUS_INVALID_LEVEL , ntvfs - > async_states - > status ) ) {
ntvfs - > async_states - > status = NT_STATUS_INVALID_INFO_CLASS ;
}
SMB2SRV_CHECK_ASYNC_STATUS ( op , struct smb2srv_setinfo_op ) ;
2007-10-07 02:10:49 +04:00
SMB2SRV_CHECK ( smb2srv_setup_reply ( req , 0x02 , false , 0 ) ) ;
2006-06-27 21:46:57 +04:00
smb2srv_send_reply ( req ) ;
}
2006-06-29 10:53:44 +04:00
static NTSTATUS smb2srv_setinfo_file ( struct smb2srv_setinfo_op * op , uint8_t smb2_level )
{
2006-07-01 18:12:13 +04:00
union smb_setfileinfo * io ;
NTSTATUS status ;
io = talloc ( op , union smb_setfileinfo ) ;
NT_STATUS_HAVE_NO_MEMORY ( io ) ;
/* the levels directly map to the passthru levels */
io - > generic . level = smb2_level + 1000 ;
io - > generic . in . file . ntvfs = op - > info - > in . file . ntvfs ;
2008-02-14 06:54:21 +03:00
/* handle cases that don't map directly */
if ( io - > generic . level = = RAW_SFILEINFO_RENAME_INFORMATION ) {
io - > generic . level = RAW_SFILEINFO_RENAME_INFORMATION_SMB2 ;
}
2006-07-01 18:12:13 +04:00
status = smbsrv_pull_passthru_sfileinfo ( io , io - > generic . level , io ,
& op - > info - > in . blob ,
2008-02-14 02:12:33 +03:00
STR_UNICODE , & op - > req - > in . bufinfo ) ;
2006-07-01 18:12:13 +04:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
return ntvfs_setfileinfo ( op - > req - > ntvfs , io ) ;
2006-06-29 10:53:44 +04:00
}
static NTSTATUS smb2srv_setinfo_fs ( struct smb2srv_setinfo_op * op , uint8_t smb2_level )
{
2006-06-29 15:17:37 +04:00
switch ( smb2_level ) {
case 0x02 :
return NT_STATUS_NOT_IMPLEMENTED ;
case 0x06 :
return NT_STATUS_ACCESS_DENIED ;
case 0x08 :
return NT_STATUS_ACCESS_DENIED ;
case 0x0A :
return NT_STATUS_ACCESS_DENIED ;
}
return NT_STATUS_INVALID_INFO_CLASS ;
2006-06-29 10:53:44 +04:00
}
static NTSTATUS smb2srv_setinfo_security ( struct smb2srv_setinfo_op * op , uint8_t smb2_level )
{
union smb_setfileinfo * io ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2006-06-29 10:53:44 +04:00
switch ( smb2_level ) {
case 0x00 :
io = talloc ( op , union smb_setfileinfo ) ;
NT_STATUS_HAVE_NO_MEMORY ( io ) ;
io - > set_secdesc . level = RAW_SFILEINFO_SEC_DESC ;
io - > set_secdesc . in . file . ntvfs = op - > info - > in . file . ntvfs ;
io - > set_secdesc . in . secinfo_flags = op - > info - > in . flags ;
io - > set_secdesc . in . sd = talloc ( io , struct security_descriptor ) ;
NT_STATUS_HAVE_NO_MEMORY ( io - > set_secdesc . in . sd ) ;
2008-01-02 07:05:13 +03:00
ndr_err = ndr_pull_struct_blob ( & op - > info - > in . blob , io , NULL ,
2007-11-09 21:24:51 +03:00
io - > set_secdesc . in . sd ,
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
return ndr_map_error2ntstatus ( ndr_err ) ;
}
2006-06-29 10:53:44 +04:00
return ntvfs_setfileinfo ( op - > req - > ntvfs , io ) ;
}
return NT_STATUS_INVALID_INFO_CLASS ;
}
2006-06-27 21:46:57 +04:00
static NTSTATUS smb2srv_setinfo_backend ( struct smb2srv_setinfo_op * op )
{
uint8_t smb2_class ;
2006-06-29 10:53:44 +04:00
uint8_t smb2_level ;
2006-06-27 21:46:57 +04:00
smb2_class = 0xFF & op - > info - > in . level ;
2006-06-29 10:53:44 +04:00
smb2_level = 0xFF & ( op - > info - > in . level > > 8 ) ;
2006-06-27 21:46:57 +04:00
switch ( smb2_class ) {
case SMB2_GETINFO_FILE :
2006-06-29 10:53:44 +04:00
return smb2srv_setinfo_file ( op , smb2_level ) ;
2006-06-27 21:46:57 +04:00
case SMB2_GETINFO_FS :
2006-06-29 10:53:44 +04:00
return smb2srv_setinfo_fs ( op , smb2_level ) ;
2006-06-27 21:46:57 +04:00
case SMB2_GETINFO_SECURITY :
2006-06-29 10:53:44 +04:00
return smb2srv_setinfo_security ( op , smb2_level ) ;
2006-06-29 15:17:37 +04:00
case 0x04 :
return NT_STATUS_NOT_SUPPORTED ;
2006-06-27 21:46:57 +04:00
}
2006-06-29 15:17:37 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2006-06-27 21:46:57 +04:00
}
2006-06-20 11:05:51 +04:00
void smb2srv_setinfo_recv ( struct smb2srv_request * req )
{
2006-06-27 21:46:57 +04:00
struct smb2_setinfo * info ;
struct smb2srv_setinfo_op * op ;
2007-10-07 02:10:49 +04:00
SMB2SRV_CHECK_BODY_SIZE ( req , 0x20 , true ) ;
2006-06-27 21:46:57 +04:00
SMB2SRV_TALLOC_IO_PTR ( info , struct smb2_setinfo ) ;
/* this overwrites req->io_ptr !*/
SMB2SRV_TALLOC_IO_PTR ( op , struct smb2srv_setinfo_op ) ;
op - > req = req ;
op - > info = info ;
SMB2SRV_SETUP_NTVFS_REQUEST ( smb2srv_setinfo_send , NTVFS_ASYNC_STATE_MAY_ASYNC ) ;
info - > in . level = SVAL ( req - > in . body , 0x02 ) ;
SMB2SRV_CHECK ( smb2_pull_s32o32_blob ( & req - > in , info , req - > in . body + 0x04 , & info - > in . blob ) ) ;
info - > in . flags = IVAL ( req - > in . body , 0x0C ) ;
info - > in . file . ntvfs = smb2srv_pull_handle ( req , req - > in . body , 0x10 ) ;
SMB2SRV_CHECK_FILE_HANDLE ( info - > in . file . ntvfs ) ;
SMB2SRV_CALL_NTVFS_BACKEND ( smb2srv_setinfo_backend ( op ) ) ;
2006-06-20 11:05:51 +04:00
}