2009-05-15 13:50:20 +04:00
/*
Unix SMB / CIFS implementation .
Core SMB2 server
Copyright ( C ) Stefan Metzmacher 2009
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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-05-15 13:50:20 +04:00
# include "smbd/globals.h"
2009-08-12 19:52:55 +04:00
# include "../libcli/smb/smb_common.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2011-03-24 15:46:20 +03:00
# include "auth.h"
2011-06-29 09:33:54 +04:00
# include "lib/param/loadparm.h"
2009-05-15 13:50:20 +04:00
static NTSTATUS smbd_smb2_tree_connect ( struct smbd_smb2_request * req ,
2009-06-03 13:31:43 +04:00
const char * in_path ,
uint8_t * out_share_type ,
uint32_t * out_share_flags ,
uint32_t * out_capabilities ,
uint32_t * out_maximal_access ,
2009-05-15 13:50:20 +04:00
uint32_t * out_tree_id ) ;
NTSTATUS smbd_smb2_request_process_tcon ( struct smbd_smb2_request * req )
{
const uint8_t * inbody ;
int i = req - > current_idx ;
uint8_t * outhdr ;
DATA_BLOB outbody ;
uint16_t in_path_offset ;
uint16_t in_path_length ;
DATA_BLOB in_path_buffer ;
char * in_path_string ;
size_t in_path_string_size ;
2010-08-30 17:56:16 +04:00
uint8_t out_share_type = 0 ;
uint32_t out_share_flags = 0 ;
uint32_t out_capabilities = 0 ;
uint32_t out_maximal_access = 0 ;
uint32_t out_tree_id = 0 ;
2009-05-15 13:50:20 +04:00
NTSTATUS status ;
bool ok ;
2011-09-06 16:01:43 +04:00
status = smbd_smb2_request_verify_sizes ( req , 0x09 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
2009-05-15 13:50:20 +04:00
}
inbody = ( const uint8_t * ) req - > in . vector [ i + 1 ] . iov_base ;
in_path_offset = SVAL ( inbody , 0x04 ) ;
in_path_length = SVAL ( inbody , 0x06 ) ;
2011-09-06 16:01:43 +04:00
if ( in_path_offset ! = ( SMB2_HDR_BODY + req - > in . vector [ i + 1 ] . iov_len ) ) {
2009-05-15 13:50:20 +04:00
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
if ( in_path_length > req - > in . vector [ i + 2 ] . iov_len ) {
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
in_path_buffer . data = ( uint8_t * ) req - > in . vector [ i + 2 ] . iov_base ;
in_path_buffer . length = in_path_length ;
ok = convert_string_talloc ( req , CH_UTF16 , CH_UNIX ,
in_path_buffer . data ,
in_path_buffer . length ,
& in_path_string ,
2011-03-24 02:59:41 +03:00
& in_path_string_size ) ;
2009-05-15 13:50:20 +04:00
if ( ! ok ) {
return smbd_smb2_request_error ( req , NT_STATUS_ILLEGAL_CHARACTER ) ;
}
2011-09-06 16:14:52 +04:00
if ( in_path_buffer . length = = 0 ) {
in_path_string_size = 0 ;
}
if ( strlen ( in_path_string ) ! = in_path_string_size ) {
return smbd_smb2_request_error ( req , NT_STATUS_BAD_NETWORK_NAME ) ;
}
2009-06-03 13:31:43 +04:00
status = smbd_smb2_tree_connect ( req , in_path_string ,
& out_share_type ,
& out_share_flags ,
& out_capabilities ,
& out_maximal_access ,
& out_tree_id ) ;
2009-05-15 13:50:20 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
}
outhdr = ( uint8_t * ) req - > out . vector [ i ] . iov_base ;
outbody = data_blob_talloc ( req - > out . vector , NULL , 0x10 ) ;
if ( outbody . data = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
SIVAL ( outhdr , SMB2_HDR_TID , out_tree_id ) ;
SSVAL ( outbody . data , 0x00 , 0x10 ) ; /* struct size */
2009-06-03 13:31:43 +04:00
SCVAL ( outbody . data , 0x02 ,
out_share_type ) ; /* share type */
2009-05-15 13:50:20 +04:00
SCVAL ( outbody . data , 0x03 , 0 ) ; /* reserved */
2009-06-03 13:31:43 +04:00
SIVAL ( outbody . data , 0x04 ,
out_share_flags ) ; /* share flags */
SIVAL ( outbody . data , 0x08 ,
out_capabilities ) ; /* capabilities */
SIVAL ( outbody . data , 0x0C ,
out_maximal_access ) ; /* maximal access */
2009-05-15 13:50:20 +04:00
return smbd_smb2_request_done ( req , outbody , NULL ) ;
}
static int smbd_smb2_tcon_destructor ( struct smbd_smb2_tcon * tcon )
{
if ( tcon - > session = = NULL ) {
return 0 ;
}
idr_remove ( tcon - > session - > tcons . idtree , tcon - > tid ) ;
DLIST_REMOVE ( tcon - > session - > tcons . list , tcon ) ;
2010-10-20 00:25:51 +04:00
SMB_ASSERT ( tcon - > session - > sconn - > num_tcons_open > 0 ) ;
tcon - > session - > sconn - > num_tcons_open - - ;
2009-05-15 13:50:20 +04:00
2009-08-11 20:09:05 +04:00
if ( tcon - > compat_conn ) {
2010-05-07 17:54:16 +04:00
set_current_service ( tcon - > compat_conn , 0 , true ) ;
2010-05-07 11:33:59 +04:00
close_cnum ( tcon - > compat_conn , tcon - > session - > vuid ) ;
2009-08-11 20:09:05 +04:00
}
2009-05-27 20:40:42 +04:00
tcon - > compat_conn = NULL ;
2009-05-15 13:50:20 +04:00
tcon - > tid = 0 ;
tcon - > session = NULL ;
return 0 ;
}
static NTSTATUS smbd_smb2_tree_connect ( struct smbd_smb2_request * req ,
const char * in_path ,
2009-06-03 13:31:43 +04:00
uint8_t * out_share_type ,
uint32_t * out_share_flags ,
uint32_t * out_capabilities ,
uint32_t * out_maximal_access ,
2009-05-15 13:50:20 +04:00
uint32_t * out_tree_id )
{
const char * share = in_path ;
2010-11-10 02:07:49 +03:00
char * service = NULL ;
2009-05-15 13:50:20 +04:00
int snum = - 1 ;
struct smbd_smb2_tcon * tcon ;
2010-02-25 05:11:07 +03:00
connection_struct * compat_conn = NULL ;
2010-05-20 08:27:43 +04:00
user_struct * compat_vuser = req - > session - > compat_vuser ;
2009-05-15 13:50:20 +04:00
int id ;
2009-05-27 20:40:42 +04:00
NTSTATUS status ;
2009-05-15 13:50:20 +04:00
if ( strncmp ( share , " \\ \\ " , 2 ) = = 0 ) {
const char * p = strchr ( share + 2 , ' \\ ' ) ;
if ( p ) {
share = p + 1 ;
}
}
DEBUG ( 10 , ( " smbd_smb2_tree_connect: path[%s] share[%s] \n " ,
in_path , share ) ) ;
2010-11-10 02:07:49 +03:00
service = talloc_strdup ( talloc_tos ( ) , share ) ;
if ( ! service ) {
return NT_STATUS_NO_MEMORY ;
}
2009-05-15 13:50:20 +04:00
strlower_m ( service ) ;
2010-05-20 08:27:43 +04:00
/* TODO: do more things... */
if ( strequal ( service , HOMES_NAME ) ) {
if ( compat_vuser - > homes_snum = = - 1 ) {
DEBUG ( 2 , ( " [homes] share not available for "
" user %s because it was not found "
" or created at session setup "
" time \n " ,
2011-07-15 09:55:31 +04:00
compat_vuser - > session_info - > unix_info - > unix_name ) ) ;
2010-05-20 08:27:43 +04:00
return NT_STATUS_BAD_NETWORK_NAME ;
}
snum = compat_vuser - > homes_snum ;
} else if ( ( compat_vuser - > homes_snum ! = - 1 )
& & strequal ( service ,
lp_servicename ( compat_vuser - > homes_snum ) ) ) {
snum = compat_vuser - > homes_snum ;
} else {
2010-11-10 02:07:49 +03:00
snum = find_service ( talloc_tos ( ) , service , & service ) ;
if ( ! service ) {
return NT_STATUS_NO_MEMORY ;
}
2010-05-20 08:27:43 +04:00
}
2009-05-15 13:50:20 +04:00
if ( snum < 0 ) {
2009-12-02 22:06:37 +03:00
DEBUG ( 3 , ( " smbd_smb2_tree_connect: couldn't find service %s \n " ,
2009-05-15 13:50:20 +04:00
service ) ) ;
return NT_STATUS_BAD_NETWORK_NAME ;
}
/* create a new tcon as child of the session */
tcon = talloc_zero ( req - > session , struct smbd_smb2_tcon ) ;
if ( tcon = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
id = idr_get_new_random ( req - > session - > tcons . idtree ,
tcon ,
req - > session - > tcons . limit ) ;
if ( id = = - 1 ) {
2009-05-27 20:40:42 +04:00
TALLOC_FREE ( tcon ) ;
2009-05-15 13:50:20 +04:00
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
tcon - > tid = id ;
tcon - > snum = snum ;
DLIST_ADD_END ( req - > session - > tcons . list , tcon ,
struct smbd_smb2_tcon * ) ;
tcon - > session = req - > session ;
2010-10-20 00:25:51 +04:00
tcon - > session - > sconn - > num_tcons_open + + ;
2009-05-15 13:50:20 +04:00
talloc_set_destructor ( tcon , smbd_smb2_tcon_destructor ) ;
2010-02-25 05:11:07 +03:00
compat_conn = make_connection_snum ( req - > sconn ,
2009-05-27 20:40:42 +04:00
snum , req - > session - > compat_vuser ,
data_blob_null , " ??? " ,
& status ) ;
2010-02-25 05:11:07 +03:00
if ( compat_conn = = NULL ) {
2009-05-27 20:40:42 +04:00
TALLOC_FREE ( tcon ) ;
return status ;
}
2010-02-25 05:11:07 +03:00
tcon - > compat_conn = talloc_move ( tcon , & compat_conn ) ;
2009-05-27 20:40:42 +04:00
tcon - > compat_conn - > cnum = tcon - > tid ;
2010-04-27 08:36:01 +04:00
if ( IS_PRINT ( tcon - > compat_conn ) ) {
2010-05-22 03:56:10 +04:00
* out_share_type = SMB2_SHARE_TYPE_PRINT ;
2010-04-27 08:36:01 +04:00
} else if ( IS_IPC ( tcon - > compat_conn ) ) {
2010-05-22 03:56:10 +04:00
* out_share_type = SMB2_SHARE_TYPE_PIPE ;
2010-04-27 08:36:01 +04:00
} else {
2010-05-22 03:56:10 +04:00
* out_share_type = SMB2_SHARE_TYPE_DISK ;
2010-04-27 08:36:01 +04:00
}
2010-05-22 03:56:10 +04:00
2011-11-24 16:49:17 +04:00
* out_share_flags = 0 ;
2010-05-22 03:56:10 +04:00
if ( lp_msdfs_root ( SNUM ( tcon - > compat_conn ) ) & & lp_host_msdfs ( ) ) {
* out_share_flags | = ( SMB2_SHAREFLAG_DFS | SMB2_SHAREFLAG_DFS_ROOT ) ;
* out_capabilities = SMB2_SHARE_CAP_DFS ;
} else {
* out_capabilities = 0 ;
}
switch ( lp_csc_policy ( SNUM ( tcon - > compat_conn ) ) ) {
case CSC_POLICY_MANUAL :
break ;
case CSC_POLICY_DOCUMENTS :
* out_share_flags | = SMB2_SHAREFLAG_AUTO_CACHING ;
break ;
case CSC_POLICY_PROGRAMS :
* out_share_flags | = SMB2_SHAREFLAG_VDO_CACHING ;
break ;
case CSC_POLICY_DISABLE :
* out_share_flags | = SMB2_SHAREFLAG_NO_CACHING ;
break ;
default :
break ;
}
2011-07-10 15:02:11 +04:00
* out_maximal_access = tcon - > compat_conn - > share_access ;
2009-06-03 13:31:43 +04:00
2009-05-15 13:50:20 +04:00
* out_tree_id = tcon - > tid ;
return NT_STATUS_OK ;
}
2009-05-22 14:42:24 +04:00
NTSTATUS smbd_smb2_request_process_tdis ( struct smbd_smb2_request * req )
{
2011-09-06 16:01:43 +04:00
NTSTATUS status ;
2009-05-22 14:42:24 +04:00
DATA_BLOB outbody ;
2011-09-06 16:01:43 +04:00
status = smbd_smb2_request_verify_sizes ( req , 0x04 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return smbd_smb2_request_error ( req , status ) ;
2009-05-22 14:42:24 +04:00
}
/*
* TODO : cancel all outstanding requests on the tcon
* and delete all file handles .
*/
TALLOC_FREE ( req - > tcon ) ;
outbody = data_blob_talloc ( req - > out . vector , NULL , 0x04 ) ;
if ( outbody . data = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
SSVAL ( outbody . data , 0x00 , 0x04 ) ; /* struct size */
SSVAL ( outbody . data , 0x02 , 0 ) ; /* reserved */
return smbd_smb2_request_done ( req , outbody , NULL ) ;
}