2001-10-15 11:50:21 +04:00
/*
Unix SMB / Netbios implementation .
Version 3.0
handle SMBsessionsetup
Copyright ( C ) Andrew Tridgell 1998 - 2001
Copyright ( C ) Andrew Bartlett 2001
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 .
*/
# include "includes.h"
2001-11-09 01:19:01 +03:00
uint32 global_client_caps = 0 ;
2001-11-12 03:08:30 +03:00
/****************************************************************************
Add the standard ' Samba ' signiture to the end of the session setup .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void add_signiture ( char * outbuf )
{
char * p ;
p = smb_buf ( outbuf ) ;
p + = srvstr_push ( outbuf , p , " Unix " , - 1 , STR_TERMINATE ) ;
p + = srvstr_push ( outbuf , p , " Samba " , - 1 , STR_TERMINATE ) ;
p + = srvstr_push ( outbuf , p , lp_workgroup ( ) , - 1 , STR_TERMINATE ) ;
set_message_end ( outbuf , p ) ;
}
2001-10-18 14:26:06 +04:00
# if HAVE_KRB5
/****************************************************************************
reply to a session setup spnego negotiate packet for kerberos
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-20 10:31:25 +04:00
static int reply_spnego_kerberos ( connection_struct * conn ,
char * inbuf , char * outbuf ,
int length , int bufsize ,
2001-10-18 14:26:06 +04:00
DATA_BLOB * secblob )
{
DATA_BLOB ticket ;
krb5_context context ;
krb5_auth_context auth_context = NULL ;
krb5_keytab keytab = NULL ;
krb5_data packet ;
krb5_ticket * tkt = NULL ;
int ret ;
2001-10-20 10:31:25 +04:00
char * realm , * client , * p ;
const struct passwd * pw ;
char * user ;
int sess_vuid ;
2001-10-31 15:37:56 +03:00
auth_serversupplied_info * server_info = NULL ;
2001-10-18 14:26:06 +04:00
realm = lp_realm ( ) ;
if ( ! spnego_parse_krb5_wrap ( * secblob , & ticket ) ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
ret = krb5_init_context ( & context ) ;
if ( ret ) {
2001-10-20 10:50:24 +04:00
DEBUG ( 1 , ( " krb5_init_context failed (%s) \n " , error_message ( ret ) ) ) ;
2001-10-18 14:26:06 +04:00
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
packet . length = ticket . length ;
packet . data = ( krb5_pointer ) ticket . data ;
2001-10-22 09:04:33 +04:00
#if 0
file_save ( " /tmp/ticket.dat " , ticket . data , ticket . length ) ;
# endif
2001-10-18 14:26:06 +04:00
if ( ( ret = krb5_rd_req ( context , & auth_context , & packet ,
2001-10-22 09:04:33 +04:00
NULL , keytab , NULL , & tkt ) ) ) {
2001-10-20 10:50:24 +04:00
DEBUG ( 3 , ( " krb5_rd_req failed (%s) \n " ,
error_message ( ret ) ) ) ;
2001-10-18 14:26:06 +04:00
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
if ( ( ret = krb5_unparse_name ( context , tkt - > enc_part2 - > client ,
& client ) ) ) {
2001-10-20 10:50:24 +04:00
DEBUG ( 3 , ( " krb5_unparse_name failed (%s) \n " ,
error_message ( ret ) ) ) ;
2001-10-18 14:26:06 +04:00
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
DEBUG ( 3 , ( " Ticket name is [%s] \n " , client ) ) ;
2001-10-20 10:31:25 +04:00
p = strchr_m ( client , ' @ ' ) ;
if ( ! p ) {
2001-10-22 00:51:27 +04:00
DEBUG ( 3 , ( " Doesn't look like a valid principal \n " ) ) ;
2001-10-20 10:31:25 +04:00
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
* p = 0 ;
if ( strcasecmp ( p + 1 , realm ) ! = 0 ) {
DEBUG ( 3 , ( " Ticket for incorrect realm %s \n " , p + 1 ) ) ;
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
2001-10-18 14:26:06 +04:00
2001-10-20 10:31:25 +04:00
user = client ;
/* the password is good - let them in */
pw = smb_getpwnam ( user , False ) ;
if ( ! pw ) {
DEBUG ( 1 , ( " Username %s is invalid on this system \n " , user ) ) ;
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
2001-10-31 15:37:56 +03:00
if ( ! make_server_info_pw ( & server_info , pw ) ) {
DEBUG ( 1 , ( " make_server_info_from_pw failed! \n " ) ) ;
return ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
}
2001-10-20 10:31:25 +04:00
2001-11-09 05:44:49 +03:00
sess_vuid = register_vuid ( server_info , user ) ;
2001-10-31 15:37:56 +03:00
free_server_info ( & server_info ) ;
2001-10-20 10:31:25 +04:00
if ( sess_vuid = = - 1 ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
set_message ( outbuf , 4 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv3 , 0 ) ;
2001-11-12 03:08:30 +03:00
add_signiture ( outbuf ) ;
2001-10-20 10:31:25 +04:00
SSVAL ( outbuf , smb_uid , sess_vuid ) ;
SSVAL ( inbuf , smb_uid , sess_vuid ) ;
2001-10-18 14:26:06 +04:00
2001-10-20 10:31:25 +04:00
return chain_reply ( inbuf , outbuf , length , bufsize ) ;
2001-10-18 14:26:06 +04:00
}
# endif
2001-10-17 12:54:19 +04:00
/****************************************************************************
send a security blob via a session setup reply
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL reply_sesssetup_blob ( connection_struct * conn , char * outbuf ,
DATA_BLOB blob )
{
char * p ;
set_message ( outbuf , 4 , 0 , True ) ;
/* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
that we aren ' t finished yet */
SIVAL ( outbuf , smb_rcls , NT_STATUS_V ( NT_STATUS_MORE_PROCESSING_REQUIRED ) ) ;
SSVAL ( outbuf , smb_vwv0 , 0xFF ) ; /* no chaining possible */
SSVAL ( outbuf , smb_vwv3 , blob . length ) ;
p = smb_buf ( outbuf ) ;
memcpy ( p , blob . data , blob . length ) ;
p + = blob . length ;
p + = srvstr_push ( outbuf , p , " Unix " , - 1 , STR_TERMINATE ) ;
p + = srvstr_push ( outbuf , p , " Samba " , - 1 , STR_TERMINATE ) ;
p + = srvstr_push ( outbuf , p , lp_workgroup ( ) , - 1 , STR_TERMINATE ) ;
set_message_end ( outbuf , p ) ;
return send_smb ( smbd_server_fd ( ) , outbuf ) ;
}
/****************************************************************************
reply to a session setup spnego negotiate packet
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-20 10:31:25 +04:00
static int reply_spnego_negotiate ( connection_struct * conn ,
char * inbuf ,
char * outbuf ,
int length , int bufsize ,
2001-10-17 12:54:19 +04:00
DATA_BLOB blob1 )
{
char * OIDs [ ASN1_MAX_OIDS ] ;
DATA_BLOB secblob ;
int i ;
uint32 ntlmssp_command , neg_flags ;
DATA_BLOB sess_key , chal , spnego_chal ;
uint8 cryptkey [ 8 ] ;
2001-10-18 14:26:06 +04:00
BOOL got_kerberos = False ;
2001-10-17 12:54:19 +04:00
/* parse out the OIDs and the first sec blob */
if ( ! parse_negTokenTarg ( blob1 , OIDs , & secblob ) ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
for ( i = 0 ; OIDs [ i ] ; i + + ) {
DEBUG ( 3 , ( " Got OID %s \n " , OIDs [ i ] ) ) ;
2001-10-21 04:10:16 +04:00
if ( strcmp ( OID_KERBEROS5 , OIDs [ i ] ) = = 0 | |
strcmp ( OID_KERBEROS5_OLD , OIDs [ i ] ) = = 0 ) {
2001-10-18 14:26:06 +04:00
got_kerberos = True ;
}
2001-10-17 12:54:19 +04:00
free ( OIDs [ i ] ) ;
}
DEBUG ( 3 , ( " Got secblob of size %d \n " , secblob . length ) ) ;
2001-10-18 14:26:06 +04:00
# if HAVE_KRB5
if ( got_kerberos ) {
2001-10-20 10:31:25 +04:00
int ret = reply_spnego_kerberos ( conn , inbuf , outbuf ,
length , bufsize , & secblob ) ;
2001-10-18 14:26:06 +04:00
data_blob_free ( & secblob ) ;
return ret ;
}
# endif
2001-10-17 12:54:19 +04:00
/* parse the NTLMSSP packet */
#if 0
file_save ( " secblob.dat " , secblob . data , secblob . length ) ;
# endif
2001-10-18 14:26:06 +04:00
if ( ! msrpc_parse ( & secblob , " CddB " ,
" NTLMSSP " ,
& ntlmssp_command ,
& neg_flags ,
& sess_key ) ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
2001-10-17 12:54:19 +04:00
data_blob_free ( & secblob ) ;
data_blob_free ( & sess_key ) ;
if ( ntlmssp_command ! = NTLMSSP_NEGOTIATE ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
DEBUG ( 3 , ( " Got neg_flags=%08x \n " , neg_flags ) ) ;
2001-10-18 14:26:06 +04:00
if ( ! last_challenge ( cryptkey ) ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
2001-10-17 12:54:19 +04:00
/* Give them the challenge. For now, ignore neg_flags and just
return the flags we want . Obviously this is not correct */
neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
NTLMSSP_NEGOTIATE_LM_KEY |
NTLMSSP_NEGOTIATE_NTLM ;
msrpc_gen ( & chal , " Cddddbdddd " ,
" NTLMSSP " ,
NTLMSSP_CHALLENGE ,
0 ,
0x30 , /* ?? */
neg_flags ,
cryptkey , 8 ,
0 , 0 , 0 ,
0x3000 ) ; /* ?? */
if ( ! spnego_gen_challenge ( & spnego_chal , & chal , & chal ) ) {
DEBUG ( 3 , ( " Failed to generate challenge \n " ) ) ;
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
/* now tell the client to send the auth packet */
reply_sesssetup_blob ( conn , outbuf , spnego_chal ) ;
data_blob_free ( & chal ) ;
data_blob_free ( & spnego_chal ) ;
/* and tell smbd that we have already replied to this packet */
return - 1 ;
}
/****************************************************************************
reply to a session setup spnego auth packet
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int reply_spnego_auth ( connection_struct * conn , char * inbuf , char * outbuf ,
int length , int bufsize ,
DATA_BLOB blob1 )
{
DATA_BLOB auth ;
char * workgroup , * user , * machine ;
DATA_BLOB lmhash , nthash , sess_key ;
2001-10-31 13:46:25 +03:00
DATA_BLOB plaintext_password = data_blob ( NULL , 0 ) ;
DATA_BLOB sec_blob ;
2001-10-17 12:54:19 +04:00
uint32 ntlmssp_command , neg_flags ;
NTSTATUS nt_status ;
int sess_vuid ;
2001-10-31 13:46:25 +03:00
char chal [ 8 ] ;
auth_usersupplied_info * user_info = NULL ;
auth_serversupplied_info * server_info = NULL ;
2001-10-17 12:54:19 +04:00
if ( ! spnego_parse_auth ( blob1 , & auth ) ) {
2001-10-17 14:46:46 +04:00
#if 0
2001-10-17 12:54:19 +04:00
file_save ( " auth.dat " , blob1 . data , blob1 . length ) ;
2001-10-17 14:46:46 +04:00
# endif
2001-10-17 12:54:19 +04:00
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
/* now the NTLMSSP encoded auth hashes */
if ( ! msrpc_parse ( & auth , " CdBBUUUBd " ,
" NTLMSSP " ,
& ntlmssp_command ,
& lmhash ,
& nthash ,
& workgroup ,
& user ,
& machine ,
& sess_key ,
& neg_flags ) ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
data_blob_free ( & auth ) ;
data_blob_free ( & sess_key ) ;
DEBUG ( 3 , ( " Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d \n " ,
user , workgroup , machine , lmhash . length , nthash . length ) ) ;
#if 0
file_save ( " nthash1.dat " , nthash . data , nthash . length ) ;
file_save ( " lmhash1.dat " , lmhash . data , lmhash . length ) ;
# endif
2001-10-31 13:46:25 +03:00
if ( ! last_challenge ( chal ) ) {
DEBUG ( 0 , ( " Encrypted login but no challange set! \n " ) ) ;
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
sec_blob = data_blob ( chal , 8 ) ;
if ( ! sec_blob . data ) {
return ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
}
if ( ! make_user_info_map ( & user_info ,
user , workgroup ,
machine , sec_blob ,
lmhash , nthash ,
plaintext_password ,
neg_flags , True ) ) {
return ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
}
nt_status = check_password ( user_info , & server_info ) ;
free_user_info ( & user_info ) ;
2001-10-17 12:54:19 +04:00
data_blob_free ( & lmhash ) ;
2001-10-31 13:46:25 +03:00
data_blob_free ( & nthash ) ;
2001-10-17 12:54:19 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2001-10-31 13:46:25 +03:00
return ERROR_NT ( nt_status_squash ( nt_status ) ) ;
2001-10-17 12:54:19 +04:00
}
2001-11-09 01:19:01 +03:00
sess_vuid = register_vuid ( server_info , user ) ;
2001-10-17 12:54:19 +04:00
2001-10-31 13:46:25 +03:00
free_server_info ( & server_info ) ;
2001-10-17 12:54:19 +04:00
if ( sess_vuid = = - 1 ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
set_message ( outbuf , 4 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv3 , 0 ) ;
2001-11-12 03:08:30 +03:00
add_signiture ( outbuf ) ;
2001-10-17 12:54:19 +04:00
SSVAL ( outbuf , smb_uid , sess_vuid ) ;
SSVAL ( inbuf , smb_uid , sess_vuid ) ;
return chain_reply ( inbuf , outbuf , length , bufsize ) ;
}
2001-10-20 15:47:44 +04:00
/****************************************************************************
reply to a session setup spnego anonymous packet
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int reply_spnego_anonymous ( connection_struct * conn , char * inbuf , char * outbuf ,
int length , int bufsize )
{
int sess_vuid ;
2001-11-09 01:19:01 +03:00
auth_usersupplied_info * user_info = NULL ;
2001-10-31 13:46:25 +03:00
auth_serversupplied_info * server_info = NULL ;
2001-10-20 15:47:44 +04:00
2001-11-09 01:19:01 +03:00
NTSTATUS nt_status ;
2001-10-20 15:47:44 +04:00
DEBUG ( 3 , ( " Got anonymous request \n " ) ) ;
2001-11-09 01:19:01 +03:00
make_user_info_guest ( & user_info ) ;
nt_status = check_password ( user_info , & server_info ) ;
2001-11-09 14:16:06 +03:00
sess_vuid = register_vuid ( server_info , lp_guestaccount ( ) ) ;
2001-10-31 13:46:25 +03:00
free_server_info ( & server_info ) ;
2001-10-20 15:47:44 +04:00
if ( sess_vuid = = - 1 ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
set_message ( outbuf , 4 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv3 , 0 ) ;
2001-11-12 03:08:30 +03:00
add_signiture ( outbuf ) ;
2001-10-20 15:47:44 +04:00
SSVAL ( outbuf , smb_uid , sess_vuid ) ;
SSVAL ( inbuf , smb_uid , sess_vuid ) ;
return chain_reply ( inbuf , outbuf , length , bufsize ) ;
}
2001-10-17 12:54:19 +04:00
/****************************************************************************
reply to a session setup command
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int reply_sesssetup_and_X_spnego ( connection_struct * conn , char * inbuf , char * outbuf ,
int length , int bufsize )
{
uint8 * p ;
DATA_BLOB blob1 ;
int ret ;
2001-10-31 13:46:25 +03:00
DEBUG ( 3 , ( " Doing spnego session setup \n " ) ) ;
2001-10-21 07:27:13 +04:00
2001-10-17 12:54:19 +04:00
if ( global_client_caps = = 0 ) {
global_client_caps = IVAL ( inbuf , smb_vwv10 ) ;
}
2001-10-23 23:10:30 +04:00
p = ( uint8 * ) smb_buf ( inbuf ) ;
2001-10-17 12:54:19 +04:00
2001-10-20 15:47:44 +04:00
if ( SVAL ( inbuf , smb_vwv7 ) = = 0 ) {
/* an anonymous request */
return reply_spnego_anonymous ( conn , inbuf , outbuf , length , bufsize ) ;
}
2001-10-17 12:54:19 +04:00
/* pull the spnego blob */
blob1 = data_blob ( p , SVAL ( inbuf , smb_vwv7 ) ) ;
2001-10-20 15:47:44 +04:00
2001-10-18 14:26:06 +04:00
#if 0
file_save ( " negotiate.dat " , blob1 . data , blob1 . length ) ;
# endif
2001-10-17 12:54:19 +04:00
if ( blob1 . data [ 0 ] = = ASN1_APPLICATION ( 0 ) ) {
/* its a negTokenTarg packet */
2001-10-20 10:31:25 +04:00
ret = reply_spnego_negotiate ( conn , inbuf , outbuf , length , bufsize , blob1 ) ;
2001-10-17 12:54:19 +04:00
data_blob_free ( & blob1 ) ;
return ret ;
}
if ( blob1 . data [ 0 ] = = ASN1_CONTEXT ( 1 ) ) {
/* its a auth packet */
ret = reply_spnego_auth ( conn , inbuf , outbuf , length , bufsize , blob1 ) ;
data_blob_free ( & blob1 ) ;
return ret ;
}
/* what sort of packet is this? */
DEBUG ( 1 , ( " Unknown packet in reply_sesssetup_and_X_spnego \n " ) ) ;
data_blob_free ( & blob1 ) ;
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
2001-10-15 11:50:21 +04:00
/****************************************************************************
reply to a session setup command
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_sesssetup_and_X ( connection_struct * conn , char * inbuf , char * outbuf ,
int length , int bufsize )
{
int sess_vuid ;
int smb_bufsize ;
2001-10-31 13:46:25 +03:00
DATA_BLOB lm_resp ;
DATA_BLOB nt_resp ;
DATA_BLOB plaintext_password ;
2001-10-15 11:50:21 +04:00
pstring user ;
2001-11-09 01:19:01 +03:00
pstring sub_user ; /* Sainitised username for substituion */
2001-10-15 11:50:21 +04:00
fstring domain ;
fstring native_os ;
fstring native_lanman ;
static BOOL done_sesssetup = False ;
extern BOOL global_encrypted_passwords_negotiated ;
2001-10-30 16:54:54 +03:00
extern BOOL global_spnego_negotiated ;
2001-10-15 11:50:21 +04:00
extern int Protocol ;
extern fstring remote_machine ;
extern userdom_struct current_user_info ;
extern int max_send ;
2001-10-31 13:46:25 +03:00
auth_usersupplied_info * user_info = NULL ;
auth_serversupplied_info * server_info = NULL ;
2001-11-09 01:19:01 +03:00
NTSTATUS nt_status ;
2001-10-15 11:50:21 +04:00
BOOL doencrypt = global_encrypted_passwords_negotiated ;
2001-10-31 13:46:25 +03:00
2001-10-15 11:50:21 +04:00
START_PROFILE ( SMBsesssetupX ) ;
2001-10-21 07:27:13 +04:00
2001-10-31 13:46:25 +03:00
ZERO_STRUCT ( lm_resp ) ;
ZERO_STRUCT ( nt_resp ) ;
ZERO_STRUCT ( plaintext_password ) ;
2001-10-21 07:27:13 +04:00
DEBUG ( 3 , ( " wct=%d flg2=0x%x \n " , CVAL ( inbuf , smb_wct ) , SVAL ( inbuf , smb_flg2 ) ) ) ;
2001-10-15 11:50:21 +04:00
2001-10-21 07:27:13 +04:00
/* a SPNEGO session setup has 12 command words, whereas a normal
NT1 session setup has 13. See the cifs spec . */
2001-10-30 16:54:54 +03:00
if ( CVAL ( inbuf , smb_wct ) = = 12 & &
2001-10-21 07:27:13 +04:00
( SVAL ( inbuf , smb_flg2 ) & FLAGS2_EXTENDED_SECURITY ) ) {
2001-10-17 12:54:19 +04:00
return reply_sesssetup_and_X_spnego ( conn , inbuf , outbuf , length , bufsize ) ;
}
2001-10-15 11:50:21 +04:00
smb_bufsize = SVAL ( inbuf , smb_vwv2 ) ;
2001-10-31 13:46:25 +03:00
2001-10-15 11:50:21 +04:00
if ( Protocol < PROTOCOL_NT1 ) {
2001-10-31 13:46:25 +03:00
uint16 passlen1 = SVAL ( inbuf , smb_vwv7 ) ;
if ( passlen1 > MAX_PASS_LEN ) {
2001-10-15 11:50:21 +04:00
return ERROR_DOS ( ERRDOS , ERRbuftoosmall ) ;
}
2001-10-31 13:46:25 +03:00
if ( doencrypt ) {
lm_resp = data_blob ( smb_buf ( inbuf ) , passlen1 ) ;
} else {
plaintext_password = data_blob ( smb_buf ( inbuf ) , passlen1 + 1 ) ;
if ( ! plaintext_password . data ) {
DEBUG ( 0 , ( " reply_sesssetup_and_X: malloc failed for plaintext_password! \n " ) ) ;
return ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
} else {
/* Ensure null termination */
plaintext_password . data [ passlen1 ] = 0 ;
}
2001-10-15 11:50:21 +04:00
}
2001-10-31 13:46:25 +03:00
srvstr_pull ( inbuf , user , smb_buf ( inbuf ) + passlen1 , sizeof ( user ) , - 1 , STR_TERMINATE ) ;
2001-10-15 11:50:21 +04:00
} else {
uint16 passlen1 = SVAL ( inbuf , smb_vwv7 ) ;
uint16 passlen2 = SVAL ( inbuf , smb_vwv8 ) ;
enum remote_arch_types ra_type = get_remote_arch ( ) ;
char * p = smb_buf ( inbuf ) ;
2001-10-31 13:46:25 +03:00
2001-10-15 11:50:21 +04:00
if ( global_client_caps = = 0 )
global_client_caps = IVAL ( inbuf , smb_vwv11 ) ;
/* client_caps is used as final determination if client is NT or Win95.
This is needed to return the correct error codes in some
circumstances .
*/
if ( ra_type = = RA_WINNT | | ra_type = = RA_WIN2K | | ra_type = = RA_WIN95 ) {
if ( ! ( global_client_caps & ( CAP_NT_SMBS | CAP_STATUS32 ) ) ) {
set_remote_arch ( RA_WIN95 ) ;
}
}
if ( passlen1 > MAX_PASS_LEN ) {
return ERROR_DOS ( ERRDOS , ERRbuftoosmall ) ;
}
2001-10-31 13:46:25 +03:00
2001-10-15 11:50:21 +04:00
passlen1 = MIN ( passlen1 , MAX_PASS_LEN ) ;
passlen2 = MIN ( passlen2 , MAX_PASS_LEN ) ;
2001-10-31 13:46:25 +03:00
2001-10-15 11:50:21 +04:00
if ( ! doencrypt ) {
/* both Win95 and WinNT stuff up the password lengths for
non - encrypting systems . Uggh .
if passlen1 = = 24 its a win95 system , and its setting the
password length incorrectly . Luckily it still works with the
default code because Win95 will null terminate the password
anyway
if passlen1 > 0 and passlen2 > 0 then maybe its a NT box and its
setting passlen2 to some random value which really stuffs
things up . we need to fix that one . */
if ( passlen1 > 0 & & passlen2 > 0 & & passlen2 ! = 24 & & passlen2 ! = 1 )
passlen2 = 0 ;
}
/* Save the lanman2 password and the NT md4 password. */
2001-10-31 13:46:25 +03:00
if ( ( doencrypt ) & & ( passlen1 ! = 0 ) & & ( passlen1 ! = 24 ) ) {
doencrypt = False ;
}
if ( doencrypt ) {
lm_resp = data_blob ( p , passlen1 ) ;
nt_resp = data_blob ( p + passlen1 , passlen2 ) ;
} else {
plaintext_password = data_blob ( p , passlen1 + 1 ) ;
/* Ensure null termination */
plaintext_password . data [ passlen1 ] = 0 ;
2001-10-15 11:50:21 +04:00
}
p + = passlen1 + passlen2 ;
p + = srvstr_pull ( inbuf , user , p , sizeof ( user ) , - 1 ,
STR_TERMINATE ) ;
p + = srvstr_pull ( inbuf , domain , p , sizeof ( domain ) ,
- 1 , STR_TERMINATE ) ;
p + = srvstr_pull ( inbuf , native_os , p , sizeof ( native_os ) ,
- 1 , STR_TERMINATE ) ;
p + = srvstr_pull ( inbuf , native_lanman , p , sizeof ( native_lanman ) ,
- 1 , STR_TERMINATE ) ;
DEBUG ( 3 , ( " Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] \n " ,
domain , native_os , native_lanman ) ) ;
}
/* don't allow for weird usernames or domains */
alpha_strcpy ( user , user , " . _-$ " , sizeof ( user ) ) ;
alpha_strcpy ( domain , domain , " . _- " , sizeof ( domain ) ) ;
if ( strstr ( user , " .. " ) | | strstr ( domain , " .. " ) ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
2001-10-31 13:46:25 +03:00
DEBUG ( 3 , ( " sesssetupX:name=[%s] \\ [%s]@[%s] \n " , domain , user , remote_machine ) ) ;
2001-11-09 01:19:01 +03:00
if ( * user ) {
2001-11-03 03:19:56 +03:00
if ( global_spnego_negotiated ) {
DEBUG ( 0 , ( " reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego. \n " ) ) ;
return ERROR_NT ( NT_STATUS_UNSUCCESSFUL ) ;
}
2001-10-15 11:50:21 +04:00
}
2001-11-09 01:19:01 +03:00
if ( * user ) {
pstrcpy ( sub_user , user ) ;
} else {
2001-11-09 14:16:06 +03:00
pstrcpy ( sub_user , lp_guestaccount ( ) ) ;
2001-11-09 01:19:01 +03:00
}
pstrcpy ( current_user_info . smb_name , sub_user ) ;
2001-10-31 13:46:25 +03:00
reload_services ( True ) ;
if ( lp_security ( ) = = SEC_SHARE ) {
/* in share level we should ignore any passwords */
data_blob_free ( & lm_resp ) ;
data_blob_free ( & nt_resp ) ;
2001-11-01 08:02:41 +03:00
data_blob_clear_free ( & plaintext_password ) ;
2001-10-15 11:50:21 +04:00
2001-11-09 01:19:01 +03:00
map_username ( sub_user ) ;
add_session_user ( sub_user ) ;
/* Then force it to null for the benfit of the code below */
* user = 0 ;
2001-10-31 13:46:25 +03:00
}
2001-10-15 11:50:21 +04:00
2001-11-09 01:19:01 +03:00
if ( ! make_user_info_for_reply ( & user_info ,
user , domain ,
lm_resp , nt_resp ,
plaintext_password , doencrypt ) ) {
return ERROR_NT ( NT_STATUS_NO_MEMORY ) ;
}
2001-10-15 11:50:21 +04:00
2001-11-09 01:19:01 +03:00
nt_status = check_password ( user_info , & server_info ) ;
free_user_info ( & user_info ) ;
data_blob_free ( & lm_resp ) ;
data_blob_free ( & nt_resp ) ;
data_blob_clear_free ( & plaintext_password ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
if NT_STATUS_EQUAL ( nt_status , NT_STATUS_NO_SUCH_USER ) {
if ( ( lp_map_to_guest ( ) = = MAP_TO_GUEST_ON_BAD_USER ) | |
( lp_map_to_guest ( ) = = MAP_TO_GUEST_ON_BAD_PASSWORD ) ) {
DEBUG ( 3 , ( " No such user %s [%s] - using guest account \n " , user , domain ) ) ;
make_server_info_guest ( & server_info ) ;
nt_status = NT_STATUS_OK ;
}
} else if NT_STATUS_EQUAL ( nt_status , NT_STATUS_WRONG_PASSWORD ) {
if ( lp_map_to_guest ( ) = = MAP_TO_GUEST_ON_BAD_PASSWORD ) {
DEBUG ( 3 , ( " Registered username %s for guest access \n " , user ) ) ;
make_server_info_guest ( & server_info ) ;
nt_status = NT_STATUS_OK ;
2001-10-15 11:50:21 +04:00
}
}
}
2001-11-09 01:19:01 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return ERROR_NT ( nt_status_squash ( nt_status ) ) ;
}
2001-10-15 11:50:21 +04:00
/* it's ok - setup a reply */
if ( Protocol < PROTOCOL_NT1 ) {
set_message ( outbuf , 3 , 0 , True ) ;
} else {
set_message ( outbuf , 3 , 0 , True ) ;
2001-11-12 03:08:30 +03:00
add_signiture ( outbuf ) ;
2001-10-15 11:50:21 +04:00
/* perhaps grab OS version here?? */
}
2001-11-09 01:19:01 +03:00
if ( server_info - > guest ) {
2001-10-31 13:46:25 +03:00
SSVAL ( outbuf , smb_vwv2 , 1 ) ;
} else {
const char * home_dir = pdb_get_homedir ( server_info - > sam_account ) ;
const char * username = pdb_get_username ( server_info - > sam_account ) ;
if ( ( home_dir & & * home_dir )
& & ( lp_servicenumber ( username ) < 0 ) ) {
add_home_service ( username , home_dir ) ;
2001-10-15 11:50:21 +04:00
}
}
2001-10-31 13:46:25 +03:00
2001-10-15 11:50:21 +04:00
/* register the name and uid as being validated, so further connections
to a uid can get through without a password , on the same VC */
2001-10-31 13:46:25 +03:00
2001-11-09 01:19:01 +03:00
sess_vuid = register_vuid ( server_info , sub_user ) ;
2001-10-31 13:46:25 +03:00
free_server_info ( & server_info ) ;
2001-10-15 11:50:21 +04:00
if ( sess_vuid = = - 1 ) {
return ERROR_NT ( NT_STATUS_LOGON_FAILURE ) ;
}
SSVAL ( outbuf , smb_uid , sess_vuid ) ;
SSVAL ( inbuf , smb_uid , sess_vuid ) ;
if ( ! done_sesssetup )
max_send = MIN ( max_send , smb_bufsize ) ;
done_sesssetup = True ;
END_PROFILE ( SMBsesssetupX ) ;
return chain_reply ( inbuf , outbuf , length , bufsize ) ;
}