2010-01-26 11:56:16 -05:00
/*
Unix SMB / CIFS implementation .
PAC Glue between Samba and the KDC
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2005 - 2009
Copyright ( C ) Simo Sorce < idra @ samba . org > 2010
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"
2023-06-16 14:49:11 +12:00
# include "kdc/authn_policy_util.h"
2010-11-11 14:09:41 +11:00
# include "kdc/kdc-glue.h"
2021-10-08 16:08:39 +13:00
# include "kdc/db-glue.h"
2010-01-26 11:56:16 -05:00
# include "kdc/pac-glue.h"
2021-10-08 16:08:39 +13:00
# include "sdb.h"
# include "sdb_hdb.h"
2021-10-01 16:14:37 +13:00
# include "librpc/gen_ndr/auth.h"
2022-02-21 19:25:06 +13:00
# include <krb5_locl.h>
2023-01-18 11:49:00 +01:00
# include "lib/replace/system/filesys.h"
2010-01-26 11:56:16 -05:00
2022-09-09 12:32:57 +02:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_KERBEROS
2021-10-11 14:47:25 +02:00
static bool samba_wdc_is_s4u2self_req ( astgs_request_t r )
{
const KDC_REQ * req = kdc_request_get_req ( r ) ;
const PA_DATA * pa_for_user = NULL ;
if ( req - > msg_type ! = krb_tgs_req ) {
return false ;
}
if ( req - > padata ! = NULL ) {
int idx = 0 ;
pa_for_user = krb5_find_padata ( req - > padata - > val ,
req - > padata - > len ,
KRB5_PADATA_FOR_USER ,
& idx ) ;
}
if ( pa_for_user ! = NULL ) {
return true ;
}
return false ;
}
2016-05-20 09:48:41 +02:00
/*
* Given the right private pointer from hdb_samba4 ,
* get a PAC from the attached ldb messages .
*
* For PKINIT we also get pk_reply_key and can add PAC_CREDENTIAL_INFO .
*/
2022-02-24 21:31:52 +01:00
static krb5_error_code samba_wdc_get_pac ( void * priv ,
astgs_request_t r ,
2022-02-22 19:41:14 +13:00
hdb_entry * client ,
hdb_entry * server ,
2016-05-20 09:48:41 +02:00
const krb5_keyblock * pk_reply_key ,
2021-12-22 17:08:43 +13:00
uint64_t pac_attributes ,
2010-01-26 11:56:16 -05:00
krb5_pac * pac )
{
2022-02-24 21:31:52 +01:00
krb5_context context = kdc_request_get_context ( ( kdc_request_t ) r ) ;
2010-01-26 11:56:16 -05:00
TALLOC_CTX * mem_ctx ;
2016-05-12 23:20:39 +02:00
DATA_BLOB * logon_blob = NULL ;
DATA_BLOB * cred_ndr = NULL ;
DATA_BLOB * * cred_ndr_ptr = NULL ;
DATA_BLOB _cred_blob = data_blob_null ;
DATA_BLOB * cred_blob = NULL ;
2016-05-13 00:13:33 +02:00
DATA_BLOB * upn_blob = NULL ;
2021-10-26 20:41:31 +13:00
DATA_BLOB * pac_attrs_blob = NULL ;
2021-10-26 20:42:41 +13:00
DATA_BLOB * requester_sid_blob = NULL ;
2023-10-09 19:32:24 +13:00
DATA_BLOB client_claims_blob = { } ;
2010-01-26 11:56:16 -05:00
krb5_error_code ret ;
NTSTATUS nt_status ;
2014-05-10 00:26:21 +02:00
struct samba_kdc_entry * skdc_entry =
2022-02-22 19:41:14 +13:00
talloc_get_type_abort ( client - > context ,
2014-05-10 00:26:21 +02:00
struct samba_kdc_entry ) ;
2022-12-02 10:49:20 +13:00
const struct samba_kdc_entry * server_entry =
talloc_get_type_abort ( server - > context ,
struct samba_kdc_entry ) ;
2022-09-27 14:51:54 +13:00
bool is_krbtgt = krb5_principal_is_krbtgt ( context , server - > principal ) ;
2022-12-02 10:49:20 +13:00
enum auth_group_inclusion group_inclusion ;
2021-10-11 14:47:25 +02:00
bool is_s4u2self = samba_wdc_is_s4u2self_req ( r ) ;
enum samba_asserted_identity asserted_identity =
( is_s4u2self ) ?
SAMBA_ASSERTED_IDENTITY_SERVICE :
SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY ;
2023-06-16 15:08:00 +12:00
struct authn_audit_info * server_audit_info = NULL ;
2023-09-05 14:08:25 +12:00
NTSTATUS reply_status = NT_STATUS_OK ;
2022-02-25 00:28:01 +01:00
2023-10-11 17:07:02 +13:00
const struct auth_user_info_dc * user_info_dc_const = NULL ;
struct auth_user_info_dc * user_info_dc_shallow_copy = NULL ;
2023-10-09 19:35:10 +13:00
struct auth_claims auth_claims = { } ;
2023-03-20 15:16:21 +13:00
2022-12-02 10:49:20 +13:00
/* 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 ;
}
2023-04-27 13:48:53 +12:00
mem_ctx = talloc_named ( client - > context , 0 , " samba_wdc_get_pac context " ) ;
2010-01-26 11:56:16 -05:00
if ( ! mem_ctx ) {
return ENOMEM ;
}
2016-05-12 23:20:39 +02:00
if ( pk_reply_key ! = NULL ) {
cred_ndr_ptr = & cred_ndr ;
}
2023-10-03 13:39:48 +13:00
ret = samba_kdc_get_user_info_from_db ( mem_ctx ,
2023-10-03 14:53:17 +13:00
server_entry - > kdc_db_ctx - > samdb ,
2023-10-03 13:39:48 +13:00
skdc_entry ,
skdc_entry - > msg ,
2023-10-11 17:07:02 +13:00
& user_info_dc_const ) ;
2023-10-03 13:39:48 +13:00
if ( ret ) {
2023-03-20 15:16:21 +13:00
talloc_free ( mem_ctx ) ;
2023-10-03 13:39:48 +13:00
return ret ;
2023-03-20 15:16:21 +13:00
}
2023-10-11 17:07:02 +13:00
/* Make a shallow copy of the user_info_dc structure. */
nt_status = authsam_shallow_copy_user_info_dc ( mem_ctx ,
user_info_dc_const ,
& user_info_dc_shallow_copy ) ;
user_info_dc_const = NULL ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DBG_ERR ( " Failed to allocate user_info_dc SIDs: %s \n " ,
nt_errstr ( nt_status ) ) ;
talloc_free ( mem_ctx ) ;
return map_errno_from_nt_status ( nt_status ) ;
}
2023-09-27 16:38:23 +13:00
nt_status = samba_kdc_add_asserted_identity ( asserted_identity ,
2023-10-11 17:07:02 +13:00
user_info_dc_shallow_copy ) ;
2023-09-27 16:38:23 +13:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DBG_ERR ( " Failed to add asserted identity: %s \n " ,
nt_errstr ( nt_status ) ) ;
talloc_free ( mem_ctx ) ;
return map_errno_from_nt_status ( nt_status ) ;
}
2023-10-09 15:19:01 +13:00
nt_status = samba_kdc_add_claims_valid ( user_info_dc_shallow_copy ) ;
2023-09-27 16:23:33 +13:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DBG_ERR ( " Failed to add Claims Valid: %s \n " ,
nt_errstr ( nt_status ) ) ;
talloc_free ( mem_ctx ) ;
return map_errno_from_nt_status ( nt_status ) ;
}
2024-02-27 11:23:03 +13:00
if ( kdc_request_get_pkinit_freshness_used ( r ) ) {
nt_status = samba_kdc_add_fresh_public_key_identity ( user_info_dc_shallow_copy ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
DBG_ERR ( " Failed to add Fresh Public Key Identity: %s \n " ,
nt_errstr ( nt_status ) ) ;
talloc_free ( mem_ctx ) ;
return map_errno_from_nt_status ( nt_status ) ;
}
}
2023-10-09 19:32:24 +13:00
ret = samba_kdc_get_claims_data_from_db ( server_entry - > kdc_db_ctx - > samdb ,
skdc_entry ,
2023-10-09 19:35:10 +13:00
& auth_claims . user_claims ) ;
2023-10-09 19:32:24 +13:00
if ( ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
nt_status = claims_data_encoded_claims_set ( mem_ctx ,
2023-10-09 19:35:10 +13:00
auth_claims . user_claims ,
2023-10-09 19:32:24 +13:00
& client_claims_blob ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( mem_ctx ) ;
return map_errno_from_nt_status ( nt_status ) ;
}
2023-06-16 15:08:00 +12:00
/*
* For an S4U2Self request , the authentication policy is not enforced .
*/
if ( ! is_s4u2self & & authn_policy_restrictions_present ( server_entry - > server_policy ) ) {
2023-10-09 19:35:10 +13:00
const hdb_entry * device = kdc_request_get_armor_client ( r ) ;
const struct auth_user_info_dc * device_info = NULL ;
if ( device ! = NULL ) {
const hdb_entry * device_krbtgt = NULL ;
struct samba_kdc_entry * device_skdc_entry = NULL ;
const struct samba_kdc_entry * device_krbtgt_skdc_entry = NULL ;
const krb5_const_pac device_pac = kdc_request_get_armor_pac ( r ) ;
struct samba_kdc_entry_pac device_pac_entry = { } ;
device_skdc_entry = talloc_get_type_abort ( device - > context ,
struct samba_kdc_entry ) ;
device_krbtgt = kdc_request_get_armor_server ( r ) ;
if ( device_krbtgt ! = NULL ) {
device_krbtgt_skdc_entry = talloc_get_type_abort ( device_krbtgt - > context ,
struct samba_kdc_entry ) ;
}
device_pac_entry = samba_kdc_entry_pac ( device_pac ,
device_skdc_entry ,
samba_kdc_entry_is_trust ( device_krbtgt_skdc_entry ) ) ;
ret = samba_kdc_get_user_info_dc ( mem_ctx ,
context ,
server_entry - > kdc_db_ctx - > samdb ,
device_pac_entry ,
& device_info ,
NULL /* resource_groups_out */ ) ;
if ( ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
ret = samba_kdc_get_claims_data ( mem_ctx ,
context ,
server_entry - > kdc_db_ctx - > samdb ,
device_pac_entry ,
& auth_claims . device_claims ) ;
if ( ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
}
2023-06-16 15:08:00 +12:00
ret = samba_kdc_allowed_to_authenticate_to ( mem_ctx ,
server_entry - > kdc_db_ctx - > samdb ,
server_entry - > kdc_db_ctx - > lp_ctx ,
skdc_entry ,
2023-10-11 17:07:02 +13:00
user_info_dc_shallow_copy ,
2023-10-09 19:35:10 +13:00
device_info ,
auth_claims ,
2023-06-16 15:08:00 +12:00
server_entry ,
& server_audit_info ,
2023-09-05 14:08:25 +12:00
& reply_status ) ;
2023-06-16 15:08:00 +12:00
if ( server_audit_info ! = NULL ) {
krb5_error_code ret2 ;
ret2 = hdb_samba4_set_steal_server_audit_info ( r , server_audit_info ) ;
if ( ret = = 0 ) {
ret = ret2 ;
}
}
2023-09-05 14:08:25 +12:00
if ( ! NT_STATUS_IS_OK ( reply_status ) ) {
2023-06-16 15:08:00 +12:00
krb5_error_code ret2 ;
2023-09-05 14:08:25 +12:00
ret2 = hdb_samba4_set_ntstatus ( r , reply_status , ret ) ;
2023-06-16 15:08:00 +12:00
if ( ret = = 0 ) {
ret = ret2 ;
}
}
if ( ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
}
2023-03-20 15:16:21 +13:00
nt_status = samba_kdc_get_logon_info_blob ( mem_ctx ,
2023-10-11 17:07:02 +13:00
user_info_dc_shallow_copy ,
2023-03-20 15:16:21 +13:00
group_inclusion ,
& logon_blob ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( mem_ctx ) ;
2023-08-11 10:02:28 +12:00
return map_errno_from_nt_status ( nt_status ) ;
2023-03-20 15:16:21 +13:00
}
if ( cred_ndr_ptr ! = NULL ) {
nt_status = samba_kdc_get_cred_ndr_blob ( mem_ctx ,
skdc_entry ,
cred_ndr_ptr ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( mem_ctx ) ;
2023-08-11 10:02:28 +12:00
return map_errno_from_nt_status ( nt_status ) ;
2023-03-20 15:16:21 +13:00
}
}
nt_status = samba_kdc_get_upn_info_blob ( mem_ctx ,
2023-10-11 17:07:02 +13:00
user_info_dc_shallow_copy ,
2023-03-20 15:16:21 +13:00
& upn_blob ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( mem_ctx ) ;
2023-08-11 10:02:28 +12:00
return map_errno_from_nt_status ( nt_status ) ;
2023-03-20 15:16:21 +13:00
}
if ( is_krbtgt ) {
nt_status = samba_kdc_get_pac_attrs_blob ( mem_ctx ,
pac_attributes ,
& pac_attrs_blob ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( mem_ctx ) ;
2023-08-11 10:02:28 +12:00
return map_errno_from_nt_status ( nt_status ) ;
2023-03-20 15:16:21 +13:00
}
nt_status = samba_kdc_get_requester_sid_blob ( mem_ctx ,
2023-10-11 17:07:02 +13:00
user_info_dc_shallow_copy ,
2023-03-20 15:16:21 +13:00
& requester_sid_blob ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
talloc_free ( mem_ctx ) ;
2023-08-11 10:02:28 +12:00
return map_errno_from_nt_status ( nt_status ) ;
2023-03-20 15:16:21 +13:00
}
}
2016-05-12 23:20:39 +02:00
if ( pk_reply_key ! = NULL & & cred_ndr ! = NULL ) {
ret = samba_kdc_encrypt_pac_credentials ( context ,
pk_reply_key ,
cred_ndr ,
mem_ctx ,
& _cred_blob ) ;
if ( ret ! = 0 ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
cred_blob = & _cred_blob ;
}
2021-10-07 15:12:35 +02:00
ret = krb5_pac_init ( context , pac ) ;
if ( ret ! = 0 ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
2016-05-12 23:20:39 +02:00
ret = samba_make_krb5_pac ( context , logon_blob , cred_blob ,
2021-10-26 20:41:31 +13:00
upn_blob , pac_attrs_blob ,
2022-02-24 23:57:31 +01:00
requester_sid_blob , NULL ,
2023-10-09 19:32:24 +13:00
& client_claims_blob , NULL , NULL ,
2022-02-24 23:57:31 +01:00
* pac ) ;
2010-01-26 11:56:16 -05:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2023-03-20 14:51:53 +13:00
static krb5_error_code samba_wdc_verify_pac2 ( astgs_request_t r ,
2023-06-20 11:14:50 +12:00
const hdb_entry * delegated_proxy ,
2023-03-20 14:51:53 +13:00
const hdb_entry * client ,
const hdb_entry * krbtgt ,
const krb5_pac pac ,
2023-10-10 15:03:22 +13:00
krb5_cksumtype ctype )
2010-01-26 11:56:16 -05:00
{
2021-10-11 14:47:25 +02:00
krb5_context context = kdc_request_get_context ( ( kdc_request_t ) r ) ;
2022-03-07 10:41:41 +01:00
struct samba_kdc_entry * client_skdc_entry = NULL ;
2014-05-10 00:49:44 +02:00
struct samba_kdc_entry * krbtgt_skdc_entry =
2022-03-07 10:41:41 +01:00
talloc_get_type_abort ( krbtgt - > context , struct samba_kdc_entry ) ;
2023-09-28 11:43:57 +13:00
struct samba_kdc_entry_pac client_pac_entry = { } ;
2022-03-07 10:41:41 +01:00
TALLOC_CTX * mem_ctx = NULL ;
2010-01-26 11:56:16 -05:00
krb5_error_code ret ;
2021-10-11 14:47:25 +02:00
bool is_s4u2self = samba_wdc_is_s4u2self_req ( r ) ;
2022-03-07 10:41:41 +01:00
bool is_in_db = false ;
2023-03-16 14:29:15 +13:00
bool is_trusted = false ;
2022-03-07 10:41:41 +01:00
uint32_t flags = 0 ;
2010-01-26 11:56:16 -05:00
2023-09-28 11:43:57 +13:00
if ( pac = = NULL ) {
return EINVAL ;
}
2023-03-20 14:51:53 +13:00
mem_ctx = talloc_named ( NULL , 0 , " samba_wdc_verify_pac2 context " ) ;
2022-03-07 10:41:41 +01:00
if ( mem_ctx = = NULL ) {
2010-01-26 11:56:16 -05:00
return ENOMEM ;
}
2021-08-09 17:20:31 +02:00
if ( client ! = NULL ) {
2022-02-22 19:41:14 +13:00
client_skdc_entry = talloc_get_type_abort ( client - > context ,
2021-08-09 17:20:31 +02:00
struct samba_kdc_entry ) ;
}
2021-10-01 16:14:37 +13:00
/*
* If the krbtgt was generated by an RODC , and we are not that
2010-09-28 13:13:28 +10:00
* RODC , then we need to regenerate the PAC - we can ' t trust
2021-10-01 16:14:37 +13:00
* it , and confirm that the RODC was permitted to print this ticket
*
2023-08-02 10:47:30 +02:00
* Because of the samba_kdc_validate_pac_blob ( ) step we can be
2021-10-01 16:14:37 +13:00
* sure that the record in ' client ' matches the SID in the
* original PAC .
*/
2023-03-16 14:29:15 +13:00
ret = samba_krbtgt_is_in_db ( krbtgt_skdc_entry , & is_in_db , & is_trusted ) ;
2012-01-11 18:06:55 +11:00
if ( ret ! = 0 ) {
2022-03-07 10:41:41 +01:00
goto out ;
2012-01-11 18:06:55 +11:00
}
2023-09-28 11:43:57 +13:00
krb5_pac_set_trusted ( pac , is_trusted ) ;
client_pac_entry = samba_kdc_entry_pac ( pac ,
client_skdc_entry ,
samba_kdc_entry_is_trust ( krbtgt_skdc_entry ) ) ;
2021-10-11 14:47:25 +02:00
if ( is_s4u2self ) {
flags | = SAMBA_KDC_FLAG_PROTOCOL_TRANSITION ;
}
2023-06-20 11:14:50 +12:00
if ( delegated_proxy ! = NULL ) {
2021-10-08 16:08:39 +13:00
krb5_enctype etype ;
Key * key = NULL ;
if ( ! is_in_db ) {
/*
* The RODC - issued PAC was signed by a KDC entry that we
* don ' t have a key for . The server signature is not
* trustworthy , since it could have been created by the
* server we got the ticket from . We must not proceed as
* otherwise the ticket signature is unchecked .
*/
2022-03-07 10:41:41 +01:00
ret = HDB_ERR_NOT_FOUND_HERE ;
goto out ;
2021-10-08 16:08:39 +13:00
}
/* Fetch the correct key depending on the checksum type. */
if ( ctype = = CKSUMTYPE_HMAC_MD5 ) {
etype = ENCTYPE_ARCFOUR_HMAC ;
} else {
ret = krb5_cksumtype_to_enctype ( context ,
ctype ,
& etype ) ;
if ( ret ! = 0 ) {
2022-03-07 10:41:41 +01:00
goto out ;
2021-10-08 16:08:39 +13:00
}
}
2022-02-22 19:41:14 +13:00
ret = hdb_enctype2key ( context , krbtgt , NULL , etype , & key ) ;
2021-10-08 16:08:39 +13:00
if ( ret ! = 0 ) {
2022-03-07 10:41:41 +01:00
goto out ;
2021-10-08 16:08:39 +13:00
}
2022-11-09 13:45:13 +13:00
/* Check the KDC, whole-PAC and ticket signatures. */
2021-10-08 16:08:39 +13:00
ret = krb5_pac_verify ( context ,
2023-03-20 14:51:53 +13:00
pac ,
2021-10-08 16:08:39 +13:00
0 ,
NULL ,
NULL ,
& key - > key ) ;
if ( ret ! = 0 ) {
2023-07-21 11:44:05 +12:00
DBG_WARNING ( " PAC KDC signature failed to verify \n " ) ;
2022-03-07 10:41:41 +01:00
goto out ;
2021-10-08 16:08:39 +13:00
}
2022-03-07 10:41:41 +01:00
flags | = SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION ;
2021-10-08 16:08:39 +13:00
}
2023-03-20 14:51:53 +13:00
ret = samba_kdc_verify_pac ( mem_ctx ,
context ,
2023-10-03 14:58:10 +13:00
krbtgt_skdc_entry - > kdc_db_ctx - > samdb ,
2023-03-20 14:51:53 +13:00
flags ,
2023-09-28 11:43:57 +13:00
client_pac_entry ,
krbtgt_skdc_entry ) ;
2023-03-20 14:51:53 +13:00
if ( ret ! = 0 ) {
goto out ;
}
out :
talloc_free ( mem_ctx ) ;
return ret ;
}
2023-07-11 16:52:25 +12:00
/* Re-sign (and reform, including possibly new groups) a PAC */
2023-03-20 14:51:53 +13:00
static krb5_error_code samba_wdc_reget_pac ( void * priv , astgs_request_t r ,
2023-06-20 11:14:50 +12:00
krb5_const_principal _client_principal ,
hdb_entry * delegated_proxy ,
krb5_const_pac delegated_proxy_pac ,
2023-03-20 14:51:53 +13:00
hdb_entry * client ,
hdb_entry * server ,
hdb_entry * krbtgt ,
krb5_pac * pac )
{
krb5_context context = kdc_request_get_context ( ( kdc_request_t ) r ) ;
2023-06-16 14:24:50 +12:00
struct samba_kdc_entry * delegated_proxy_skdc_entry = NULL ;
2023-06-20 11:14:50 +12:00
krb5_const_principal delegated_proxy_principal = NULL ;
2023-09-28 11:43:57 +13:00
struct samba_kdc_entry_pac delegated_proxy_pac_entry = { } ;
2023-03-20 14:51:53 +13:00
struct samba_kdc_entry * client_skdc_entry = NULL ;
2023-09-28 11:43:57 +13:00
struct samba_kdc_entry_pac client_pac_entry = { } ;
struct samba_kdc_entry_pac device = { } ;
2023-03-20 14:51:53 +13:00
const struct samba_kdc_entry * server_skdc_entry =
talloc_get_type_abort ( server - > context , struct samba_kdc_entry ) ;
const struct samba_kdc_entry * krbtgt_skdc_entry =
talloc_get_type_abort ( krbtgt - > context , struct samba_kdc_entry ) ;
TALLOC_CTX * mem_ctx = NULL ;
krb5_pac new_pac = NULL ;
2023-06-16 14:49:11 +12:00
struct authn_audit_info * server_audit_info = NULL ;
2023-03-20 14:51:53 +13:00
krb5_error_code ret ;
2023-09-05 14:08:25 +12:00
NTSTATUS reply_status = NT_STATUS_OK ;
2023-03-20 14:51:53 +13:00
uint32_t flags = 0 ;
2023-09-28 11:43:57 +13:00
if ( pac = = NULL ) {
return EINVAL ;
}
2023-03-20 14:51:53 +13:00
mem_ctx = talloc_named ( NULL , 0 , " samba_wdc_reget_pac context " ) ;
if ( mem_ctx = = NULL ) {
return ENOMEM ;
}
2023-06-20 11:14:50 +12:00
if ( delegated_proxy ! = NULL ) {
2023-06-16 14:24:50 +12:00
delegated_proxy_skdc_entry = talloc_get_type_abort ( delegated_proxy - > context ,
struct samba_kdc_entry ) ;
2023-06-20 11:14:50 +12:00
delegated_proxy_principal = delegated_proxy - > principal ;
}
2023-09-28 11:43:57 +13:00
delegated_proxy_pac_entry = samba_kdc_entry_pac ( delegated_proxy_pac ,
delegated_proxy_skdc_entry ,
/* The S4U2Proxy
* evidence ticket could
* not have been signed
* or issued by a krbtgt
* trust account . */
false /* is_from_trust */ ) ;
2023-03-20 14:51:53 +13:00
if ( client ! = NULL ) {
client_skdc_entry = talloc_get_type_abort ( client - > context ,
struct samba_kdc_entry ) ;
}
2023-09-28 11:43:57 +13:00
device = samba_kdc_get_device_pac ( r ) ;
2023-03-20 14:51:53 +13:00
2016-01-07 17:25:26 +01:00
ret = krb5_pac_init ( context , & new_pac ) ;
if ( ret ! = 0 ) {
2021-10-18 16:00:45 +13:00
new_pac = NULL ;
goto out ;
2016-01-07 17:25:26 +01:00
}
2023-09-28 11:43:57 +13:00
client_pac_entry = samba_kdc_entry_pac ( * pac ,
client_skdc_entry ,
samba_kdc_entry_is_trust ( krbtgt_skdc_entry ) ) ;
2023-03-20 14:51:53 +13:00
2022-03-07 10:41:41 +01:00
ret = samba_kdc_update_pac ( mem_ctx ,
context ,
krbtgt_skdc_entry - > kdc_db_ctx - > samdb ,
2023-06-16 14:24:50 +12:00
krbtgt_skdc_entry - > kdc_db_ctx - > lp_ctx ,
2022-03-07 10:41:41 +01:00
flags ,
2023-09-28 11:43:57 +13:00
client_pac_entry ,
2022-03-07 10:41:41 +01:00
server - > principal ,
server_skdc_entry ,
delegated_proxy_principal ,
2023-09-28 11:43:57 +13:00
delegated_proxy_pac_entry ,
device ,
2023-06-16 14:49:11 +12:00
new_pac ,
& server_audit_info ,
2023-09-05 14:08:25 +12:00
& reply_status ) ;
2023-06-16 14:49:11 +12:00
if ( server_audit_info ! = NULL ) {
krb5_error_code ret2 ;
ret2 = hdb_samba4_set_steal_server_audit_info ( r , server_audit_info ) ;
2023-06-26 17:09:22 +12:00
if ( ret = = 0 ) {
2023-06-16 14:49:11 +12:00
ret = ret2 ;
}
}
2023-09-05 14:08:25 +12:00
if ( ! NT_STATUS_IS_OK ( reply_status ) ) {
2023-06-16 14:49:11 +12:00
krb5_error_code ret2 ;
2023-09-05 14:08:25 +12:00
ret2 = hdb_samba4_set_ntstatus ( r , reply_status , ret ) ;
2023-06-26 17:09:22 +12:00
if ( ret = = 0 ) {
2023-06-16 14:49:11 +12:00
ret = ret2 ;
}
}
2022-03-07 10:41:41 +01:00
if ( ret ! = 0 ) {
krb5_pac_free ( context , new_pac ) ;
2023-01-18 11:49:00 +01:00
if ( ret = = ENOATTR ) {
2022-03-07 10:41:41 +01:00
krb5_pac_free ( context , * pac ) ;
* pac = NULL ;
ret = 0 ;
2016-01-07 17:25:26 +01:00
}
2022-03-07 10:41:41 +01:00
goto out ;
2016-01-07 17:25:26 +01:00
}
2022-03-07 10:41:41 +01:00
/* Replace the pac */
2016-01-07 17:25:26 +01:00
krb5_pac_free ( context , * pac ) ;
* pac = new_pac ;
2010-01-26 11:56:16 -05:00
2022-03-07 10:41:41 +01:00
out :
2010-01-26 11:56:16 -05:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2023-03-20 14:51:53 +13:00
/* Verify a PAC's SID and signatures */
2021-10-08 16:08:39 +13:00
2023-03-20 14:51:53 +13:00
static krb5_error_code samba_wdc_verify_pac ( void * priv , astgs_request_t r ,
2023-06-20 11:14:50 +12:00
krb5_const_principal _client_principal ,
hdb_entry * delegated_proxy ,
2023-03-20 14:51:53 +13:00
hdb_entry * client ,
2023-06-20 11:21:27 +12:00
hdb_entry * _server ,
2023-03-20 14:51:53 +13:00
hdb_entry * krbtgt ,
2023-04-18 14:28:01 +12:00
EncTicketPart * ticket ,
2023-10-10 15:03:22 +13:00
krb5_pac pac )
2021-10-08 16:08:39 +13:00
{
2022-02-24 21:31:52 +01:00
krb5_context context = kdc_request_get_context ( ( kdc_request_t ) r ) ;
krb5_kdc_configuration * config = kdc_request_get_config ( ( kdc_request_t ) r ) ;
2021-10-08 16:08:39 +13:00
struct samba_kdc_entry * krbtgt_skdc_entry =
2022-02-22 19:41:14 +13:00
talloc_get_type_abort ( krbtgt - > context ,
2021-10-08 16:08:39 +13:00
struct samba_kdc_entry ) ;
krb5_error_code ret ;
krb5_cksumtype ctype = CKSUMTYPE_NONE ;
2022-02-22 19:41:14 +13:00
hdb_entry signing_krbtgt_hdb ;
2021-10-08 16:08:39 +13:00
2023-06-20 11:14:50 +12:00
if ( delegated_proxy ) {
2023-09-05 14:15:11 +12:00
uint16_t pac_kdc_signature_rodc_id ;
const unsigned int local_tgs_rodc_id = krbtgt_skdc_entry - > kdc_db_ctx - > my_krbtgt_number ;
const uint16_t header_ticket_rodc_id = krbtgt - > kvno > > 16 ;
2021-10-08 16:08:39 +13:00
/*
2023-06-20 11:14:50 +12:00
* We ' re using delegated_proxy for the moment to indicate cases
* where the ticket was encrypted with the server key , and not a
* krbtgt key . This cannot be trusted , so we need to find a
* krbtgt key that signs the PAC in order to trust the ticket .
2021-10-08 16:08:39 +13:00
*
* The krbtgt passed in to this function refers to the krbtgt
* used to decrypt the ticket of the server requesting
* S4U2Proxy .
*
* When we implement service ticket renewal , we need to check
* the PAC , and this will need to be updated .
*/
ret = krb5_pac_get_kdc_checksum_info ( context ,
2023-03-20 14:51:53 +13:00
pac ,
2021-10-08 16:08:39 +13:00
& ctype ,
2023-09-05 14:15:11 +12:00
& pac_kdc_signature_rodc_id ) ;
2021-10-08 16:08:39 +13:00
if ( ret ! = 0 ) {
2023-07-21 11:44:05 +12:00
DBG_WARNING ( " Failed to get PAC checksum info \n " ) ;
2021-10-08 16:08:39 +13:00
return ret ;
}
/*
* We need to check the KDC and ticket signatures , fetching the
* correct key based on the enctype .
*/
2023-09-05 14:15:11 +12:00
if ( local_tgs_rodc_id ! = 0 ) {
2021-10-08 16:08:39 +13:00
/*
* If we are an RODC , and we are not the KDC that signed
* the evidence ticket , then we need to proxy the
* request .
*/
2023-09-05 14:15:11 +12:00
if ( local_tgs_rodc_id ! = pac_kdc_signature_rodc_id ) {
2021-10-08 16:08:39 +13:00
return HDB_ERR_NOT_FOUND_HERE ;
}
} else {
/*
* If we are a DC , the ticket may have been signed by a
* different KDC than the one that issued the header
* ticket .
*/
2023-09-05 14:15:11 +12:00
if ( pac_kdc_signature_rodc_id ! = header_ticket_rodc_id ) {
2022-03-23 04:17:01 +01:00
struct sdb_entry signing_krbtgt_sdb ;
2021-10-08 16:08:39 +13:00
/*
* Fetch our key from the database . To support
* key rollover , we ' re going to need to try
* multiple keys by trial and error . For now ,
* krbtgt keys aren ' t assumed to change .
*/
ret = samba_kdc_fetch ( context ,
krbtgt_skdc_entry - > kdc_db_ctx ,
2022-02-22 19:41:14 +13:00
krbtgt - > principal ,
2023-10-17 20:24:04 +13:00
SDB_F_GET_KRBTGT | SDB_F_RODC_NUMBER_SPECIFIED | SDB_F_CANON ,
( ( uint32_t ) pac_kdc_signature_rodc_id ) < < 16 ,
2022-03-23 04:17:01 +01:00
& signing_krbtgt_sdb ) ;
2021-10-08 16:08:39 +13:00
if ( ret ! = 0 ) {
return ret ;
}
2022-03-23 03:57:38 +01:00
ret = sdb_entry_to_hdb_entry ( context ,
2022-03-23 04:17:01 +01:00
& signing_krbtgt_sdb ,
2022-03-23 03:57:38 +01:00
& signing_krbtgt_hdb ) ;
2022-03-23 04:17:01 +01:00
sdb_entry_free ( & signing_krbtgt_sdb ) ;
2021-10-08 16:08:39 +13:00
if ( ret ! = 0 ) {
return ret ;
}
/*
* Replace the krbtgt entry with our own entry
* for further processing .
*/
krbtgt = & signing_krbtgt_hdb ;
}
}
2022-05-30 19:18:17 +12:00
} else if ( ! krbtgt_skdc_entry - > is_trust ) {
/*
* We expect to have received a TGT , so check that we haven ' t
* been given a kpasswd ticket instead . We don ' t need to do this
* check for an incoming trust , as they use a different secret
* and can ' t be confused with a normal TGT .
*/
struct timeval now = krb5_kdc_get_time ( ) ;
/*
* Check if the ticket is in the last two minutes of its
* life .
*/
2023-04-18 14:28:01 +12:00
KerberosTime lifetime = rk_time_sub ( ticket - > endtime , now . tv_sec ) ;
2022-05-30 19:18:17 +12:00
if ( lifetime < = CHANGEPW_LIFETIME ) {
/*
* This ticket has at most two minutes left to live . It
* may be a kpasswd ticket rather than a TGT , so don ' t
* accept it .
*/
kdc_audit_addreason ( ( kdc_request_t ) r ,
" Ticket is not a ticket-granting ticket " ) ;
return KRB5KRB_AP_ERR_TKT_EXPIRED ;
}
2021-10-08 16:08:39 +13:00
}
2023-03-20 14:51:53 +13:00
ret = samba_wdc_verify_pac2 ( r ,
2023-06-20 11:14:50 +12:00
delegated_proxy ,
2023-03-20 14:51:53 +13:00
client ,
krbtgt ,
pac ,
2023-10-10 15:03:22 +13:00
ctype ) ;
2021-10-08 16:08:39 +13:00
if ( krbtgt = = & signing_krbtgt_hdb ) {
2022-02-22 19:41:14 +13:00
hdb_free_entry ( context , config - > db [ 0 ] , & signing_krbtgt_hdb ) ;
2021-10-08 16:08:39 +13:00
}
return ret ;
}
2010-01-31 12:49:07 -05:00
static char * get_netbios_name ( TALLOC_CTX * mem_ctx , HostAddresses * addrs )
{
char * nb_name = NULL ;
2010-04-11 23:22:01 +02:00
size_t len ;
unsigned int i ;
2010-01-31 12:49:07 -05:00
for ( i = 0 ; addrs & & i < addrs - > len ; i + + ) {
if ( addrs - > val [ i ] . addr_type ! = KRB5_ADDRESS_NETBIOS ) {
continue ;
}
len = MIN ( addrs - > val [ i ] . address . length , 15 ) ;
nb_name = talloc_strndup ( mem_ctx ,
addrs - > val [ i ] . address . data , len ) ;
if ( nb_name ) {
break ;
}
}
2012-08-13 20:17:20 +02:00
if ( ( nb_name = = NULL ) | | ( nb_name [ 0 ] = = ' \0 ' ) ) {
2010-01-31 12:49:07 -05:00
return NULL ;
}
/* Strip space padding */
2012-08-13 20:17:20 +02:00
for ( len = strlen ( nb_name ) - 1 ;
( len > 0 ) & & ( nb_name [ len ] = = ' ' ) ;
- - len ) {
nb_name [ len ] = ' \0 ' ;
2010-01-31 12:49:07 -05:00
}
return nb_name ;
}
2010-01-26 11:56:16 -05:00
static krb5_error_code samba_wdc_check_client_access ( void * priv ,
2021-12-24 16:58:22 +13:00
astgs_request_t r )
2010-01-26 11:56:16 -05:00
{
2023-06-16 15:05:48 +12:00
krb5_context context = kdc_request_get_context ( ( kdc_request_t ) r ) ;
2023-06-16 15:00:29 +12:00
TALLOC_CTX * tmp_ctx = NULL ;
const hdb_entry * client = NULL ;
2010-01-31 12:49:07 -05:00
struct samba_kdc_entry * kdc_entry ;
2023-09-28 11:43:57 +13:00
struct samba_kdc_entry_pac device = { } ;
2023-06-16 15:05:48 +12:00
struct authn_audit_info * client_audit_info = NULL ;
2010-01-26 11:56:16 -05:00
bool password_change ;
2010-01-31 12:49:07 -05:00
char * workstation ;
NTSTATUS nt_status ;
2023-06-16 15:05:48 +12:00
NTSTATUS check_device_status = NT_STATUS_OK ;
krb5_error_code ret = 0 ;
2010-01-26 11:56:16 -05:00
2023-06-16 15:00:29 +12:00
client = kdc_request_get_client ( r ) ;
2022-02-23 09:53:27 +13:00
2023-06-16 15:00:29 +12:00
tmp_ctx = talloc_named ( client - > context , 0 , " samba_wdc_check_client_access " ) ;
if ( tmp_ctx = = NULL ) {
return ENOMEM ;
}
2023-06-16 15:02:35 +12:00
kdc_entry = talloc_get_type_abort ( client - > context , struct samba_kdc_entry ) ;
2023-06-16 15:05:48 +12:00
2023-09-28 11:43:57 +13:00
device = samba_kdc_get_device_pac ( r ) ;
2023-06-16 15:05:48 +12:00
ret = samba_kdc_check_device ( tmp_ctx ,
context ,
kdc_entry - > kdc_db_ctx - > samdb ,
kdc_entry - > kdc_db_ctx - > lp_ctx ,
2023-09-28 11:43:57 +13:00
device ,
2023-06-16 15:05:48 +12:00
kdc_entry - > client_policy ,
& client_audit_info ,
& check_device_status ) ;
if ( client_audit_info ! = NULL ) {
krb5_error_code ret2 ;
ret2 = hdb_samba4_set_steal_client_audit_info ( r , client_audit_info ) ;
if ( ret2 ) {
ret = ret2 ;
}
}
kdc_entry - > reject_status = check_device_status ;
if ( ! NT_STATUS_IS_OK ( check_device_status ) ) {
krb5_error_code ret2 ;
/*
* Add the NTSTATUS to the request so we can return it in the
* ‘ e - data ’ field later .
*/
ret2 = hdb_samba4_set_ntstatus ( r , check_device_status , ret ) ;
if ( ret2 ) {
ret = ret2 ;
}
}
if ( ret ) {
/*
* As we didn ’ t get far enough to check the server policy , only
* the client policy will be referenced in the authentication
* log message .
*/
talloc_free ( tmp_ctx ) ;
return ret ;
}
2023-06-16 15:00:29 +12:00
workstation = get_netbios_name ( tmp_ctx ,
2022-02-23 09:53:27 +13:00
kdc_request_get_req ( r ) - > req_body . addresses ) ;
2023-06-16 15:05:48 +12:00
password_change = ( kdc_request_get_server ( r ) & & kdc_request_get_server ( r ) - > flags . change_pw ) ;
2010-01-26 11:56:16 -05:00
2010-01-31 12:49:07 -05:00
nt_status = samba_kdc_check_client_access ( kdc_entry ,
2022-02-23 09:53:27 +13:00
kdc_request_get_cname ( ( kdc_request_t ) r ) ,
2010-01-31 12:49:07 -05:00
workstation ,
password_change ) ;
2010-01-26 11:56:16 -05:00
2023-06-16 15:05:48 +12:00
kdc_entry - > reject_status = nt_status ;
2010-01-31 12:49:07 -05:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2023-05-17 15:47:18 +12:00
krb5_error_code ret2 ;
2010-01-31 12:49:07 -05:00
if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_NO_MEMORY ) ) {
2023-06-16 15:00:29 +12:00
talloc_free ( tmp_ctx ) ;
2010-01-31 12:49:07 -05:00
return ENOMEM ;
2010-01-26 11:56:16 -05:00
}
2023-05-17 15:47:18 +12:00
ret = samba_kdc_map_policy_err ( nt_status ) ;
/*
* Add the NTSTATUS to the request so we can return it in the
* ‘ e - data ’ field later .
*/
ret2 = hdb_samba4_set_ntstatus ( r , nt_status , ret ) ;
if ( ret2 ) {
ret = ret2 ;
}
2023-06-16 15:00:29 +12:00
talloc_free ( tmp_ctx ) ;
2023-05-17 15:47:18 +12:00
return ret ;
2010-01-26 11:56:16 -05:00
}
2010-01-31 12:49:07 -05:00
/* Now do the standard Heimdal check */
2023-06-16 15:00:29 +12:00
talloc_free ( tmp_ctx ) ;
2021-06-23 12:08:34 +12:00
return KRB5_PLUGIN_NO_HANDLE ;
2010-01-26 11:56:16 -05:00
}
2021-12-24 16:59:42 +13:00
/* this function allocates 'data' using malloc.
* The caller is responsible for freeing it */
static krb5_error_code samba_kdc_build_supported_etypes ( uint32_t supported_etypes ,
krb5_data * e_data )
{
e_data - > data = malloc ( 4 ) ;
if ( e_data - > data = = NULL ) {
return ENOMEM ;
}
e_data - > length = 4 ;
PUSH_LE_U32 ( e_data - > data , 0 , supported_etypes ) ;
return 0 ;
}
static krb5_error_code samba_wdc_finalize_reply ( void * priv ,
astgs_request_t r )
{
struct samba_kdc_entry * server_kdc_entry ;
uint32_t supported_enctypes ;
2022-02-23 09:53:27 +13:00
server_kdc_entry = talloc_get_type ( kdc_request_get_server ( r ) - > context , struct samba_kdc_entry ) ;
2021-12-24 16:59:42 +13:00
/*
* If the canonicalize flag is set , add PA - SUPPORTED - ENCTYPES padata
* type to indicate what encryption types the server supports .
*/
supported_enctypes = server_kdc_entry - > supported_enctypes ;
2022-02-23 09:53:27 +13:00
if ( kdc_request_get_req ( r ) - > req_body . kdc_options . canonicalize & & supported_enctypes ! = 0 ) {
2021-12-24 16:59:42 +13:00
krb5_error_code ret ;
2022-02-23 09:53:27 +13:00
PA_DATA md ;
2021-12-24 16:59:42 +13:00
2022-02-23 09:53:27 +13:00
ret = samba_kdc_build_supported_etypes ( supported_enctypes , & md . padata_value ) ;
2021-12-24 16:59:42 +13:00
if ( ret ! = 0 ) {
return ret ;
}
2022-02-23 09:53:27 +13:00
md . padata_type = KRB5_PADATA_SUPPORTED_ETYPES ;
ret = kdc_request_add_encrypted_padata ( r , & md ) ;
2021-12-24 16:59:42 +13:00
if ( ret ! = 0 ) {
/*
* So we do not leak the allocated
2023-07-21 12:38:09 +12:00
* memory on md in the error case
2021-12-24 16:59:42 +13:00
*/
2022-02-23 09:53:27 +13:00
krb5_data_free ( & md . padata_value ) ;
2021-12-24 16:59:42 +13:00
}
}
return 0 ;
}
2010-01-26 11:56:16 -05:00
static krb5_error_code samba_wdc_plugin_init ( krb5_context context , void * * ptr )
{
* ptr = NULL ;
return 0 ;
}
static void samba_wdc_plugin_fini ( void * ptr )
{
return ;
}
2022-02-21 19:25:06 +13:00
static krb5_error_code samba_wdc_referral_policy ( void * priv ,
astgs_request_t r )
{
2022-02-23 09:53:27 +13:00
return kdc_request_get_error_code ( ( kdc_request_t ) r ) ;
2022-02-21 19:25:06 +13:00
}
2024-05-13 10:58:51 +12:00
static krb5_error_code samba_wdc_hwauth_policy ( void * priv , astgs_request_t r )
{
const hdb_entry * client = kdc_request_get_client ( r ) ;
krb5_error_code ret = 0 ;
if ( client ! = NULL & & client - > flags . require_hwauth ) {
krb5_error_code ret2 ;
ret = KRB5KDC_ERR_POLICY ;
ret2 = hdb_samba4_set_ntstatus (
r , NT_STATUS_SMARTCARD_LOGON_REQUIRED , ret ) ;
if ( ret2 ) {
ret = ret2 ;
}
}
return ret ;
}
2022-02-22 14:39:13 +13:00
struct krb5plugin_kdc_ftable kdc_plugin_table = {
2024-05-13 10:58:51 +12:00
. minor_version = KRB5_PLUGIN_KDC_VERSION_12 ,
2010-01-26 11:56:16 -05:00
. init = samba_wdc_plugin_init ,
. fini = samba_wdc_plugin_fini ,
2023-03-20 14:51:53 +13:00
. pac_verify = samba_wdc_verify_pac ,
. pac_update = samba_wdc_reget_pac ,
2010-01-26 11:56:16 -05:00
. client_access = samba_wdc_check_client_access ,
2021-12-24 16:59:42 +13:00
. finalize_reply = samba_wdc_finalize_reply ,
2021-12-02 11:34:24 +13:00
. pac_generate = samba_wdc_get_pac ,
2022-02-21 19:25:06 +13:00
. referral_policy = samba_wdc_referral_policy ,
2024-05-13 10:58:51 +12:00
. hwauth_policy = samba_wdc_hwauth_policy ,
2010-01-26 11:56:16 -05:00
} ;