2003-08-13 01:53:07 +00:00
/*
Unix SMB / CIFS implementation .
Password and authentication handling
Copyright ( C ) Andrew Bartlett 2001 - 2002
2005-01-09 12:55:25 +00:00
Copyright ( C ) Stefan Metzmacher 2005
2003-08-13 01:53:07 +00: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"
2006-08-30 11:29:34 +00:00
# include "lib/util/dlinklist.h"
2004-11-02 02:57:18 +00:00
# include "auth/auth.h"
2005-06-16 11:36:09 +00:00
# include "lib/events/events.h"
2006-02-23 12:48:13 +00:00
# include "build.h"
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00: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 01:53:07 +00:00
/****************************************************************************
Try to get a challenge out of the various authentication modules .
Returns a const char of length 8 bytes .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-10-29 17:40:19 +00:00
_PUBLIC_ NTSTATUS auth_get_challenge ( struct auth_context * auth_ctx , const uint8_t * * _chal )
2003-08-13 01:53:07 +00:00
{
2005-01-09 12:55:25 +00: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 01:53:07 +00:00
}
2005-01-09 12:55:25 +00:00
for ( method = auth_ctx - > methods ; method ; method = method - > next ) {
DATA_BLOB challenge = data_blob ( NULL , 0 ) ;
2004-05-02 08:45:00 +00:00
2005-01-09 12:55:25 +00:00
nt_status = method - > ops - > get_challenge ( method , auth_ctx , & challenge ) ;
if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_NOT_IMPLEMENTED ) ) {
2003-08-13 01:53:07 +00:00
continue ;
}
2005-01-09 12:55:25 +00:00
NT_STATUS_NOT_OK_RETURN ( nt_status ) ;
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00:00
if ( challenge . length ! = 8 ) {
DEBUG ( 0 , ( " auth_get_challenge: invalid challenge (length %u) by mothod [%s] \n " ,
2005-07-17 09:20:52 +00:00
( unsigned ) challenge . length , method - > ops - > name ) ) ;
2005-01-09 12:55:25 +00:00
return NT_STATUS_INTERNAL_ERROR ;
2003-08-13 01:53:07 +00:00
}
2005-01-09 12:55:25 +00:00
auth_ctx - > challenge . data = challenge ;
auth_ctx - > challenge . set_by = method - > ops - > name ;
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00:00
break ;
}
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00:00
if ( ! auth_ctx - > challenge . set_by ) {
uint8_t chal [ 8 ] ;
generate_random_buffer ( chal , 8 ) ;
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00: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 01:53:07 +00:00
2005-01-09 12:55:25 +00:00
auth_ctx - > challenge . may_be_modified = True ;
2003-08-13 01:53:07 +00:00
}
2005-01-09 12:55:25 +00: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 01:53:07 +00:00
}
2006-07-27 13:02:27 +00:00
struct auth_check_password_sync_state {
BOOL finished ;
NTSTATUS status ;
struct auth_serversupplied_info * server_info ;
} ;
static void auth_check_password_sync_callback ( struct auth_check_password_request * req ,
void * private_data )
{
struct auth_check_password_sync_state * s = talloc_get_type ( private_data ,
struct auth_check_password_sync_state ) ;
s - > finished = True ;
s - > status = auth_check_password_recv ( req , s , & s - > server_info ) ;
}
2003-08-13 01:53:07 +00:00
/**
* Check a user ' s Plaintext , LM or NTLM password .
2006-07-27 13:02:27 +00:00
* ( sync version )
2003-08-13 01:53:07 +00:00
*
* 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 .
*
2006-07-27 13:02:27 +00:00
* @ param auth_ctx Supplies the challenges and some other data .
* Must be created with auth_context_create ( ) , and the challenges should be
2003-08-13 01:53:07 +00:00
* filled in , either at creation or by calling the challenge geneation
* function auth_get_challenge ( ) .
*
2006-07-27 13:02:27 +00:00
* @ param user_info Contains the user supplied components , including the passwords .
*
* @ param mem_ctx The parent memory context for the server_info structure
*
2003-08-13 01:53:07 +00:00
* @ 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 12:55:25 +00: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 )
2006-07-27 13:02:27 +00:00
{
struct auth_check_password_sync_state * sync_state ;
NTSTATUS status ;
sync_state = talloc_zero ( auth_ctx , struct auth_check_password_sync_state ) ;
NT_STATUS_HAVE_NO_MEMORY ( sync_state ) ;
auth_check_password_send ( auth_ctx , user_info , auth_check_password_sync_callback , sync_state ) ;
while ( ! sync_state - > finished ) {
event_loop_once ( auth_ctx - > event_ctx ) ;
}
status = sync_state - > status ;
if ( NT_STATUS_IS_OK ( status ) ) {
* server_info = talloc_steal ( mem_ctx , sync_state - > server_info ) ;
}
talloc_free ( sync_state ) ;
return status ;
}
struct auth_check_password_request {
struct auth_context * auth_ctx ;
const struct auth_usersupplied_info * user_info ;
struct auth_serversupplied_info * server_info ;
struct auth_method_context * method ;
NTSTATUS status ;
struct {
void ( * fn ) ( struct auth_check_password_request * req , void * private_data ) ;
void * private_data ;
} callback ;
} ;
static void auth_check_password_async_timed_handler ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * ptr )
{
struct auth_check_password_request * req = talloc_get_type ( ptr , struct auth_check_password_request ) ;
req - > status = req - > method - > ops - > check_password ( req - > method , req , req - > user_info , & req - > server_info ) ;
req - > callback . fn ( req , req - > callback . private_data ) ;
}
/**
* Check a user ' s Plaintext , LM or NTLM password .
* async send hook
*
* 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 auth_ctx 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 user_info Contains the user supplied components , including the passwords .
*
* @ param callback A callback function which will be called when the operation is finished .
* The callback function needs to call auth_check_password_recv ( ) to get the return values
*
* @ param private_data A private pointer which will ba passed to the callback function
*
* */
void auth_check_password_send ( struct auth_context * auth_ctx ,
const struct auth_usersupplied_info * user_info ,
void ( * callback ) ( struct auth_check_password_request * req , void * private_data ) ,
void * private_data )
2003-08-13 01:53:07 +00:00
{
2004-05-02 08:45:00 +00:00
/* if all the modules say 'not for me' this is reasonable */
2005-07-22 04:10:07 +00:00
NTSTATUS nt_status ;
2005-01-09 12:55:25 +00:00
struct auth_method_context * method ;
const uint8_t * challenge ;
2006-07-27 13:02:27 +00:00
struct auth_usersupplied_info * user_info_tmp ;
struct auth_check_password_request * req = NULL ;
2003-08-13 01:53:07 +00:00
2006-07-27 13:02:27 +00:00
DEBUG ( 3 , ( " auth_check_password_send: Checking password for unmapped user [%s] \\ [%s]@[%s] \n " ,
2005-01-09 12:55:25 +00:00
user_info - > client . domain_name , user_info - > client . account_name , user_info - > workstation_name ) ) ;
2003-08-13 01:53:07 +00:00
2006-07-27 13:02:27 +00:00
req = talloc_zero ( auth_ctx , struct auth_check_password_request ) ;
if ( ! req ) {
callback ( NULL , private_data ) ;
return ;
}
req - > auth_ctx = auth_ctx ;
req - > user_info = user_info ;
req - > callback . fn = callback ;
req - > callback . private_data = private_data ;
2005-07-22 04:10:07 +00:00
if ( ! user_info - > mapped_state ) {
2006-07-27 13:02:27 +00:00
nt_status = map_user_info ( req , user_info , & user_info_tmp ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) goto failed ;
2005-07-22 04:10:07 +00:00
user_info = user_info_tmp ;
2006-07-27 13:02:27 +00:00
req - > user_info = user_info_tmp ;
2005-07-22 04:10:07 +00:00
}
2006-07-27 13:02:27 +00:00
DEBUGADD ( 3 , ( " auth_check_password_send: mapped user is: [%s] \\ [%s]@[%s] \n " ,
2005-07-22 04:10:07 +00:00
user_info - > mapped . domain_name , user_info - > mapped . account_name , user_info - > workstation_name ) ) ;
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00:00
nt_status = auth_get_challenge ( auth_ctx , & challenge ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2006-07-27 13:02:27 +00:00
DEBUG ( 0 , ( " auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s \n " ,
2005-07-17 09:20:52 +00:00
( unsigned ) auth_ctx - > challenge . data . length , auth_ctx - > challenge . set_by , nt_errstr ( nt_status ) ) ) ;
2006-07-27 13:02:27 +00:00
goto failed ;
2004-06-07 03:46:32 +00:00
}
2005-01-09 12:55:25 +00:00
if ( auth_ctx - > challenge . set_by ) {
2006-07-27 13:02:27 +00:00
DEBUG ( 10 , ( " auth_check_password_send: auth_context challenge created by %s \n " ,
2005-01-09 12:55:25 +00:00
auth_ctx - > challenge . set_by ) ) ;
2003-08-13 01:53:07 +00:00
}
2006-07-27 13:02:27 +00:00
DEBUG ( 10 , ( " auth_check_password_send: challenge is: \n " ) ) ;
2005-01-09 12:55:25 +00:00
dump_data ( 5 , auth_ctx - > challenge . data . data , auth_ctx - > challenge . data . length ) ;
2003-08-13 01:53:07 +00:00
2005-07-22 04:10:07 +00:00
nt_status = NT_STATUS_NO_SUCH_USER ; /* If all the modules say 'not for me', then this is reasonable */
2005-01-09 12:55:25 +00:00
for ( method = auth_ctx - > methods ; method ; method = method - > next ) {
2004-05-02 08:45:00 +00:00
NTSTATUS result ;
2006-07-27 13:02:27 +00:00
struct timed_event * te = NULL ;
2003-08-13 01:53:07 +00:00
2006-07-27 11:24:18 +00:00
/* check if the module wants to chek the password */
2006-07-27 13:02:27 +00:00
result = method - > ops - > want_check ( method , req , user_info ) ;
2006-07-27 11:24:18 +00:00
if ( NT_STATUS_EQUAL ( result , NT_STATUS_NOT_IMPLEMENTED ) ) {
2006-07-27 13:02:27 +00:00
DEBUG ( 11 , ( " auth_check_password_send: %s had nothing to say \n " , method - > ops - > name ) ) ;
2006-07-27 11:24:18 +00:00
continue ;
2004-05-02 08:45:00 +00:00
}
2003-08-13 01:53:07 +00:00
2006-07-27 11:24:18 +00:00
nt_status = result ;
2006-07-27 13:02:27 +00:00
req - > method = method ;
2006-07-27 11:24:18 +00:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) break ;
2006-07-27 13:02:27 +00:00
te = event_add_timed ( auth_ctx - > event_ctx , req ,
timeval_zero ( ) ,
auth_check_password_async_timed_handler , req ) ;
if ( ! te ) {
nt_status = NT_STATUS_NO_MEMORY ;
goto failed ;
}
return ;
2003-08-13 01:53:07 +00:00
}
2006-07-27 13:02:27 +00:00
failed :
req - > status = nt_status ;
req - > callback . fn ( req , req - > callback . private_data ) ;
}
/**
* Check a user ' s Plaintext , LM or NTLM password .
* async receive function
*
* 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 req The async auth_check_password state , passes to the callers callback function
*
* @ param mem_ctx The parent memory context for the server_info structure
*
* @ 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 .
*
* */
NTSTATUS auth_check_password_recv ( struct auth_check_password_request * req ,
TALLOC_CTX * mem_ctx ,
struct auth_serversupplied_info * * server_info )
{
NTSTATUS status ;
NT_STATUS_HAVE_NO_MEMORY ( req ) ;
if ( NT_STATUS_IS_OK ( req - > status ) ) {
2006-08-03 09:29:12 +00:00
DEBUG ( 5 , ( " auth_check_password_recv: %s authentication for user [%s \\ %s] succeeded \n " ,
2006-07-27 13:02:27 +00:00
req - > method - > ops - > name , req - > server_info - > domain_name , req - > server_info - > account_name ) ) ;
* server_info = talloc_steal ( mem_ctx , req - > server_info ) ;
} else {
2006-08-03 09:29:12 +00:00
DEBUG ( 2 , ( " auth_check_password_recv: %s authentication for user [%s \\ %s] FAILED with error %s \n " ,
2006-07-27 13:02:27 +00:00
( req - > method ? req - > method - > ops - > name : " NO_METHOD " ) ,
req - > user_info - > mapped . domain_name ,
req - > user_info - > mapped . account_name ,
nt_errstr ( req - > status ) ) ) ;
2004-05-02 08:45:00 +00:00
}
2003-08-13 01:53:07 +00:00
2006-07-27 13:02:27 +00:00
status = req - > status ;
talloc_free ( req ) ;
return status ;
2003-08-13 01:53:07 +00:00
}
/***************************************************************************
Make a auth_info struct for the auth subsystem
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-16 11:36:09 +00:00
NTSTATUS auth_context_create ( TALLOC_CTX * mem_ctx , const char * * methods ,
2006-07-31 14:05:08 +00:00
struct event_context * ev ,
struct messaging_context * msg ,
struct auth_context * * auth_ctx )
2003-08-13 01:53:07 +00:00
{
2005-01-09 12:55:25 +00:00
int i ;
struct auth_context * ctx ;
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00:00
if ( ! methods ) {
DEBUG ( 0 , ( " auth_context_create: No auth method list!? \n " ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
2003-08-13 01:53:07 +00:00
}
2004-02-03 11:10:56 +00:00
2006-07-31 14:05:08 +00:00
if ( ! ev ) {
DEBUG ( 0 , ( " auth_context_create: called with out event context \n " ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
if ( ! msg ) {
DEBUG ( 0 , ( " auth_context_create: called with out messaging context \n " ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
2005-01-09 12:55:25 +00: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 ;
2006-07-31 14:05:08 +00:00
ctx - > event_ctx = ev ;
ctx - > msg_ctx = msg ;
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00:00
for ( i = 0 ; methods [ i ] ; i + + ) {
struct auth_method_context * method ;
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00:00
method = talloc ( ctx , struct auth_method_context ) ;
NT_STATUS_HAVE_NO_MEMORY ( method ) ;
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00: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 01:53:07 +00:00
}
2005-01-09 12:55:25 +00:00
if ( ! ctx - > methods ) {
return NT_STATUS_INTERNAL_ERROR ;
2003-08-13 01:53:07 +00:00
}
2005-01-09 12:55:25 +00:00
* auth_ctx = ctx ;
2003-08-13 01:53:07 +00:00
2005-01-09 12:55:25 +00:00
return NT_STATUS_OK ;
2003-08-13 01:53:07 +00:00
}
2004-02-03 11:10:56 +00:00
/* the list of currently registered AUTH backends */
2004-12-03 06:24:38 +00:00
static struct auth_backend {
2004-02-03 11:10:56 +00: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-14 22:23:23 +00:00
NTSTATUS auth_register ( const void * _ops )
2004-02-03 11:10:56 +00: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 06:24:38 +00:00
backends = realloc_p ( backends , struct auth_backend , num_backends + 1 ) ;
2004-02-03 11:10:56 +00:00
if ( ! backends ) {
2006-03-20 00:28:12 +00:00
return NT_STATUS_NO_MEMORY ;
2004-02-03 11:10:56 +00:00
}
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 12:55:25 +00:00
sizeof ( struct auth_method_context ) ,
2004-02-03 11:10:56 +00:00
sizeof ( struct auth_context ) ,
sizeof ( struct auth_usersupplied_info ) ,
2005-01-09 12:55:25 +00:00
sizeof ( struct auth_serversupplied_info )
2004-02-03 11:10:56 +00:00
} ;
return & critical_sizes ;
}
2006-04-06 16:08:46 +00:00
NTSTATUS auth_init ( void )
2004-07-13 21:04:56 +00:00
{
2006-04-06 16:08:46 +00:00
static BOOL initialized = False ;
2006-03-07 17:53:28 +00:00
init_module_fn static_init [ ] = STATIC_auth_MODULES ;
2006-04-06 16:08:46 +00:00
init_module_fn * shared_init ;
if ( initialized ) return NT_STATUS_OK ;
initialized = True ;
shared_init = load_samba_modules ( NULL , " auth " ) ;
2005-12-26 16:46:55 +00:00
run_init_functions ( static_init ) ;
run_init_functions ( shared_init ) ;
talloc_free ( shared_init ) ;
2004-07-13 21:04:56 +00:00
return NT_STATUS_OK ;
}
2006-04-06 16:08:46 +00:00
NTSTATUS server_service_auth_init ( void )
{
return auth_init ( ) ;
}