2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
Password and authentication handling
Copyright ( C ) Andrew Bartlett 2001 - 2002
2005-01-09 15:55:25 +03:00
Copyright ( C ) Stefan Metzmacher 2005
2003-08-13 05:53:07 +04:00
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"
2004-11-02 09:42:15 +03:00
# include "dlinklist.h"
2004-11-02 05:57:18 +03:00
# include "auth/auth.h"
2005-06-16 15:36:09 +04:00
# include "lib/events/events.h"
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
/***************************************************************************
Set a fixed challenge
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS auth_context_set_challenge ( struct auth_context * auth_ctx , const uint8_t chal [ 8 ] , const char * set_by )
{
auth_ctx - > challenge . set_by = talloc_strdup ( auth_ctx , set_by ) ;
NT_STATUS_HAVE_NO_MEMORY ( auth_ctx - > challenge . set_by ) ;
auth_ctx - > challenge . data = data_blob_talloc ( auth_ctx , chal , 8 ) ;
NT_STATUS_HAVE_NO_MEMORY ( auth_ctx - > challenge . data . data ) ;
return NT_STATUS_OK ;
}
/***************************************************************************
Set a fixed challenge
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL auth_challenge_may_be_modified ( struct auth_context * auth_ctx )
{
return auth_ctx - > challenge . may_be_modified ;
}
2003-08-13 05:53:07 +04:00
/****************************************************************************
Try to get a challenge out of the various authentication modules .
Returns a const char of length 8 bytes .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-01-09 15:55:25 +03:00
NTSTATUS auth_get_challenge ( struct auth_context * auth_ctx , const uint8_t * * _chal )
2003-08-13 05:53:07 +04:00
{
2005-01-09 15:55:25 +03:00
NTSTATUS nt_status ;
struct auth_method_context * method ;
if ( auth_ctx - > challenge . data . length ) {
DEBUG ( 5 , ( " auth_get_challenge: returning previous challenge by module %s (normal) \n " ,
auth_ctx - > challenge . set_by ) ) ;
* _chal = auth_ctx - > challenge . data . data ;
return NT_STATUS_OK ;
2003-08-13 05:53:07 +04:00
}
2005-01-09 15:55:25 +03:00
for ( method = auth_ctx - > methods ; method ; method = method - > next ) {
DATA_BLOB challenge = data_blob ( NULL , 0 ) ;
2004-05-02 12:45:00 +04:00
2005-01-09 15:55:25 +03:00
nt_status = method - > ops - > get_challenge ( method , auth_ctx , & challenge ) ;
if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_NOT_IMPLEMENTED ) ) {
2003-08-13 05:53:07 +04:00
continue ;
}
2005-01-09 15:55:25 +03:00
NT_STATUS_NOT_OK_RETURN ( nt_status ) ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
if ( challenge . length ! = 8 ) {
DEBUG ( 0 , ( " auth_get_challenge: invalid challenge (length %u) by mothod [%s] \n " ,
challenge . length , method - > ops - > name ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
2003-08-13 05:53:07 +04:00
}
2005-01-09 15:55:25 +03:00
auth_ctx - > challenge . data = challenge ;
auth_ctx - > challenge . set_by = method - > ops - > name ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
break ;
}
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
if ( ! auth_ctx - > challenge . set_by ) {
uint8_t chal [ 8 ] ;
generate_random_buffer ( chal , 8 ) ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
auth_ctx - > challenge . data = data_blob_talloc ( auth_ctx , chal , 8 ) ;
NT_STATUS_HAVE_NO_MEMORY ( auth_ctx - > challenge . data . data ) ;
auth_ctx - > challenge . set_by = " random " ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
auth_ctx - > challenge . may_be_modified = True ;
2003-08-13 05:53:07 +04:00
}
2005-01-09 15:55:25 +03:00
DEBUG ( 10 , ( " auth_get_challenge: challenge set by %s \n " ,
auth_ctx - > challenge . set_by ) ) ;
* _chal = auth_ctx - > challenge . data . data ;
return NT_STATUS_OK ;
2003-08-13 05:53:07 +04:00
}
/**
* Check a user ' s Plaintext , LM or NTLM password .
*
* Check a user ' s password , as given in the user_info struct and return various
* interesting details in the server_info struct .
*
* The return value takes precedence over the contents of the server_info
* struct . When the return is other than NT_STATUS_OK the contents
* of that structure is undefined .
*
* @ param user_info Contains the user supplied components , including the passwords .
* Must be created with make_user_info ( ) or one of its wrappers .
*
* @ param auth_context Supplies the challenges and some other data .
* Must be created with make_auth_context ( ) , and the challenges should be
* filled in , either at creation or by calling the challenge geneation
* function auth_get_challenge ( ) .
*
* @ param server_info If successful , contains information about the authentication ,
* including a SAM_ACCOUNT struct describing the user .
*
* @ return An NTSTATUS with NT_STATUS_OK or an appropriate error .
*
* */
2005-01-09 15:55:25 +03:00
NTSTATUS auth_check_password ( struct auth_context * auth_ctx ,
TALLOC_CTX * mem_ctx ,
const struct auth_usersupplied_info * user_info ,
struct auth_serversupplied_info * * server_info )
2003-08-13 05:53:07 +04:00
{
2004-05-02 12:45:00 +04:00
/* if all the modules say 'not for me' this is reasonable */
NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER ;
2005-01-09 15:55:25 +03:00
struct auth_method_context * method ;
const char * method_name = " NO METHOD " ;
const uint8_t * challenge ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
DEBUG ( 3 , ( " auth_check_password: Checking password for unmapped user [%s] \\ [%s]@[%s] \n " ,
user_info - > client . domain_name , user_info - > client . account_name , user_info - > workstation_name ) ) ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
DEBUGADD ( 3 , ( " auth_check_password: mapped user is: [%s] \\ [%s]@[%s] \n " ,
user_info - > domain_name , user_info - > account_name , user_info - > workstation_name ) ) ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
nt_status = auth_get_challenge ( auth_ctx , & challenge ) ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 0 , ( " auth_check_password: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s \n " ,
auth_ctx - > challenge . data . length , auth_ctx - > challenge . set_by , nt_errstr ( nt_status ) ) ) ;
return nt_status ;
2004-06-07 07:46:32 +04:00
}
2005-01-09 15:55:25 +03:00
if ( auth_ctx - > challenge . set_by ) {
DEBUG ( 10 , ( " auth_check_password: auth_context challenge created by %s \n " ,
auth_ctx - > challenge . set_by ) ) ;
2003-08-13 05:53:07 +04:00
}
DEBUG ( 10 , ( " challenge is: \n " ) ) ;
2005-01-09 15:55:25 +03:00
dump_data ( 5 , auth_ctx - > challenge . data . data , auth_ctx - > challenge . data . length ) ;
2003-08-13 05:53:07 +04:00
# ifdef DEBUG_PASSWORD
DEBUG ( 100 , ( " user_info has passwords of length %d and %d \n " ,
user_info - > lm_resp . length , user_info - > nt_resp . length ) ) ;
DEBUG ( 100 , ( " lm: \n " ) ) ;
dump_data ( 100 , user_info - > lm_resp . data , user_info - > lm_resp . length ) ;
DEBUG ( 100 , ( " nt: \n " ) ) ;
dump_data ( 100 , user_info - > nt_resp . data , user_info - > nt_resp . length ) ;
# endif
2005-01-09 15:55:25 +03:00
for ( method = auth_ctx - > methods ; method ; method = method - > next ) {
2004-05-02 12:45:00 +04:00
NTSTATUS result ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
result = method - > ops - > check_password ( method , mem_ctx , user_info , server_info ) ;
2004-05-02 12:45:00 +04:00
/* check if the module did anything */
2005-01-09 15:55:25 +03:00
if ( ! NT_STATUS_EQUAL ( result , NT_STATUS_NOT_IMPLEMENTED ) ) {
method_name = method - > ops - > name ;
nt_status = result ;
break ;
2004-05-02 12:45:00 +04:00
}
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
DEBUG ( 11 , ( " auth_check_password: %s had nothing to say \n " , method - > ops - > name ) ) ;
2003-08-13 05:53:07 +04:00
}
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2005-01-09 15:55:25 +03:00
DEBUG ( 2 , ( " auth_check_password: %s authentication for user [%s \\ %s] FAILED with error %s \n " ,
method_name , user_info - > domain_name , user_info - > account_name ,
nt_errstr ( nt_status ) ) ) ;
return nt_status ;
2004-05-02 12:45:00 +04:00
}
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
DEBUG ( 5 , ( " auth_check_password: %s authentication for user [%s \\ %s] succeeded \n " ,
method_name , ( * server_info ) - > domain_name , ( * server_info ) - > account_name ) ) ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
return nt_status ;
2003-08-13 05:53:07 +04:00
}
/***************************************************************************
Make a auth_info struct for the auth subsystem
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-16 15:36:09 +04:00
NTSTATUS auth_context_create ( TALLOC_CTX * mem_ctx , const char * * methods ,
struct auth_context * * auth_ctx ,
struct event_context * ev )
2003-08-13 05:53:07 +04:00
{
2005-01-09 15:55:25 +03:00
int i ;
struct auth_context * ctx ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
if ( ! methods ) {
DEBUG ( 0 , ( " auth_context_create: No auth method list!? \n " ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
2003-08-13 05:53:07 +04:00
}
2004-02-03 14:10:56 +03:00
2005-01-09 15:55:25 +03:00
ctx = talloc ( mem_ctx , struct auth_context ) ;
NT_STATUS_HAVE_NO_MEMORY ( ctx ) ;
ctx - > challenge . set_by = NULL ;
ctx - > challenge . may_be_modified = False ;
ctx - > challenge . data = data_blob ( NULL , 0 ) ;
ctx - > methods = NULL ;
2005-06-16 15:36:09 +04:00
if ( ev = = NULL ) {
ev = event_context_init ( ctx ) ;
if ( ev = = NULL ) {
talloc_free ( ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
}
ctx - > event_ctx = ev ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
for ( i = 0 ; methods [ i ] ; i + + ) {
struct auth_method_context * method ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
method = talloc ( ctx , struct auth_method_context ) ;
NT_STATUS_HAVE_NO_MEMORY ( method ) ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
method - > ops = auth_backend_byname ( methods [ i ] ) ;
if ( ! method - > ops ) {
DEBUG ( 1 , ( " auth_context_create: failed to find method=%s \n " ,
methods [ i ] ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
method - > auth_ctx = ctx ;
method - > depth = i ;
DLIST_ADD_END ( ctx - > methods , method , struct auth_method_context * ) ;
2003-08-13 05:53:07 +04:00
}
2005-01-09 15:55:25 +03:00
if ( ! ctx - > methods ) {
return NT_STATUS_INTERNAL_ERROR ;
2003-08-13 05:53:07 +04:00
}
2005-01-09 15:55:25 +03:00
* auth_ctx = ctx ;
2003-08-13 05:53:07 +04:00
2005-01-09 15:55:25 +03:00
return NT_STATUS_OK ;
2003-08-13 05:53:07 +04:00
}
2004-02-03 14:10:56 +03:00
/* the list of currently registered AUTH backends */
2004-12-03 09:24:38 +03:00
static struct auth_backend {
2004-02-03 14:10:56 +03:00
const struct auth_operations * ops ;
} * backends = NULL ;
static int num_backends ;
/*
register a AUTH backend .
The ' name ' can be later used by other backends to find the operations
structure for this backend .
*/
2004-11-15 01:23:23 +03:00
NTSTATUS auth_register ( const void * _ops )
2004-02-03 14:10:56 +03:00
{
const struct auth_operations * ops = _ops ;
struct auth_operations * new_ops ;
if ( auth_backend_byname ( ops - > name ) ! = NULL ) {
/* its already registered! */
DEBUG ( 0 , ( " AUTH backend '%s' already registered \n " ,
ops - > name ) ) ;
return NT_STATUS_OBJECT_NAME_COLLISION ;
}
2004-12-03 09:24:38 +03:00
backends = realloc_p ( backends , struct auth_backend , num_backends + 1 ) ;
2004-02-03 14:10:56 +03:00
if ( ! backends ) {
smb_panic ( " out of memory in auth_register " ) ;
}
new_ops = smb_xmemdup ( ops , sizeof ( * ops ) ) ;
new_ops - > name = smb_xstrdup ( ops - > name ) ;
backends [ num_backends ] . ops = new_ops ;
num_backends + + ;
DEBUG ( 3 , ( " AUTH backend '%s' registered \n " ,
ops - > name ) ) ;
return NT_STATUS_OK ;
}
/*
return the operations structure for a named backend of the specified type
*/
const struct auth_operations * auth_backend_byname ( const char * name )
{
int i ;
for ( i = 0 ; i < num_backends ; i + + ) {
if ( strcmp ( backends [ i ] . ops - > name , name ) = = 0 ) {
return backends [ i ] . ops ;
}
}
return NULL ;
}
/*
return the AUTH interface version , and the size of some critical types
This can be used by backends to either detect compilation errors , or provide
multiple implementations for different smbd compilation options in one module
*/
const struct auth_critical_sizes * auth_interface_version ( void )
{
static const struct auth_critical_sizes critical_sizes = {
AUTH_INTERFACE_VERSION ,
sizeof ( struct auth_operations ) ,
2005-01-09 15:55:25 +03:00
sizeof ( struct auth_method_context ) ,
2004-02-03 14:10:56 +03:00
sizeof ( struct auth_context ) ,
sizeof ( struct auth_usersupplied_info ) ,
2005-01-09 15:55:25 +03:00
sizeof ( struct auth_serversupplied_info )
2004-02-03 14:10:56 +03:00
} ;
return & critical_sizes ;
}
2004-07-14 01:04:56 +04:00
NTSTATUS server_service_auth_init ( void )
{
return NT_STATUS_OK ;
}