2010-01-31 21:29:57 +03:00
/*
MIT - Samba4 library
Copyright ( c ) 2010 , Simo Sorce < idra @ samba . org >
2016-06-09 17:02:23 +03:00
Copyright ( c ) 2014 - 2015 Guenther Deschner < gd @ samba . org >
Copyright ( c ) 2014 - 2016 Andreas Schneider < asn @ samba . org >
2010-01-31 21:29:57 +03: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/>.
*/
2011-02-04 04:51:45 +03:00
# define TEVENT_DEPRECATED 1
2010-01-31 21:29:57 +03:00
# include "includes.h"
# include "param/param.h"
# include "dsdb/samdb/samdb.h"
# include "system/kerberos.h"
2023-01-18 13:49:00 +03:00
# include "lib/replace/system/filesys.h"
2018-06-11 17:15:10 +03:00
# include <com_err.h>
2014-05-12 16:33:14 +04:00
# include <kdb.h>
2015-07-30 15:46:48 +03:00
# include <kadm5/kadm_err.h>
2014-05-12 16:33:14 +04:00
# include "kdc/sdb.h"
# include "kdc/sdb_kdb.h"
2010-01-31 21:29:57 +03:00
# include "auth/kerberos/kerberos.h"
2016-09-30 08:43:31 +03:00
# include "auth/kerberos/pac_utils.h"
2010-01-31 21:29:57 +03:00
# include "kdc/samba_kdc.h"
# include "kdc/pac-glue.h"
# include "kdc/db-glue.h"
2015-07-30 15:46:48 +03:00
# include "auth/auth.h"
# include "kdc/kpasswd_glue.h"
2015-05-20 18:19:35 +03:00
# include "auth/auth_sam.h"
2010-01-31 21:29:57 +03:00
2014-05-12 12:50:33 +04:00
# include "mit_samba.h"
2010-01-31 21:29:57 +03:00
2021-07-14 13:49:11 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_KERBEROS
2014-05-12 12:50:33 +04:00
void mit_samba_context_free ( struct mit_samba_context * ctx )
2010-01-31 21:29:57 +03:00
{
2023-08-09 07:13:20 +03:00
/* free MIT's krb5_context */
2010-01-31 21:29:57 +03:00
if ( ctx - > context ) {
krb5_free_context ( ctx - > context ) ;
}
/* then free everything else */
talloc_free ( ctx ) ;
}
2018-06-11 17:15:10 +03:00
/*
2022-09-27 04:46:14 +03:00
* Implement a callback to log to the MIT KDC log facility
2018-06-11 17:15:10 +03:00
*
* http : //web.mit.edu/kerberos/krb5-devel/doc/plugindev/general.html#logging-from-kdc-and-kadmind-plugin-modules
*/
static void mit_samba_debug ( void * private_ptr , int msg_level , const char * msg )
{
2021-10-19 13:15:50 +03:00
int is_error = errno ;
2018-06-11 17:15:10 +03:00
if ( msg_level > 0 ) {
is_error = 0 ;
}
2023-09-06 04:09:24 +03:00
com_err ( " mitkdc " , is_error , " %s " , msg ) ;
2018-06-11 17:15:10 +03:00
}
2023-08-16 06:57:00 +03:00
krb5_error_code mit_samba_context_init ( struct mit_samba_context * * _ctx )
2010-01-31 21:29:57 +03:00
{
2010-09-28 07:05:37 +04:00
NTSTATUS status ;
2010-01-31 21:29:57 +03:00
struct mit_samba_context * ctx ;
const char * s4_conf_file ;
2023-08-16 06:57:00 +03:00
krb5_error_code ret ;
2023-12-19 05:58:49 +03:00
struct samba_kdc_base_context base_ctx = { } ;
2010-01-31 21:29:57 +03:00
2014-05-12 23:35:45 +04:00
ctx = talloc_zero ( NULL , struct mit_samba_context ) ;
2010-01-31 21:29:57 +03:00
if ( ! ctx ) {
ret = ENOMEM ;
goto done ;
}
2010-09-28 07:05:37 +04:00
base_ctx . ev_ctx = tevent_context_init ( ctx ) ;
if ( ! base_ctx . ev_ctx ) {
2010-01-31 21:29:57 +03:00
ret = ENOMEM ;
goto done ;
}
2011-02-04 04:51:45 +03:00
tevent_loop_allow_nesting ( base_ctx . ev_ctx ) ;
2010-11-29 05:25:59 +03:00
base_ctx . lp_ctx = loadparm_init_global ( false ) ;
2010-09-28 07:05:37 +04:00
if ( ! base_ctx . lp_ctx ) {
2010-01-31 21:29:57 +03:00
ret = ENOMEM ;
goto done ;
}
2015-07-30 18:29:51 +03:00
2018-06-11 17:15:10 +03:00
debug_set_callback ( NULL , mit_samba_debug ) ;
2015-07-30 18:29:51 +03:00
2010-01-31 21:29:57 +03:00
/* init s4 configuration */
2010-09-28 07:05:37 +04:00
s4_conf_file = lpcfg_configfile ( base_ctx . lp_ctx ) ;
2021-02-02 11:29:14 +03:00
if ( s4_conf_file ! = NULL ) {
char * p = talloc_strdup ( ctx , s4_conf_file ) ;
if ( p = = NULL ) {
ret = ENOMEM ;
goto done ;
}
lpcfg_load ( base_ctx . lp_ctx , p ) ;
TALLOC_FREE ( p ) ;
2010-01-31 21:29:57 +03:00
} else {
2010-09-28 07:05:37 +04:00
lpcfg_load_default ( base_ctx . lp_ctx ) ;
2010-01-31 21:29:57 +03:00
}
2010-09-28 07:05:37 +04:00
status = samba_kdc_setup_db_ctx ( ctx , & base_ctx , & ctx - > db_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret = EINVAL ;
2010-01-31 21:29:57 +03:00
goto done ;
}
2023-08-09 07:13:20 +03:00
/* init MIT's krb_context and log facilities */
2010-01-31 21:29:57 +03:00
ret = smb_krb5_init_context_basic ( ctx ,
ctx - > db_ctx - > lp_ctx ,
& ctx - > context ) ;
if ( ret ) {
goto done ;
}
ret = 0 ;
done :
if ( ret ) {
mit_samba_context_free ( ctx ) ;
} else {
* _ctx = ctx ;
}
return ret ;
}
2014-08-06 17:41:05 +04:00
int mit_samba_generate_salt ( krb5_data * salt )
{
if ( salt = = NULL ) {
return EINVAL ;
}
salt - > length = 16 ;
salt - > data = malloc ( salt - > length ) ;
if ( salt - > data = = NULL ) {
return ENOMEM ;
}
generate_random_buffer ( ( uint8_t * ) salt - > data , salt - > length ) ;
return 0 ;
}
int mit_samba_generate_random_password ( krb5_data * pwd )
{
TALLOC_CTX * tmp_ctx ;
char * password ;
2023-08-16 06:57:53 +03:00
char * data = NULL ;
const unsigned length = 24 ;
2014-08-06 17:41:05 +04:00
if ( pwd = = NULL ) {
return EINVAL ;
}
tmp_ctx = talloc_named ( NULL ,
0 ,
2022-09-27 04:46:23 +03:00
" mit_samba_generate_random_password context " ) ;
2014-08-06 17:41:05 +04:00
if ( tmp_ctx = = NULL ) {
return ENOMEM ;
}
2023-08-16 06:57:53 +03:00
password = generate_random_password ( tmp_ctx , length , length ) ;
2014-08-06 17:41:05 +04:00
if ( password = = NULL ) {
talloc_free ( tmp_ctx ) ;
return ENOMEM ;
}
2023-08-16 06:57:53 +03:00
data = strdup ( password ) ;
2014-08-06 17:41:05 +04:00
talloc_free ( tmp_ctx ) ;
2023-08-16 06:57:53 +03:00
if ( data = = NULL ) {
2014-08-06 17:41:05 +04:00
return ENOMEM ;
}
2023-08-16 06:57:53 +03:00
* pwd = smb_krb5_make_data ( data , length ) ;
2014-08-06 17:41:05 +04:00
return 0 ;
}
2023-08-16 06:57:00 +03:00
krb5_error_code mit_samba_get_principal ( struct mit_samba_context * ctx ,
krb5_const_principal principal ,
unsigned int kflags ,
krb5_db_entry * * _kentry )
2010-01-31 21:29:57 +03:00
{
2022-03-23 06:17:01 +03:00
struct sdb_entry sentry = { } ;
2014-05-12 16:33:14 +04:00
krb5_db_entry * kentry ;
2023-08-16 06:57:00 +03:00
krb5_error_code ret ;
2022-01-25 17:57:07 +03:00
uint32_t sflags = 0 ;
2017-01-27 14:11:33 +03:00
krb5_principal referral_principal = NULL ;
2010-01-31 21:29:57 +03:00
2017-01-26 18:54:30 +03:00
kentry = calloc ( 1 , sizeof ( krb5_db_entry ) ) ;
2014-05-12 16:33:14 +04:00
if ( kentry = = NULL ) {
2010-01-31 21:29:57 +03:00
return ENOMEM ;
}
2020-09-19 15:16:20 +03:00
/*
* The MIT KDC code that wants the canonical name in all lookups , and
* takes care to canonicalize only when appropriate .
*/
sflags | = SDB_F_FORCE_CANON ;
2021-10-04 12:53:55 +03:00
if ( kflags & KRB5_KDB_FLAG_REFERRAL_OK ) {
sflags | = SDB_F_CANON ;
}
if ( kflags & KRB5_KDB_FLAG_CLIENT ) {
sflags | = SDB_F_GET_CLIENT ;
2022-06-27 17:04:56 +03:00
sflags | = SDB_F_FOR_AS_REQ ;
2021-10-04 12:53:55 +03:00
} else {
2022-03-15 09:33:57 +03:00
int equal = smb_krb5_principal_is_tgs ( ctx - > context , principal ) ;
if ( equal = = - 1 ) {
return ENOMEM ;
}
2021-10-04 12:53:55 +03:00
2022-03-15 09:33:57 +03:00
if ( equal ) {
sflags | = SDB_F_GET_KRBTGT ;
} else {
sflags | = SDB_F_GET_SERVER ;
2022-06-27 17:04:56 +03:00
sflags | = SDB_F_FOR_TGS_REQ ;
2021-10-04 12:53:55 +03:00
}
}
2015-07-30 15:36:55 +03:00
/* always set this or the created_by data will not be populated by samba's
* backend and we will fail to parse the entry later */
sflags | = SDB_F_ADMIN_DATA ;
2010-01-31 21:29:57 +03:00
2017-01-27 14:11:33 +03:00
fetch_referral_principal :
2010-01-31 21:29:57 +03:00
ret = samba_kdc_fetch ( ctx - > context , ctx - > db_ctx ,
2022-03-23 06:17:01 +03:00
principal , sflags , 0 , & sentry ) ;
2014-05-12 16:33:14 +04:00
switch ( ret ) {
case 0 :
break ;
case SDB_ERR_NOENTRY :
ret = KRB5_KDB_NOENTRY ;
goto done ;
2017-01-27 14:11:33 +03:00
case SDB_ERR_WRONG_REALM : {
char * dest_realm = NULL ;
const char * our_realm = lpcfg_realm ( ctx - > db_ctx - > lp_ctx ) ;
if ( sflags & SDB_F_FOR_AS_REQ ) {
/*
* If this is a request for a TGT , we are done . The KDC
* will return the correct error to the client .
*/
ret = 0 ;
break ;
}
if ( referral_principal ! = NULL ) {
2022-03-23 06:17:01 +03:00
sdb_entry_free ( & sentry ) ;
2017-01-27 14:11:33 +03:00
ret = KRB5_KDB_NOENTRY ;
goto done ;
}
2016-02-15 10:31:16 +03:00
/*
2017-01-27 14:11:33 +03:00
* We get a TGS request
*
* cifs / dc7 . SAMBA2008R2 . EXAMPLE . COM @ ADDOM . SAMBA . EXAMPLE . COM
*
* to our DC for the realm
*
* ADDOM . SAMBA . EXAMPLE . COM
*
2023-10-17 01:21:00 +03:00
* We look up if we have an entry in the database and get an
2023-08-02 11:47:30 +03:00
* entry with the principal :
2017-01-27 14:11:33 +03:00
*
* cifs / dc7 . SAMBA2008R2 . EXAMPLE . COM @ SAMBA2008R2 . EXAMPLE . COM
*
* and the error : SDB_ERR_WRONG_REALM .
*
* In the case of a TGS - REQ we need to return a referral ticket
2023-09-04 07:52:57 +03:00
* for the next trust hop to the client . This ticket will have
2017-01-27 14:11:33 +03:00
* the following principal :
*
* krbtgt / SAMBA2008R2 . EXAMPLE . COM @ ADDOM . SAMBA . EXAMPLE . COM
*
* We just redo the lookup in the database with the referral
* principal and return success .
2016-02-15 10:31:16 +03:00
*/
2018-11-20 19:45:11 +03:00
dest_realm = smb_krb5_principal_get_realm (
2022-03-23 06:17:01 +03:00
ctx , ctx - > context , sentry . principal ) ;
sdb_entry_free ( & sentry ) ;
2017-01-27 14:11:33 +03:00
if ( dest_realm = = NULL ) {
ret = KRB5_KDB_NOENTRY ;
goto done ;
}
ret = smb_krb5_make_principal ( ctx - > context ,
& referral_principal ,
our_realm ,
KRB5_TGS_NAME ,
dest_realm ,
NULL ) ;
2018-11-20 19:45:11 +03:00
TALLOC_FREE ( dest_realm ) ;
2017-01-27 14:11:33 +03:00
if ( ret ! = 0 ) {
goto done ;
}
principal = referral_principal ;
goto fetch_referral_principal ;
}
2014-05-12 16:33:14 +04:00
case SDB_ERR_NOT_FOUND_HERE :
/* FIXME: RODC support */
default :
goto done ;
}
2022-03-23 06:17:01 +03:00
ret = sdb_entry_to_krb5_db_entry ( ctx - > context , & sentry , kentry ) ;
2010-01-31 21:29:57 +03:00
2022-03-23 06:17:01 +03:00
sdb_entry_free ( & sentry ) ;
2010-01-31 21:29:57 +03:00
done :
2017-01-27 14:11:33 +03:00
krb5_free_principal ( ctx - > context , referral_principal ) ;
referral_principal = NULL ;
2010-01-31 21:29:57 +03:00
if ( ret ) {
2014-05-12 16:33:14 +04:00
free ( kentry ) ;
2010-01-31 21:29:57 +03:00
} else {
2014-05-12 16:33:14 +04:00
* _kentry = kentry ;
2010-01-31 21:29:57 +03:00
}
return ret ;
}
2023-08-16 06:57:00 +03:00
krb5_error_code mit_samba_get_firstkey ( struct mit_samba_context * ctx ,
krb5_db_entry * * _kentry )
2010-01-31 21:29:57 +03:00
{
2022-03-23 06:17:01 +03:00
struct sdb_entry sentry = { } ;
2014-05-12 16:33:14 +04:00
krb5_db_entry * kentry ;
2023-08-16 06:57:00 +03:00
krb5_error_code ret ;
2010-01-31 21:29:57 +03:00
2014-05-12 16:33:14 +04:00
kentry = malloc ( sizeof ( krb5_db_entry ) ) ;
if ( kentry = = NULL ) {
2010-01-31 21:29:57 +03:00
return ENOMEM ;
}
2024-04-24 04:45:08 +03:00
ret = samba_kdc_firstkey ( ctx - > context , ctx - > db_ctx , SDB_F_ADMIN_DATA , & sentry ) ;
2014-05-12 16:33:14 +04:00
switch ( ret ) {
case 0 :
break ;
case SDB_ERR_NOENTRY :
free ( kentry ) ;
return KRB5_KDB_NOENTRY ;
case SDB_ERR_NOT_FOUND_HERE :
/* FIXME: RODC support */
default :
free ( kentry ) ;
return ret ;
}
2022-03-23 06:17:01 +03:00
ret = sdb_entry_to_krb5_db_entry ( ctx - > context , & sentry , kentry ) ;
2014-05-12 16:33:14 +04:00
2022-03-23 06:17:01 +03:00
sdb_entry_free ( & sentry ) ;
2010-01-31 21:29:57 +03:00
if ( ret ) {
2014-05-12 16:33:14 +04:00
free ( kentry ) ;
2010-01-31 21:29:57 +03:00
} else {
2014-05-12 16:33:14 +04:00
* _kentry = kentry ;
2010-01-31 21:29:57 +03:00
}
return ret ;
}
2023-08-16 06:57:00 +03:00
krb5_error_code mit_samba_get_nextkey ( struct mit_samba_context * ctx ,
krb5_db_entry * * _kentry )
2010-01-31 21:29:57 +03:00
{
2022-03-23 06:17:01 +03:00
struct sdb_entry sentry = { } ;
2014-05-12 16:33:14 +04:00
krb5_db_entry * kentry ;
2023-08-16 06:57:00 +03:00
krb5_error_code ret ;
2010-01-31 21:29:57 +03:00
2014-05-12 16:33:14 +04:00
kentry = malloc ( sizeof ( krb5_db_entry ) ) ;
if ( kentry = = NULL ) {
2010-01-31 21:29:57 +03:00
return ENOMEM ;
}
2024-04-24 04:45:08 +03:00
ret = samba_kdc_nextkey ( ctx - > context , ctx - > db_ctx , SDB_F_ADMIN_DATA , & sentry ) ;
2014-05-12 16:33:14 +04:00
switch ( ret ) {
case 0 :
break ;
case SDB_ERR_NOENTRY :
free ( kentry ) ;
return KRB5_KDB_NOENTRY ;
case SDB_ERR_NOT_FOUND_HERE :
/* FIXME: RODC support */
default :
free ( kentry ) ;
return ret ;
}
2022-03-23 06:17:01 +03:00
ret = sdb_entry_to_krb5_db_entry ( ctx - > context , & sentry , kentry ) ;
2014-05-12 16:33:14 +04:00
2022-03-23 06:17:01 +03:00
sdb_entry_free ( & sentry ) ;
2010-01-31 21:29:57 +03:00
if ( ret ) {
2014-05-12 16:33:14 +04:00
free ( kentry ) ;
2010-01-31 21:29:57 +03:00
} else {
2014-05-12 16:33:14 +04:00
* _kentry = kentry ;
2010-01-31 21:29:57 +03:00
}
return ret ;
}
2023-08-16 06:57:00 +03:00
krb5_error_code mit_samba_get_pac ( struct mit_samba_context * smb_ctx ,
krb5_context context ,
uint32_t flags ,
krb5_db_entry * client ,
krb5_db_entry * server ,
krb5_keyblock * replaced_reply_key ,
krb5_pac * pac )
2016-09-29 03:03:35 +03:00
{
TALLOC_CTX * tmp_ctx ;
2023-10-11 07:07:02 +03:00
const struct auth_user_info_dc * user_info_dc = NULL ;
struct auth_user_info_dc * user_info_dc_shallow_copy = NULL ;
2016-09-29 03:03:35 +03:00
DATA_BLOB * logon_info_blob = NULL ;
DATA_BLOB * upn_dns_info_blob = NULL ;
DATA_BLOB * cred_ndr = NULL ;
DATA_BLOB * * cred_ndr_ptr = NULL ;
DATA_BLOB cred_blob = data_blob_null ;
DATA_BLOB * pcred_blob = NULL ;
2021-12-13 10:33:05 +03:00
DATA_BLOB * pac_attrs_blob = NULL ;
DATA_BLOB * requester_sid_blob = NULL ;
2023-06-26 02:10:51 +03:00
const DATA_BLOB * client_claims_blob = NULL ;
2016-09-29 03:03:35 +03:00
NTSTATUS nt_status ;
krb5_error_code code ;
struct samba_kdc_entry * skdc_entry ;
2022-12-02 00:49:20 +03:00
struct samba_kdc_entry * server_entry = NULL ;
2023-07-03 00:04:01 +03:00
bool is_krbtgt ;
2022-09-27 04:51:54 +03:00
/* Only include resource groups in a service ticket. */
2022-12-02 00:49:20 +03:00
enum auth_group_inclusion group_inclusion ;
2021-10-11 15:47:25 +03:00
enum samba_asserted_identity asserted_identity =
( flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION ) ?
SAMBA_ASSERTED_IDENTITY_SERVICE :
SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY ;
2016-09-29 03:03:35 +03:00
2023-07-03 00:04:01 +03:00
if ( client = = NULL ) {
return EINVAL ;
}
2016-09-29 03:03:35 +03:00
skdc_entry = talloc_get_type_abort ( client - > e_data ,
struct samba_kdc_entry ) ;
2023-07-03 00:04:01 +03:00
if ( server = = NULL ) {
return EINVAL ;
}
2023-09-05 08:06:00 +03:00
{
int result = smb_krb5_principal_is_tgs ( smb_ctx - > context , server - > princ ) ;
if ( result = = - 1 ) {
return ENOMEM ;
}
is_krbtgt = result ;
}
2022-12-02 00:49:20 +03:00
server_entry = talloc_get_type_abort ( server - > e_data ,
struct samba_kdc_entry ) ;
/* Only include resource groups in a service ticket. */
if ( is_krbtgt ) {
group_inclusion = AUTH_EXCLUDE_RESOURCE_GROUPS ;
} else if ( server_entry - > supported_enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED ) {
group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS ;
} else {
group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED ;
}
2016-09-29 03:03:35 +03:00
tmp_ctx = talloc_named ( smb_ctx ,
0 ,
2022-09-27 04:46:23 +03:00
" mit_samba_get_pac context " ) ;
2016-09-29 03:03:35 +03:00
if ( tmp_ctx = = NULL ) {
return ENOMEM ;
}
/* Check if we have a PREAUTH key */
2021-10-04 12:53:55 +03:00
if ( replaced_reply_key ! = NULL ) {
2016-09-29 03:03:35 +03:00
cred_ndr_ptr = & cred_ndr ;
}
2023-10-03 03:39:48 +03:00
code = samba_kdc_get_user_info_from_db ( tmp_ctx ,
2023-10-03 04:53:17 +03:00
server_entry - > kdc_db_ctx - > samdb ,
2023-10-03 03:39:48 +03:00
skdc_entry ,
skdc_entry - > msg ,
& user_info_dc ) ;
if ( code ) {
2016-09-29 03:03:35 +03:00
talloc_free ( tmp_ctx ) ;
2023-10-03 03:39:48 +03:00
return code ;
2016-09-29 03:03:35 +03:00
}
2023-10-11 07:07:02 +03:00
/* Make a shallow copy of the user_info_dc structure. */
nt_status = authsam_shallow_copy_user_info_dc ( tmp_ctx ,
user_info_dc ,
& user_info_dc_shallow_copy ) ;
user_info_dc = NULL ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DBG_ERR ( " Failed to allocate shallow copy of user_info_dc: %s \n " ,
nt_errstr ( nt_status ) ) ;
talloc_free ( tmp_ctx ) ;
return map_errno_from_nt_status ( nt_status ) ;
}
2023-09-27 06:38:23 +03:00
nt_status = samba_kdc_add_asserted_identity ( asserted_identity ,
2023-10-11 07:07:02 +03:00
user_info_dc_shallow_copy ) ;
2023-09-27 06:38:23 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DBG_ERR ( " Failed to add asserted identity: %s \n " ,
nt_errstr ( nt_status ) ) ;
talloc_free ( tmp_ctx ) ;
return EINVAL ;
}
2023-10-09 05:19:01 +03:00
nt_status = samba_kdc_add_claims_valid ( user_info_dc_shallow_copy ) ;
2023-09-27 06:23:33 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DBG_ERR ( " Failed to add Claims Valid: %s \n " ,
nt_errstr ( nt_status ) ) ;
talloc_free ( tmp_ctx ) ;
return EINVAL ;
}
2023-10-11 07:07:02 +03:00
/* We no longer need to modify this, so assign to const variable */
user_info_dc = user_info_dc_shallow_copy ;
2023-03-20 05:16:21 +03:00
nt_status = samba_kdc_get_logon_info_blob ( tmp_ctx ,
2023-05-10 05:54:21 +03:00
user_info_dc ,
2023-03-20 05:16:21 +03:00
group_inclusion ,
& logon_info_blob ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( tmp_ctx ) ;
return EINVAL ;
}
if ( cred_ndr_ptr ! = NULL ) {
nt_status = samba_kdc_get_cred_ndr_blob ( tmp_ctx ,
skdc_entry ,
cred_ndr_ptr ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( tmp_ctx ) ;
return EINVAL ;
}
}
nt_status = samba_kdc_get_upn_info_blob ( tmp_ctx ,
2023-05-10 05:54:21 +03:00
user_info_dc ,
2023-03-20 05:16:21 +03:00
& upn_dns_info_blob ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( tmp_ctx ) ;
return EINVAL ;
}
if ( is_krbtgt ) {
nt_status = samba_kdc_get_pac_attrs_blob ( tmp_ctx ,
PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY ,
& pac_attrs_blob ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( tmp_ctx ) ;
return EINVAL ;
}
nt_status = samba_kdc_get_requester_sid_blob ( tmp_ctx ,
2023-05-10 05:54:21 +03:00
user_info_dc ,
2023-03-20 05:16:21 +03:00
& requester_sid_blob ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( tmp_ctx ) ;
return EINVAL ;
}
}
2023-03-20 06:58:47 +03:00
nt_status = samba_kdc_get_claims_blob ( tmp_ctx ,
skdc_entry ,
& client_claims_blob ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( tmp_ctx ) ;
return EINVAL ;
}
2021-10-04 12:53:55 +03:00
if ( replaced_reply_key ! = NULL & & cred_ndr ! = NULL ) {
2016-09-29 03:03:35 +03:00
code = samba_kdc_encrypt_pac_credentials ( context ,
2021-10-04 12:53:55 +03:00
replaced_reply_key ,
2016-09-29 03:03:35 +03:00
cred_ndr ,
tmp_ctx ,
& cred_blob ) ;
if ( code ! = 0 ) {
talloc_free ( tmp_ctx ) ;
return code ;
}
pcred_blob = & cred_blob ;
}
code = samba_make_krb5_pac ( context ,
logon_info_blob ,
pcred_blob ,
upn_dns_info_blob ,
2021-12-13 10:33:05 +03:00
pac_attrs_blob ,
requester_sid_blob ,
2023-05-19 04:15:45 +03:00
NULL /* deleg_blob */ ,
2023-03-20 06:58:47 +03:00
client_claims_blob ,
2023-05-19 04:15:45 +03:00
NULL /* device_info_blob */ ,
NULL /* device_claims_blob */ ,
2021-10-07 16:12:35 +03:00
* pac ) ;
2016-09-29 03:03:35 +03:00
talloc_free ( tmp_ctx ) ;
return code ;
}
2021-10-04 12:53:55 +03:00
krb5_error_code mit_samba_update_pac ( struct mit_samba_context * ctx ,
krb5_context context ,
2022-03-08 09:34:16 +03:00
int kdc_flags ,
2021-10-04 12:53:55 +03:00
krb5_db_entry * client ,
krb5_db_entry * server ,
krb5_db_entry * krbtgt ,
krb5_pac old_pac ,
krb5_pac new_pac )
{
TALLOC_CTX * tmp_ctx = NULL ;
krb5_error_code code ;
struct samba_kdc_entry * client_skdc_entry = NULL ;
struct samba_kdc_entry * server_skdc_entry = NULL ;
struct samba_kdc_entry * krbtgt_skdc_entry = NULL ;
2023-09-28 01:43:57 +03:00
struct samba_kdc_entry_pac client_pac_entry = { } ;
2021-10-04 12:53:55 +03:00
bool is_in_db = false ;
2023-03-16 04:29:15 +03:00
bool is_trusted = false ;
2023-08-21 04:46:57 +03:00
uint32_t flags = 0 ;
2021-10-04 12:53:55 +03:00
/* Create a memory context early so code can use talloc_stackframe() */
tmp_ctx = talloc_named ( ctx , 0 , " mit_samba_update_pac context " ) ;
if ( tmp_ctx = = NULL ) {
return ENOMEM ;
}
if ( client ! = NULL ) {
client_skdc_entry =
talloc_get_type_abort ( client - > e_data ,
struct samba_kdc_entry ) ;
}
if ( krbtgt = = NULL ) {
code = EINVAL ;
goto done ;
}
krbtgt_skdc_entry =
talloc_get_type_abort ( krbtgt - > e_data ,
struct samba_kdc_entry ) ;
2023-07-03 00:04:01 +03:00
if ( server = = NULL ) {
code = EINVAL ;
goto done ;
}
2022-03-08 09:34:16 +03:00
server_skdc_entry =
talloc_get_type_abort ( server - > e_data ,
struct samba_kdc_entry ) ;
2021-10-04 12:53:55 +03:00
/*
* If the krbtgt was generated by an RODC , and we are not that
* RODC , then we need to regenerate the PAC - we can ' t trust
* it , and confirm that the RODC was permitted to print this ticket
*
* Because of the samba_kdc_validate_pac_blob ( ) step we can be
* sure that the record in ' client ' or ' server ' matches the SID in the
* original PAC .
*/
code = samba_krbtgt_is_in_db ( krbtgt_skdc_entry ,
& is_in_db ,
2023-03-16 04:29:15 +03:00
& is_trusted ) ;
2021-10-04 12:53:55 +03:00
if ( code ! = 0 ) {
goto done ;
}
2023-08-16 01:18:59 +03:00
if ( kdc_flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION ) {
flags | = SAMBA_KDC_FLAG_PROTOCOL_TRANSITION ;
}
2022-03-08 09:34:16 +03:00
if ( kdc_flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION ) {
flags | = SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION ;
2021-10-04 12:53:55 +03:00
}
2023-09-28 01:43:57 +03:00
client_pac_entry = samba_kdc_entry_pac_from_trusted ( old_pac ,
client_skdc_entry ,
samba_kdc_entry_is_trust ( krbtgt_skdc_entry ) ,
is_trusted ) ;
2023-03-20 04:51:53 +03:00
code = samba_kdc_verify_pac ( tmp_ctx ,
context ,
2023-10-03 04:58:10 +03:00
krbtgt_skdc_entry - > kdc_db_ctx - > samdb ,
2023-03-20 04:51:53 +03:00
flags ,
2023-09-28 01:43:57 +03:00
client_pac_entry ,
krbtgt_skdc_entry ) ;
2023-03-20 04:51:53 +03:00
if ( code ! = 0 ) {
goto done ;
}
2022-03-08 09:34:16 +03:00
code = samba_kdc_update_pac ( tmp_ctx ,
context ,
krbtgt_skdc_entry - > kdc_db_ctx - > samdb ,
2023-06-16 05:24:50 +03:00
krbtgt_skdc_entry - > kdc_db_ctx - > lp_ctx ,
2022-03-08 09:34:16 +03:00
flags ,
2023-09-28 01:43:57 +03:00
client_pac_entry ,
2022-03-08 09:34:16 +03:00
server - > princ ,
server_skdc_entry ,
2023-05-19 04:15:45 +03:00
NULL /* delegated_proxy_principal */ ,
2023-09-28 01:43:57 +03:00
( struct samba_kdc_entry_pac ) { } /* delegated_proxy */ ,
( struct samba_kdc_entry_pac ) { } /* device */ ,
2023-06-16 05:49:11 +03:00
new_pac ,
NULL /* server_audit_info_out */ ,
NULL /* status_out */ ) ;
2022-03-08 09:34:16 +03:00
if ( code ! = 0 ) {
2023-01-18 13:49:00 +03:00
if ( code = = ENOATTR ) {
2021-10-04 12:53:55 +03:00
/*
2022-03-08 09:34:16 +03:00
* We can ' t tell the KDC to not issue a PAC . It will
* just return the newly allocated empty PAC .
2021-10-04 12:53:55 +03:00
*/
2022-03-08 09:34:16 +03:00
code = 0 ;
2021-10-04 12:53:55 +03:00
}
}
done :
talloc_free ( tmp_ctx ) ;
return code ;
}
2016-09-30 08:43:31 +03:00
2014-05-15 18:43:59 +04:00
/* provide header, function is exported but there are no public headers */
krb5_error_code encode_krb5_padata_sequence ( krb5_pa_data * const * rep , krb5_data * * code ) ;
/* this function allocates 'data' using malloc.
* The caller is responsible for freeing it */
static void samba_kdc_build_edata_reply ( NTSTATUS nt_status , DATA_BLOB * e_data )
{
krb5_error_code ret = 0 ;
2018-11-07 23:53:35 +03:00
krb5_pa_data pa , * ppa [ 2 ] ;
2014-05-15 18:43:59 +04:00
krb5_data * d = NULL ;
if ( ! e_data )
return ;
e_data - > data = NULL ;
e_data - > length = 0 ;
pa . magic = KV5M_PA_DATA ;
2022-09-23 07:27:46 +03:00
pa . pa_type = KRB5_PADATA_PW_SALT /* KERB_ERR_TYPE_EXTENDED */ ;
2014-05-15 18:43:59 +04:00
pa . length = 12 ;
pa . contents = malloc ( pa . length ) ;
if ( ! pa . contents ) {
return ;
}
SIVAL ( pa . contents , 0 , NT_STATUS_V ( nt_status ) ) ;
SIVAL ( pa . contents , 4 , 0 ) ;
SIVAL ( pa . contents , 8 , 1 ) ;
2018-11-07 23:53:35 +03:00
ppa [ 0 ] = & pa ;
ppa [ 1 ] = NULL ;
2014-05-15 18:43:59 +04:00
2018-11-07 23:53:35 +03:00
ret = encode_krb5_padata_sequence ( ppa , & d ) ;
2014-05-15 18:43:59 +04:00
free ( pa . contents ) ;
if ( ret ) {
return ;
}
e_data - > data = ( uint8_t * ) d - > data ;
e_data - > length = d - > length ;
/* free d, not d->data - gd */
free ( d ) ;
return ;
}
2023-08-16 06:57:00 +03:00
krb5_error_code mit_samba_check_client_access ( struct mit_samba_context * ctx ,
krb5_db_entry * client ,
const char * client_name ,
krb5_db_entry * server ,
const char * server_name ,
const char * netbios_name ,
bool password_change ,
DATA_BLOB * e_data )
2010-01-31 21:29:57 +03:00
{
2014-05-12 16:33:14 +04:00
struct samba_kdc_entry * skdc_entry ;
2010-01-31 21:29:57 +03:00
NTSTATUS nt_status ;
2014-05-12 16:33:14 +04:00
skdc_entry = talloc_get_type ( client - > e_data , struct samba_kdc_entry ) ;
2010-01-31 21:29:57 +03:00
2014-05-12 16:33:14 +04:00
nt_status = samba_kdc_check_client_access ( skdc_entry ,
2010-01-31 21:29:57 +03:00
client_name ,
netbios_name ,
password_change ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_NO_MEMORY ) ) {
return ENOMEM ;
}
samba_kdc_build_edata_reply ( nt_status , e_data ) ;
return samba_kdc_map_policy_err ( nt_status ) ;
}
return 0 ;
}
2023-08-16 06:57:00 +03:00
krb5_error_code mit_samba_check_s4u2proxy ( struct mit_samba_context * ctx ,
const krb5_db_entry * server ,
krb5_const_principal target_principal )
2010-01-31 21:29:57 +03:00
{
2021-11-22 22:09:31 +03:00
struct samba_kdc_entry * server_skdc_entry =
talloc_get_type_abort ( server - > e_data , struct samba_kdc_entry ) ;
krb5_error_code code ;
2010-01-31 21:29:57 +03:00
2021-11-22 22:09:31 +03:00
code = samba_kdc_check_s4u2proxy ( ctx - > context ,
ctx - > db_ctx ,
server_skdc_entry ,
target_principal ) ;
2010-01-31 21:29:57 +03:00
2021-11-22 22:09:31 +03:00
return code ;
2010-01-31 21:29:57 +03:00
}
2015-07-30 15:46:48 +03:00
2021-12-14 13:17:15 +03:00
krb5_error_code mit_samba_check_allowed_to_delegate_from (
struct mit_samba_context * ctx ,
krb5_const_principal client_principal ,
krb5_const_principal server_principal ,
krb5_pac header_pac ,
const krb5_db_entry * proxy )
{
struct samba_kdc_entry * proxy_skdc_entry =
talloc_get_type_abort ( proxy - > e_data , struct samba_kdc_entry ) ;
2023-10-10 05:12:30 +03:00
struct auth_user_info_dc * user_info_dc = NULL ;
TALLOC_CTX * mem_ctx = NULL ;
2021-12-14 13:17:15 +03:00
krb5_error_code code ;
2023-10-10 05:12:30 +03:00
mem_ctx = talloc_new ( NULL ) ;
if ( mem_ctx = = NULL ) {
return ENOMEM ;
}
2023-10-10 05:16:24 +03:00
/*
* FIXME : If ever we support RODCs , we must check that the PAC has not
* been issued by an RODC ( other than ourselves ) — otherwise the PAC
* cannot be trusted . Because the plugin interface does not give us the
* client entry , we cannot look up its groups in the database .
*/
2023-10-10 05:12:30 +03:00
code = kerberos_pac_to_user_info_dc ( mem_ctx ,
header_pac ,
ctx - > context ,
& user_info_dc ,
AUTH_INCLUDE_RESOURCE_GROUPS ,
NULL ,
NULL ,
NULL ) ;
if ( code ! = 0 ) {
goto out ;
}
2021-12-14 13:17:15 +03:00
code = samba_kdc_check_s4u2proxy_rbcd ( ctx - > context ,
ctx - > db_ctx ,
client_principal ,
server_principal ,
2023-10-10 05:12:30 +03:00
user_info_dc ,
2023-10-10 05:38:29 +03:00
NULL /* device_info_dc */ ,
( struct auth_claims ) { } ,
2021-12-14 13:17:15 +03:00
proxy_skdc_entry ) ;
2023-10-10 05:12:30 +03:00
out :
talloc_free ( mem_ctx ) ;
2021-12-14 13:17:15 +03:00
return code ;
}
2015-07-30 15:46:48 +03:00
static krb5_error_code mit_samba_change_pwd_error ( krb5_context context ,
NTSTATUS result ,
enum samPwdChangeReason reject_reason ,
struct samr_DomInfo1 * dominfo )
{
krb5_error_code code = KADM5_PASS_Q_GENERIC ;
if ( NT_STATUS_EQUAL ( result , NT_STATUS_NO_SUCH_USER ) ) {
code = KADM5_BAD_PRINCIPAL ;
krb5_set_error_message ( context ,
code ,
" No such user when changing password " ) ;
}
if ( NT_STATUS_EQUAL ( result , NT_STATUS_ACCESS_DENIED ) ) {
code = KADM5_PASS_Q_GENERIC ;
krb5_set_error_message ( context ,
code ,
" Not permitted to change password " ) ;
}
if ( NT_STATUS_EQUAL ( result , NT_STATUS_PASSWORD_RESTRICTION ) & &
dominfo ! = NULL ) {
switch ( reject_reason ) {
case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT :
code = KADM5_PASS_Q_TOOSHORT ;
krb5_set_error_message ( context ,
code ,
" Password too short, password "
" must be at least %d characters "
" long. " ,
dominfo - > min_password_length ) ;
break ;
case SAM_PWD_CHANGE_NOT_COMPLEX :
code = KADM5_PASS_Q_DICT ;
krb5_set_error_message ( context ,
code ,
" Password does not meet "
" complexity requirements " ) ;
break ;
case SAM_PWD_CHANGE_PWD_IN_HISTORY :
code = KADM5_PASS_TOOSOON ;
krb5_set_error_message ( context ,
code ,
" Password is already in password "
" history. New password must not "
" match any of your %d previous "
" passwords. " ,
dominfo - > password_history_length ) ;
break ;
default :
code = KADM5_PASS_Q_GENERIC ;
krb5_set_error_message ( context ,
code ,
" Password change rejected, "
" password changes may not be "
" permitted on this account, or "
" the minimum password age may "
" not have elapsed. " ) ;
break ;
}
}
return code ;
}
2023-08-16 06:57:00 +03:00
krb5_error_code mit_samba_kpasswd_change_password ( struct mit_samba_context * ctx ,
char * pwd ,
krb5_db_entry * db_entry )
2015-07-30 15:46:48 +03:00
{
NTSTATUS status ;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL ;
TALLOC_CTX * tmp_ctx ;
DATA_BLOB password ;
enum samPwdChangeReason reject_reason ;
struct samr_DomInfo1 * dominfo ;
const char * error_string = NULL ;
2023-10-11 07:07:02 +03:00
const struct auth_user_info_dc * user_info_dc = NULL ;
2021-07-12 14:05:59 +03:00
struct samba_kdc_entry * p =
talloc_get_type_abort ( db_entry - > e_data , struct samba_kdc_entry ) ;
2015-07-30 15:46:48 +03:00
krb5_error_code code = 0 ;
# ifdef DEBUG_PASSWORD
2023-07-21 02:44:05 +03:00
DBG_WARNING ( " mit_samba_kpasswd_change_password called with: %s \n " , pwd ) ;
2015-07-30 15:46:48 +03:00
# endif
tmp_ctx = talloc_named ( ctx , 0 , " mit_samba_kpasswd_change_password " ) ;
if ( tmp_ctx = = NULL ) {
return ENOMEM ;
}
2023-10-03 03:39:48 +03:00
code = samba_kdc_get_user_info_from_db ( tmp_ctx ,
2023-10-03 04:53:17 +03:00
ctx - > db_ctx - > samdb ,
2023-10-03 03:39:48 +03:00
p ,
p - > msg ,
& user_info_dc ) ;
if ( code ) {
const char * krb5err = krb5_get_error_message ( ctx - > context , code ) ;
2023-10-03 02:32:13 +03:00
DBG_WARNING ( " samba_kdc_get_user_info_from_db failed: %s \n " ,
2023-10-03 03:39:48 +03:00
krb5err ! = NULL ? krb5err : " <unknown> " ) ;
krb5_free_error_message ( ctx - > context , krb5err ) ;
2023-08-11 01:23:10 +03:00
goto out ;
2015-07-30 15:46:48 +03:00
}
status = auth_generate_session_info ( tmp_ctx ,
ctx - > db_ctx - > lp_ctx ,
ctx - > db_ctx - > samdb ,
user_info_dc ,
0 , /* session_info_flags */
& ctx - > session_info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2023-07-21 02:44:05 +03:00
DBG_WARNING ( " auth_generate_session_info failed: %s \n " ,
nt_errstr ( status ) ) ;
2023-08-11 01:23:10 +03:00
code = EINVAL ;
goto out ;
2015-07-30 15:46:48 +03:00
}
/* password is expected as UTF16 */
if ( ! convert_string_talloc ( tmp_ctx , CH_UTF8 , CH_UTF16 ,
pwd , strlen ( pwd ) ,
& password . data , & password . length ) ) {
2023-07-21 02:44:05 +03:00
DBG_WARNING ( " convert_string_talloc failed \n " ) ;
2023-08-11 01:23:10 +03:00
code = EINVAL ;
goto out ;
2015-07-30 15:46:48 +03:00
}
status = samdb_kpasswd_change_password ( tmp_ctx ,
ctx - > db_ctx - > lp_ctx ,
ctx - > db_ctx - > ev_ctx ,
ctx - > session_info ,
& password ,
& reject_reason ,
& dominfo ,
& error_string ,
& result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2023-07-21 02:44:05 +03:00
DBG_WARNING ( " samdb_kpasswd_change_password failed: %s \n " ,
nt_errstr ( status ) ) ;
2015-07-30 15:46:48 +03:00
code = KADM5_PASS_Q_GENERIC ;
krb5_set_error_message ( ctx - > context , code , " %s " , error_string ) ;
goto out ;
}
if ( ! NT_STATUS_IS_OK ( result ) ) {
code = mit_samba_change_pwd_error ( ctx - > context ,
result ,
reject_reason ,
dominfo ) ;
}
out :
talloc_free ( tmp_ctx ) ;
return code ;
}
2015-05-20 18:19:35 +03:00
void mit_samba_zero_bad_password_count ( krb5_db_entry * db_entry )
{
2022-11-07 19:21:44 +03:00
/* struct netr_SendToSamBase *send_to_sam = NULL; */
2021-07-12 14:05:59 +03:00
struct samba_kdc_entry * p =
talloc_get_type_abort ( db_entry - > e_data , struct samba_kdc_entry ) ;
2015-05-20 18:19:35 +03:00
struct ldb_dn * domain_dn ;
domain_dn = ldb_get_default_basedn ( p - > kdc_db_ctx - > samdb ) ;
authsam_logon_success_accounting ( p - > kdc_db_ctx - > samdb ,
p - > msg ,
domain_dn ,
2017-05-30 14:58:43 +03:00
true ,
2022-11-07 19:21:44 +03:00
NULL , NULL ) ;
2017-05-30 14:58:43 +03:00
/* TODO: RODC support */
2015-05-20 18:19:35 +03:00
}
void mit_samba_update_bad_password_count ( krb5_db_entry * db_entry )
{
2021-07-12 14:05:59 +03:00
struct samba_kdc_entry * p =
talloc_get_type_abort ( db_entry - > e_data , struct samba_kdc_entry ) ;
2015-05-20 18:19:35 +03:00
authsam_update_bad_pwd_count ( p - > kdc_db_ctx - > samdb ,
p - > msg ,
ldb_get_default_basedn ( p - > kdc_db_ctx - > samdb ) ) ;
}
2021-07-12 14:12:00 +03:00
bool mit_samba_princ_needs_pac ( krb5_db_entry * db_entry )
{
struct samba_kdc_entry * skdc_entry =
talloc_get_type_abort ( db_entry - > e_data , struct samba_kdc_entry ) ;
return samba_princ_needs_pac ( skdc_entry ) ;
}