2005-10-12 20:22:45 +00:00
/*
Unix SMB / CIFS implementation .
Authenticate a user
Copyright ( C ) Volker Lendecke 2005
2005-10-28 13:42:00 +00:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2005
2005-10-12 20:22:45 +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"
# include "libcli/composite/composite.h"
# include "winbind/wb_async_helpers.h"
# include "winbind/wb_server.h"
# include "smbd/service_stream.h"
2005-11-05 09:34:07 +00:00
# include "smbd/service_task.h"
2005-10-12 20:22:45 +00:00
# include "libcli/auth/credentials.h"
2005-10-31 06:01:55 +00:00
/* Oh, there is so much to keep an eye on when authenticating a user. Oh my! */
2005-10-12 20:22:45 +00:00
struct pam_auth_crap_state {
struct composite_context * ctx ;
2005-10-15 19:18:05 +00:00
struct event_context * event_ctx ;
2005-10-31 04:17:51 +00:00
uint32_t logon_parameters ;
2005-10-12 20:22:45 +00:00
const char * domain_name ;
const char * user_name ;
const char * workstation ;
DATA_BLOB chal , nt_resp , lm_resp ;
struct creds_CredentialState * creds_state ;
struct netr_Authenticator auth , auth2 ;
struct netr_NetworkInfo ninfo ;
struct netr_LogonSamLogon r ;
struct netr_UserSessionKey user_session_key ;
struct netr_LMSessionKey lm_key ;
DATA_BLOB info3 ;
} ;
2005-11-05 09:34:07 +00:00
/*
* NTLM authentication .
2005-10-31 06:01:55 +00:00
*/
2005-11-05 09:34:07 +00:00
static void pam_auth_crap_recv_domain ( struct composite_context * ctx ) ;
static void pam_auth_crap_recv_samlogon ( struct rpc_request * req ) ;
struct composite_context * wb_cmd_pam_auth_crap_send ( TALLOC_CTX * mem_ctx ,
struct wbsrv_service * service ,
2005-10-31 04:17:51 +00:00
uint32_t logon_parameters ,
2005-10-14 21:05:45 +00:00
const char * domain ,
const char * user ,
const char * workstation ,
DATA_BLOB chal ,
DATA_BLOB nt_resp ,
DATA_BLOB lm_resp )
2005-10-12 20:22:45 +00:00
{
2005-11-05 09:34:07 +00:00
struct composite_context * result , * ctx ;
2005-10-12 20:22:45 +00:00
struct pam_auth_crap_state * state ;
2005-11-05 09:34:07 +00:00
result = talloc ( mem_ctx , struct composite_context ) ;
if ( result = = NULL ) goto failed ;
result - > state = COMPOSITE_STATE_IN_PROGRESS ;
result - > async . fn = NULL ;
result - > event_ctx = service - > task - > event_ctx ;
2005-10-12 20:22:45 +00:00
2005-11-05 09:34:07 +00:00
state = talloc ( result , struct pam_auth_crap_state ) ;
if ( state = = NULL ) goto failed ;
state - > ctx = result ;
result - > private_data = state ;
2005-10-12 20:22:45 +00:00
2005-10-31 04:17:51 +00:00
state - > logon_parameters = logon_parameters ;
2005-10-12 20:22:45 +00:00
state - > domain_name = talloc_strdup ( state , domain ) ;
if ( state - > domain_name = = NULL ) goto failed ;
state - > user_name = talloc_strdup ( state , user ) ;
if ( state - > user_name = = NULL ) goto failed ;
state - > workstation = talloc_strdup ( state , workstation ) ;
if ( state - > workstation = = NULL ) goto failed ;
state - > chal = data_blob_talloc ( state , chal . data , chal . length ) ;
if ( ( chal . data ! = NULL ) & & ( state - > chal . data = = NULL ) ) goto failed ;
state - > nt_resp = data_blob_talloc ( state , nt_resp . data , nt_resp . length ) ;
if ( ( nt_resp . data ! = NULL ) & &
( state - > nt_resp . data = = NULL ) ) goto failed ;
state - > lm_resp = data_blob_talloc ( state , lm_resp . data , lm_resp . length ) ;
if ( ( lm_resp . data ! = NULL ) & &
( state - > lm_resp . data = = NULL ) ) goto failed ;
2005-11-05 09:34:07 +00:00
ctx = wb_sid2domain_send ( state , service , service - > primary_sid ) ;
if ( ctx = = NULL ) goto failed ;
ctx - > async . fn = pam_auth_crap_recv_domain ;
ctx - > async . private_data = state ;
return result ;
2005-10-12 20:22:45 +00:00
failed :
2005-11-05 09:34:07 +00:00
talloc_free ( result ) ;
2005-10-12 20:22:45 +00:00
return NULL ;
}
2005-10-31 06:01:55 +00:00
/*
NTLM Authentication
Send of a SamLogon request to authenticate a user .
*/
2005-11-05 09:34:07 +00:00
static void pam_auth_crap_recv_domain ( struct composite_context * ctx )
2005-10-12 20:22:45 +00:00
{
struct pam_auth_crap_state * state =
2005-11-05 09:34:07 +00:00
talloc_get_type ( ctx - > async . private_data ,
struct pam_auth_crap_state ) ;
struct rpc_request * req ;
struct wbsrv_domain * domain ;
state - > ctx - > status = wb_sid2domain_recv ( ctx , & domain ) ;
2005-10-19 13:45:44 +00:00
state - > creds_state =
cli_credentials_get_netlogon_creds ( domain - > schannel_creds ) ;
2005-10-15 19:18:05 +00:00
2005-10-12 20:22:45 +00:00
creds_client_authenticator ( state - > creds_state , & state - > auth ) ;
state - > ninfo . identity_info . account_name . string = state - > user_name ;
state - > ninfo . identity_info . domain_name . string = state - > domain_name ;
2005-10-31 04:17:51 +00:00
state - > ninfo . identity_info . parameter_control = state - > logon_parameters ;
2005-10-12 20:22:45 +00:00
state - > ninfo . identity_info . logon_id_low = 0 ;
state - > ninfo . identity_info . logon_id_high = 0 ;
state - > ninfo . identity_info . workstation . string = state - > workstation ;
SMB_ASSERT ( state - > chal . length = = sizeof ( state - > ninfo . challenge ) ) ;
memcpy ( state - > ninfo . challenge , state - > chal . data ,
sizeof ( state - > ninfo . challenge ) ) ;
state - > ninfo . nt . length = state - > nt_resp . length ;
state - > ninfo . nt . data = state - > nt_resp . data ;
state - > ninfo . lm . length = state - > lm_resp . length ;
state - > ninfo . lm . data = state - > lm_resp . data ;
state - > r . in . server_name = talloc_asprintf (
2005-10-19 13:45:44 +00:00
state , " \\ \\ %s " , dcerpc_server_name ( domain - > netlogon_pipe ) ) ;
2005-11-05 09:34:07 +00:00
if ( composite_nomem ( state - > r . in . server_name , state - > ctx ) ) return ;
2005-10-12 20:22:45 +00:00
2005-10-23 17:22:00 +00:00
ZERO_STRUCT ( state - > auth2 ) ;
2005-10-19 13:45:44 +00:00
state - > r . in . workstation =
cli_credentials_get_workstation ( domain - > schannel_creds ) ;
2005-10-12 20:22:45 +00:00
state - > r . in . credential = & state - > auth ;
state - > r . in . return_authenticator = & state - > auth2 ;
state - > r . in . logon_level = 2 ;
state - > r . in . validation_level = 3 ;
state - > r . in . logon . network = & state - > ninfo ;
state - > r . out . return_authenticator = NULL ;
2005-11-05 09:34:07 +00:00
req = dcerpc_netr_LogonSamLogon_send ( domain - > netlogon_pipe , state ,
& state - > r ) ;
composite_continue_rpc ( state - > ctx , req , pam_auth_crap_recv_samlogon ,
state ) ;
2005-10-12 20:22:45 +00:00
}
2005-10-31 06:01:55 +00:00
/*
NTLM Authentication
2005-11-05 09:34:07 +00:00
Check the SamLogon reply , decrypt and parse out the session keys and the
info3 structure .
2005-10-31 06:01:55 +00:00
*/
2005-11-05 09:34:07 +00:00
static void pam_auth_crap_recv_samlogon ( struct rpc_request * req )
2005-10-12 20:22:45 +00:00
{
struct pam_auth_crap_state * state =
2005-11-05 09:34:07 +00:00
talloc_get_type ( req - > async . private ,
struct pam_auth_crap_state ) ;
2005-10-12 20:22:45 +00:00
struct netr_SamBaseInfo * base ;
DATA_BLOB tmp_blob ;
2005-11-05 09:34:07 +00:00
state - > ctx - > status = dcerpc_ndr_request_recv ( req ) ;
if ( ! composite_is_ok ( state - > ctx ) ) return ;
2005-10-15 19:18:05 +00:00
2005-10-12 20:22:45 +00:00
if ( ( state - > r . out . return_authenticator = = NULL ) | |
( ! creds_client_check ( state - > creds_state ,
& state - > r . out . return_authenticator - > cred ) ) ) {
DEBUG ( 0 , ( " Credentials check failed! \n " ) ) ;
2005-11-05 09:34:07 +00:00
composite_error ( state - > ctx , NT_STATUS_ACCESS_DENIED ) ;
return ;
2005-10-12 20:22:45 +00:00
}
2005-11-05 09:34:07 +00:00
state - > ctx - > status = state - > r . out . result ;
if ( ! composite_is_ok ( state - > ctx ) ) return ;
2005-10-31 06:01:55 +00:00
/* Decrypt the session keys before we reform the info3, so the
* person on the other end of winbindd pipe doesn ' t have to .
* They won ' t have the encryption key anyway */
2005-10-12 20:22:45 +00:00
creds_decrypt_samlogon ( state - > creds_state ,
state - > r . in . validation_level ,
& state - > r . out . validation ) ;
2005-11-05 09:34:07 +00:00
state - > ctx - > status = ndr_push_struct_blob (
& tmp_blob , state , state - > r . out . validation . sam3 ,
2005-10-12 20:22:45 +00:00
( ndr_push_flags_fn_t ) ndr_push_netr_SamInfo3 ) ;
2005-11-05 09:34:07 +00:00
if ( ! composite_is_ok ( state - > ctx ) ) return ;
2005-10-31 06:01:55 +00:00
/* The Samba3 protocol is a bit broken (due to non-IDL
* heritage , so for compatability we must add a non - zero 4
* bytes to the info3 */
2005-10-12 20:22:45 +00:00
state - > info3 = data_blob_talloc ( state , NULL , tmp_blob . length + 4 ) ;
2005-11-05 09:34:07 +00:00
if ( composite_nomem ( state - > info3 . data , state - > ctx ) ) return ;
2005-10-12 20:22:45 +00:00
SIVAL ( state - > info3 . data , 0 , 1 ) ;
memcpy ( state - > info3 . data + 4 , tmp_blob . data , tmp_blob . length ) ;
2005-11-05 09:34:07 +00:00
/* We actually only ask for level 3, and assume it above, but
* anyway . . . */
2005-10-12 20:22:45 +00:00
base = NULL ;
switch ( state - > r . in . validation_level ) {
case 2 :
base = & state - > r . out . validation . sam2 - > base ;
break ;
case 3 :
base = & state - > r . out . validation . sam3 - > base ;
break ;
case 6 :
base = & state - > r . out . validation . sam6 - > base ;
break ;
}
if ( base = = NULL ) {
2005-11-05 09:34:07 +00:00
composite_error ( state - > ctx , NT_STATUS_INTERNAL_ERROR ) ;
return ;
2005-10-12 20:22:45 +00:00
}
state - > user_session_key = base - > key ;
state - > lm_key = base - > LMSessKey ;
2005-10-31 06:01:55 +00:00
/* Give the caller the most accurate username possible.
* Assists where case sensitive comparisons may be done by our
* ntlm_auth callers */
2005-10-28 13:42:00 +00:00
if ( base - > account_name . string ) {
state - > user_name = base - > account_name . string ;
talloc_steal ( state , base - > account_name . string ) ;
}
if ( base - > domain . string ) {
state - > domain_name = base - > domain . string ;
talloc_steal ( state , base - > domain . string ) ;
}
2005-11-05 09:34:07 +00:00
composite_done ( state - > ctx ) ;
2005-10-12 20:22:45 +00:00
}
2005-10-14 21:05:45 +00:00
NTSTATUS wb_cmd_pam_auth_crap_recv ( struct composite_context * c ,
TALLOC_CTX * mem_ctx ,
DATA_BLOB * info3 ,
struct netr_UserSessionKey * user_session_key ,
2005-10-28 13:42:00 +00:00
struct netr_LMSessionKey * lm_key ,
char * * unix_username )
2005-10-12 20:22:45 +00:00
{
2005-10-23 17:22:00 +00:00
struct pam_auth_crap_state * state =
talloc_get_type ( c - > private_data , struct pam_auth_crap_state ) ;
2005-10-12 20:22:45 +00:00
NTSTATUS status = composite_wait ( c ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
info3 - > length = state - > info3 . length ;
info3 - > data = talloc_steal ( mem_ctx , state - > info3 . data ) ;
* user_session_key = state - > user_session_key ;
* lm_key = state - > lm_key ;
2005-10-28 13:42:00 +00:00
* unix_username = talloc_asprintf ( mem_ctx , " %s%s%s " ,
2005-11-05 09:34:07 +00:00
state - > domain_name ,
lp_winbind_separator ( ) ,
2005-10-28 13:42:00 +00:00
state - > user_name ) ;
if ( ! * unix_username ) {
status = NT_STATUS_NO_MEMORY ;
}
2005-10-12 20:22:45 +00:00
}
2005-10-23 17:22:00 +00:00
talloc_free ( state ) ;
2005-10-12 20:22:45 +00:00
return status ;
}
2005-11-05 09:34:07 +00:00
NTSTATUS wb_cmd_pam_auth_crap ( TALLOC_CTX * mem_ctx ,
struct wbsrv_service * service ,
2005-10-31 04:17:51 +00:00
uint32_t logon_parameters ,
2005-10-14 21:05:45 +00:00
const char * domain , const char * user ,
const char * workstation ,
DATA_BLOB chal , DATA_BLOB nt_resp ,
2005-11-05 09:34:07 +00:00
DATA_BLOB lm_resp ,
2005-10-14 21:05:45 +00:00
DATA_BLOB * info3 ,
struct netr_UserSessionKey * user_session_key ,
2005-10-28 13:42:00 +00:00
struct netr_LMSessionKey * lm_key ,
char * * unix_username )
2005-10-12 20:22:45 +00:00
{
struct composite_context * c =
2005-11-05 09:34:07 +00:00
wb_cmd_pam_auth_crap_send ( mem_ctx , service , logon_parameters ,
2005-10-31 04:17:51 +00:00
domain , user , workstation ,
2005-10-14 21:05:45 +00:00
chal , nt_resp , lm_resp ) ;
return wb_cmd_pam_auth_crap_recv ( c , mem_ctx , info3 , user_session_key ,
2005-10-28 13:42:00 +00:00
lm_key , unix_username ) ;
}
2005-11-05 09:34:07 +00:00
struct composite_context * wb_cmd_pam_auth_send ( TALLOC_CTX * mem_ctx ,
struct wbsrv_service * service ,
2005-10-28 13:42:00 +00:00
const char * domain ,
const char * user ,
const char * password )
{
struct cli_credentials * credentials ;
const char * workstation ;
NTSTATUS status ;
DATA_BLOB chal , nt_resp , lm_resp , names_blob ;
int flags = CLI_CRED_NTLM_AUTH ;
if ( lp_client_lanman_auth ( ) ) {
flags | = CLI_CRED_LANMAN_AUTH ;
}
if ( lp_client_ntlmv2_auth ( ) ) {
flags | = CLI_CRED_NTLMv2_AUTH ;
}
DEBUG ( 5 , ( " wbsrv_samba3_pam_auth_crap called \n " ) ) ;
2005-11-05 09:34:07 +00:00
credentials = cli_credentials_init ( mem_ctx ) ;
2005-10-28 13:42:00 +00:00
if ( ! credentials ) {
return NULL ;
}
cli_credentials_set_conf ( credentials ) ;
cli_credentials_set_domain ( credentials , domain , CRED_SPECIFIED ) ;
cli_credentials_set_username ( credentials , user , CRED_SPECIFIED ) ;
cli_credentials_set_password ( credentials , password , CRED_SPECIFIED ) ;
2005-11-05 09:34:07 +00:00
chal = data_blob_talloc ( mem_ctx , NULL , 8 ) ;
2005-10-28 13:42:00 +00:00
if ( ! chal . data ) {
return NULL ;
}
generate_random_buffer ( chal . data , chal . length ) ;
2005-11-05 09:34:07 +00:00
cli_credentials_get_ntlm_username_domain ( credentials , mem_ctx ,
2005-10-28 13:42:00 +00:00
& user , & domain ) ;
/* for best compatability with multiple vitual netbios names
* on the host , this should be generated from the
* cli_credentials associated with the machine account */
workstation = cli_credentials_get_workstation ( credentials ) ;
2005-11-05 09:34:07 +00:00
names_blob = NTLMv2_generate_names_blob (
mem_ctx ,
cli_credentials_get_workstation ( credentials ) ,
cli_credentials_get_domain ( credentials ) ) ;
2005-10-28 13:42:00 +00:00
2005-11-05 09:34:07 +00:00
status = cli_credentials_get_ntlm_response (
credentials , mem_ctx , & flags , chal , names_blob ,
& lm_resp , & nt_resp , NULL , NULL ) ;
2005-10-28 13:42:00 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
2005-11-05 09:34:07 +00:00
return wb_cmd_pam_auth_crap_send ( mem_ctx , service ,
0 /* logon parameters */ ,
domain , user , workstation ,
chal , nt_resp , lm_resp ) ;
2005-10-28 13:42:00 +00:00
}
NTSTATUS wb_cmd_pam_auth_recv ( struct composite_context * c )
{
struct pam_auth_crap_state * state =
talloc_get_type ( c - > private_data , struct pam_auth_crap_state ) ;
NTSTATUS status = composite_wait ( c ) ;
talloc_free ( state ) ;
return status ;
}
2005-11-05 09:34:07 +00:00
NTSTATUS wb_cmd_pam_auth ( TALLOC_CTX * mem_ctx , struct wbsrv_service * service ,
2005-10-28 13:42:00 +00:00
const char * domain , const char * user ,
const char * password )
{
struct composite_context * c =
2005-11-05 09:34:07 +00:00
wb_cmd_pam_auth_send ( mem_ctx , service , domain , user , password ) ;
2005-10-28 13:42:00 +00:00
return wb_cmd_pam_auth_recv ( c ) ;
2005-10-12 20:22:45 +00:00
}