2009-05-14 17:32:02 +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"
# include "smbd/globals.h"
# include "../source4/libcli/smb2/smb2_constants.h"
extern enum protocol_types Protocol ;
2009-05-19 12:47:51 +04:00
/*
* this is the entry point if SMB2 is selected via
* the SMB negprot
*/
void reply_smb2002 ( struct smb_request * req , uint16_t choice )
{
uint8_t * smb2_inbuf ;
uint8_t * smb2_hdr ;
uint8_t * smb2_body ;
uint8_t * smb2_dyn ;
size_t len = 4 + SMB2_HDR_BODY + 0x24 + 2 ;
smb2_inbuf = talloc_zero_array ( talloc_tos ( ) , uint8_t , len ) ;
if ( smb2_inbuf = = NULL ) {
DEBUG ( 0 , ( " Could not push spnego blob \n " ) ) ;
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
smb2_hdr = smb2_inbuf + 4 ;
smb2_body = smb2_hdr + SMB2_HDR_BODY ;
smb2_dyn = smb2_body + 0x24 ;
SIVAL ( smb2_hdr , SMB2_HDR_PROTOCOL_ID , SMB2_MAGIC ) ;
SIVAL ( smb2_hdr , SMB2_HDR_LENGTH , SMB2_HDR_BODY ) ;
SSVAL ( smb2_body , 0x00 , 0x0024 ) ; /* struct size */
SSVAL ( smb2_body , 0x02 , 0x0001 ) ; /* dialect count */
SSVAL ( smb2_dyn , 0x00 , 0x0202 ) ; /* dialect 2.002 */
req - > outbuf = NULL ;
smbd_smb2_first_negprot ( smbd_server_conn , smb2_inbuf , len ) ;
return ;
}
2009-05-14 17:32:02 +04:00
NTSTATUS smbd_smb2_request_process_negprot ( struct smbd_smb2_request * req )
{
const uint8_t * inbody ;
const uint8_t * indyn = NULL ;
int i = req - > current_idx ;
DATA_BLOB outbody ;
DATA_BLOB outdyn ;
DATA_BLOB negprot_spnego_blob ;
uint16_t security_offset ;
DATA_BLOB security_buffer ;
size_t expected_body_size = 0x24 ;
size_t body_size ;
size_t expected_dyn_size = 0 ;
size_t c ;
2009-05-22 23:26:03 +04:00
uint16_t security_mode ;
2009-05-14 17:32:02 +04:00
uint16_t dialect_count ;
uint16_t dialect ;
2009-05-22 23:26:03 +04:00
uint32_t capabilities ;
2009-05-14 17:32:02 +04:00
/* TODO: drop the connection with INVALI_PARAMETER */
if ( req - > in . vector [ i + 1 ] . iov_len ! = ( expected_body_size & 0xFFFFFFFE ) ) {
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
inbody = ( const uint8_t * ) req - > in . vector [ i + 1 ] . iov_base ;
body_size = SVAL ( inbody , 0x00 ) ;
if ( body_size ! = expected_body_size ) {
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
dialect_count = SVAL ( inbody , 0x02 ) ;
if ( dialect_count = = 0 ) {
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
expected_dyn_size = dialect_count * 2 ;
if ( req - > in . vector [ i + 2 ] . iov_len < expected_dyn_size ) {
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
indyn = ( const uint8_t * ) req - > in . vector [ i + 2 ] . iov_base ;
for ( c = 0 ; c < dialect_count ; c + + ) {
dialect = SVAL ( indyn , c * 2 ) ;
2009-05-22 23:26:03 +04:00
if ( dialect = = SMB2_DIALECT_REVISION_202 ) {
2009-05-14 17:32:02 +04:00
break ;
}
}
2009-05-22 23:26:03 +04:00
if ( dialect ! = SMB2_DIALECT_REVISION_202 ) {
2009-05-14 17:32:02 +04:00
return smbd_smb2_request_error ( req , NT_STATUS_INVALID_PARAMETER ) ;
}
Protocol = PROTOCOL_SMB2 ;
if ( get_remote_arch ( ) ! = RA_SAMBA ) {
set_remote_arch ( RA_VISTA ) ;
}
/* negprot_spnego() returns a the server guid in the first 16 bytes */
negprot_spnego_blob = negprot_spnego ( ) ;
if ( negprot_spnego_blob . data = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
talloc_steal ( req , negprot_spnego_blob . data ) ;
if ( negprot_spnego_blob . length < 16 ) {
return smbd_smb2_request_error ( req , NT_STATUS_INTERNAL_ERROR ) ;
}
2009-05-22 23:26:03 +04:00
security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED ;
if ( lp_server_signing ( ) = = Required ) {
security_mode | = SMB2_NEGOTIATE_SIGNING_REQUIRED ;
}
capabilities = 0 ;
if ( lp_host_msdfs ( ) ) {
capabilities | = SMB2_CAP_DFS ;
}
2009-05-14 17:32:02 +04:00
security_offset = SMB2_HDR_BODY + 0x40 ;
2009-06-04 22:14:20 +04:00
# if 1
/* Try SPNEGO auth... */
2009-05-14 17:32:02 +04:00
security_buffer = data_blob_const ( negprot_spnego_blob . data + 16 ,
negprot_spnego_blob . length - 16 ) ;
2009-06-04 22:14:20 +04:00
# else
2009-05-20 21:45:28 +04:00
/* for now we want raw NTLMSSP */
security_buffer = data_blob_const ( NULL , 0 ) ;
2009-06-04 22:14:20 +04:00
# endif
2009-05-20 21:45:28 +04:00
2009-05-14 17:32:02 +04:00
outbody = data_blob_talloc ( req - > out . vector , NULL , 0x40 ) ;
if ( outbody . data = = NULL ) {
return smbd_smb2_request_error ( req , NT_STATUS_NO_MEMORY ) ;
}
SSVAL ( outbody . data , 0x00 , 0x40 + 1 ) ; /* struct size */
2009-05-22 23:26:03 +04:00
SSVAL ( outbody . data , 0x02 ,
security_mode ) ; /* security mode */
2009-05-14 17:32:02 +04:00
SSVAL ( outbody . data , 0x04 , dialect ) ; /* dialect revision */
SSVAL ( outbody . data , 0x06 , 0 ) ; /* reserved */
memcpy ( outbody . data + 0x08 ,
negprot_spnego_blob . data , 16 ) ; /* server guid */
2009-05-22 23:26:03 +04:00
SIVAL ( outbody . data , 0x18 ,
capabilities ) ; /* capabilities */
2009-05-14 17:32:02 +04:00
SIVAL ( outbody . data , 0x1C , 0x00010000 ) ; /* max transact size */
SIVAL ( outbody . data , 0x20 , 0x00010000 ) ; /* max read size */
SIVAL ( outbody . data , 0x24 , 0x00010000 ) ; /* max write size */
SBVAL ( outbody . data , 0x28 , 0 ) ; /* system time */
SBVAL ( outbody . data , 0x30 , 0 ) ; /* server start time */
SSVAL ( outbody . data , 0x38 ,
security_offset ) ; /* security buffer offset */
SSVAL ( outbody . data , 0x3A ,
security_buffer . length ) ; /* security buffer length */
SIVAL ( outbody . data , 0x3C , 0 ) ; /* reserved */
outdyn = security_buffer ;
return smbd_smb2_request_done ( req , outbody , & outdyn ) ;
}