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-01-16 06:29:54 +03:00
SQUID_2_5_NTLMSSP
2002-11-25 00:08:36 +03:00
} ;
2002-11-24 11:32:03 +03:00
extern int winbindd_fd ;
static const char * helper_protocol ;
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 ;
2003-04-07 11:10:53 +04:00
static int diagnostics ;
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 ,
uint8 lm_key [ 16 ] ,
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-04-07 11:10:53 +04:00
request . data . auth_crap . flags = flags ;
2003-01-16 06:29:54 +03:00
2003-04-07 11:10:53 +04:00
fstrcpy ( request . data . auth_crap . user , username ) ;
fstrcpy ( request . data . auth_crap . domain , domain ) ;
fstrcpy ( request . data . auth_crap . workstation , workstation ) ;
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-04-07 11:10:53 +04:00
if ( ( flags & WINBIND_PAM_LMKEY ) & & lm_key
& & ( 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 ) ) ;
}
if ( ( flags & WINBIND_PAM_NTKEY ) & & nt_key
& & ( 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 " ) ) ;
dump_data ( 10 , 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 " ) ;
}
}
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 ) ;
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 ] ;
if ( request_lm_key )
2003-04-07 11:10:53 +04:00
flags | = WINBIND_PAM_LMKEY ;
2003-03-24 12:54:13 +03:00
if ( request_nt_key )
2003-04-07 11:10:53 +04:00
flags | = WINBIND_PAM_NTKEY ;
nt_status = contact_winbind_auth_crap ( opt_username , opt_domain ,
opt_workstation ,
& opt_challenge ,
& opt_lm_response ,
& opt_nt_response ,
flags ,
lm_key ,
nt_key ,
& error_string ) ;
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-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 ) ) {
hex_encode ( lm_key ,
sizeof ( lm_key ) ,
& hex_lm_key ) ;
d_printf ( " LM_KEY: %s \n " , hex_lm_key ) ;
SAFE_FREE ( hex_lm_key ) ;
}
if ( request_nt_key
& & ( memcmp ( zeros , nt_key ,
sizeof ( nt_key ) ) ! = 0 ) ) {
hex_encode ( nt_key ,
sizeof ( nt_key ) ,
& hex_nt_key ) ;
d_printf ( " NT_KEY: %s \n " , hex_nt_key ) ;
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-28 09:18:30 +04:00
static const 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-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 ] ;
uchar lm_hash [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
flags | = WINBIND_PAM_LMKEY ;
SMBencrypt ( opt_password , chall . data , lm_response . data ) ;
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 ,
NULL ,
& 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 " ) ) ;
dump_data ( 1 , lm_key , 8 ) ;
DEBUG ( 1 , ( " expected: \n " ) ) ;
dump_data ( 1 , lm_hash , 8 ) ;
}
return True ;
}
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 ;
flags | = WINBIND_PAM_LMKEY ;
flags | = WINBIND_PAM_NTKEY ;
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 " ) ) ;
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 " ) ) ;
dump_data ( 1 , session_key . data , session_key . length ) ;
pass = False ;
}
return pass ;
}
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 ) ;
char nt_key [ 16 ] ;
char nt_hash [ 16 ] ;
DATA_BLOB chall = get_challenge ( ) ;
char * error_string ;
flags | = WINBIND_PAM_NTKEY ;
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 ,
NULL ,
& nt_response ,
flags ,
NULL ,
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 ( 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 " ) ) ;
dump_data ( 1 , session_key . data , session_key . length ) ;
pass = False ;
}
return pass ;
}
/*
Tests :
- LM only
- NT and LM
- NT
- 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 [ ] = {
{ test_lm , " test LM " } ,
{ test_lm_ntlm , " test LM and NTLM " } ,
{ test_ntlm , " test NTLM " }
/* {test_lm_ntlmv2, "test NTLMv2"}, */
/* {test_lm_ntlmv2, "test NTLMv2 and LMv2"}, */
/* {test_lm_ntlmv2, "test LMv2"} */
} ;
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-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 ;
/* 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-04-07 11:10:53 +04:00
challenge = smb_xmalloc ( ( strlen ( hex_challenge ) + 1 ) / 2 ) ;
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-04-07 11:10:53 +04:00
lm_response = smb_xmalloc ( ( strlen ( hex_lm_response ) + 1 ) / 2 ) ;
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-04-07 11:10:53 +04:00
nt_response = smb_xmalloc ( ( strlen ( hex_nt_response ) + 1 ) / 2 ) ;
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 ) ;
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
snprintf ( user , sizeof ( user ) - 1 , " %s%c%s " , opt_domain , winbind_separator ( ) , opt_username ) ;
if ( ! check_plaintext_auth ( user , opt_password , True ) ) {
2002-11-24 11:32:03 +03:00
exit ( 1 ) ;
}
}
/* Exit code */
poptFreeContext ( pc ) ;
return 0 ;
}