2003-01-15 15:52:38 +03:00
/*
Unix SMB / Netbios implementation .
Version 3.0
handle NLTMSSP , server side
Copyright ( C ) Andrew Tridgell 2001
Copyright ( C ) Andrew Bartlett 2001 - 2003
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"
/**
* Default challange generation code .
*
*/
static const uint8 * get_challenge ( void * cookie )
{
static uchar chal [ 8 ] ;
generate_random_buffer ( chal , sizeof ( chal ) , False ) ;
return chal ;
}
NTSTATUS ntlmssp_server_start ( NTLMSSP_STATE * * ntlmssp_state )
{
TALLOC_CTX * mem_ctx ;
mem_ctx = talloc_init ( " NTLMSSP context " ) ;
* ntlmssp_state = talloc_zero ( mem_ctx , sizeof ( * * ntlmssp_state ) ) ;
if ( ! * ntlmssp_state ) {
DEBUG ( 0 , ( " ntlmssp_start: talloc failed! \n " ) ) ;
talloc_destroy ( mem_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
ZERO_STRUCTP ( * ntlmssp_state ) ;
( * ntlmssp_state ) - > mem_ctx = mem_ctx ;
( * ntlmssp_state ) - > get_challenge = get_challenge ;
( * ntlmssp_state ) - > get_global_myname = global_myname ;
( * ntlmssp_state ) - > get_domain = lp_workgroup ;
return NT_STATUS_OK ;
}
NTSTATUS ntlmssp_server_end ( NTLMSSP_STATE * * ntlmssp_state )
{
TALLOC_CTX * mem_ctx = ( * ntlmssp_state ) - > mem_ctx ;
2003-01-15 23:39:33 +03:00
data_blob_free ( & ( * ntlmssp_state ) - > chal ) ;
2003-01-15 15:52:38 +03:00
data_blob_free ( & ( * ntlmssp_state ) - > lm_resp ) ;
data_blob_free ( & ( * ntlmssp_state ) - > nt_resp ) ;
SAFE_FREE ( ( * ntlmssp_state ) - > user ) ;
SAFE_FREE ( ( * ntlmssp_state ) - > domain ) ;
SAFE_FREE ( ( * ntlmssp_state ) - > workstation ) ;
talloc_destroy ( mem_ctx ) ;
* ntlmssp_state = NULL ;
return NT_STATUS_OK ;
}
NTSTATUS ntlmssp_server_update ( NTLMSSP_STATE * ntlmssp_state ,
DATA_BLOB request , DATA_BLOB * reply )
{
uint32 ntlmssp_command ;
if ( ! msrpc_parse ( & request , " Cd " ,
" NTLMSSP " ,
& ntlmssp_command ) ) {
return NT_STATUS_LOGON_FAILURE ;
}
if ( ntlmssp_command = = NTLMSSP_NEGOTIATE ) {
return ntlmssp_negotiate ( ntlmssp_state , request , reply ) ;
} else if ( ntlmssp_command = = NTLMSSP_AUTH ) {
return ntlmssp_auth ( ntlmssp_state , request , reply ) ;
} else {
return NT_STATUS_LOGON_FAILURE ;
}
}
static const char * ntlmssp_target_name ( NTLMSSP_STATE * ntlmssp_state ,
uint32 neg_flags , uint32 * chal_flags )
{
if ( neg_flags & NTLMSSP_REQUEST_TARGET ) {
* chal_flags | = NTLMSSP_CHAL_TARGET_INFO ;
* chal_flags | = NTLMSSP_REQUEST_TARGET ;
if ( lp_server_role ( ) = = ROLE_STANDALONE ) {
* chal_flags | = NTLMSSP_TARGET_TYPE_SERVER ;
return ntlmssp_state - > get_global_myname ( ) ;
} else {
* chal_flags | = NTLMSSP_TARGET_TYPE_DOMAIN ;
return ntlmssp_state - > get_domain ( ) ;
} ;
} else {
return " " ;
}
}
NTSTATUS ntlmssp_negotiate ( NTLMSSP_STATE * ntlmssp_state ,
DATA_BLOB request , DATA_BLOB * reply )
{
DATA_BLOB struct_blob ;
fstring dnsname , dnsdomname ;
uint32 ntlmssp_command , neg_flags , chal_flags ;
char * cliname = NULL , * domname = NULL ;
const uint8 * cryptkey ;
const char * target_name ;
/* parse the NTLMSSP packet */
#if 0
file_save ( " ntlmssp_negotiate.dat " , request . data , request . length ) ;
# endif
if ( ! msrpc_parse ( & request , " CddAA " ,
" NTLMSSP " ,
& ntlmssp_command ,
& neg_flags ,
& cliname ,
& domname ) ) {
return NT_STATUS_LOGON_FAILURE ;
}
SAFE_FREE ( cliname ) ;
SAFE_FREE ( domname ) ;
debug_ntlmssp_flags ( neg_flags ) ;
cryptkey = ntlmssp_state - > get_challenge ( ntlmssp_state - > auth_context ) ;
2003-01-15 23:39:33 +03:00
data_blob_free ( & ntlmssp_state - > chal ) ;
ntlmssp_state - > chal = data_blob ( cryptkey , 8 ) ;
2003-01-15 15:52:38 +03:00
/* Give them the challenge. For now, ignore neg_flags and just
return the flags we want . Obviously this is not correct */
chal_flags =
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_NTLM ;
if ( neg_flags & NTLMSSP_NEGOTIATE_UNICODE ) {
chal_flags | = NTLMSSP_NEGOTIATE_UNICODE ;
ntlmssp_state - > unicode = True ;
} else {
chal_flags | = NTLMSSP_NEGOTIATE_OEM ;
}
target_name = ntlmssp_target_name ( ntlmssp_state ,
neg_flags , & chal_flags ) ;
/* This should be a 'netbios domain -> DNS domain' mapping */
dnsdomname [ 0 ] = ' \0 ' ;
get_mydomname ( dnsdomname ) ;
strlower ( dnsdomname ) ;
dnsname [ 0 ] = ' \0 ' ;
get_myfullname ( dnsname ) ;
strlower ( dnsname ) ;
if ( chal_flags & NTLMSSP_CHAL_TARGET_INFO )
{
const char * target_name_dns = " " ;
if ( chal_flags | = NTLMSSP_TARGET_TYPE_DOMAIN ) {
target_name_dns = dnsdomname ;
} else if ( chal_flags | = NTLMSSP_TARGET_TYPE_SERVER ) {
target_name_dns = dnsname ;
}
/* the numbers here are the string type flags */
msrpc_gen ( & struct_blob , " aaaaa " ,
ntlmssp_state - > unicode , NTLMSSP_NAME_TYPE_DOMAIN , target_name ,
ntlmssp_state - > unicode , NTLMSSP_NAME_TYPE_SERVER , ntlmssp_state - > get_global_myname ( ) ,
ntlmssp_state - > unicode , NTLMSSP_NAME_TYPE_DOMAIN_DNS , target_name_dns ,
ntlmssp_state - > unicode , NTLMSSP_NAME_TYPE_SERVER_DNS , dnsdomname ,
ntlmssp_state - > unicode , 0 , " " ) ;
} else {
struct_blob = data_blob ( NULL , 0 ) ;
}
{
const char * gen_string ;
if ( ntlmssp_state - > unicode ) {
gen_string = " CdUdbddB " ;
} else {
gen_string = " CdAdbddB " ;
}
msrpc_gen ( reply , gen_string ,
" NTLMSSP " ,
NTLMSSP_CHALLENGE ,
target_name ,
chal_flags ,
cryptkey , 8 ,
0 , 0 ,
struct_blob . data , struct_blob . length ) ;
}
data_blob_free ( & struct_blob ) ;
return NT_STATUS_MORE_PROCESSING_REQUIRED ;
}
NTSTATUS ntlmssp_auth ( NTLMSSP_STATE * ntlmssp_state ,
DATA_BLOB request , DATA_BLOB * reply )
{
DATA_BLOB sess_key ;
uint32 ntlmssp_command , neg_flags ;
NTSTATUS nt_status ;
const char * parse_string ;
/* parse the NTLMSSP packet */
#if 0
file_save ( " ntlmssp_auth.dat " , request . data , request . length ) ;
# endif
if ( ntlmssp_state - > unicode ) {
parse_string = " CdBBUUUBd " ;
} else {
parse_string = " CdBBAAABd " ;
}
data_blob_free ( & ntlmssp_state - > lm_resp ) ;
data_blob_free ( & ntlmssp_state - > nt_resp ) ;
SAFE_FREE ( ntlmssp_state - > user ) ;
SAFE_FREE ( ntlmssp_state - > domain ) ;
SAFE_FREE ( ntlmssp_state - > workstation ) ;
/* now the NTLMSSP encoded auth hashes */
if ( ! msrpc_parse ( & request , parse_string ,
" NTLMSSP " ,
& ntlmssp_command ,
& ntlmssp_state - > lm_resp ,
& ntlmssp_state - > nt_resp ,
& ntlmssp_state - > domain ,
& ntlmssp_state - > user ,
& ntlmssp_state - > workstation ,
& sess_key ,
& neg_flags ) ) {
return NT_STATUS_LOGON_FAILURE ;
}
data_blob_free ( & sess_key ) ;
DEBUG ( 3 , ( " Got user=[%s] domain=[%s] workstation=[%s] len1=%d len2=%d \n " ,
ntlmssp_state - > user , ntlmssp_state - > domain , ntlmssp_state - > workstation , ntlmssp_state - > lm_resp . length , ntlmssp_state - > nt_resp . length ) ) ;
#if 0
file_save ( " nthash1.dat " , & ntlmssp_state - > nt_resp . data , & ntlmssp_state - > nt_resp . length ) ;
file_save ( " lmhash1.dat " , & ntlmssp_state - > lm_resp . data , & ntlmssp_state - > lm_resp . length ) ;
# endif
nt_status = ntlmssp_state - > check_password ( ntlmssp_state - > auth_context ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return nt_status ;
}
* reply = data_blob ( NULL , 0 ) ;
return nt_status ;
}