2011-12-16 16:55:36 +11:00
/*
Unix SMB / Netbios implementation .
Version 3.0
2011-12-31 22:57:18 +11:00
handle GENSEC authentication , server side
2011-12-16 16:55:36 +11:00
Copyright ( C ) Andrew Tridgell 2001
Copyright ( C ) Andrew Bartlett 2001 - 2003 , 2011
2011-12-31 22:57:18 +11:00
Copyright ( C ) Simo Sorce 2010.
2011-12-16 16:55:36 +11: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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "auth.h"
# include "../lib/tsocket/tsocket.h"
# include "auth/gensec/gensec.h"
# include "lib/param/param.h"
2011-12-31 22:57:18 +11:00
# ifdef HAVE_KRB5
2012-03-31 22:09:22 -04:00
# include "auth/kerberos/pac_utils.h"
2011-12-31 22:57:18 +11:00
# endif
2012-01-02 13:06:29 +11:00
# include "librpc/crypto/gse.h"
2012-01-12 21:16:36 +11:00
# include "auth/credentials/credentials.h"
2012-07-23 12:47:01 +10:00
# include "lib/param/loadparm.h"
2013-09-18 18:23:40 +02:00
# include "librpc/gen_ndr/dcerpc.h"
2011-12-31 22:57:18 +11:00
static NTSTATUS auth3_generate_session_info_pac ( struct auth4_context * auth_ctx ,
TALLOC_CTX * mem_ctx ,
struct smb_krb5_context * smb_krb5_context ,
DATA_BLOB * pac_blob ,
const char * princ_name ,
const struct tsocket_address * remote_address ,
uint32_t session_info_flags ,
struct auth_session_info * * session_info )
{
TALLOC_CTX * tmp_ctx ;
struct PAC_LOGON_INFO * logon_info = NULL ;
bool is_mapped ;
bool is_guest ;
char * ntuser ;
char * ntdomain ;
char * username ;
char * rhost ;
struct passwd * pw ;
NTSTATUS status ;
int rc ;
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( ! tmp_ctx ) {
return NT_STATUS_NO_MEMORY ;
}
if ( pac_blob ) {
# ifdef HAVE_KRB5
2012-07-05 13:17:00 -07:00
status = kerberos_pac_logon_info ( tmp_ctx , * pac_blob , NULL , NULL ,
NULL , NULL , 0 , & logon_info ) ;
2011-12-31 22:57:18 +11:00
# else
status = NT_STATUS_ACCESS_DENIED ;
# endif
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
}
}
rc = get_remote_hostname ( remote_address ,
& rhost ,
tmp_ctx ) ;
if ( rc < 0 ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
if ( strequal ( rhost , " UNKNOWN " ) ) {
rhost = tsocket_address_inet_addr_string ( remote_address ,
tmp_ctx ) ;
if ( rhost = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
}
status = get_user_from_kerberos_info ( tmp_ctx , rhost ,
princ_name , logon_info ,
& is_mapped , & is_guest ,
& ntuser , & ntdomain ,
& username , & pw ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to map kerberos principal to system user "
" (%s) \n " , nt_errstr ( status ) ) ) ;
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
2012-01-10 22:01:44 +11:00
/* save the PAC data if we have it */
if ( logon_info ) {
netsamlogon_cache_store ( ntuser , & logon_info - > info3 ) ;
}
2011-12-31 22:57:18 +11:00
2012-01-26 09:21:21 +01:00
/* setup the string used by %U */
sub_set_smb_name ( username ) ;
/* reload services so that the new %U is taken into account */
lp_load ( get_dyn_CONFIGFILE ( ) , false , false , true , true ) ;
2011-12-31 22:57:18 +11:00
status = make_session_info_krb5 ( mem_ctx ,
ntuser , ntdomain , username , pw ,
logon_info , is_guest , is_mapped , NULL /* No session key for now, caller will sort it out */ ,
session_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to map kerberos pac to server info (%s) \n " ,
nt_errstr ( status ) ) ) ;
status = NT_STATUS_ACCESS_DENIED ;
goto done ;
}
DEBUG ( 5 , ( __location__ " OK: user: %s domain: %s client: %s \n " ,
ntuser , ntdomain , rhost ) ) ;
status = NT_STATUS_OK ;
done :
TALLOC_FREE ( tmp_ctx ) ;
return status ;
}
2011-12-16 16:55:36 +11:00
2012-02-03 16:14:42 +11:00
static struct auth4_context * make_auth4_context_s3 ( TALLOC_CTX * mem_ctx , struct auth_context * auth_context )
{
struct auth4_context * auth4_context = talloc_zero ( mem_ctx , struct auth4_context ) ;
if ( auth4_context = = NULL ) {
DEBUG ( 10 , ( " failed to allocate auth4_context failed \n " ) ) ;
return NULL ;
}
auth4_context - > generate_session_info_pac = auth3_generate_session_info_pac ;
auth4_context - > generate_session_info = auth3_generate_session_info ;
2012-02-03 16:33:44 +11:00
auth4_context - > get_ntlm_challenge = auth3_get_challenge ;
auth4_context - > set_ntlm_challenge = auth3_set_challenge ;
auth4_context - > check_ntlm_password = auth3_check_password ;
2012-02-03 16:14:42 +11:00
auth4_context - > private_data = talloc_steal ( auth4_context , auth_context ) ;
return auth4_context ;
}
NTSTATUS make_auth4_context ( TALLOC_CTX * mem_ctx , struct auth4_context * * auth4_context_out )
{
struct auth_context * auth_context ;
NTSTATUS nt_status ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
NT_STATUS_HAVE_NO_MEMORY ( tmp_ctx ) ;
nt_status = make_auth_context_subsystem ( tmp_ctx , & auth_context ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
TALLOC_FREE ( tmp_ctx ) ;
return nt_status ;
}
if ( auth_context - > make_auth4_context ) {
nt_status = auth_context - > make_auth4_context ( mem_ctx , auth4_context_out ) ;
TALLOC_FREE ( tmp_ctx ) ;
return nt_status ;
} else {
struct auth4_context * auth4_context = make_auth4_context_s3 ( tmp_ctx , auth_context ) ;
if ( auth4_context = = NULL ) {
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
* auth4_context_out = talloc_steal ( mem_ctx , auth4_context ) ;
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
}
2011-12-26 12:13:21 +11:00
NTSTATUS auth_generic_prepare ( TALLOC_CTX * mem_ctx ,
const struct tsocket_address * remote_address ,
2011-12-26 14:23:15 +11:00
struct gensec_security * * gensec_security_out )
2011-12-16 16:55:36 +11:00
{
2011-12-26 14:23:15 +11:00
struct gensec_security * gensec_security ;
2011-12-16 16:55:36 +11:00
struct auth_context * auth_context ;
NTSTATUS nt_status ;
2011-12-26 14:23:15 +11:00
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
NT_STATUS_HAVE_NO_MEMORY ( tmp_ctx ) ;
2011-12-16 16:55:36 +11:00
2011-12-26 14:23:15 +11:00
nt_status = make_auth_context_subsystem ( tmp_ctx , & auth_context ) ;
2011-12-16 16:55:36 +11:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2011-12-26 14:23:15 +11:00
TALLOC_FREE ( tmp_ctx ) ;
2011-12-16 16:55:36 +11:00
return nt_status ;
}
if ( auth_context - > prepare_gensec ) {
2011-12-26 14:23:15 +11:00
nt_status = auth_context - > prepare_gensec ( tmp_ctx ,
& gensec_security ) ;
2011-12-16 16:55:36 +11:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2011-12-26 14:23:15 +11:00
TALLOC_FREE ( tmp_ctx ) ;
2011-12-16 16:55:36 +11:00
return nt_status ;
}
} else {
2013-08-05 11:20:21 +02:00
const struct gensec_security_ops * * backends = NULL ;
2011-12-16 16:55:36 +11:00
struct gensec_settings * gensec_settings ;
struct loadparm_context * lp_ctx ;
2012-01-12 16:12:02 +01:00
size_t idx = 0 ;
2012-01-12 21:16:36 +11:00
struct cli_credentials * server_credentials ;
2012-01-31 16:17:48 +11:00
const char * dns_name ;
const char * dns_domain ;
2012-02-03 16:14:42 +11:00
struct auth4_context * auth4_context = make_auth4_context_s3 ( tmp_ctx , auth_context ) ;
2011-12-31 22:57:18 +11:00
if ( auth4_context = = NULL ) {
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
2012-06-27 23:24:39 +10:00
lp_ctx = loadparm_init_s3 ( tmp_ctx , loadparm_s3_helpers ( ) ) ;
2011-12-16 16:55:36 +11:00
if ( lp_ctx = = NULL ) {
DEBUG ( 10 , ( " loadparm_init_s3 failed \n " ) ) ;
2011-12-26 14:23:15 +11:00
TALLOC_FREE ( tmp_ctx ) ;
2011-12-16 16:55:36 +11:00
return NT_STATUS_INVALID_SERVER_STATE ;
}
2011-12-26 14:23:15 +11:00
gensec_settings = lpcfg_gensec_settings ( tmp_ctx , lp_ctx ) ;
2011-12-16 16:55:36 +11:00
if ( lp_ctx = = NULL ) {
DEBUG ( 10 , ( " lpcfg_gensec_settings failed \n " ) ) ;
2011-12-26 14:23:15 +11:00
TALLOC_FREE ( tmp_ctx ) ;
2011-12-16 16:55:36 +11:00
return NT_STATUS_NO_MEMORY ;
}
2012-01-31 16:17:48 +11:00
/*
* This should be a ' netbios domain - > DNS domain '
* mapping , and can currently validly return NULL on
* poorly configured systems .
*
* This is used for the NTLMSSP server
*
*/
dns_name = get_mydnsfullname ( ) ;
if ( dns_name = = NULL ) {
dns_name = " " ;
}
dns_domain = get_mydnsdomname ( tmp_ctx ) ;
if ( dns_domain = = NULL ) {
dns_domain = " " ;
}
gensec_settings - > server_dns_name = strlower_talloc ( gensec_settings , dns_name ) ;
if ( gensec_settings - > server_dns_name = = NULL ) {
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
gensec_settings - > server_dns_domain = strlower_talloc ( gensec_settings , dns_domain ) ;
if ( gensec_settings - > server_dns_domain = = NULL ) {
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
2013-08-05 11:20:21 +02:00
backends = talloc_zero_array ( gensec_settings ,
2013-09-18 18:23:40 +02:00
const struct gensec_security_ops * , 5 ) ;
2013-08-05 11:20:21 +02:00
if ( backends = = NULL ) {
2011-12-26 14:23:15 +11:00
TALLOC_FREE ( tmp_ctx ) ;
2011-12-26 11:39:29 +11:00
return NT_STATUS_NO_MEMORY ;
}
2013-08-05 11:20:21 +02:00
gensec_settings - > backends = backends ;
2011-12-26 11:39:29 +11:00
2012-01-31 16:29:02 +11:00
gensec_init ( ) ;
2012-03-11 07:04:38 +11:00
/* These need to be in priority order, krb5 before NTLMSSP */
2012-03-11 06:44:17 +11:00
# if defined(HAVE_KRB5)
2013-08-05 11:20:21 +02:00
backends [ idx + + ] = & gensec_gse_krb5_security_ops ;
2012-01-02 13:06:29 +11:00
# endif
2013-08-05 11:20:21 +02:00
backends [ idx + + ] = gensec_security_by_oid ( NULL , GENSEC_OID_NTLMSSP ) ;
2012-03-11 07:04:38 +11:00
2013-08-05 11:20:21 +02:00
backends [ idx + + ] = gensec_security_by_oid ( NULL , GENSEC_OID_SPNEGO ) ;
2012-01-12 16:12:02 +01:00
2013-09-18 18:23:40 +02:00
backends [ idx + + ] = gensec_security_by_auth_type ( NULL , DCERPC_AUTH_TYPE_SCHANNEL ) ;
2012-01-12 21:16:36 +11:00
/*
* This is anonymous for now , because we just use it
* to set the kerberos state at the moment
*/
server_credentials = cli_credentials_init_anon ( tmp_ctx ) ;
if ( ! server_credentials ) {
DEBUG ( 0 , ( " auth_generic_prepare: Failed to init server credentials \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
cli_credentials_set_conf ( server_credentials , lp_ctx ) ;
if ( lp_security ( ) = = SEC_ADS | | USE_KERBEROS_KEYTAB ) {
cli_credentials_set_kerberos_state ( server_credentials , CRED_AUTO_USE_KERBEROS ) ;
} else {
cli_credentials_set_kerberos_state ( server_credentials , CRED_DONT_USE_KERBEROS ) ;
}
2011-12-26 14:23:15 +11:00
nt_status = gensec_server_start ( tmp_ctx , gensec_settings ,
2011-12-31 22:57:18 +11:00
auth4_context , & gensec_security ) ;
2011-12-16 16:55:36 +11:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2011-12-26 14:23:15 +11:00
TALLOC_FREE ( tmp_ctx ) ;
2011-12-16 16:55:36 +11:00
return nt_status ;
}
2012-01-12 21:16:36 +11:00
gensec_set_credentials ( gensec_security , server_credentials ) ;
2011-12-26 14:23:15 +11:00
talloc_unlink ( tmp_ctx , lp_ctx ) ;
2012-01-12 21:16:36 +11:00
talloc_unlink ( tmp_ctx , server_credentials ) ;
2011-12-26 14:23:15 +11:00
talloc_unlink ( tmp_ctx , gensec_settings ) ;
2011-12-31 22:57:18 +11:00
talloc_unlink ( tmp_ctx , auth4_context ) ;
2011-12-16 16:55:36 +11:00
}
2011-12-26 14:23:15 +11:00
nt_status = gensec_set_remote_address ( gensec_security ,
2011-12-16 16:55:36 +11:00
remote_address ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2011-12-26 14:23:15 +11:00
TALLOC_FREE ( tmp_ctx ) ;
2011-12-16 16:55:36 +11:00
return nt_status ;
}
2011-12-26 14:23:15 +11:00
* gensec_security_out = talloc_steal ( mem_ctx , gensec_security ) ;
TALLOC_FREE ( tmp_ctx ) ;
2011-12-16 16:55:36 +11:00
return NT_STATUS_OK ;
}
2012-02-03 23:32:26 +11:00
NTSTATUS auth_check_password_session_info ( struct auth4_context * auth_context ,
TALLOC_CTX * mem_ctx ,
struct auth_usersupplied_info * user_info ,
struct auth_session_info * * session_info )
{
NTSTATUS nt_status ;
void * server_info ;
nt_status = auth_context - > check_ntlm_password ( auth_context ,
talloc_tos ( ) ,
user_info ,
& server_info , NULL , NULL ) ;
if ( NT_STATUS_IS_OK ( nt_status ) ) {
nt_status = auth_context - > generate_session_info ( auth_context ,
mem_ctx ,
server_info ,
user_info - > client . account_name ,
AUTH_SESSION_INFO_UNIX_TOKEN |
AUTH_SESSION_INFO_DEFAULT_GROUPS ,
session_info ) ;
TALLOC_FREE ( server_info ) ;
}
return nt_status ;
}