2005-04-25 09:03:50 +04:00
/*
Unix SMB / Netbios implementation .
Version 3.0
handle NLTMSSP , client server side parsing
Copyright ( C ) Andrew Tridgell 2001
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2001 - 2005
Copyright ( C ) Stefan Metzmacher 2005
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
2005-04-25 09:03:50 +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/>.
2005-04-25 09:03:50 +04:00
*/
# include "includes.h"
2009-01-31 13:34:12 +03:00
# include "system/network.h"
2009-12-16 18:41:21 +03:00
# include "lib/tsocket/tsocket.h"
2005-04-25 09:03:50 +04:00
# include "auth/ntlmssp/ntlmssp.h"
2010-05-24 22:03:42 +04:00
# include "../librpc/gen_ndr/ndr_ntlmssp.h"
2010-08-06 10:14:11 +04:00
# include "../libcli/auth/ntlmssp_ndr.h"
2010-08-06 15:31:21 +04:00
# include "../libcli/auth/ntlmssp_private.h"
2009-04-16 04:17:17 +04:00
# include "../libcli/auth/libcli_auth.h"
2008-09-24 17:30:23 +04:00
# include "../lib/crypto/crypto.h"
2006-11-07 03:48:36 +03:00
# include "auth/gensec/gensec.h"
2010-04-13 06:00:06 +04:00
# include "auth/gensec/gensec_proto.h"
2006-11-07 03:48:36 +03:00
# include "auth/auth.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2005-04-25 09:03:50 +04:00
2010-08-06 11:53:44 +04:00
/**
* Next state function for the Negotiate packet ( GENSEC wrapper )
*
* @ param gensec_security GENSEC state
* @ param out_mem_ctx Memory context for * out
* @ param in The request , as a DATA_BLOB . reply . data must be NULL
* @ param out The reply , as an allocated DATA_BLOB , caller to free .
* @ return Errors or MORE_PROCESSING_REQUIRED if ( normal ) a reply is required .
*/
NTSTATUS gensec_ntlmssp_server_negotiate ( struct gensec_security * gensec_security ,
TALLOC_CTX * out_mem_ctx ,
const DATA_BLOB request , DATA_BLOB * reply )
{
struct gensec_ntlmssp_context * gensec_ntlmssp =
talloc_get_type_abort ( gensec_security - > private_data ,
struct gensec_ntlmssp_context ) ;
struct ntlmssp_state * ntlmssp_state = gensec_ntlmssp - > ntlmssp_state ;
return ntlmssp_server_negotiate ( ntlmssp_state , out_mem_ctx , request , reply ) ;
}
/**
* Next state function for the Authenticate packet ( GENSEC wrapper )
*
* @ param gensec_security GENSEC state
* @ param out_mem_ctx Memory context for * out
* @ param in The request , as a DATA_BLOB . reply . data must be NULL
* @ param out The reply , as an allocated DATA_BLOB , caller to free .
* @ return Errors or NT_STATUS_OK if authentication sucessful
*/
NTSTATUS gensec_ntlmssp_server_auth ( struct gensec_security * gensec_security ,
TALLOC_CTX * out_mem_ctx ,
const DATA_BLOB in , DATA_BLOB * out )
{
struct gensec_ntlmssp_context * gensec_ntlmssp =
talloc_get_type_abort ( gensec_security - > private_data ,
struct gensec_ntlmssp_context ) ;
struct ntlmssp_state * ntlmssp_state = gensec_ntlmssp - > ntlmssp_state ;
return ntlmssp_server_auth ( ntlmssp_state , out_mem_ctx , in , out ) ;
2010-11-29 16:33:08 +03:00
}
2010-08-06 11:53:44 +04:00
2005-04-25 09:03:50 +04:00
/**
* Return the challenge as determined by the authentication subsystem
* @ return an 8 byte random challenge
*/
2009-12-30 19:57:54 +03:00
static NTSTATUS auth_ntlmssp_get_challenge ( const struct ntlmssp_state * ntlmssp_state ,
2009-12-29 12:44:19 +03:00
uint8_t chal [ 8 ] )
2005-04-25 09:03:50 +04:00
{
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context * gensec_ntlmssp =
2009-12-30 19:57:54 +03:00
talloc_get_type_abort ( ntlmssp_state - > callback_private ,
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context ) ;
struct auth_context * auth_context = gensec_ntlmssp - > auth_context ;
2005-04-25 09:03:50 +04:00
NTSTATUS status ;
2009-12-29 19:56:56 +03:00
status = auth_context - > get_challenge ( auth_context , chal ) ;
2005-04-25 09:03:50 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-08-01 18:10:06 +04:00
DEBUG ( 1 , ( " auth_ntlmssp_get_challenge: failed to get challenge: %s \n " ,
nt_errstr ( status ) ) ) ;
2009-12-29 12:44:19 +03:00
return status ;
2005-04-25 09:03:50 +04:00
}
2009-12-29 12:44:19 +03:00
return NT_STATUS_OK ;
2005-04-25 09:03:50 +04:00
}
/**
* Some authentication methods ' fix ' the challenge , so we may not be able to set it
*
* @ return If the effective challenge used by the auth subsystem may be modified
*/
2009-12-30 19:57:54 +03:00
static bool auth_ntlmssp_may_set_challenge ( const struct ntlmssp_state * ntlmssp_state )
2005-04-25 09:03:50 +04:00
{
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context * gensec_ntlmssp =
2009-12-30 19:57:54 +03:00
talloc_get_type_abort ( ntlmssp_state - > callback_private ,
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context ) ;
struct auth_context * auth_context = gensec_ntlmssp - > auth_context ;
return auth_context - > challenge_may_be_modified ( auth_context ) ;
2005-04-25 09:03:50 +04:00
}
/**
* NTLM2 authentication modifies the effective challenge ,
* @ param challenge The new challenge value
*/
2009-12-30 19:57:54 +03:00
static NTSTATUS auth_ntlmssp_set_challenge ( struct ntlmssp_state * ntlmssp_state , DATA_BLOB * challenge )
2005-04-25 09:03:50 +04:00
{
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context * gensec_ntlmssp =
2009-12-30 19:57:54 +03:00
talloc_get_type_abort ( ntlmssp_state - > callback_private ,
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context ) ;
struct auth_context * auth_context = gensec_ntlmssp - > auth_context ;
2005-04-25 09:03:50 +04:00
NTSTATUS nt_status ;
const uint8_t * chal ;
if ( challenge - > length ! = 8 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
chal = challenge - > data ;
2009-12-29 19:56:56 +03:00
nt_status = auth_context - > set_challenge ( auth_context ,
chal ,
" NTLMSSP callback (NTLM2) " ) ;
2005-04-25 09:03:50 +04:00
return nt_status ;
}
/**
* Check the password on an NTLMSSP login .
*
* Return the session keys used on the connection .
*/
2009-12-30 19:57:54 +03:00
static NTSTATUS auth_ntlmssp_check_password ( struct ntlmssp_state * ntlmssp_state ,
2010-09-16 08:37:20 +04:00
TALLOC_CTX * mem_ctx ,
2009-12-29 18:14:05 +03:00
DATA_BLOB * user_session_key , DATA_BLOB * lm_session_key )
2005-04-25 09:03:50 +04:00
{
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context * gensec_ntlmssp =
2009-12-30 19:57:54 +03:00
talloc_get_type_abort ( ntlmssp_state - > callback_private ,
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context ) ;
struct auth_context * auth_context = gensec_ntlmssp - > auth_context ;
2005-04-25 09:03:50 +04:00
NTSTATUS nt_status ;
2009-12-29 18:02:00 +03:00
struct auth_usersupplied_info * user_info ;
2010-05-04 10:44:08 +04:00
user_info = talloc_zero ( ntlmssp_state , struct auth_usersupplied_info ) ;
2005-07-22 08:10:07 +04:00
if ( ! user_info ) {
return NT_STATUS_NO_MEMORY ;
}
2005-04-25 09:03:50 +04:00
2005-10-28 12:54:37 +04:00
user_info - > logon_parameters = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT ;
2005-07-22 08:10:07 +04:00
user_info - > flags = 0 ;
2007-10-07 02:16:19 +04:00
user_info - > mapped_state = false ;
2009-12-30 19:57:54 +03:00
user_info - > client . account_name = ntlmssp_state - > user ;
user_info - > client . domain_name = ntlmssp_state - > domain ;
2010-05-25 13:59:23 +04:00
user_info - > workstation_name = ntlmssp_state - > client . netbios_name ;
2009-12-30 10:06:28 +03:00
user_info - > remote_host = gensec_get_remote_address ( gensec_ntlmssp - > gensec_security ) ;
2006-01-10 01:12:53 +03:00
2005-07-22 08:10:07 +04:00
user_info - > password_state = AUTH_PASSWORD_RESPONSE ;
2009-12-30 19:57:54 +03:00
user_info - > password . response . lanman = ntlmssp_state - > lm_resp ;
user_info - > password . response . lanman . data = talloc_steal ( user_info , ntlmssp_state - > lm_resp . data ) ;
user_info - > password . response . nt = ntlmssp_state - > nt_resp ;
user_info - > password . response . nt . data = talloc_steal ( user_info , ntlmssp_state - > nt_resp . data ) ;
2005-04-25 09:03:50 +04:00
2009-12-29 19:56:56 +03:00
nt_status = auth_context - > check_password ( auth_context ,
gensec_ntlmssp ,
user_info ,
& gensec_ntlmssp - > server_info ) ;
2005-04-25 09:03:50 +04:00
talloc_free ( user_info ) ;
NT_STATUS_NOT_OK_RETURN ( nt_status ) ;
2009-12-29 19:56:56 +03:00
if ( gensec_ntlmssp - > server_info - > user_session_key . length ) {
2009-12-29 18:02:00 +03:00
DEBUG ( 10 , ( " Got NT session key of length %u \n " ,
2009-12-29 19:56:56 +03:00
( unsigned ) gensec_ntlmssp - > server_info - > user_session_key . length ) ) ;
* user_session_key = gensec_ntlmssp - > server_info - > user_session_key ;
2010-09-16 08:37:20 +04:00
talloc_steal ( mem_ctx , user_session_key - > data ) ;
gensec_ntlmssp - > server_info - > user_session_key = data_blob_null ;
2005-04-25 09:03:50 +04:00
}
2009-12-29 19:56:56 +03:00
if ( gensec_ntlmssp - > server_info - > lm_session_key . length ) {
2009-12-29 18:02:00 +03:00
DEBUG ( 10 , ( " Got LM session key of length %u \n " ,
2009-12-29 19:56:56 +03:00
( unsigned ) gensec_ntlmssp - > server_info - > lm_session_key . length ) ) ;
* lm_session_key = gensec_ntlmssp - > server_info - > lm_session_key ;
2010-09-16 08:37:20 +04:00
talloc_steal ( mem_ctx , lm_session_key - > data ) ;
gensec_ntlmssp - > server_info - > lm_session_key = data_blob_null ;
2005-04-25 09:03:50 +04:00
}
return nt_status ;
}
/**
* Return the credentials of a logged on user , including session keys
* etc .
*
* Only valid after a successful authentication
*
* May only be called once per authentication .
*
*/
NTSTATUS gensec_ntlmssp_session_info ( struct gensec_security * gensec_security ,
struct auth_session_info * * session_info )
{
NTSTATUS nt_status ;
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context * gensec_ntlmssp =
2009-12-30 10:23:13 +03:00
talloc_get_type_abort ( gensec_security - > private_data ,
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context ) ;
2009-12-30 19:57:54 +03:00
struct ntlmssp_state * ntlmssp_state = gensec_ntlmssp - > ntlmssp_state ;
2009-12-29 19:56:56 +03:00
2010-04-13 06:00:06 +04:00
nt_status = gensec_generate_session_info ( ntlmssp_state ,
gensec_security ,
gensec_ntlmssp - > server_info ,
session_info ) ;
2005-04-25 09:03:50 +04:00
NT_STATUS_NOT_OK_RETURN ( nt_status ) ;
( * session_info ) - > session_key = data_blob_talloc ( * session_info ,
2009-12-30 19:57:54 +03:00
ntlmssp_state - > session_key . data ,
ntlmssp_state - > session_key . length ) ;
2005-04-25 14:33:00 +04:00
return NT_STATUS_OK ;
}
/**
* Start NTLMSSP on the server side
*
*/
NTSTATUS gensec_ntlmssp_server_start ( struct gensec_security * gensec_security )
{
NTSTATUS nt_status ;
2009-12-30 19:57:54 +03:00
struct ntlmssp_state * ntlmssp_state ;
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context * gensec_ntlmssp ;
2005-04-25 14:33:00 +04:00
nt_status = gensec_ntlmssp_start ( gensec_security ) ;
NT_STATUS_NOT_OK_RETURN ( nt_status ) ;
2009-12-30 10:23:13 +03:00
gensec_ntlmssp = talloc_get_type_abort ( gensec_security - > private_data ,
2009-12-29 19:56:56 +03:00
struct gensec_ntlmssp_context ) ;
2009-12-30 19:57:54 +03:00
ntlmssp_state = gensec_ntlmssp - > ntlmssp_state ;
2009-12-29 19:56:56 +03:00
2009-12-30 19:57:54 +03:00
ntlmssp_state - > role = NTLMSSP_SERVER ;
2005-04-25 14:33:00 +04:00
2009-12-30 19:57:54 +03:00
ntlmssp_state - > expected_state = NTLMSSP_NEGOTIATE ;
2005-04-25 14:33:00 +04:00
2010-07-16 08:32:42 +04:00
ntlmssp_state - > allow_lm_key = ( lpcfg_lanman_auth ( gensec_security - > settings - > lp_ctx )
2008-11-02 04:05:48 +03:00
& & gensec_setting_bool ( gensec_security - > settings , " ntlmssp_server " , " allow_lm_key " , false ) ) ;
2005-04-25 14:33:00 +04:00
2009-12-30 19:57:54 +03:00
ntlmssp_state - > neg_flags =
2009-08-25 14:12:59 +04:00
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_VERSION ;
2005-04-25 14:33:00 +04:00
2009-12-30 19:57:54 +03:00
ntlmssp_state - > lm_resp = data_blob ( NULL , 0 ) ;
ntlmssp_state - > nt_resp = data_blob ( NULL , 0 ) ;
2005-04-25 14:58:46 +04:00
2008-11-02 04:05:48 +03:00
if ( gensec_setting_bool ( gensec_security - > settings , " ntlmssp_server " , " 128bit " , true ) ) {
2009-12-30 19:57:54 +03:00
ntlmssp_state - > neg_flags | = NTLMSSP_NEGOTIATE_128 ;
2005-04-25 14:33:00 +04:00
}
2008-11-02 04:05:48 +03:00
if ( gensec_setting_bool ( gensec_security - > settings , " ntlmssp_server " , " 56bit " , true ) ) {
2009-12-30 19:57:54 +03:00
ntlmssp_state - > neg_flags | = NTLMSSP_NEGOTIATE_56 ;
2006-07-12 04:02:50 +04:00
}
2008-11-02 04:05:48 +03:00
if ( gensec_setting_bool ( gensec_security - > settings , " ntlmssp_server " , " keyexchange " , true ) ) {
2009-12-30 19:57:54 +03:00
ntlmssp_state - > neg_flags | = NTLMSSP_NEGOTIATE_KEY_EXCH ;
2005-04-25 14:33:00 +04:00
}
2008-11-02 04:05:48 +03:00
if ( gensec_setting_bool ( gensec_security - > settings , " ntlmssp_server " , " alwayssign " , true ) ) {
2009-12-30 19:57:54 +03:00
ntlmssp_state - > neg_flags | = NTLMSSP_NEGOTIATE_ALWAYS_SIGN ;
2006-11-20 23:58:00 +03:00
}
2008-11-02 04:05:48 +03:00
if ( gensec_setting_bool ( gensec_security - > settings , " ntlmssp_server " , " ntlm2 " , true ) ) {
2009-12-30 19:57:54 +03:00
ntlmssp_state - > neg_flags | = NTLMSSP_NEGOTIATE_NTLM2 ;
2005-04-25 14:33:00 +04:00
}
if ( gensec_security - > want_features & GENSEC_FEATURE_SIGN ) {
2009-12-30 19:57:54 +03:00
ntlmssp_state - > neg_flags | = NTLMSSP_NEGOTIATE_SIGN ;
2005-04-25 14:33:00 +04:00
}
if ( gensec_security - > want_features & GENSEC_FEATURE_SEAL ) {
2009-12-30 19:57:54 +03:00
ntlmssp_state - > neg_flags | = NTLMSSP_NEGOTIATE_SEAL ;
2005-04-25 14:33:00 +04:00
}
2009-12-29 19:56:56 +03:00
gensec_ntlmssp - > auth_context = gensec_security - > auth_context ;
2005-04-25 14:33:00 +04:00
2009-12-30 19:57:54 +03:00
ntlmssp_state - > get_challenge = auth_ntlmssp_get_challenge ;
ntlmssp_state - > may_set_challenge = auth_ntlmssp_may_set_challenge ;
ntlmssp_state - > set_challenge = auth_ntlmssp_set_challenge ;
ntlmssp_state - > check_password = auth_ntlmssp_check_password ;
2010-07-16 08:32:42 +04:00
if ( lpcfg_server_role ( gensec_security - > settings - > lp_ctx ) = = ROLE_STANDALONE ) {
2009-12-30 19:57:54 +03:00
ntlmssp_state - > server . is_standalone = true ;
2009-12-30 12:14:07 +03:00
} else {
2009-12-30 19:57:54 +03:00
ntlmssp_state - > server . is_standalone = false ;
2009-12-30 12:14:07 +03:00
}
2005-04-25 09:03:50 +04:00
2010-07-16 08:32:42 +04:00
ntlmssp_state - > server . netbios_name = lpcfg_netbios_name ( gensec_security - > settings - > lp_ctx ) ;
2009-12-30 17:14:38 +03:00
2010-07-16 08:32:42 +04:00
ntlmssp_state - > server . netbios_domain = lpcfg_workgroup ( gensec_security - > settings - > lp_ctx ) ;
2009-12-30 17:14:38 +03:00
{
char dnsdomname [ MAXHOSTNAMELEN ] , dnsname [ MAXHOSTNAMELEN ] ;
/* Find out the DNS domain name */
dnsdomname [ 0 ] = ' \0 ' ;
2010-07-16 08:32:42 +04:00
safe_strcpy ( dnsdomname , lpcfg_dnsdomain ( gensec_security - > settings - > lp_ctx ) , sizeof ( dnsdomname ) - 1 ) ;
2009-12-30 17:14:38 +03:00
/* Find out the DNS host name */
2009-12-30 19:57:54 +03:00
safe_strcpy ( dnsname , ntlmssp_state - > server . netbios_name , sizeof ( dnsname ) - 1 ) ;
2009-12-30 17:14:38 +03:00
if ( dnsdomname [ 0 ] ! = ' \0 ' ) {
safe_strcat ( dnsname , " . " , sizeof ( dnsname ) - 1 ) ;
safe_strcat ( dnsname , dnsdomname , sizeof ( dnsname ) - 1 ) ;
}
strlower_m ( dnsname ) ;
2009-12-30 19:57:54 +03:00
ntlmssp_state - > server . dns_name = talloc_strdup ( ntlmssp_state ,
2009-12-30 17:14:38 +03:00
dnsname ) ;
2009-12-30 19:57:54 +03:00
NT_STATUS_HAVE_NO_MEMORY ( ntlmssp_state - > server . dns_name ) ;
2009-12-30 17:14:38 +03:00
2009-12-30 19:57:54 +03:00
ntlmssp_state - > server . dns_domain = talloc_strdup ( ntlmssp_state ,
2009-12-30 17:14:38 +03:00
dnsdomname ) ;
2009-12-30 19:57:54 +03:00
NT_STATUS_HAVE_NO_MEMORY ( ntlmssp_state - > server . dns_domain ) ;
2009-12-30 17:14:38 +03:00
}
2005-04-25 09:03:50 +04:00
return NT_STATUS_OK ;
}
2005-04-25 14:33:00 +04:00