2009-12-23 23:17:16 +03:00
/*
2005-06-29 17:55:09 +04:00
Unix SMB / CIFS implementation .
PAC Glue between Samba and the KDC
2009-12-23 23:17:16 +03:00
2009-05-26 06:31:39 +04:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2005 - 2009
2010-01-26 19:06:00 +03:00
Copyright ( C ) Simo Sorce < idra @ samba . org > 2010
2005-06-29 17:55:09 +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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-06-29 17:55:09 +04:00
( at your option ) any later version .
2009-12-23 23:17:16 +03:00
2005-06-29 17:55:09 +04:00
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 .
2009-12-23 23:17:16 +03:00
2005-06-29 17:55:09 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-06-29 17:55:09 +04:00
*/
# include "includes.h"
2009-06-12 16:27:19 +04:00
# include "../libds/common/flags.h"
2005-11-07 05:29:37 +03:00
# include "lib/ldb/include/ldb.h"
2007-01-10 04:51:35 +03:00
# include "librpc/gen_ndr/ndr_krb5pac.h"
2005-11-07 05:29:37 +03:00
# include "librpc/gen_ndr/krb5pac.h"
# include "auth/auth.h"
2006-03-07 14:07:23 +03:00
# include "auth/auth_sam.h"
2007-12-10 06:33:29 +03:00
# include "auth/auth_sam_reply.h"
2008-06-04 17:39:17 +04:00
# include "kdc/kdc.h"
2009-05-26 06:31:39 +04:00
# include "param/param.h"
2005-11-07 05:29:37 +03:00
2010-02-14 02:30:36 +03:00
static
2010-01-26 19:43:54 +03:00
NTSTATUS samba_get_logon_info_pac_blob ( TALLOC_CTX * mem_ctx ,
struct auth_serversupplied_info * info ,
DATA_BLOB * pac_data )
2007-01-10 04:51:35 +03:00
{
struct netr_SamInfo3 * info3 ;
2010-01-26 19:06:00 +03:00
union PAC_INFO pac_info ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2010-01-26 19:06:00 +03:00
NTSTATUS nt_status ;
2005-11-07 05:29:37 +03:00
2010-01-26 19:06:00 +03:00
ZERO_STRUCT ( pac_info ) ;
2007-01-10 04:51:35 +03:00
2010-01-26 19:06:00 +03:00
nt_status = auth_convert_server_info_saminfo3 ( mem_ctx , info , & info3 ) ;
2007-01-10 04:51:35 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2010-01-26 19:06:00 +03:00
DEBUG ( 1 , ( " Getting Samba info failed: %s \n " ,
nt_errstr ( nt_status ) ) ) ;
return nt_status ;
2007-01-10 04:51:35 +03:00
}
2010-01-26 19:06:00 +03:00
pac_info . logon_info . info = talloc_zero ( mem_ctx , struct PAC_LOGON_INFO ) ;
2005-06-29 17:55:09 +04:00
if ( ! mem_ctx ) {
2010-01-26 19:06:00 +03:00
return NT_STATUS_NO_MEMORY ;
2005-06-29 17:55:09 +04:00
}
2010-01-26 19:06:00 +03:00
pac_info . logon_info . info - > info3 = * info3 ;
2007-01-10 04:51:35 +03:00
2010-05-09 19:20:01 +04:00
ndr_err = ndr_push_union_blob ( pac_data , mem_ctx , & pac_info ,
2008-08-19 15:23:09 +04:00
PAC_TYPE_LOGON_INFO ,
( ndr_push_flags_fn_t ) ndr_push_PAC_INFO ) ;
2007-11-09 21:24:51 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
nt_status = ndr_map_error2ntstatus ( ndr_err ) ;
2010-01-26 19:06:00 +03:00
DEBUG ( 1 , ( " PAC (presig) push failed: %s \n " ,
nt_errstr ( nt_status ) ) ) ;
return nt_status ;
}
return NT_STATUS_OK ;
}
2010-01-26 19:43:54 +03:00
krb5_error_code samba_make_krb5_pac ( krb5_context context ,
DATA_BLOB * pac_blob ,
krb5_pac * pac )
2010-01-26 19:06:00 +03:00
{
krb5_data pac_data ;
krb5_error_code ret ;
2010-04-22 16:29:52 +04:00
/* The user account may be set not to want the PAC */
if ( ! pac_blob ) {
return 0 ;
}
2010-01-26 19:09:32 +03:00
ret = krb5_data_copy ( & pac_data , pac_blob - > data , pac_blob - > length ) ;
2007-01-10 04:51:35 +03:00
if ( ret ! = 0 ) {
2005-07-04 06:36:16 +04:00
return ret ;
}
2007-01-10 04:51:35 +03:00
ret = krb5_pac_init ( context , pac ) ;
if ( ret ! = 0 ) {
krb5_data_free ( & pac_data ) ;
return ret ;
2005-11-07 05:29:37 +03:00
}
2007-01-10 04:51:35 +03:00
ret = krb5_pac_add_buffer ( context , * pac , PAC_TYPE_LOGON_INFO , & pac_data ) ;
krb5_data_free ( & pac_data ) ;
if ( ret ! = 0 ) {
2005-11-07 05:29:37 +03:00
return ret ;
}
2007-01-10 04:51:35 +03:00
return ret ;
2005-11-07 05:29:37 +03:00
}
2010-01-26 19:43:54 +03:00
bool samba_princ_needs_pac ( struct hdb_entry_ex * princ )
2005-11-07 05:29:37 +03:00
{
2010-01-26 19:09:32 +03:00
2010-01-28 08:19:59 +03:00
struct samba_kdc_entry * p = talloc_get_type ( princ - > ctx , struct samba_kdc_entry ) ;
2010-10-05 11:27:36 +04:00
uint32_t userAccountControl ;
2007-01-10 04:51:35 +03:00
2010-01-26 19:09:32 +03:00
/* The service account may be set not to want the PAC */
2009-02-01 01:43:43 +03:00
userAccountControl = ldb_msg_find_attr_as_uint ( p - > msg , " userAccountControl " , 0 ) ;
2005-11-07 05:29:37 +03:00
if ( userAccountControl & UF_NO_AUTH_DATA_REQUIRED ) {
2010-01-26 19:09:32 +03:00
return false ;
}
return true ;
}
2010-09-28 06:53:06 +04:00
/* Was the krbtgt an RODC (and we are not) */
bool samba_krbtgt_was_untrusted_rodc ( struct hdb_entry_ex * princ )
{
struct samba_kdc_entry * p = talloc_get_type ( princ - > ctx , struct samba_kdc_entry ) ;
int rodc_krbtgt_number ;
/* The service account may be set not to want the PAC */
rodc_krbtgt_number = ldb_msg_find_attr_as_int ( p - > msg , " msDS-SecondaryKrbTgtNumber " , - 1 ) ;
if ( rodc_krbtgt_number ! = p - > kdc_db_ctx - > my_krbtgt_number ) {
return true ;
}
return false ;
}
2010-01-26 19:43:54 +03:00
NTSTATUS samba_kdc_get_pac_blob ( TALLOC_CTX * mem_ctx ,
struct hdb_entry_ex * client ,
DATA_BLOB * * _pac_blob )
2010-01-26 19:09:32 +03:00
{
2010-01-28 08:19:59 +03:00
struct samba_kdc_entry * p = talloc_get_type ( client - > ctx , struct samba_kdc_entry ) ;
2010-01-26 19:09:32 +03:00
struct auth_serversupplied_info * server_info ;
DATA_BLOB * pac_blob ;
NTSTATUS nt_status ;
/* The user account may be set not to want the PAC */
2010-01-26 19:43:54 +03:00
if ( ! samba_princ_needs_pac ( client ) ) {
2010-01-26 19:09:32 +03:00
* _pac_blob = NULL ;
return NT_STATUS_OK ;
}
pac_blob = talloc_zero ( mem_ctx , DATA_BLOB ) ;
if ( ! pac_blob ) {
return NT_STATUS_NO_MEMORY ;
2005-11-07 05:29:37 +03:00
}
2010-01-28 08:19:59 +03:00
nt_status = authsam_make_server_info ( mem_ctx , p - > kdc_db_ctx - > samdb ,
2010-07-16 08:32:42 +04:00
lpcfg_netbios_name ( p - > kdc_db_ctx - > lp_ctx ) ,
lpcfg_sam_name ( p - > kdc_db_ctx - > lp_ctx ) ,
2009-05-26 06:31:39 +04:00
p - > realm_dn ,
2009-02-01 01:43:43 +03:00
p - > msg ,
2007-01-10 04:51:35 +03:00
data_blob ( NULL , 0 ) ,
data_blob ( NULL , 0 ) ,
& server_info ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 0 , ( " Getting user info for PAC failed: %s \n " ,
nt_errstr ( nt_status ) ) ) ;
2010-01-26 19:09:32 +03:00
return nt_status ;
}
2010-05-09 19:20:01 +04:00
nt_status = samba_get_logon_info_pac_blob ( mem_ctx , server_info , pac_blob ) ;
2010-01-26 19:09:32 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DEBUG ( 0 , ( " Building PAC failed: %s \n " ,
nt_errstr ( nt_status ) ) ) ;
return nt_status ;
}
* _pac_blob = pac_blob ;
return NT_STATUS_OK ;
}
2010-01-26 19:43:54 +03:00
NTSTATUS samba_kdc_update_pac_blob ( TALLOC_CTX * mem_ctx ,
krb5_context context ,
krb5_pac * pac , DATA_BLOB * pac_blob )
2010-01-26 19:09:32 +03:00
{
struct auth_serversupplied_info * server_info ;
krb5_error_code ret ;
NTSTATUS nt_status ;
2010-05-09 19:20:01 +04:00
ret = kerberos_pac_to_server_info ( mem_ctx , * pac ,
2010-01-26 19:09:32 +03:00
context , & server_info ) ;
if ( ret ) {
return NT_STATUS_UNSUCCESSFUL ;
}
2010-05-09 19:20:01 +04:00
nt_status = samba_get_logon_info_pac_blob ( mem_ctx ,
2010-01-26 19:09:32 +03:00
server_info , pac_blob ) ;
return nt_status ;
}
2010-01-31 20:49:07 +03:00
/* this function allocates 'data' using malloc.
* The caller is responsible for freeing it */
void samba_kdc_build_edata_reply ( NTSTATUS nt_status , DATA_BLOB * e_data )
2008-03-13 07:21:14 +03:00
{
PA_DATA pa ;
unsigned char * buf ;
size_t len ;
krb5_error_code ret = 0 ;
if ( ! e_data )
return ;
pa . padata_type = KRB5_PADATA_PW_SALT ;
pa . padata_value . length = 12 ;
pa . padata_value . data = malloc ( pa . padata_value . length ) ;
if ( ! pa . padata_value . data ) {
e_data - > length = 0 ;
e_data - > data = NULL ;
return ;
}
SIVAL ( pa . padata_value . data , 0 , NT_STATUS_V ( nt_status ) ) ;
SIVAL ( pa . padata_value . data , 4 , 0 ) ;
SIVAL ( pa . padata_value . data , 8 , 1 ) ;
ASN1_MALLOC_ENCODE ( PA_DATA , buf , len , & pa , & len , ret ) ;
free ( pa . padata_value . data ) ;
e_data - > data = buf ;
e_data - > length = len ;
return ;
}
2010-01-31 20:49:07 +03:00
/* function to map policy errors */
krb5_error_code samba_kdc_map_policy_err ( NTSTATUS nt_status )
{
krb5_error_code ret ;
if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_PASSWORD_MUST_CHANGE ) )
ret = KRB5KDC_ERR_KEY_EXPIRED ;
else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_PASSWORD_EXPIRED ) )
ret = KRB5KDC_ERR_KEY_EXPIRED ;
else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_ACCOUNT_EXPIRED ) )
ret = KRB5KDC_ERR_CLIENT_REVOKED ;
else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_ACCOUNT_DISABLED ) )
ret = KRB5KDC_ERR_CLIENT_REVOKED ;
else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_INVALID_LOGON_HOURS ) )
ret = KRB5KDC_ERR_CLIENT_REVOKED ;
else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_ACCOUNT_LOCKED_OUT ) )
ret = KRB5KDC_ERR_CLIENT_REVOKED ;
else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_INVALID_WORKSTATION ) )
ret = KRB5KDC_ERR_POLICY ;
else
ret = KRB5KDC_ERR_POLICY ;
return ret ;
}
/* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
* for consistency */
NTSTATUS samba_kdc_check_client_access ( struct samba_kdc_entry * kdc_entry ,
const char * client_name ,
const char * workstation ,
bool password_change )
{
TALLOC_CTX * tmp_ctx ;
NTSTATUS nt_status ;
tmp_ctx = talloc_named ( NULL , 0 , " samba_kdc_check_client_access " ) ;
if ( ! tmp_ctx ) {
return NT_STATUS_NO_MEMORY ;
}
/* we allow all kinds of trusts here */
nt_status = authsam_account_ok ( tmp_ctx ,
kdc_entry - > kdc_db_ctx - > samdb ,
MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT ,
kdc_entry - > realm_dn , kdc_entry - > msg ,
workstation , client_name ,
true , password_change ) ;
talloc_free ( tmp_ctx ) ;
return nt_status ;
}