2002-11-24 11:32:03 +03:00
/*
Unix SMB / CIFS implementation .
Winbind status program .
Copyright ( C ) Tim Potter 2000 - 2002
2003-04-07 11:10:53 +04:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2003
2002-11-24 11:32:03 +03:00
Copyright ( C ) Francesco Chemolli < kinkie @ kame . usr . dsi . unimi . it > 2000
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"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_WINBIND
# define SQUID_BUFFER_SIZE 2010
2002-11-25 00:08:36 +03:00
enum squid_mode {
2003-01-16 06:29:54 +03:00
SQUID_2_4_BASIC ,
2002-11-25 00:08:36 +03:00
SQUID_2_5_BASIC ,
2003-07-29 19:00:38 +04:00
SQUID_2_5_NTLMSSP ,
2003-08-01 11:59:23 +04:00
GSS_SPNEGO ,
GSS_SPNEGO_CLIENT
2002-11-25 00:08:36 +03:00
} ;
2002-11-24 11:32:03 +03:00
extern int winbindd_fd ;
2003-04-07 11:10:53 +04:00
static const char * opt_username ;
static const char * opt_domain ;
static const char * opt_workstation ;
static const char * opt_password ;
static DATA_BLOB opt_challenge ;
static DATA_BLOB opt_lm_response ;
static DATA_BLOB opt_nt_response ;
2003-03-24 12:54:13 +03:00
static int request_lm_key ;
static int request_nt_key ;
2002-11-24 11:32:03 +03:00
static char winbind_separator ( void )
{
struct winbindd_response response ;
static BOOL got_sep ;
static char sep ;
if ( got_sep )
return sep ;
ZERO_STRUCT ( response ) ;
/* Send off request */
if ( winbindd_request ( WINBINDD_INFO , NULL , & response ) ! =
NSS_STATUS_SUCCESS ) {
d_printf ( " could not obtain winbind separator! \n " ) ;
return ' \\ ' ;
}
sep = response . data . info . winbind_separator ;
got_sep = True ;
if ( ! sep ) {
d_printf ( " winbind separator was NULL! \n " ) ;
return ' \\ ' ;
}
return sep ;
}
static const char * get_winbind_domain ( void )
{
struct winbindd_response response ;
static fstring winbind_domain ;
2003-01-16 06:29:54 +03:00
if ( * winbind_domain ) {
return winbind_domain ;
}
2002-11-24 11:32:03 +03:00
ZERO_STRUCT ( response ) ;
/* Send off request */
if ( winbindd_request ( WINBINDD_DOMAIN_NAME , NULL , & response ) ! =
NSS_STATUS_SUCCESS ) {
d_printf ( " could not obtain winbind domain name! \n " ) ;
return NULL ;
}
fstrcpy ( winbind_domain , response . data . domain_name ) ;
return winbind_domain ;
}
2003-01-16 06:29:54 +03:00
static const char * get_winbind_netbios_name ( void )
{
struct winbindd_response response ;
static fstring winbind_netbios_name ;
if ( * winbind_netbios_name ) {
return winbind_netbios_name ;
}
ZERO_STRUCT ( response ) ;
/* Send off request */
if ( winbindd_request ( WINBINDD_NETBIOS_NAME , NULL , & response ) ! =
NSS_STATUS_SUCCESS ) {
d_printf ( " could not obtain winbind netbios name! \n " ) ;
return NULL ;
}
fstrcpy ( winbind_netbios_name , response . data . netbios_name ) ;
return winbind_netbios_name ;
}
2002-11-24 11:32:03 +03:00
/* Authenticate a user with a plaintext password */
static BOOL check_plaintext_auth ( const char * user , const char * pass , BOOL stdout_diagnostics )
{
struct winbindd_request request ;
struct winbindd_response response ;
NSS_STATUS result ;
/* Send off request */
ZERO_STRUCT ( request ) ;
ZERO_STRUCT ( response ) ;
fstrcpy ( request . data . auth . user , user ) ;
fstrcpy ( request . data . auth . pass , pass ) ;
result = winbindd_request ( WINBINDD_PAM_AUTH , & request , & response ) ;
/* Display response */
if ( stdout_diagnostics ) {
if ( ( result ! = NSS_STATUS_SUCCESS ) & & ( response . data . auth . nt_status = = 0 ) ) {
d_printf ( " Reading winbind reply failed! (0x01) \n " ) ;
}
2003-04-07 11:10:53 +04:00
d_printf ( " %s: %s (0x%x) \n " ,
2002-11-24 11:32:03 +03:00
response . data . auth . nt_status_string ,
2003-04-07 11:10:53 +04:00
response . data . auth . error_string ,
2002-11-24 11:32:03 +03:00
response . data . auth . nt_status ) ;
} else {
if ( ( result ! = NSS_STATUS_SUCCESS ) & & ( response . data . auth . nt_status = = 0 ) ) {
DEBUG ( 1 , ( " Reading winbind reply failed! (0x01) \n " ) ) ;
}
2003-04-07 11:10:53 +04:00
DEBUG ( 3 , ( " %s: %s (0x%x) \n " ,
response . data . auth . nt_status_string ,
response . data . auth . error_string ,
response . data . auth . nt_status ) ) ;
2002-11-24 11:32:03 +03:00
}
return ( result = = NSS_STATUS_SUCCESS ) ;
}
2003-04-07 11:10:53 +04:00
/* authenticate a user with an encrypted username/password */
static NTSTATUS contact_winbind_auth_crap ( const char * username ,
const char * domain ,
const char * workstation ,
const DATA_BLOB * challenge ,
const DATA_BLOB * lm_response ,
const DATA_BLOB * nt_response ,
uint32 flags ,
2003-05-05 09:01:59 +04:00
uint8 lm_key [ 8 ] ,
2003-04-07 11:10:53 +04:00
uint8 nt_key [ 16 ] ,
char * * error_string )
2003-01-16 06:29:54 +03:00
{
2003-04-07 11:10:53 +04:00
NTSTATUS nt_status ;
NSS_STATUS result ;
2003-01-16 06:29:54 +03:00
struct winbindd_request request ;
struct winbindd_response response ;
2003-04-07 11:10:53 +04:00
static uint8 zeros [ 16 ] ;
2003-01-16 06:29:54 +03:00
ZERO_STRUCT ( request ) ;
ZERO_STRUCT ( response ) ;
2003-07-07 09:11:10 +04:00
request . flags = flags ;
2003-01-16 06:29:54 +03:00
2003-08-12 04:46:15 +04:00
if ( push_utf8_fstring ( request . data . auth_crap . user , username ) = = - 1 ) {
* error_string = smb_xstrdup (
" unable to create utf8 string for username " ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
if ( push_utf8_fstring ( request . data . auth_crap . domain , domain ) = = - 1 ) {
* error_string = smb_xstrdup (
" unable to create utf8 string for domain " ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
2003-04-07 11:10:53 +04:00
2003-08-12 04:46:15 +04:00
if ( push_utf8_fstring ( request . data . auth_crap . workstation ,
workstation ) = = - 1 ) {
* error_string = smb_xstrdup (
" unable to create utf8 string for workstation " ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
2003-04-07 11:10:53 +04:00
memcpy ( request . data . auth_crap . chal , challenge - > data , MIN ( challenge - > length , 8 ) ) ;
2003-01-16 06:29:54 +03:00
2003-04-07 11:10:53 +04:00
if ( lm_response & & lm_response - > length ) {
memcpy ( request . data . auth_crap . lm_resp , lm_response - > data , MIN ( lm_response - > length , sizeof ( request . data . auth_crap . lm_resp ) ) ) ;
request . data . auth_crap . lm_resp_len = lm_response - > length ;
}
if ( nt_response & & nt_response - > length ) {
memcpy ( request . data . auth_crap . nt_resp , nt_response - > data , MIN ( nt_response - > length , sizeof ( request . data . auth_crap . nt_resp ) ) ) ;
request . data . auth_crap . nt_resp_len = nt_response - > length ;
}
2003-01-16 06:29:54 +03:00
result = winbindd_request ( WINBINDD_PAM_AUTH_CRAP , & request , & response ) ;
/* Display response */
if ( ( result ! = NSS_STATUS_SUCCESS ) & & ( response . data . auth . nt_status = = 0 ) ) {
2003-04-07 11:10:53 +04:00
nt_status = NT_STATUS_UNSUCCESSFUL ;
if ( error_string )
* error_string = smb_xstrdup ( " Reading winbind reply failed! " ) ;
return nt_status ;
}
nt_status = ( NT_STATUS ( response . data . auth . nt_status ) ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
if ( error_string )
* error_string = smb_xstrdup ( response . data . auth . error_string ) ;
return nt_status ;
2003-01-16 06:29:54 +03:00
}
2003-07-07 09:11:10 +04:00
if ( ( flags & WBFLAG_PAM_LMKEY ) & & lm_key
2003-04-07 11:10:53 +04:00
& & ( memcmp ( zeros , response . data . auth . first_8_lm_hash ,
sizeof ( response . data . auth . first_8_lm_hash ) ) ! = 0 ) ) {
memcpy ( lm_key , response . data . auth . first_8_lm_hash ,
sizeof ( response . data . auth . first_8_lm_hash ) ) ;
}
2003-07-07 09:11:10 +04:00
if ( ( flags & WBFLAG_PAM_NTKEY ) & & nt_key
2003-04-07 11:10:53 +04:00
& & ( memcmp ( zeros , response . data . auth . nt_session_key ,
sizeof ( response . data . auth . nt_session_key ) ) ! = 0 ) ) {
memcpy ( nt_key , response . data . auth . nt_session_key ,
sizeof ( response . data . auth . nt_session_key ) ) ;
}
return nt_status ;
}
static NTSTATUS winbind_pw_check ( struct ntlmssp_state * ntlmssp_state )
{
return contact_winbind_auth_crap ( ntlmssp_state - > user , ntlmssp_state - > domain ,
ntlmssp_state - > workstation ,
& ntlmssp_state - > chal ,
& ntlmssp_state - > lm_resp ,
& ntlmssp_state - > nt_resp ,
0 ,
NULL ,
NULL ,
NULL ) ;
2003-01-16 06:29:54 +03:00
}
static void manage_squid_ntlmssp_request ( enum squid_mode squid_mode ,
char * buf , int length )
{
2003-03-24 12:54:13 +03:00
static NTLMSSP_STATE * ntlmssp_state = NULL ;
2003-01-16 06:29:54 +03:00
DATA_BLOB request , reply ;
NTSTATUS nt_status ;
2003-03-24 12:54:13 +03:00
if ( strlen ( buf ) < 2 ) {
DEBUG ( 1 , ( " NTLMSSP query [%s] invalid " , buf ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
if ( strlen ( buf ) > 3 ) {
request = base64_decode_data_blob ( buf + 3 ) ;
} else if ( strcmp ( buf , " YR " ) = = 0 ) {
request = data_blob ( NULL , 0 ) ;
if ( ntlmssp_state )
ntlmssp_server_end ( & ntlmssp_state ) ;
} else {
DEBUG ( 1 , ( " NTLMSSP query [%s] invalid " , buf ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
2003-01-16 06:29:54 +03:00
if ( ! ntlmssp_state ) {
ntlmssp_server_start ( & ntlmssp_state ) ;
ntlmssp_state - > check_password = winbind_pw_check ;
ntlmssp_state - > get_domain = get_winbind_domain ;
ntlmssp_state - > get_global_myname = get_winbind_netbios_name ;
}
2003-03-24 12:54:13 +03:00
DEBUG ( 10 , ( " got NTLMSSP packet: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 10 , ( const char * ) request . data , request . length ) ;
2003-01-16 06:29:54 +03:00
nt_status = ntlmssp_server_update ( ntlmssp_state , request , & reply ) ;
if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
char * reply_base64 = base64_encode_data_blob ( reply ) ;
x_fprintf ( x_stdout , " TT %s \n " , reply_base64 ) ;
SAFE_FREE ( reply_base64 ) ;
data_blob_free ( & reply ) ;
2003-03-24 12:54:13 +03:00
DEBUG ( 10 , ( " NTLMSSP challenge \n " ) ) ;
2003-01-16 06:29:54 +03:00
} else if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
x_fprintf ( x_stdout , " NA %s \n " , nt_errstr ( nt_status ) ) ;
2003-03-24 12:54:13 +03:00
DEBUG ( 10 , ( " NTLMSSP %s \n " , nt_errstr ( nt_status ) ) ) ;
2003-01-16 06:29:54 +03:00
} else {
x_fprintf ( x_stdout , " AF %s \\ %s \n " , ntlmssp_state - > domain , ntlmssp_state - > user ) ;
2003-03-24 12:54:13 +03:00
DEBUG ( 10 , ( " NTLMSSP OK! \n " ) ) ;
2003-01-16 06:29:54 +03:00
}
data_blob_free ( & request ) ;
}
static void manage_squid_basic_request ( enum squid_mode squid_mode ,
char * buf , int length )
{
char * user , * pass ;
user = buf ;
pass = memchr ( buf , ' ' , length ) ;
if ( ! pass ) {
DEBUG ( 2 , ( " Password not found. Denying access \n " ) ) ;
x_fprintf ( x_stderr , " ERR \n " ) ;
return ;
}
* pass = ' \0 ' ;
pass + + ;
if ( squid_mode = = SQUID_2_5_BASIC ) {
rfc1738_unescape ( user ) ;
rfc1738_unescape ( pass ) ;
}
if ( check_plaintext_auth ( user , pass , False ) ) {
x_fprintf ( x_stdout , " OK \n " ) ;
} else {
x_fprintf ( x_stdout , " ERR \n " ) ;
}
}
2003-07-29 19:00:38 +04:00
static void offer_gss_spnego_mechs ( void ) {
DATA_BLOB token ;
SPNEGO_DATA spnego ;
ssize_t len ;
char * reply_base64 ;
2003-08-15 06:57:59 +04:00
pstring principal ;
pstring myname_lower ;
2003-07-29 19:00:38 +04:00
ZERO_STRUCT ( spnego ) ;
2003-07-31 14:24:10 +04:00
2003-08-15 06:57:59 +04:00
pstrcpy ( myname_lower , global_myname ( ) ) ;
strlower_m ( myname_lower ) ;
pstr_sprintf ( principal , " %s$@%s " , myname_lower , lp_realm ( ) ) ;
2003-07-31 14:24:10 +04:00
/* Server negTokenInit (mech offerings) */
2003-07-29 19:00:38 +04:00
spnego . type = SPNEGO_NEG_TOKEN_INIT ;
2003-08-15 06:57:59 +04:00
spnego . negTokenInit . mechTypes = smb_xmalloc ( sizeof ( char * ) * 3 ) ;
# ifdef HAVE_KRB5
spnego . negTokenInit . mechTypes [ 0 ] = smb_xstrdup ( OID_KERBEROS5_OLD ) ;
spnego . negTokenInit . mechTypes [ 1 ] = smb_xstrdup ( OID_NTLMSSP ) ;
spnego . negTokenInit . mechTypes [ 2 ] = NULL ;
# else
2003-07-31 14:24:10 +04:00
spnego . negTokenInit . mechTypes [ 0 ] = smb_xstrdup ( OID_NTLMSSP ) ;
spnego . negTokenInit . mechTypes [ 1 ] = NULL ;
2003-08-15 06:57:59 +04:00
# endif
2003-07-29 19:00:38 +04:00
2003-08-15 06:57:59 +04:00
spnego . negTokenInit . mechListMIC = data_blob ( principal ,
strlen ( principal ) ) ;
2003-07-29 19:00:38 +04:00
len = write_spnego_data ( & token , & spnego ) ;
2003-07-31 14:24:10 +04:00
free_spnego_data ( & spnego ) ;
2003-07-29 19:00:38 +04:00
if ( len = = - 1 ) {
DEBUG ( 1 , ( " Could not write SPNEGO data blob \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
reply_base64 = base64_encode_data_blob ( token ) ;
2003-08-01 11:59:23 +04:00
x_fprintf ( x_stdout , " TT %s * \n " , reply_base64 ) ;
2003-07-29 19:00:38 +04:00
SAFE_FREE ( reply_base64 ) ;
data_blob_free ( & token ) ;
DEBUG ( 10 , ( " sent SPNEGO negTokenInit \n " ) ) ;
return ;
}
static void manage_gss_spnego_request ( enum squid_mode squid_mode ,
char * buf , int length )
{
static NTLMSSP_STATE * ntlmssp_state = NULL ;
2003-08-12 05:54:26 +04:00
SPNEGO_DATA request , response ;
DATA_BLOB token ;
2003-07-29 19:00:38 +04:00
NTSTATUS status ;
ssize_t len ;
2003-08-12 23:00:08 +04:00
char * user = NULL ;
char * domain = NULL ;
2003-08-01 11:59:23 +04:00
const char * reply_code ;
char * reply_base64 ;
pstring reply_argument ;
2003-07-29 19:00:38 +04:00
if ( strlen ( buf ) < 2 ) {
if ( ntlmssp_state ! = NULL ) {
DEBUG ( 1 , ( " Request for initial SPNEGO request where "
" we already have a state \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
DEBUG ( 1 , ( " NTLMSSP query [%s] invalid " , buf ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
if ( ( strlen ( buf ) = = 2 ) & & ( strcmp ( buf , " YR " ) = = 0 ) ) {
/* Initial request, get the negTokenInit offering
mechanisms */
offer_gss_spnego_mechs ( ) ;
return ;
}
/* All subsequent requests are "KK" (Knock, Knock ;)) and have
a blob . This might be negTokenInit or negTokenTarg */
if ( ( strlen ( buf ) < = 3 ) | | ( strncmp ( buf , " KK " , 2 ) ! = 0 ) ) {
DEBUG ( 1 , ( " GSS-SPNEGO query [%s] invalid \n " , buf ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
2003-08-12 05:54:26 +04:00
token = base64_decode_data_blob ( buf + 3 ) ;
len = read_spnego_data ( token , & request ) ;
data_blob_free ( & token ) ;
2003-07-29 19:00:38 +04:00
if ( len = = - 1 ) {
DEBUG ( 1 , ( " GSS-SPNEGO query [%s] invalid " , buf ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
2003-08-12 05:54:26 +04:00
if ( request . type = = SPNEGO_NEG_TOKEN_INIT ) {
2003-07-29 19:00:38 +04:00
/* Second request from Client. This is where the
client offers its mechanism to use . We currently
only support NTLMSSP , the decision for Kerberos
would be taken here . */
2003-08-12 05:54:26 +04:00
if ( ( request . negTokenInit . mechTypes = = NULL ) | |
( request . negTokenInit . mechTypes [ 0 ] = = NULL ) ) {
2003-07-29 19:00:38 +04:00
DEBUG ( 1 , ( " Client did not offer any mechanism " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
2003-08-12 23:00:08 +04:00
if ( strcmp ( request . negTokenInit . mechTypes [ 0 ] , OID_NTLMSSP ) = = 0 ) {
if ( request . negTokenInit . mechToken . data = = NULL ) {
DEBUG ( 1 , ( " Client did not provide NTLMSSP data \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
if ( ntlmssp_state ! = NULL ) {
DEBUG ( 1 , ( " Client wants a new NTLMSSP challenge, but "
" already got one \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
ntlmssp_server_end ( & ntlmssp_state ) ;
return ;
}
ntlmssp_server_start ( & ntlmssp_state ) ;
ntlmssp_state - > check_password = winbind_pw_check ;
ntlmssp_state - > get_domain = get_winbind_domain ;
ntlmssp_state - > get_global_myname = get_winbind_netbios_name ;
DEBUG ( 10 , ( " got NTLMSSP packet: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 10 , ( const char * ) request . negTokenInit . mechToken . data ,
2003-08-12 23:00:08 +04:00
request . negTokenInit . mechToken . length ) ;
2003-08-13 00:50:56 +04:00
response . type = SPNEGO_NEG_TOKEN_TARG ;
response . negTokenTarg . supportedMech = strdup ( OID_NTLMSSP ) ;
response . negTokenTarg . mechListMIC = data_blob ( NULL , 0 ) ;
2003-08-12 23:00:08 +04:00
status = ntlmssp_server_update ( ntlmssp_state ,
request . negTokenInit . mechToken ,
& response . negTokenTarg . responseToken ) ;
2003-07-29 19:00:38 +04:00
}
2003-08-15 06:57:59 +04:00
# ifdef HAVE_KRB5
if ( strcmp ( request . negTokenInit . mechTypes [ 0 ] , OID_KERBEROS5_OLD ) = = 0 ) {
char * principal ;
DATA_BLOB auth_data ;
DATA_BLOB ap_rep ;
uint8 session_key [ 16 ] ;
if ( request . negTokenInit . mechToken . data = = NULL ) {
DEBUG ( 1 , ( " Client did not provide Kerberos data \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
response . type = SPNEGO_NEG_TOKEN_TARG ;
response . negTokenTarg . supportedMech = strdup ( OID_KERBEROS5_OLD ) ;
response . negTokenTarg . mechListMIC = data_blob ( NULL , 0 ) ;
response . negTokenTarg . responseToken = data_blob ( NULL , 0 ) ;
status = ads_verify_ticket ( lp_realm ( ) ,
& request . negTokenInit . mechToken ,
& principal , & auth_data , & ap_rep ,
session_key ) ;
/* Now in "principal" we have the name we are
authenticated as . */
if ( NT_STATUS_IS_OK ( status ) ) {
domain = strchr ( principal , ' @ ' ) ;
if ( domain = = NULL ) {
DEBUG ( 1 , ( " Did not get a valid principal "
" from ads_verify_ticket \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
* domain + + = ' \0 ' ;
domain = strdup ( domain ) ;
user = strdup ( principal ) ;
data_blob_free ( & ap_rep ) ;
data_blob_free ( & auth_data ) ;
SAFE_FREE ( principal ) ;
}
}
# endif
2003-07-29 19:00:38 +04:00
} else {
2003-08-13 00:50:56 +04:00
if ( ( request . negTokenTarg . supportedMech = = NULL ) | |
( strcmp ( request . negTokenTarg . supportedMech , OID_NTLMSSP ) ! = 0 ) ) {
/* Kerberos should never send a negTokenTarg, OID_NTLMSSP
is the only one we support that sends this stuff */
DEBUG ( 1 , ( " Got a negTokenTarg for something non-NTLMSSP: %s \n " ,
request . negTokenTarg . supportedMech ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
2003-07-29 19:00:38 +04:00
2003-08-12 05:54:26 +04:00
if ( request . negTokenTarg . responseToken . data = = NULL ) {
2003-08-13 00:50:56 +04:00
DEBUG ( 1 , ( " Got a negTokenTarg without a responseToken! \n " ) ) ;
2003-07-29 19:00:38 +04:00
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
status = ntlmssp_server_update ( ntlmssp_state ,
2003-08-12 05:54:26 +04:00
request . negTokenTarg . responseToken ,
& response . negTokenTarg . responseToken ) ;
2003-08-12 23:00:08 +04:00
2003-08-13 00:50:56 +04:00
response . type = SPNEGO_NEG_TOKEN_TARG ;
response . negTokenTarg . supportedMech = strdup ( OID_NTLMSSP ) ;
response . negTokenTarg . mechListMIC = data_blob ( NULL , 0 ) ;
2003-08-12 23:00:08 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
user = strdup ( ntlmssp_state - > user ) ;
domain = strdup ( ntlmssp_state - > domain ) ;
ntlmssp_server_end ( & ntlmssp_state ) ;
}
2003-08-12 05:54:26 +04:00
}
2003-07-29 19:00:38 +04:00
2003-08-12 05:54:26 +04:00
free_spnego_data ( & request ) ;
2003-07-29 19:00:38 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
2003-08-12 05:54:26 +04:00
response . negTokenTarg . negResult = SPNEGO_ACCEPT_COMPLETED ;
2003-08-01 11:59:23 +04:00
reply_code = " AF " ;
2003-08-12 23:00:08 +04:00
pstr_sprintf ( reply_argument , " %s \\ %s " , domain , user ) ;
2003-08-01 11:59:23 +04:00
} else if ( NT_STATUS_EQUAL ( status ,
NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
2003-08-12 05:54:26 +04:00
response . negTokenTarg . negResult = SPNEGO_ACCEPT_INCOMPLETE ;
2003-08-01 11:59:23 +04:00
reply_code = " TT " ;
pstr_sprintf ( reply_argument , " * " ) ;
} else {
2003-08-12 05:54:26 +04:00
response . negTokenTarg . negResult = SPNEGO_REJECT ;
2003-08-01 11:59:23 +04:00
reply_code = " NA " ;
pstrcpy ( reply_argument , nt_errstr ( status ) ) ;
2003-07-29 19:00:38 +04:00
}
2003-08-12 23:00:08 +04:00
SAFE_FREE ( user ) ;
SAFE_FREE ( domain ) ;
2003-08-12 05:54:26 +04:00
len = write_spnego_data ( & token , & response ) ;
free_spnego_data ( & response ) ;
2003-07-29 19:00:38 +04:00
if ( len = = - 1 ) {
DEBUG ( 1 , ( " Could not write SPNEGO data blob \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
reply_base64 = base64_encode_data_blob ( token ) ;
2003-08-01 11:59:23 +04:00
x_fprintf ( x_stdout , " %s %s %s \n " ,
reply_code , reply_base64 , reply_argument ) ;
2003-07-29 19:00:38 +04:00
SAFE_FREE ( reply_base64 ) ;
data_blob_free ( & token ) ;
return ;
}
2003-08-01 11:59:23 +04:00
static NTLMSSP_CLIENT_STATE * client_ntlmssp_state = NULL ;
2003-08-04 17:10:43 +04:00
static BOOL manage_client_ntlmssp_init ( SPNEGO_DATA spnego )
2003-08-01 11:59:23 +04:00
{
NTSTATUS status ;
DATA_BLOB null_blob = data_blob ( NULL , 0 ) ;
DATA_BLOB to_server ;
char * to_server_base64 ;
const char * my_mechs [ ] = { OID_NTLMSSP , NULL } ;
DEBUG ( 10 , ( " Got spnego negTokenInit with NTLMSSP \n " ) ) ;
if ( client_ntlmssp_state ! = NULL ) {
DEBUG ( 1 , ( " Request for initial SPNEGO request where "
" we already have a state \n " ) ) ;
2003-08-04 17:10:43 +04:00
return False ;
2003-08-01 11:59:23 +04:00
}
if ( ( opt_username = = NULL ) | | ( opt_domain = = NULL ) ) {
DEBUG ( 1 , ( " Need username and domain for NTLMSSP \n " ) ) ;
2003-08-04 17:10:43 +04:00
return False ;
2003-08-01 11:59:23 +04:00
}
if ( opt_password = = NULL ) {
/* Request a password from the calling process. After
sending it , the calling process should retry with
the negTokenInit . */
DEBUG ( 10 , ( " Requesting password \n " ) ) ;
x_fprintf ( x_stdout , " PW \n " ) ;
2003-08-04 17:10:43 +04:00
return True ;
2003-08-01 11:59:23 +04:00
}
status = ntlmssp_client_start ( & client_ntlmssp_state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Could not start NTLMSSP client: %s \n " ,
nt_errstr ( status ) ) ) ;
ntlmssp_client_end ( & client_ntlmssp_state ) ;
2003-08-04 17:10:43 +04:00
return False ;
2003-08-01 11:59:23 +04:00
}
status = ntlmssp_set_username ( client_ntlmssp_state , opt_username ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Could not set username: %s \n " ,
nt_errstr ( status ) ) ) ;
ntlmssp_client_end ( & client_ntlmssp_state ) ;
2003-08-04 17:10:43 +04:00
return False ;
2003-08-01 11:59:23 +04:00
}
status = ntlmssp_set_domain ( client_ntlmssp_state , opt_domain ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Could not set domain: %s \n " ,
nt_errstr ( status ) ) ) ;
ntlmssp_client_end ( & client_ntlmssp_state ) ;
2003-08-04 17:10:43 +04:00
return False ;
2003-08-01 11:59:23 +04:00
}
status = ntlmssp_set_password ( client_ntlmssp_state , opt_password ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Could not set password: %s \n " ,
nt_errstr ( status ) ) ) ;
ntlmssp_client_end ( & client_ntlmssp_state ) ;
2003-08-04 17:10:43 +04:00
return False ;
2003-08-01 11:59:23 +04:00
}
spnego . type = SPNEGO_NEG_TOKEN_INIT ;
spnego . negTokenInit . mechTypes = my_mechs ;
spnego . negTokenInit . reqFlags = 0 ;
spnego . negTokenInit . mechListMIC = null_blob ;
status = ntlmssp_client_update ( client_ntlmssp_state , null_blob ,
& spnego . negTokenInit . mechToken ) ;
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
DEBUG ( 1 , ( " Expected MORE_PROCESSING_REQUIRED, got: %s \n " ,
nt_errstr ( status ) ) ) ;
ntlmssp_client_end ( & client_ntlmssp_state ) ;
2003-08-04 17:10:43 +04:00
return False ;
2003-08-01 11:59:23 +04:00
}
write_spnego_data ( & to_server , & spnego ) ;
data_blob_free ( & spnego . negTokenInit . mechToken ) ;
to_server_base64 = base64_encode_data_blob ( to_server ) ;
data_blob_free ( & to_server ) ;
x_fprintf ( x_stdout , " KK %s \n " , to_server_base64 ) ;
SAFE_FREE ( to_server_base64 ) ;
2003-08-04 17:10:43 +04:00
return True ;
2003-08-01 11:59:23 +04:00
}
static void manage_client_ntlmssp_targ ( SPNEGO_DATA spnego )
{
NTSTATUS status ;
DATA_BLOB null_blob = data_blob ( NULL , 0 ) ;
DATA_BLOB request ;
DATA_BLOB to_server ;
char * to_server_base64 ;
DEBUG ( 10 , ( " Got spnego negTokenTarg with NTLMSSP \n " ) ) ;
if ( client_ntlmssp_state = = NULL ) {
DEBUG ( 1 , ( " Got NTLMSSP tArg without a client state \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
ntlmssp_client_end ( & client_ntlmssp_state ) ;
return ;
}
if ( spnego . negTokenTarg . negResult = = SPNEGO_REJECT ) {
x_fprintf ( x_stdout , " NA \n " ) ;
ntlmssp_client_end ( & client_ntlmssp_state ) ;
return ;
}
if ( spnego . negTokenTarg . negResult = = SPNEGO_ACCEPT_COMPLETED ) {
x_fprintf ( x_stdout , " AF \n " ) ;
ntlmssp_client_end ( & client_ntlmssp_state ) ;
return ;
}
status = ntlmssp_client_update ( client_ntlmssp_state ,
spnego . negTokenTarg . responseToken ,
& request ) ;
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
DEBUG ( 1 , ( " Expected MORE_PROCESSING_REQUIRED from "
" ntlmssp_client_update, got: %s \n " ,
nt_errstr ( status ) ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
data_blob_free ( & request ) ;
ntlmssp_client_end ( & client_ntlmssp_state ) ;
return ;
}
spnego . type = SPNEGO_NEG_TOKEN_TARG ;
spnego . negTokenTarg . negResult = SPNEGO_ACCEPT_INCOMPLETE ;
spnego . negTokenTarg . supportedMech = OID_NTLMSSP ;
spnego . negTokenTarg . responseToken = request ;
spnego . negTokenTarg . mechListMIC = null_blob ;
write_spnego_data ( & to_server , & spnego ) ;
data_blob_free ( & request ) ;
to_server_base64 = base64_encode_data_blob ( to_server ) ;
data_blob_free ( & to_server ) ;
x_fprintf ( x_stdout , " KK %s \n " , to_server_base64 ) ;
SAFE_FREE ( to_server_base64 ) ;
return ;
}
2003-08-14 21:21:22 +04:00
# ifdef HAVE_KRB5
2003-08-04 17:10:43 +04:00
static BOOL manage_client_krb5_init ( SPNEGO_DATA spnego )
2003-08-01 11:59:23 +04:00
{
2003-08-13 00:50:56 +04:00
char * principal ;
DATA_BLOB tkt , to_server ;
unsigned char session_key_krb5 [ 16 ] ;
SPNEGO_DATA reply ;
char * reply_base64 ;
const char * my_mechs [ ] = { OID_KERBEROS5_OLD , NULL } ;
ssize_t len ;
if ( ( spnego . negTokenInit . mechListMIC . data = = NULL ) | |
( spnego . negTokenInit . mechListMIC . length = = 0 ) ) {
DEBUG ( 1 , ( " Did not get a principal for krb5 \n " ) ) ;
return False ;
}
principal = malloc ( spnego . negTokenInit . mechListMIC . length + 1 ) ;
if ( principal = = NULL ) {
DEBUG ( 1 , ( " Could not malloc principal \n " ) ) ;
return False ;
}
memcpy ( principal , spnego . negTokenInit . mechListMIC . data ,
spnego . negTokenInit . mechListMIC . length ) ;
principal [ spnego . negTokenInit . mechListMIC . length ] = ' \0 ' ;
tkt = cli_krb5_get_ticket ( principal , 0 , session_key_krb5 ) ;
if ( tkt . data = = NULL ) {
pstring user ;
/* Let's try to first get the TGT, for that we need a
password . */
if ( opt_password = = NULL ) {
DEBUG ( 10 , ( " Requesting password \n " ) ) ;
x_fprintf ( x_stdout , " PW \n " ) ;
return True ;
}
pstr_sprintf ( user , " %s@%s " , opt_username , opt_domain ) ;
if ( kerberos_kinit_password ( user , opt_password , 0 ) ! = 0 ) {
DEBUG ( 10 , ( " Requesting TGT failed \n " ) ) ;
x_fprintf ( x_stdout , " NA \n " ) ;
return True ;
}
tkt = cli_krb5_get_ticket ( principal , 0 , session_key_krb5 ) ;
}
ZERO_STRUCT ( reply ) ;
reply . type = SPNEGO_NEG_TOKEN_INIT ;
reply . negTokenInit . mechTypes = my_mechs ;
reply . negTokenInit . reqFlags = 0 ;
reply . negTokenInit . mechToken = tkt ;
reply . negTokenInit . mechListMIC = data_blob ( NULL , 0 ) ;
len = write_spnego_data ( & to_server , & reply ) ;
data_blob_free ( & tkt ) ;
if ( len = = - 1 ) {
DEBUG ( 1 , ( " Could not write SPNEGO data blob \n " ) ) ;
return False ;
}
reply_base64 = base64_encode_data_blob ( to_server ) ;
x_fprintf ( x_stdout , " KK %s * \n " , reply_base64 ) ;
SAFE_FREE ( reply_base64 ) ;
data_blob_free ( & to_server ) ;
DEBUG ( 10 , ( " sent GSS-SPNEGO KERBEROS5 negTokenInit \n " ) ) ;
return True ;
2003-08-01 11:59:23 +04:00
}
static void manage_client_krb5_targ ( SPNEGO_DATA spnego )
{
2003-08-13 00:50:56 +04:00
switch ( spnego . negTokenTarg . negResult ) {
case SPNEGO_ACCEPT_INCOMPLETE :
DEBUG ( 1 , ( " Got a Kerberos negTokenTarg with ACCEPT_INCOMPLETE \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
break ;
case SPNEGO_ACCEPT_COMPLETED :
DEBUG ( 10 , ( " Accept completed \n " ) ) ;
x_fprintf ( x_stdout , " AF \n " ) ;
break ;
case SPNEGO_REJECT :
DEBUG ( 10 , ( " Rejected \n " ) ) ;
x_fprintf ( x_stdout , " NA \n " ) ;
break ;
default :
DEBUG ( 1 , ( " Got an invalid negTokenTarg \n " ) ) ;
x_fprintf ( x_stdout , " AF \n " ) ;
}
2003-08-01 11:59:23 +04:00
}
2003-08-14 21:21:22 +04:00
# endif
2003-08-01 11:59:23 +04:00
static void manage_gss_spnego_client_request ( enum squid_mode squid_mode ,
char * buf , int length )
{
DATA_BLOB request ;
SPNEGO_DATA spnego ;
ssize_t len ;
if ( strlen ( buf ) < = 3 ) {
DEBUG ( 1 , ( " SPNEGO query [%s] too short \n " , buf ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
request = base64_decode_data_blob ( buf + 3 ) ;
if ( strncmp ( buf , " PW " , 3 ) = = 0 ) {
/* We asked for a password and obviously got it :-) */
2003-08-15 08:42:05 +04:00
opt_password = strndup ( ( const char * ) request . data , request . length ) ;
2003-08-01 11:59:23 +04:00
if ( opt_password = = NULL ) {
DEBUG ( 1 , ( " Out of memory \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
data_blob_free ( & request ) ;
return ;
}
x_fprintf ( x_stdout , " OK \n " ) ;
data_blob_free ( & request ) ;
return ;
}
if ( ( strncmp ( buf , " TT " , 3 ) ! = 0 ) & &
( strncmp ( buf , " AF " , 3 ) ! = 0 ) & &
( strncmp ( buf , " NA " , 3 ) ! = 0 ) ) {
DEBUG ( 1 , ( " SPNEGO request [%s] invalid \n " , buf ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
data_blob_free ( & request ) ;
return ;
}
/* So we got a server challenge to generate a SPNEGO
client - to - server request . . . */
len = read_spnego_data ( request , & spnego ) ;
data_blob_free ( & request ) ;
if ( len = = - 1 ) {
DEBUG ( 1 , ( " Could not read SPNEGO data for [%s] \n " , buf ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
if ( spnego . type = = SPNEGO_NEG_TOKEN_INIT ) {
/* The server offers a list of mechanisms */
const char * * mechType = spnego . negTokenInit . mechTypes ;
while ( * mechType ! = NULL ) {
2003-08-14 21:21:22 +04:00
# ifdef HAVE_KRB5
2003-08-04 17:10:43 +04:00
if ( ( strcmp ( * mechType , OID_KERBEROS5_OLD ) = = 0 ) | |
( strcmp ( * mechType , OID_KERBEROS5 ) = = 0 ) ) {
if ( manage_client_krb5_init ( spnego ) )
goto out ;
2003-08-01 11:59:23 +04:00
}
2003-08-14 21:21:22 +04:00
# endif
2003-08-01 11:59:23 +04:00
2003-08-04 17:10:43 +04:00
if ( strcmp ( * mechType , OID_NTLMSSP ) = = 0 ) {
if ( manage_client_ntlmssp_init ( spnego ) )
goto out ;
2003-08-01 11:59:23 +04:00
}
mechType + + ;
}
DEBUG ( 1 , ( " Server offered no compatible mechanism \n " ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
}
if ( spnego . type = = SPNEGO_NEG_TOKEN_TARG ) {
2003-08-04 17:10:43 +04:00
if ( spnego . negTokenTarg . supportedMech = = NULL ) {
/* On accept/reject Windows does not send the
mechanism anymore . Handle that here and
shut down the mechanisms . */
switch ( spnego . negTokenTarg . negResult ) {
case SPNEGO_ACCEPT_COMPLETED :
x_fprintf ( x_stdout , " AF \n " ) ;
break ;
case SPNEGO_REJECT :
x_fprintf ( x_stdout , " NA \n " ) ;
break ;
default :
DEBUG ( 1 , ( " Got a negTokenTarg with no mech and an "
" unknown negResult: %d \n " ,
spnego . negTokenTarg . negResult ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
}
ntlmssp_client_end ( & client_ntlmssp_state ) ;
goto out ;
}
2003-08-01 11:59:23 +04:00
if ( strcmp ( spnego . negTokenTarg . supportedMech ,
OID_NTLMSSP ) = = 0 ) {
manage_client_ntlmssp_targ ( spnego ) ;
goto out ;
}
2003-08-14 21:21:22 +04:00
# if HAVE_KRB5
2003-08-01 11:59:23 +04:00
if ( strcmp ( spnego . negTokenTarg . supportedMech ,
OID_KERBEROS5_OLD ) = = 0 ) {
manage_client_krb5_targ ( spnego ) ;
goto out ;
}
2003-08-14 21:21:22 +04:00
# endif
2003-08-01 11:59:23 +04:00
}
DEBUG ( 1 , ( " Got an SPNEGO token I could not handle [%s]! \n " , buf ) ) ;
x_fprintf ( x_stdout , " BH \n " ) ;
return ;
out :
free_spnego_data ( & spnego ) ;
return ;
}
2003-01-16 06:29:54 +03:00
static void manage_squid_request ( enum squid_mode squid_mode )
2002-11-24 11:32:03 +03:00
{
char buf [ SQUID_BUFFER_SIZE + 1 ] ;
int length ;
2003-01-16 06:29:54 +03:00
char * c ;
2002-11-24 11:32:03 +03:00
static BOOL err ;
2003-03-24 12:54:13 +03:00
/* this is not a typo - x_fgets doesn't work too well under squid */
if ( fgets ( buf , sizeof ( buf ) - 1 , stdin ) = = NULL ) {
DEBUG ( 1 , ( " fgets() failed! dying..... errno=%d (%s) \n " , ferror ( stdin ) ,
strerror ( ferror ( stdin ) ) ) ) ;
2002-11-24 11:32:03 +03:00
exit ( 1 ) ; /* BIIG buffer */
}
c = memchr ( buf , ' \n ' , sizeof ( buf ) - 1 ) ;
if ( c ) {
* c = ' \0 ' ;
length = c - buf ;
} else {
err = 1 ;
return ;
}
if ( err ) {
DEBUG ( 2 , ( " Oversized message \n " ) ) ;
x_fprintf ( x_stderr , " ERR \n " ) ;
err = 0 ;
return ;
}
DEBUG ( 10 , ( " Got '%s' from squid (length: %d). \n " , buf , length ) ) ;
if ( buf [ 0 ] = = ' \0 ' ) {
DEBUG ( 2 , ( " Invalid Request \n " ) ) ;
x_fprintf ( x_stderr , " ERR \n " ) ;
return ;
}
2002-11-25 00:08:36 +03:00
2003-01-16 06:29:54 +03:00
if ( squid_mode = = SQUID_2_5_BASIC | | squid_mode = = SQUID_2_4_BASIC ) {
manage_squid_basic_request ( squid_mode , buf , length ) ;
} else if ( squid_mode = = SQUID_2_5_NTLMSSP ) {
manage_squid_ntlmssp_request ( squid_mode , buf , length ) ;
2003-07-29 19:00:38 +04:00
} else if ( squid_mode = = GSS_SPNEGO ) {
manage_gss_spnego_request ( squid_mode , buf , length ) ;
2003-08-01 11:59:23 +04:00
} else if ( squid_mode = = GSS_SPNEGO_CLIENT ) {
manage_gss_spnego_client_request ( squid_mode , buf , length ) ;
2002-11-24 11:32:03 +03:00
}
}
2003-01-16 06:29:54 +03:00
static void squid_stream ( enum squid_mode squid_mode ) {
2002-11-24 11:32:03 +03:00
/* initialize FDescs */
x_setbuf ( x_stdout , NULL ) ;
x_setbuf ( x_stderr , NULL ) ;
while ( 1 ) {
2003-01-16 06:29:54 +03:00
manage_squid_request ( squid_mode ) ;
2002-11-24 11:32:03 +03:00
}
}
/* Authenticate a user with a challenge/response */
static BOOL check_auth_crap ( void )
{
2003-04-07 11:10:53 +04:00
NTSTATUS nt_status ;
uint32 flags = 0 ;
char lm_key [ 8 ] ;
char nt_key [ 16 ] ;
char * hex_lm_key ;
char * hex_nt_key ;
char * error_string ;
2003-03-24 12:54:13 +03:00
static uint8 zeros [ 16 ] ;
2003-05-12 05:49:03 +04:00
x_setbuf ( x_stdout , NULL ) ;
2003-03-24 12:54:13 +03:00
if ( request_lm_key )
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_LMKEY ;
2003-03-24 12:54:13 +03:00
if ( request_nt_key )
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_NTKEY ;
2003-04-07 11:10:53 +04:00
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& opt_challenge ,
& opt_lm_response ,
& opt_nt_response ,
flags ,
2003-08-15 08:42:05 +04:00
( unsigned char * ) lm_key ,
( unsigned char * ) nt_key ,
2003-04-07 11:10:53 +04:00
& error_string ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2003-05-12 04:18:45 +04:00
x_fprintf ( x_stdout , " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
2003-04-07 11:10:53 +04:00
SAFE_FREE ( error_string ) ;
return False ;
}
2003-03-24 12:54:13 +03:00
2003-04-07 11:10:53 +04:00
if ( request_lm_key
& & ( memcmp ( zeros , lm_key ,
sizeof ( lm_key ) ) ! = 0 ) ) {
2003-08-15 08:42:05 +04:00
hex_encode ( ( const unsigned char * ) lm_key ,
2003-04-07 11:10:53 +04:00
sizeof ( lm_key ) ,
& hex_lm_key ) ;
2003-05-12 04:18:45 +04:00
x_fprintf ( x_stdout , " LM_KEY: %s \n " , hex_lm_key ) ;
2003-04-07 11:10:53 +04:00
SAFE_FREE ( hex_lm_key ) ;
}
if ( request_nt_key
& & ( memcmp ( zeros , nt_key ,
sizeof ( nt_key ) ) ! = 0 ) ) {
2003-08-15 08:42:05 +04:00
hex_encode ( ( const unsigned char * ) nt_key ,
2003-04-07 11:10:53 +04:00
sizeof ( nt_key ) ,
& hex_nt_key ) ;
2003-05-12 04:18:45 +04:00
x_fprintf ( x_stdout , " NT_KEY: %s \n " , hex_nt_key ) ;
2003-04-07 11:10:53 +04:00
SAFE_FREE ( hex_nt_key ) ;
}
2002-11-24 11:32:03 +03:00
2003-04-07 11:10:53 +04:00
return True ;
}
/*
Authenticate a user with a challenge / response , checking session key
and valid authentication types
*/
2003-04-30 18:01:16 +04:00
static DATA_BLOB get_challenge ( void )
2003-04-07 11:10:53 +04:00
{
static DATA_BLOB chal ;
if ( opt_challenge . length )
return opt_challenge ;
2002-11-24 11:32:03 +03:00
2003-04-07 11:10:53 +04:00
chal = data_blob ( NULL , 8 ) ;
2002-11-24 11:32:03 +03:00
2003-04-07 11:10:53 +04:00
generate_random_buffer ( chal . data , chal . length , False ) ;
return chal ;
}
2002-11-24 11:32:03 +03:00
2003-05-05 10:33:58 +04:00
/*
* Test LM authentication , no NT response supplied
*/
2003-04-07 11:10:53 +04:00
static BOOL test_lm ( void )
{
NTSTATUS nt_status ;
uint32 flags = 0 ;
DATA_BLOB lm_response = data_blob ( NULL , 24 ) ;
2002-11-24 11:32:03 +03:00
2003-04-07 11:10:53 +04:00
uchar lm_key [ 8 ] ;
2003-05-05 09:01:59 +04:00
uchar nt_key [ 16 ] ;
2003-04-07 11:10:53 +04:00
uchar lm_hash [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
2003-05-05 09:01:59 +04:00
ZERO_STRUCT ( lm_key ) ;
ZERO_STRUCT ( nt_key ) ;
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_LMKEY ;
flags | = WBFLAG_PAM_NTKEY ;
2003-04-07 11:10:53 +04:00
2003-05-05 09:01:59 +04:00
SMBencrypt ( opt_password , chall . data , lm_response . data ) ;
2003-04-07 11:10:53 +04:00
E_deshash ( opt_password , lm_hash ) ;
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain , opt_workstation ,
& chall ,
& lm_response ,
NULL ,
flags ,
lm_key ,
2003-05-05 09:01:59 +04:00
nt_key ,
2003-04-07 11:10:53 +04:00
& error_string ) ;
data_blob_free ( & lm_response ) ;
2002-11-24 11:32:03 +03:00
2003-04-07 11:10:53 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
d_printf ( " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
return False ;
}
if ( memcmp ( lm_hash , lm_key ,
sizeof ( lm_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " LM Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " lm_key: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) lm_key , 8 ) ;
2003-04-07 11:10:53 +04:00
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) lm_hash , 8 ) ;
2003-04-07 11:10:53 +04:00
}
2003-05-05 09:01:59 +04:00
if ( memcmp ( lm_hash , nt_key , 8 ) ! = 0 ) {
DEBUG ( 1 , ( " Session Key (first 8, lm hash) does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " nt_key: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) nt_key , 8 ) ;
2003-05-05 09:01:59 +04:00
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) lm_hash , 8 ) ;
2003-05-05 09:01:59 +04:00
}
2003-04-07 11:10:53 +04:00
return True ;
}
2003-05-05 10:33:58 +04:00
/*
* Test the normal ' LM and NTLM ' combination
*/
2003-04-07 11:10:53 +04:00
static BOOL test_lm_ntlm ( void )
{
BOOL pass = True ;
NTSTATUS nt_status ;
uint32 flags = 0 ;
DATA_BLOB lm_response = data_blob ( NULL , 24 ) ;
DATA_BLOB nt_response = data_blob ( NULL , 24 ) ;
DATA_BLOB session_key = data_blob ( NULL , 16 ) ;
uchar lm_key [ 8 ] ;
uchar nt_key [ 16 ] ;
uchar lm_hash [ 16 ] ;
uchar nt_hash [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
2003-05-05 09:01:59 +04:00
ZERO_STRUCT ( lm_key ) ;
ZERO_STRUCT ( nt_key ) ;
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_LMKEY ;
flags | = WBFLAG_PAM_NTKEY ;
2003-04-07 11:10:53 +04:00
SMBencrypt ( opt_password , chall . data , lm_response . data ) ;
E_deshash ( opt_password , lm_hash ) ;
SMBNTencrypt ( opt_password , chall . data , nt_response . data ) ;
E_md4hash ( opt_password , nt_hash ) ;
SMBsesskeygen_ntv1 ( nt_hash , NULL , session_key . data ) ;
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& chall ,
& lm_response ,
& nt_response ,
flags ,
lm_key ,
nt_key ,
& error_string ) ;
data_blob_free ( & lm_response ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
d_printf ( " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
SAFE_FREE ( error_string ) ;
return False ;
}
if ( memcmp ( lm_hash , lm_key ,
sizeof ( lm_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " LM Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " lm_key: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) lm_key , 8 ) ;
2003-04-07 11:10:53 +04:00
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) lm_hash , 8 ) ;
2003-04-07 11:10:53 +04:00
pass = False ;
}
if ( memcmp ( session_key . data , nt_key ,
sizeof ( nt_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " NT Session Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " nt_key: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) nt_key , 16 ) ;
2003-04-07 11:10:53 +04:00
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) session_key . data , session_key . length ) ;
2003-04-07 11:10:53 +04:00
pass = False ;
}
return pass ;
}
2003-05-05 10:33:58 +04:00
/*
* Test the NTLM response only , no LM .
*/
2003-04-07 11:10:53 +04:00
static BOOL test_ntlm ( void )
{
BOOL pass = True ;
NTSTATUS nt_status ;
uint32 flags = 0 ;
DATA_BLOB nt_response = data_blob ( NULL , 24 ) ;
DATA_BLOB session_key = data_blob ( NULL , 16 ) ;
2003-05-05 17:23:07 +04:00
char lm_key [ 8 ] ;
2003-04-07 11:10:53 +04:00
char nt_key [ 16 ] ;
2003-05-05 17:23:07 +04:00
char lm_hash [ 16 ] ;
2003-04-07 11:10:53 +04:00
char nt_hash [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
2003-05-05 17:23:07 +04:00
ZERO_STRUCT ( lm_key ) ;
2003-05-05 09:01:59 +04:00
ZERO_STRUCT ( nt_key ) ;
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_LMKEY ;
flags | = WBFLAG_PAM_NTKEY ;
2003-04-07 11:10:53 +04:00
SMBNTencrypt ( opt_password , chall . data , nt_response . data ) ;
2003-08-15 08:42:05 +04:00
E_md4hash ( opt_password , ( unsigned char * ) nt_hash ) ;
SMBsesskeygen_ntv1 ( ( const unsigned char * ) nt_hash , NULL , session_key . data ) ;
2003-04-07 11:10:53 +04:00
2003-08-15 08:42:05 +04:00
E_deshash ( opt_password , ( unsigned char * ) lm_hash ) ;
2003-05-05 17:23:07 +04:00
2003-04-07 11:10:53 +04:00
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& chall ,
NULL ,
& nt_response ,
flags ,
2003-08-15 08:42:05 +04:00
( unsigned char * ) lm_key ,
( unsigned char * ) nt_key ,
2003-04-07 11:10:53 +04:00
& error_string ) ;
data_blob_free ( & nt_response ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
d_printf ( " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
SAFE_FREE ( error_string ) ;
return False ;
}
2003-05-05 17:23:07 +04:00
if ( memcmp ( lm_hash , lm_key ,
sizeof ( lm_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " LM Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " lm_key: \n " ) ) ;
dump_data ( 1 , lm_key , 8 ) ;
DEBUG ( 1 , ( " expected: \n " ) ) ;
dump_data ( 1 , lm_hash , 8 ) ;
pass = False ;
}
2003-04-07 11:10:53 +04:00
if ( memcmp ( session_key . data , nt_key ,
sizeof ( nt_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " NT Session Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " nt_key: \n " ) ) ;
dump_data ( 1 , nt_key , 16 ) ;
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) session_key . data , session_key . length ) ;
2003-04-07 11:10:53 +04:00
pass = False ;
}
return pass ;
}
2003-05-05 10:33:58 +04:00
/*
2003-05-09 10:03:11 +04:00
* Test the NTLM response only , but in the LM field .
2003-05-05 10:33:58 +04:00
*/
2003-05-05 09:01:59 +04:00
static BOOL test_ntlm_in_lm ( void )
{
BOOL pass = True ;
NTSTATUS nt_status ;
uint32 flags = 0 ;
DATA_BLOB nt_response = data_blob ( NULL , 24 ) ;
uchar lm_key [ 8 ] ;
uchar lm_hash [ 16 ] ;
uchar nt_key [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
ZERO_STRUCT ( nt_key ) ;
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_LMKEY ;
flags | = WBFLAG_PAM_NTKEY ;
2003-05-05 09:01:59 +04:00
SMBNTencrypt ( opt_password , chall . data , nt_response . data ) ;
E_deshash ( opt_password , lm_hash ) ;
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& chall ,
& nt_response ,
NULL ,
flags ,
lm_key ,
nt_key ,
& error_string ) ;
data_blob_free ( & nt_response ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
d_printf ( " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
SAFE_FREE ( error_string ) ;
return False ;
}
if ( memcmp ( lm_hash , lm_key ,
sizeof ( lm_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " LM Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " lm_key: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) lm_key , 8 ) ;
2003-05-05 09:01:59 +04:00
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) lm_hash , 8 ) ;
2003-05-05 09:01:59 +04:00
pass = False ;
}
if ( memcmp ( lm_hash , nt_key , 8 ) ! = 0 ) {
DEBUG ( 1 , ( " Session Key (first 8 lm hash) does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " nt_key: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) nt_key , 16 ) ;
2003-05-05 09:01:59 +04:00
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) lm_hash , 8 ) ;
2003-05-05 09:01:59 +04:00
pass = False ;
}
return pass ;
}
2003-05-05 10:33:58 +04:00
/*
2003-05-09 10:03:11 +04:00
* Test the NTLM response only , but in the both the NT and LM fields .
2003-05-05 10:33:58 +04:00
*/
2003-05-05 09:01:59 +04:00
static BOOL test_ntlm_in_both ( void )
{
BOOL pass = True ;
NTSTATUS nt_status ;
uint32 flags = 0 ;
DATA_BLOB nt_response = data_blob ( NULL , 24 ) ;
DATA_BLOB session_key = data_blob ( NULL , 16 ) ;
char lm_key [ 8 ] ;
char lm_hash [ 16 ] ;
char nt_key [ 16 ] ;
char nt_hash [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
ZERO_STRUCT ( lm_key ) ;
ZERO_STRUCT ( nt_key ) ;
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_LMKEY ;
flags | = WBFLAG_PAM_NTKEY ;
2003-05-05 09:01:59 +04:00
SMBNTencrypt ( opt_password , chall . data , nt_response . data ) ;
2003-08-15 08:42:05 +04:00
E_md4hash ( opt_password , ( unsigned char * ) nt_hash ) ;
SMBsesskeygen_ntv1 ( ( const unsigned char * ) nt_hash , NULL , session_key . data ) ;
2003-05-05 09:01:59 +04:00
2003-08-15 08:42:05 +04:00
E_deshash ( opt_password , ( unsigned char * ) lm_hash ) ;
2003-05-05 09:01:59 +04:00
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& chall ,
& nt_response ,
& nt_response ,
flags ,
2003-08-15 08:42:05 +04:00
( unsigned char * ) lm_key ,
( unsigned char * ) nt_key ,
2003-05-05 09:01:59 +04:00
& error_string ) ;
data_blob_free ( & nt_response ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
d_printf ( " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
SAFE_FREE ( error_string ) ;
return False ;
}
if ( memcmp ( lm_hash , lm_key ,
sizeof ( lm_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " LM Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " lm_key: \n " ) ) ;
dump_data ( 1 , lm_key , 8 ) ;
DEBUG ( 1 , ( " expected: \n " ) ) ;
dump_data ( 1 , lm_hash , 8 ) ;
pass = False ;
}
if ( memcmp ( session_key . data , nt_key ,
sizeof ( nt_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " NT Session Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " nt_key: \n " ) ) ;
dump_data ( 1 , nt_key , 16 ) ;
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) session_key . data , session_key . length ) ;
2003-05-05 09:01:59 +04:00
pass = False ;
}
return pass ;
}
2003-05-05 10:33:58 +04:00
/*
* Test the NTLMv2 response only
*/
2003-05-05 09:01:59 +04:00
static BOOL test_ntlmv2 ( void )
{
BOOL pass = True ;
NTSTATUS nt_status ;
uint32 flags = 0 ;
DATA_BLOB ntlmv2_response = data_blob ( NULL , 0 ) ;
DATA_BLOB nt_session_key = data_blob ( NULL , 0 ) ;
2003-05-09 18:42:20 +04:00
DATA_BLOB names_blob = NTLMv2_generate_names_blob ( get_winbind_netbios_name ( ) , get_winbind_domain ( ) ) ;
2003-05-05 09:01:59 +04:00
uchar nt_key [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
ZERO_STRUCT ( nt_key ) ;
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_NTKEY ;
2003-05-05 09:01:59 +04:00
2003-05-09 18:42:20 +04:00
if ( ! SMBNTLMv2encrypt ( opt_username , opt_domain , opt_password , & chall ,
& names_blob ,
NULL , & ntlmv2_response ,
& nt_session_key ) ) {
data_blob_free ( & names_blob ) ;
2003-05-05 09:01:59 +04:00
return False ;
}
2003-05-09 18:42:20 +04:00
data_blob_free ( & names_blob ) ;
2003-05-05 09:01:59 +04:00
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& chall ,
NULL ,
& ntlmv2_response ,
flags ,
2003-05-09 18:42:20 +04:00
NULL ,
2003-05-05 09:01:59 +04:00
nt_key ,
& error_string ) ;
data_blob_free ( & ntlmv2_response ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
d_printf ( " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
SAFE_FREE ( error_string ) ;
return False ;
}
if ( memcmp ( nt_session_key . data , nt_key ,
sizeof ( nt_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " NT Session Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " nt_key: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) nt_key , 16 ) ;
2003-05-05 09:01:59 +04:00
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) nt_session_key . data , nt_session_key . length ) ;
2003-05-05 09:01:59 +04:00
pass = False ;
}
return pass ;
}
2003-05-05 10:33:58 +04:00
/*
* Test the NTLMv2 and LMv2 responses
*/
2003-05-05 09:01:59 +04:00
static BOOL test_lmv2_ntlmv2 ( void )
{
BOOL pass = True ;
NTSTATUS nt_status ;
uint32 flags = 0 ;
DATA_BLOB ntlmv2_response = data_blob ( NULL , 0 ) ;
DATA_BLOB lmv2_response = data_blob ( NULL , 0 ) ;
DATA_BLOB nt_session_key = data_blob ( NULL , 0 ) ;
2003-05-09 18:42:20 +04:00
DATA_BLOB names_blob = NTLMv2_generate_names_blob ( get_winbind_netbios_name ( ) , get_winbind_domain ( ) ) ;
2003-05-05 09:01:59 +04:00
uchar nt_key [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
ZERO_STRUCT ( nt_key ) ;
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_NTKEY ;
2003-05-05 09:01:59 +04:00
2003-05-09 18:42:20 +04:00
if ( ! SMBNTLMv2encrypt ( opt_username , opt_domain , opt_password , & chall ,
& names_blob ,
2003-05-05 09:01:59 +04:00
& lmv2_response , & ntlmv2_response ,
2003-05-09 18:42:20 +04:00
& nt_session_key ) ) {
data_blob_free ( & names_blob ) ;
2003-05-05 09:01:59 +04:00
return False ;
}
2003-05-09 18:42:20 +04:00
data_blob_free ( & names_blob ) ;
2003-05-05 09:01:59 +04:00
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& chall ,
& lmv2_response ,
& ntlmv2_response ,
flags ,
2003-05-09 18:42:20 +04:00
NULL ,
2003-05-05 09:01:59 +04:00
nt_key ,
& error_string ) ;
data_blob_free ( & lmv2_response ) ;
data_blob_free ( & ntlmv2_response ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
d_printf ( " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
SAFE_FREE ( error_string ) ;
return False ;
}
if ( memcmp ( nt_session_key . data , nt_key ,
sizeof ( nt_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " NT Session Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " nt_key: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) nt_key , 16 ) ;
2003-05-05 09:01:59 +04:00
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) nt_session_key . data , nt_session_key . length ) ;
2003-05-05 09:01:59 +04:00
pass = False ;
}
return pass ;
}
2003-05-05 10:33:58 +04:00
/*
* Test the LMv2 response only
*/
2003-05-05 09:01:59 +04:00
static BOOL test_lmv2 ( void )
{
BOOL pass = True ;
NTSTATUS nt_status ;
uint32 flags = 0 ;
DATA_BLOB lmv2_response = data_blob ( NULL , 0 ) ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
2003-05-09 18:42:20 +04:00
if ( ! SMBNTLMv2encrypt ( opt_username , opt_domain , opt_password , & chall ,
NULL ,
& lmv2_response , NULL ,
NULL ) ) {
2003-05-05 09:01:59 +04:00
return False ;
}
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& chall ,
& lmv2_response ,
NULL ,
flags ,
2003-05-09 18:42:20 +04:00
NULL ,
NULL ,
2003-05-05 09:01:59 +04:00
& error_string ) ;
data_blob_free ( & lmv2_response ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
d_printf ( " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
SAFE_FREE ( error_string ) ;
return False ;
}
return pass ;
}
2003-05-09 10:03:11 +04:00
/*
* Test the normal ' LM and NTLM ' combination but deliberately break one
*/
static BOOL test_ntlm_broken ( BOOL break_lm )
{
BOOL pass = True ;
NTSTATUS nt_status ;
uint32 flags = 0 ;
DATA_BLOB lm_response = data_blob ( NULL , 24 ) ;
DATA_BLOB nt_response = data_blob ( NULL , 24 ) ;
DATA_BLOB session_key = data_blob ( NULL , 16 ) ;
uchar lm_key [ 8 ] ;
uchar nt_key [ 16 ] ;
uchar lm_hash [ 16 ] ;
uchar nt_hash [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
ZERO_STRUCT ( lm_key ) ;
ZERO_STRUCT ( nt_key ) ;
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_LMKEY ;
flags | = WBFLAG_PAM_NTKEY ;
2003-05-09 10:03:11 +04:00
SMBencrypt ( opt_password , chall . data , lm_response . data ) ;
E_deshash ( opt_password , lm_hash ) ;
SMBNTencrypt ( opt_password , chall . data , nt_response . data ) ;
E_md4hash ( opt_password , nt_hash ) ;
SMBsesskeygen_ntv1 ( nt_hash , NULL , session_key . data ) ;
if ( break_lm )
lm_response . data [ 0 ] + + ;
else
nt_response . data [ 0 ] + + ;
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& chall ,
& lm_response ,
& nt_response ,
flags ,
lm_key ,
nt_key ,
& error_string ) ;
data_blob_free ( & lm_response ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
d_printf ( " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
SAFE_FREE ( error_string ) ;
return False ;
}
if ( memcmp ( lm_hash , lm_key ,
sizeof ( lm_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " LM Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " lm_key: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) lm_key , 8 ) ;
2003-05-09 10:03:11 +04:00
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) lm_hash , 8 ) ;
2003-05-09 10:03:11 +04:00
pass = False ;
}
if ( memcmp ( session_key . data , nt_key ,
sizeof ( nt_key ) ) ! = 0 ) {
DEBUG ( 1 , ( " NT Session Key does not match expectations! \n " ) ) ;
DEBUG ( 1 , ( " nt_key: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) nt_key , 16 ) ;
2003-05-09 10:03:11 +04:00
DEBUG ( 1 , ( " expected: \n " ) ) ;
2003-08-15 08:42:05 +04:00
dump_data ( 1 , ( const char * ) session_key . data , session_key . length ) ;
2003-05-09 10:03:11 +04:00
pass = False ;
}
return pass ;
}
static BOOL test_ntlm_lm_broken ( void )
{
return test_ntlm_broken ( True ) ;
}
static BOOL test_ntlm_ntlm_broken ( void )
{
return test_ntlm_broken ( False ) ;
}
static BOOL test_ntlmv2_broken ( BOOL break_lmv2 )
{
BOOL pass = True ;
NTSTATUS nt_status ;
uint32 flags = 0 ;
DATA_BLOB ntlmv2_response = data_blob ( NULL , 0 ) ;
DATA_BLOB lmv2_response = data_blob ( NULL , 0 ) ;
DATA_BLOB nt_session_key = data_blob ( NULL , 0 ) ;
2003-05-09 18:42:20 +04:00
DATA_BLOB names_blob = NTLMv2_generate_names_blob ( get_winbind_netbios_name ( ) , get_winbind_domain ( ) ) ;
2003-05-09 10:03:11 +04:00
uchar nt_key [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
ZERO_STRUCT ( nt_key ) ;
2003-07-07 09:11:10 +04:00
flags | = WBFLAG_PAM_NTKEY ;
2003-05-09 18:42:20 +04:00
if ( ! SMBNTLMv2encrypt ( opt_username , opt_domain , opt_password , & chall ,
& names_blob ,
2003-05-09 10:03:11 +04:00
& lmv2_response , & ntlmv2_response ,
2003-05-09 18:42:20 +04:00
& nt_session_key ) ) {
data_blob_free ( & names_blob ) ;
2003-05-09 10:03:11 +04:00
return False ;
}
2003-05-09 18:42:20 +04:00
data_blob_free ( & names_blob ) ;
2003-05-09 10:03:11 +04:00
/* Heh - this should break the appropriate password hash nicely! */
if ( break_lmv2 )
lmv2_response . data [ 0 ] + + ;
else
ntlmv2_response . data [ 0 ] + + ;
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& chall ,
& lmv2_response ,
& ntlmv2_response ,
flags ,
2003-05-09 18:42:20 +04:00
NULL ,
2003-05-09 10:03:11 +04:00
nt_key ,
& error_string ) ;
data_blob_free ( & lmv2_response ) ;
data_blob_free ( & ntlmv2_response ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
d_printf ( " %s (0x%x) \n " ,
error_string ,
NT_STATUS_V ( nt_status ) ) ;
SAFE_FREE ( error_string ) ;
return False ;
}
return pass ;
}
static BOOL test_ntlmv2_lmv2_broken ( void )
{
return test_ntlmv2_broken ( True ) ;
}
static BOOL test_ntlmv2_ntlmv2_broken ( void )
{
return test_ntlmv2_broken ( False ) ;
}
2003-04-07 11:10:53 +04:00
/*
Tests :
- LM only
- NT and LM
- NT
2003-05-09 10:03:11 +04:00
- NT in LM field
- NT in both fields
2003-04-07 11:10:53 +04:00
- NTLMv2
- NTLMv2 and LMv2
- LMv2
check we get the correct session key in each case
check what values we get for the LM session key
*/
struct ntlm_tests {
2003-04-28 10:19:11 +04:00
BOOL ( * fn ) ( void ) ;
2003-04-07 11:10:53 +04:00
const char * name ;
} test_table [ ] = {
2003-05-09 10:03:11 +04:00
{ test_lm , " LM " } ,
{ test_lm_ntlm , " LM and NTLM " } ,
{ test_ntlm , " NTLM " } ,
{ test_ntlm_in_lm , " NTLM in LM " } ,
{ test_ntlm_in_both , " NTLM in both " } ,
{ test_ntlmv2 , " NTLMv2 " } ,
{ test_lmv2_ntlmv2 , " NTLMv2 and LMv2 " } ,
{ test_lmv2 , " LMv2 " } ,
{ test_ntlmv2_lmv2_broken , " NTLMv2 and LMv2, LMv2 broken " } ,
{ test_ntlmv2_ntlmv2_broken , " NTLMv2 and LMv2, NTLMv2 broken " } ,
{ test_ntlm_lm_broken , " NTLM and LM, LM broken " } ,
{ test_ntlm_ntlm_broken , " NTLM and LM, NTLM broken " }
2003-04-07 11:10:53 +04:00
} ;
static BOOL diagnose_ntlm_auth ( void )
{
unsigned int i ;
BOOL pass = True ;
for ( i = 0 ; test_table [ i ] . fn ; i + + ) {
if ( ! test_table [ i ] . fn ( ) ) {
DEBUG ( 1 , ( " Test %s failed! \n " , test_table [ i ] . name ) ) ;
pass = False ;
2003-03-24 12:54:13 +03:00
}
}
2003-04-07 11:10:53 +04:00
return pass ;
2002-11-24 11:32:03 +03:00
}
/* Main program */
2003-01-17 07:12:12 +03:00
enum {
2002-11-24 11:32:03 +03:00
OPT_USERNAME = 1000 ,
OPT_DOMAIN ,
OPT_WORKSTATION ,
OPT_CHALLENGE ,
OPT_RESPONSE ,
OPT_LM ,
OPT_NT ,
2003-03-24 12:54:13 +03:00
OPT_PASSWORD ,
OPT_LM_KEY ,
2003-04-07 11:10:53 +04:00
OPT_NT_KEY ,
OPT_DIAGNOSTICS
2002-11-24 11:32:03 +03:00
} ;
2003-04-07 11:10:53 +04:00
int main ( int argc , const char * * argv )
2002-11-24 11:32:03 +03:00
{
int opt ;
2003-05-05 09:01:59 +04:00
static const char * helper_protocol ;
static int diagnostics ;
2002-11-24 11:32:03 +03:00
2003-04-07 11:10:53 +04:00
static const char * hex_challenge ;
static const char * hex_lm_response ;
static const char * hex_nt_response ;
char * challenge ;
char * lm_response ;
char * nt_response ;
size_t challenge_len ;
size_t lm_response_len ;
size_t nt_response_len ;
2002-11-24 11:32:03 +03:00
poptContext pc ;
2003-04-07 11:10:53 +04:00
/* NOTE: DO NOT change this interface without considering the implications!
This is an external interface , which other programs will use to interact
with this helper .
*/
/* We do not use single-letter command abbreviations, because they harm future
interface stability . */
2002-11-24 11:32:03 +03:00
struct poptOption long_options [ ] = {
POPT_AUTOHELP
{ " helper-protocol " , 0 , POPT_ARG_STRING , & helper_protocol , OPT_DOMAIN , " operate as a stdio-based helper " , " helper protocol to use " } ,
2003-04-07 11:10:53 +04:00
{ " username " , 0 , POPT_ARG_STRING , & opt_username , OPT_USERNAME , " username " } ,
{ " domain " , 0 , POPT_ARG_STRING , & opt_domain , OPT_DOMAIN , " domain name " } ,
{ " workstation " , 0 , POPT_ARG_STRING , & opt_workstation , OPT_WORKSTATION , " workstation " } ,
2002-11-24 11:32:03 +03:00
{ " challenge " , 0 , POPT_ARG_STRING , & hex_challenge , OPT_CHALLENGE , " challenge (HEX encoded) " } ,
{ " lm-response " , 0 , POPT_ARG_STRING , & hex_lm_response , OPT_LM , " LM Response to the challenge (HEX encoded) " } ,
{ " nt-response " , 0 , POPT_ARG_STRING , & hex_nt_response , OPT_NT , " NT or NTLMv2 Response to the challenge (HEX encoded) " } ,
2003-04-07 11:10:53 +04:00
{ " password " , 0 , POPT_ARG_STRING , & opt_password , OPT_PASSWORD , " User's plaintext password " } ,
2003-03-24 12:54:13 +03:00
{ " request-lm-key " , 0 , POPT_ARG_NONE , & request_lm_key , OPT_LM_KEY , " Retreive LM session key " } ,
{ " request-nt-key " , 0 , POPT_ARG_NONE , & request_nt_key , OPT_NT_KEY , " Retreive NT session key " } ,
2003-04-07 11:10:53 +04:00
{ " diagnostics " , 0 , POPT_ARG_NONE , & diagnostics , OPT_DIAGNOSTICS , " Perform diagnostics on the authentictaion chain " } ,
2003-04-14 07:59:04 +04:00
POPT_COMMON_SAMBA
POPT_TABLEEND
2002-11-24 11:32:03 +03:00
} ;
/* Samba client initialisation */
dbf = x_stderr ;
2003-05-12 04:18:45 +04:00
/* Samba client initialisation */
if ( ! lp_load ( dyn_CONFIGFILE , True , False , False ) ) {
d_fprintf ( stderr , " wbinfo: error opening config file %s. Error was %s \n " ,
dyn_CONFIGFILE , strerror ( errno ) ) ;
exit ( 1 ) ;
}
2002-11-24 11:32:03 +03:00
/* Parse options */
pc = poptGetContext ( " ntlm_auth " , argc , argv , long_options , 0 ) ;
/* Parse command line options */
if ( argc = = 1 ) {
poptPrintHelp ( pc , stderr , 0 ) ;
return 1 ;
}
pc = poptGetContext ( NULL , argc , ( const char * * ) argv , long_options ,
POPT_CONTEXT_KEEP_FIRST ) ;
while ( ( opt = poptGetNextOpt ( pc ) ) ! = - 1 ) {
switch ( opt ) {
case OPT_CHALLENGE :
2003-05-12 04:18:45 +04:00
challenge = smb_xmalloc ( ( strlen ( hex_challenge ) ) / 2 + 1 ) ;
2003-04-07 11:10:53 +04:00
if ( ( challenge_len = strhex_to_str ( challenge ,
strlen ( hex_challenge ) ,
hex_challenge ) ) ! = 8 ) {
x_fprintf ( x_stderr , " hex decode of %s failed (only got %u bytes)! \n " ,
2003-03-24 12:54:13 +03:00
hex_challenge , challenge_len ) ;
2002-11-24 11:32:03 +03:00
exit ( 1 ) ;
}
2003-04-07 11:10:53 +04:00
opt_challenge = data_blob ( challenge , challenge_len ) ;
SAFE_FREE ( challenge ) ;
2002-11-24 11:32:03 +03:00
break ;
case OPT_LM :
2003-05-12 04:18:45 +04:00
lm_response = smb_xmalloc ( ( strlen ( hex_lm_response ) ) / 2 + 1 ) ;
2003-04-07 11:10:53 +04:00
lm_response_len = strhex_to_str ( lm_response ,
strlen ( hex_lm_response ) ,
hex_lm_response ) ;
if ( lm_response_len ! = 24 ) {
x_fprintf ( x_stderr , " hex decode of %s failed! \n " , hex_lm_response ) ;
2002-11-24 11:32:03 +03:00
exit ( 1 ) ;
}
2003-04-07 11:10:53 +04:00
opt_lm_response = data_blob ( lm_response , lm_response_len ) ;
SAFE_FREE ( lm_response ) ;
2002-11-24 11:32:03 +03:00
break ;
2003-03-24 12:54:13 +03:00
case OPT_NT :
2003-05-12 04:18:45 +04:00
nt_response = smb_xmalloc ( ( strlen ( hex_nt_response ) + 2 ) / 2 + 1 ) ;
2003-04-07 11:10:53 +04:00
nt_response_len = strhex_to_str ( nt_response ,
strlen ( hex_nt_response ) ,
hex_nt_response ) ;
if ( nt_response_len < 24 ) {
x_fprintf ( x_stderr , " hex decode of %s failed! \n " , hex_nt_response ) ;
2002-11-24 11:32:03 +03:00
exit ( 1 ) ;
}
2003-04-07 11:10:53 +04:00
opt_nt_response = data_blob ( nt_response , nt_response_len ) ;
SAFE_FREE ( nt_response ) ;
2002-11-24 11:32:03 +03:00
break ;
}
}
if ( helper_protocol ) {
2003-01-16 06:29:54 +03:00
if ( strcmp ( helper_protocol , " squid-2.5-ntlmssp " ) = = 0 ) {
squid_stream ( SQUID_2_5_NTLMSSP ) ;
} else if ( strcmp ( helper_protocol , " squid-2.5-basic " ) = = 0 ) {
squid_stream ( SQUID_2_5_BASIC ) ;
2002-11-25 00:08:36 +03:00
} else if ( strcmp ( helper_protocol , " squid-2.4-basic " ) = = 0 ) {
2003-01-16 06:29:54 +03:00
squid_stream ( SQUID_2_4_BASIC ) ;
2003-07-29 19:00:38 +04:00
} else if ( strcmp ( helper_protocol , " gss-spnego " ) = = 0 ) {
squid_stream ( GSS_SPNEGO ) ;
2003-08-01 11:59:23 +04:00
} else if ( strcmp ( helper_protocol , " gss-spnego-client " ) = = 0 ) {
squid_stream ( GSS_SPNEGO_CLIENT ) ;
2002-11-25 00:08:36 +03:00
} else {
2003-04-07 11:10:53 +04:00
x_fprintf ( x_stderr , " unknown helper protocol [%s] \n " , helper_protocol ) ;
2002-11-25 00:08:36 +03:00
exit ( 1 ) ;
2002-11-24 11:32:03 +03:00
}
}
2003-04-07 11:10:53 +04:00
if ( ! opt_username ) {
x_fprintf ( x_stderr , " username must be specified! \n \n " ) ;
poptPrintHelp ( pc , stderr , 0 ) ;
exit ( 1 ) ;
}
if ( opt_domain = = NULL ) {
opt_domain = get_winbind_domain ( ) ;
2002-11-24 11:32:03 +03:00
}
2003-04-07 11:10:53 +04:00
if ( opt_workstation = = NULL ) {
opt_workstation = " " ;
2002-11-24 11:32:03 +03:00
}
2003-04-07 11:10:53 +04:00
if ( opt_challenge . length ) {
2002-11-24 11:32:03 +03:00
if ( ! check_auth_crap ( ) ) {
exit ( 1 ) ;
}
2003-04-07 11:10:53 +04:00
exit ( 0 ) ;
}
if ( ! opt_password ) {
opt_password = getpass ( " password: " ) ;
}
if ( diagnostics ) {
if ( ! diagnose_ntlm_auth ( ) ) {
exit ( 1 ) ;
}
} else {
2002-11-24 11:32:03 +03:00
fstring user ;
2003-04-07 11:10:53 +04:00
2003-07-23 16:33:59 +04:00
fstr_sprintf ( user , " %s%c%s " , opt_domain , winbind_separator ( ) , opt_username ) ;
2003-04-07 11:10:53 +04:00
if ( ! check_plaintext_auth ( user , opt_password , True ) ) {
2002-11-24 11:32:03 +03:00
exit ( 1 ) ;
}
}
/* Exit code */
poptFreeContext ( pc ) ;
return 0 ;
}