2007-01-10 01:57:32 +00:00
/*
2021-12-24 01:52:32 +01:00
* Copyright ( c ) 2006 - 2017 Kungliga Tekniska Högskolan
2008-10-27 11:35:07 +01:00
* ( Royal Institute of Technology , Stockholm , Sweden ) .
* All rights reserved .
2007-01-10 01:57:32 +00:00
*
2008-10-27 11:35:07 +01:00
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
2007-01-10 01:57:32 +00:00
*
2008-10-27 11:35:07 +01:00
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
2007-01-10 01:57:32 +00:00
*
2008-10-27 11:35:07 +01:00
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
2007-01-10 01:57:32 +00:00
*
2008-10-27 11:35:07 +01:00
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
2007-01-10 01:57:32 +00:00
*
2008-10-27 11:35:07 +01:00
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
2007-01-10 01:57:32 +00:00
*/
# include "krb5_locl.h"
2022-03-01 14:17:54 +13:00
# include <heimbasepriv.h>
2008-03-19 10:17:42 +11:00
# include <wind.h>
2022-03-01 14:17:54 +13:00
# include <assert.h>
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
/*
* https : //learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/3341cfa2-6ef5-42e0-b7bc-4544884bf399
*/
2007-01-10 01:57:32 +00:00
struct PAC_INFO_BUFFER {
2022-10-14 16:45:37 +13:00
uint32_t type ; /* ULONG ulType in the original */
uint32_t buffersize ; /* ULONG cbBufferSize in the original */
uint64_t offset ; /* ULONG64 Offset in the original
* this being the offset from the beginning of the
* struct PACTYPE to the beginning of the buffer
* containing data of type ulType
*/
2007-01-10 01:57:32 +00:00
} ;
2022-10-14 16:45:37 +13:00
/*
* https : //learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/6655b92f-ab06-490b-845d-037e6987275f
*/
2007-01-10 01:57:32 +00:00
struct PACTYPE {
2022-10-14 16:45:37 +13:00
uint32_t numbuffers ; /* named cBuffers of type ULONG in the original */
uint32_t version ; /* Named Version of type ULONG in the original */
struct PAC_INFO_BUFFER buffers [ 1 ] ; /* an ellipsis (...) in the original */
2007-01-10 01:57:32 +00:00
} ;
2022-10-14 16:45:37 +13:00
/*
* A PAC starts with a PACTYPE header structure that is followed by an array of
* numbuffers PAC_INFO_BUFFER structures , each of which points to a buffer
* beyond the last PAC_INFO_BUFFER structures .
*/
2008-03-19 10:17:42 +11:00
struct krb5_pac_data {
2007-01-10 01:57:32 +00:00
struct PACTYPE * pac ;
krb5_data data ;
struct PAC_INFO_BUFFER * server_checksum ;
struct PAC_INFO_BUFFER * privsvr_checksum ;
struct PAC_INFO_BUFFER * logon_name ;
2021-12-24 01:52:32 +01:00
struct PAC_INFO_BUFFER * upn_dns_info ;
2021-08-13 12:44:37 +03:00
struct PAC_INFO_BUFFER * ticket_checksum ;
2021-12-24 01:52:32 +01:00
struct PAC_INFO_BUFFER * attributes_info ;
2022-11-09 13:45:13 +13:00
struct PAC_INFO_BUFFER * full_checksum ;
2021-08-13 12:44:37 +03:00
krb5_data ticket_sign_data ;
2021-12-24 01:52:32 +01:00
/* PAC_UPN_DNS_INFO */
krb5_principal upn_princ ;
uint32_t upn_flags ;
krb5_principal canon_princ ;
krb5_data sid ;
/* PAC_ATTRIBUTES_INFO */
uint64_t pac_attributes ;
2007-01-10 01:57:32 +00:00
} ;
2007-06-13 05:44:24 +00:00
# define PAC_ALIGNMENT 8
2007-01-10 01:57:32 +00:00
2007-06-13 05:44:24 +00:00
# define PACTYPE_SIZE 8
# define PAC_INFO_BUFFER_SIZE 16
2007-01-10 01:57:32 +00:00
2022-03-01 14:17:54 +13:00
# define PAC_LOGON_INFO 1
# define PAC_CREDENTIALS_INFO 2
2007-06-13 05:44:24 +00:00
# define PAC_SERVER_CHECKSUM 6
# define PAC_PRIVSVR_CHECKSUM 7
# define PAC_LOGON_NAME 10
# define PAC_CONSTRAINED_DELEGATION 11
2021-12-24 01:52:32 +01:00
# define PAC_UPN_DNS_INFO 12
2021-08-13 12:44:37 +03:00
# define PAC_TICKET_CHECKSUM 16
2021-12-24 01:52:32 +01:00
# define PAC_ATTRIBUTES_INFO 17
# define PAC_REQUESTOR_SID 18
2022-11-09 13:45:13 +13:00
# define PAC_FULL_CHECKSUM 19
2021-12-24 01:52:32 +01:00
/* Flag in PAC_UPN_DNS_INFO */
# define PAC_EXTRA_LOGON_INFO_FLAGS_UPN_DEFAULTED 0x1
# define PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID 0x2
2007-01-10 01:57:32 +00:00
# define CHECK(r,f,l) \
do { \
if ( ( ( r ) = f ) ! = 0 ) { \
2008-10-27 11:35:07 +01:00
krb5_clear_error_message ( context ) ; \
2007-01-10 01:57:32 +00:00
goto l ; \
} \
} while ( 0 )
2022-03-01 14:17:54 +13:00
static const char zeros [ PAC_ALIGNMENT ] ;
static void HEIM_CALLCONV
pac_dealloc ( void * ctx )
{
krb5_pac pac = ( krb5_pac ) ctx ;
krb5_data_free ( & pac - > data ) ;
krb5_data_free ( & pac - > ticket_sign_data ) ;
if ( pac - > upn_princ ) {
free_Principal ( pac - > upn_princ ) ;
free ( pac - > upn_princ ) ;
}
if ( pac - > canon_princ ) {
free_Principal ( pac - > canon_princ ) ;
free ( pac - > canon_princ ) ;
}
krb5_data_free ( & pac - > sid ) ;
free ( pac - > pac ) ;
}
struct heim_type_data pac_object = {
HEIM_TID_PAC ,
" heim-pac " ,
NULL ,
pac_dealloc ,
NULL ,
NULL ,
NULL ,
NULL
} ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
/*
* Returns the size of the PACTYPE header + the PAC_INFO_BUFFER array . This is
* also the end of the whole thing , and any offsets to buffers from
* thePAC_INFO_BUFFER [ ] entries have to be beyond it .
*/
static krb5_error_code
pac_header_size ( krb5_context context , uint32_t num_buffers , uint32_t * result )
{
krb5_error_code ret ;
uint32_t header_size ;
/* Guard against integer overflow */
if ( num_buffers > UINT32_MAX / PAC_INFO_BUFFER_SIZE ) {
ret = EOVERFLOW ;
krb5_set_error_message ( context , ret , " PAC has too many buffers " ) ;
return ret ;
}
header_size = PAC_INFO_BUFFER_SIZE * num_buffers ;
/* Guard against integer overflow */
if ( header_size > UINT32_MAX - PACTYPE_SIZE ) {
ret = EOVERFLOW ;
krb5_set_error_message ( context , ret , " PAC has too many buffers " ) ;
return ret ;
}
header_size + = PACTYPE_SIZE ;
* result = header_size ;
return 0 ;
}
/* Output `size' + `addend' + padding for alignment if it doesn't overflow */
static krb5_error_code
pac_aligned_size ( krb5_context context ,
uint32_t size ,
uint32_t addend ,
uint32_t * aligned_size )
{
krb5_error_code ret ;
if ( size > UINT32_MAX - addend | |
( size + addend ) > UINT32_MAX - ( PAC_ALIGNMENT - 1 ) ) {
ret = EOVERFLOW ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
return ret ;
}
size + = addend ;
size + = PAC_ALIGNMENT - 1 ;
size & = ~ ( PAC_ALIGNMENT - 1 ) ;
* aligned_size = size ;
return 0 ;
}
2010-11-11 11:27:33 +11:00
/*
* HMAC - MD5 checksum over any key ( needed for the PAC routines )
*/
static krb5_error_code
HMAC_MD5_any_checksum ( krb5_context context ,
const krb5_keyblock * key ,
const void * data ,
size_t len ,
unsigned usage ,
Checksum * result )
{
2011-03-14 23:06:40 +01:00
struct _krb5_key_data local_key ;
2021-12-24 01:52:32 +01:00
struct krb5_crypto_iov iov ;
2010-11-11 11:27:33 +11:00
krb5_error_code ret ;
memset ( & local_key , 0 , sizeof ( local_key ) ) ;
ret = krb5_copy_keyblock ( context , key , & local_key . key ) ;
if ( ret )
return ret ;
ret = krb5_data_alloc ( & result - > checksum , 16 ) ;
if ( ret ) {
krb5_free_keyblock ( context , local_key . key ) ;
return ret ;
}
result - > cksumtype = CKSUMTYPE_HMAC_MD5 ;
2021-12-24 01:52:32 +01:00
iov . data . data = ( void * ) data ;
iov . data . length = len ;
iov . flags = KRB5_CRYPTO_TYPE_DATA ;
ret = _krb5_HMAC_MD5_checksum ( context , NULL , & local_key , usage , & iov , 1 ,
result ) ;
2010-11-11 11:27:33 +11:00
if ( ret )
krb5_data_free ( & result - > checksum ) ;
2011-07-15 09:10:30 +02:00
2010-11-11 11:27:33 +11:00
krb5_free_keyblock ( context , local_key . key ) ;
return ret ;
}
2007-01-10 01:57:32 +00:00
/*
*
*/
2010-11-29 11:24:08 +11:00
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2007-01-10 01:57:32 +00:00
krb5_pac_parse ( krb5_context context , const void * ptr , size_t len ,
2008-03-19 10:17:42 +11:00
krb5_pac * pac )
2007-01-10 01:57:32 +00:00
{
2022-10-14 16:45:37 +13:00
krb5_error_code ret = 0 ;
2008-03-19 10:17:42 +11:00
krb5_pac p ;
2007-01-10 01:57:32 +00:00
krb5_storage * sp = NULL ;
2022-10-14 16:45:37 +13:00
uint32_t i , num_buffers , version , header_size = 0 ;
uint32_t prev_start = 0 ;
uint32_t prev_end = 0 ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
* pac = NULL ;
2022-03-01 14:17:54 +13:00
p = _heim_alloc_object ( & pac_object , sizeof ( * p ) ) ;
2022-10-14 16:45:37 +13:00
if ( p )
sp = krb5_storage_from_readonly_mem ( ptr , len ) ;
if ( sp = = NULL )
2010-11-29 11:24:08 +11:00
ret = krb5_enomem ( context ) ;
2022-10-14 16:45:37 +13:00
if ( ret = = 0 ) {
krb5_storage_set_flags ( sp , KRB5_STORAGE_BYTEORDER_LE ) ;
ret = krb5_ret_uint32 ( sp , & num_buffers ) ;
2007-01-10 01:57:32 +00:00
}
2022-10-14 16:45:37 +13:00
if ( ret = = 0 )
ret = krb5_ret_uint32 ( sp , & version ) ;
if ( ret = = 0 & & num_buffers < 1 )
krb5_set_error_message ( context , ret = EINVAL ,
N_ ( " PAC has too few buffers " , " " ) ) ;
if ( ret = = 0 & & num_buffers > 1000 )
krb5_set_error_message ( context , ret = EINVAL ,
N_ ( " PAC has too many buffers " , " " ) ) ;
if ( ret = = 0 & & version ! = 0 )
krb5_set_error_message ( context , ret = EINVAL ,
2021-08-13 12:44:37 +03:00
N_ ( " PAC has wrong version %d " , " " ) ,
2022-10-14 16:45:37 +13:00
( int ) version ) ;
if ( ret = = 0 )
ret = pac_header_size ( context , num_buffers , & header_size ) ;
if ( ret = = 0 & & header_size > len )
krb5_set_error_message ( context , ret = EOVERFLOW ,
N_ ( " PAC encoding invalid, would overflow buffers " , " " ) ) ;
if ( ret = = 0 )
p - > pac = calloc ( 1 , header_size ) ;
if ( ret = = 0 & & p - > pac = = NULL )
2010-11-29 11:24:08 +11:00
ret = krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
if ( ret = = 0 ) {
p - > pac - > numbuffers = num_buffers ;
p - > pac - > version = version ;
2007-01-10 01:57:32 +00:00
}
2022-10-14 16:45:37 +13:00
for ( i = 0 ; ret = = 0 & & i < p - > pac - > numbuffers ; i + + ) {
ret = krb5_ret_uint32 ( sp , & p - > pac - > buffers [ i ] . type ) ;
if ( ret = = 0 )
ret = krb5_ret_uint32 ( sp , & p - > pac - > buffers [ i ] . buffersize ) ;
if ( ret = = 0 )
ret = krb5_ret_uint64 ( sp , & p - > pac - > buffers [ i ] . offset ) ;
if ( ret )
break ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
/* Consistency checks (we don't check for wasted space) */
if ( p - > pac - > buffers [ i ] . offset & ( PAC_ALIGNMENT - 1 ) ) {
krb5_set_error_message ( context , ret = EINVAL ,
2017-02-18 09:00:26 +13:00
N_ ( " PAC out of alignment " , " " ) ) ;
2022-10-14 16:45:37 +13:00
break ;
2007-01-10 01:57:32 +00:00
}
2022-10-14 16:45:37 +13:00
if ( p - > pac - > buffers [ i ] . offset > len | |
p - > pac - > buffers [ i ] . buffersize > len | |
len - p - > pac - > buffers [ i ] . offset < p - > pac - > buffers [ i ] . buffersize ) {
krb5_set_error_message ( context , ret = EOVERFLOW ,
N_ ( " PAC buffer overflow " , " " ) ) ;
break ;
2007-01-10 01:57:32 +00:00
}
2022-10-14 16:45:37 +13:00
if ( p - > pac - > buffers [ i ] . offset < header_size ) {
krb5_set_error_message ( context , ret = EINVAL ,
2008-10-27 11:35:07 +01:00
N_ ( " PAC offset inside header: %lu %lu " , " " ) ,
2022-10-14 16:45:37 +13:00
( unsigned long ) p - > pac - > buffers [ i ] . offset ,
( unsigned long ) header_size ) ;
break ;
2007-01-10 01:57:32 +00:00
}
2022-10-14 16:45:37 +13:00
/*
* We ' d like to check for non - overlapping of buffers , but the buffers
* need not be in the same order as the PAC_INFO_BUFFER [ ] entries
* pointing to them ! To fully check for overlap we ' d have to have an
* O ( N ^ 2 ) loop after we parse all the PAC_INFO_BUFFER [ ] .
*
* But we can check that each buffer does not overlap the previous
* buffer .
*/
if ( prev_start ) {
if ( p - > pac - > buffers [ i ] . offset > = prev_start & &
p - > pac - > buffers [ i ] . offset < prev_end ) {
krb5_set_error_message ( context , ret = EINVAL ,
N_ ( " PAC overlap " , " " ) ) ;
break ;
}
if ( p - > pac - > buffers [ i ] . offset < prev_start & &
p - > pac - > buffers [ i ] . offset +
p - > pac - > buffers [ i ] . buffersize > prev_start ) {
krb5_set_error_message ( context , ret = EINVAL ,
N_ ( " PAC overlap " , " " ) ) ;
break ;
}
}
prev_start = p - > pac - > buffers [ i ] . offset ;
prev_end = p - > pac - > buffers [ i ] . offset + p - > pac - > buffers [ i ] . buffersize ;
/* Let's save pointers to buffers we'll need later */
switch ( p - > pac - > buffers [ i ] . type ) {
case PAC_SERVER_CHECKSUM :
if ( p - > server_checksum )
krb5_set_error_message ( context , ret = EINVAL ,
2021-08-13 12:44:37 +03:00
N_ ( " PAC has multiple server checksums " , " " ) ) ;
2022-10-14 16:45:37 +13:00
else
p - > server_checksum = & p - > pac - > buffers [ i ] ;
break ;
case PAC_PRIVSVR_CHECKSUM :
if ( p - > privsvr_checksum )
krb5_set_error_message ( context , ret = EINVAL ,
N_ ( " PAC has multiple KDC checksums " , " " ) ) ;
else
p - > privsvr_checksum = & p - > pac - > buffers [ i ] ;
break ;
case PAC_LOGON_NAME :
if ( p - > logon_name )
krb5_set_error_message ( context , ret = EINVAL ,
N_ ( " PAC has multiple logon names " , " " ) ) ;
else
p - > logon_name = & p - > pac - > buffers [ i ] ;
break ;
case PAC_UPN_DNS_INFO :
if ( p - > upn_dns_info )
krb5_set_error_message ( context , ret = EINVAL ,
2021-12-24 01:52:32 +01:00
N_ ( " PAC has multiple UPN DNS info buffers " , " " ) ) ;
2022-10-14 16:45:37 +13:00
else
p - > upn_dns_info = & p - > pac - > buffers [ i ] ;
break ;
case PAC_TICKET_CHECKSUM :
if ( p - > ticket_checksum )
krb5_set_error_message ( context , ret = EINVAL ,
2021-08-13 12:44:37 +03:00
N_ ( " PAC has multiple ticket checksums " , " " ) ) ;
2022-10-14 16:45:37 +13:00
else
p - > ticket_checksum = & p - > pac - > buffers [ i ] ;
break ;
case PAC_ATTRIBUTES_INFO :
if ( p - > attributes_info )
krb5_set_error_message ( context , ret = EINVAL ,
2021-12-24 01:52:32 +01:00
N_ ( " PAC has multiple attributes info buffers " , " " ) ) ;
2022-10-14 16:45:37 +13:00
else
p - > attributes_info = & p - > pac - > buffers [ i ] ;
break ;
2022-11-09 13:45:13 +13:00
case PAC_FULL_CHECKSUM :
if ( p - > full_checksum )
krb5_set_error_message ( context , ret = EINVAL ,
N_ ( " PAC has multiple full checksums " , " " ) ) ;
else
p - > full_checksum = & p - > pac - > buffers [ i ] ;
break ;
2022-10-14 16:45:37 +13:00
default : break ;
}
2007-01-10 01:57:32 +00:00
}
2022-10-14 16:45:37 +13:00
if ( ret = = 0 )
ret = krb5_data_copy ( & p - > data , ptr , len ) ;
if ( ret = = 0 ) {
* pac = p ;
p = NULL ;
2007-01-10 01:57:32 +00:00
}
2022-10-14 16:45:37 +13:00
if ( sp )
krb5_storage_free ( sp ) ;
krb5_pac_free ( context , p ) ;
2007-01-10 01:57:32 +00:00
return ret ;
}
2010-11-29 11:24:08 +11:00
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2008-03-19 10:17:42 +11:00
krb5_pac_init ( krb5_context context , krb5_pac * pac )
2007-01-10 01:57:32 +00:00
{
krb5_error_code ret ;
2008-03-19 10:17:42 +11:00
krb5_pac p ;
2007-01-10 01:57:32 +00:00
2022-03-01 14:17:54 +13:00
p = _heim_alloc_object ( & pac_object , sizeof ( * p ) ) ;
2007-01-10 01:57:32 +00:00
if ( p = = NULL ) {
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
}
p - > pac = calloc ( 1 , sizeof ( * p - > pac ) ) ;
if ( p - > pac = = NULL ) {
2022-03-01 14:17:54 +13:00
krb5_pac_free ( context , p ) ;
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
}
ret = krb5_data_alloc ( & p - > data , PACTYPE_SIZE ) ;
if ( ret ) {
free ( p - > pac ) ;
2022-03-01 14:17:54 +13:00
krb5_pac_free ( context , p ) ;
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
}
2022-10-14 16:45:37 +13:00
memset ( p - > data . data , 0 , p - > data . length ) ;
2007-01-10 01:57:32 +00:00
* pac = p ;
return 0 ;
}
2022-10-14 16:45:37 +13:00
/**
* Add a PAC buffer ` nd ' of type ` type ' to the pac ` p ' .
*
* @ param context
* @ param p
* @ param type
* @ param nd
*
* @ return 0 on success or a Kerberos or system error .
*/
2010-11-29 11:24:08 +11:00
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2008-03-19 10:17:42 +11:00
krb5_pac_add_buffer ( krb5_context context , krb5_pac p ,
2022-10-14 16:45:37 +13:00
uint32_t type , const krb5_data * nd )
2007-01-10 01:57:32 +00:00
{
krb5_error_code ret ;
void * ptr ;
2022-10-14 16:45:37 +13:00
size_t old_len = p - > data . length ;
uint32_t len , offset , header_size ;
2007-01-10 01:57:32 +00:00
uint32_t i ;
2022-10-14 16:45:37 +13:00
uint32_t num_buffers ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
assert ( nd - > data ! = NULL ) ;
2022-03-01 14:17:54 +13:00
2022-10-14 16:45:37 +13:00
num_buffers = p - > pac - > numbuffers ;
ret = pac_header_size ( context , num_buffers + 1 , & header_size ) ;
if ( ret )
return ret ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
ptr = realloc ( p - > pac , header_size ) ;
2010-11-11 11:27:33 +11:00
if ( ptr = = NULL )
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2010-11-11 11:27:33 +11:00
2007-01-10 01:57:32 +00:00
p - > pac = ptr ;
2022-10-14 16:45:37 +13:00
p - > pac - > buffers [ num_buffers ] . type = 0 ;
p - > pac - > buffers [ num_buffers ] . buffersize = 0 ;
p - > pac - > buffers [ num_buffers ] . offset = 0 ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
/*
* Check that we can adjust all the buffer offsets in the existing
* PAC_INFO_BUFFERs , since changing the size of PAC_INFO_BUFFER [ ] means
* changing the offsets of buffers following that array .
*
* We don ' t adjust them until we can ' t fail .
*/
for ( i = 0 ; i < num_buffers ; i + + ) {
if ( p - > pac - > buffers [ i ] . offset > UINT32_MAX - PAC_INFO_BUFFER_SIZE ) {
krb5_set_error_message ( context , ret = EOVERFLOW ,
" too many / too large PAC buffers " ) ;
return ret ;
}
2007-01-10 01:57:32 +00:00
}
2008-10-27 11:35:07 +01:00
2022-10-14 16:45:37 +13:00
/*
* The new buffer ' s offset must be past the end of the buffers we have
* ( p - > data ) , which is the sum of the header and p - > data . length .
*/
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
/* Set offset = p->data.length + PAC_INFO_BUFFER_SIZE + alignment */
ret = pac_aligned_size ( context , p - > data . length , PAC_INFO_BUFFER_SIZE , & offset ) ;
if ( ret = = 0 )
/* Set the new length = offset + nd->length + alignment */
ret = pac_aligned_size ( context , offset , nd - > length , & len ) ;
if ( ret ) {
krb5_set_error_message ( context , ret , " PAC buffer too large " ) ;
return ret ;
}
2007-01-10 01:57:32 +00:00
ret = krb5_data_realloc ( & p - > data , len ) ;
if ( ret ) {
2008-10-27 11:35:07 +01:00
krb5_set_error_message ( context , ret , N_ ( " malloc: out of memory " , " " ) ) ;
2007-01-10 01:57:32 +00:00
return ret ;
}
2022-10-14 16:45:37 +13:00
/* Zero out the new allocation to zero out any padding */
memset ( ( char * ) p - > data . data + old_len , 0 , len - old_len ) ;
p - > pac - > buffers [ num_buffers ] . type = type ;
p - > pac - > buffers [ num_buffers ] . buffersize = nd - > length ;
p - > pac - > buffers [ num_buffers ] . offset = offset ;
/* Adjust all the buffer offsets in the existing PAC_INFO_BUFFERs now */
for ( i = 0 ; i < num_buffers ; i + + )
p - > pac - > buffers [ i ] . offset + = PAC_INFO_BUFFER_SIZE ;
2008-10-27 11:35:07 +01:00
/*
2022-10-14 16:45:37 +13:00
* Make place for new PAC INFO BUFFER header
2007-06-13 05:44:24 +00:00
*/
2022-10-14 16:45:37 +13:00
header_size - = PAC_INFO_BUFFER_SIZE ;
memmove ( ( unsigned char * ) p - > data . data + header_size + PAC_INFO_BUFFER_SIZE ,
( unsigned char * ) p - > data . data + header_size ,
old_len - header_size ) ;
/* Clear the space where we would put the new PAC_INFO_BUFFER[] element */
memset ( ( unsigned char * ) p - > data . data + header_size , 0 ,
PAC_INFO_BUFFER_SIZE ) ;
2007-01-10 01:57:32 +00:00
/*
2022-10-14 16:45:37 +13:00
* Copy in new data part
2007-01-10 01:57:32 +00:00
*/
2022-10-14 16:45:37 +13:00
memcpy ( ( unsigned char * ) p - > data . data + offset , nd - > data , nd - > length ) ;
2007-01-10 01:57:32 +00:00
p - > pac - > numbuffers + = 1 ;
return 0 ;
}
2008-10-27 11:35:07 +01:00
/**
* Get the PAC buffer of specific type from the pac .
*
* @ param context Kerberos 5 context .
* @ param p the pac structure returned by krb5_pac_parse ( ) .
* @ param type type of buffer to get
* @ param data return data , free with krb5_data_free ( ) .
*
2022-10-14 16:45:37 +13:00
* @ return Returns 0 to indicate success , ENOENT to indicate that a buffer of
* the given type was not found , or a Kerberos or system error code .
2008-10-27 11:35:07 +01:00
*
* @ ingroup krb5_pac
*/
2010-11-29 11:24:08 +11:00
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2022-03-10 16:12:43 +01:00
krb5_pac_get_buffer ( krb5_context context , krb5_const_pac p ,
2007-01-10 01:57:32 +00:00
uint32_t type , krb5_data * data )
{
krb5_error_code ret ;
uint32_t i ;
for ( i = 0 ; i < p - > pac - > numbuffers ; i + + ) {
2022-10-14 16:45:37 +13:00
size_t len = p - > pac - > buffers [ i ] . buffersize ;
size_t offset = p - > pac - > buffers [ i ] . offset ;
2007-01-10 01:57:32 +00:00
if ( p - > pac - > buffers [ i ] . type ! = type )
continue ;
2022-10-14 16:45:37 +13:00
if ( ! data )
return 0 ;
2022-03-01 14:17:54 +13:00
2022-10-14 16:45:37 +13:00
ret = krb5_data_copy ( data , ( unsigned char * ) p - > data . data + offset , len ) ;
if ( ret )
krb5_set_error_message ( context , ret , N_ ( " malloc: out of memory " , " " ) ) ;
return ret ;
2007-01-10 01:57:32 +00:00
}
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , ENOENT , " No PAC buffer of type %lu was found " ,
( unsigned long ) type ) ;
2007-01-10 01:57:32 +00:00
return ENOENT ;
}
2022-03-01 14:17:54 +13:00
static struct {
uint32_t type ;
krb5_data name ;
} pac_buffer_name_map [ ] = {
# define PAC_MAP_ENTRY(type, name) { PAC_##type, { sizeof(name) - 1, name } }
PAC_MAP_ENTRY ( LOGON_INFO , " logon-info " ) ,
PAC_MAP_ENTRY ( CREDENTIALS_INFO , " credentials-info " ) ,
PAC_MAP_ENTRY ( SERVER_CHECKSUM , " server-checksum " ) ,
PAC_MAP_ENTRY ( PRIVSVR_CHECKSUM , " privsvr-checksum " ) ,
PAC_MAP_ENTRY ( LOGON_NAME , " client-info " ) ,
PAC_MAP_ENTRY ( CONSTRAINED_DELEGATION , " delegation-info " ) ,
PAC_MAP_ENTRY ( UPN_DNS_INFO , " upn-dns-info " ) ,
PAC_MAP_ENTRY ( TICKET_CHECKSUM , " ticket-checksum " ) ,
PAC_MAP_ENTRY ( ATTRIBUTES_INFO , " attributes-info " ) ,
PAC_MAP_ENTRY ( REQUESTOR_SID , " requestor-sid " )
} ;
/*
*
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2022-03-10 16:12:43 +01:00
_krb5_pac_get_buffer_by_name ( krb5_context context , krb5_const_pac p ,
2022-03-01 14:17:54 +13:00
const krb5_data * name , krb5_data * data )
{
size_t i ;
for ( i = 0 ;
i < sizeof ( pac_buffer_name_map ) / sizeof ( pac_buffer_name_map [ 0 ] ) ;
i + + ) {
if ( krb5_data_cmp ( name , & pac_buffer_name_map [ i ] . name ) = = 0 )
return krb5_pac_get_buffer ( context , p , pac_buffer_name_map [ i ] . type , data ) ;
}
krb5_set_error_message ( context , ENOENT , " No PAC buffer with name %.*s was found " ,
( int ) name - > length , ( char * ) name - > data ) ;
return ENOENT ;
}
2007-01-10 01:57:32 +00:00
/*
*
*/
2010-11-29 11:24:08 +11:00
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2007-01-10 01:57:32 +00:00
krb5_pac_get_types ( krb5_context context ,
2022-03-10 16:12:43 +01:00
krb5_const_pac p ,
2007-01-10 01:57:32 +00:00
size_t * len ,
uint32_t * * types )
{
size_t i ;
2021-12-24 01:52:32 +01:00
* types = calloc ( p - > pac - > numbuffers , sizeof ( * * types ) ) ;
2007-01-10 01:57:32 +00:00
if ( * types = = NULL ) {
* len = 0 ;
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
}
for ( i = 0 ; i < p - > pac - > numbuffers ; i + + )
( * types ) [ i ] = p - > pac - > buffers [ i ] . type ;
* len = p - > pac - > numbuffers ;
return 0 ;
}
/*
*
*/
2010-11-29 11:24:08 +11:00
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
2008-03-19 10:17:42 +11:00
krb5_pac_free ( krb5_context context , krb5_pac pac )
2007-01-10 01:57:32 +00:00
{
2022-03-01 14:17:54 +13:00
heim_release ( pac ) ;
2007-01-10 01:57:32 +00:00
}
/*
*
*/
static krb5_error_code
verify_checksum ( krb5_context context ,
const struct PAC_INFO_BUFFER * sig ,
const krb5_data * data ,
void * ptr , size_t len ,
2022-11-09 13:45:13 +13:00
const krb5_keyblock * key ,
krb5_boolean strict_cksumtype_match )
2007-01-10 01:57:32 +00:00
{
krb5_storage * sp = NULL ;
uint32_t type ;
krb5_error_code ret ;
Checksum cksum ;
2021-08-13 12:44:37 +03:00
size_t cksumsize ;
2007-01-10 01:57:32 +00:00
2007-07-03 08:00:08 +00:00
memset ( & cksum , 0 , sizeof ( cksum ) ) ;
2022-10-14 16:45:37 +13:00
sp = krb5_storage_from_mem ( ( char * ) data - > data + sig - > offset ,
2007-01-10 01:57:32 +00:00
sig - > buffersize ) ;
2010-11-11 11:27:33 +11:00
if ( sp = = NULL )
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2010-11-11 11:27:33 +11:00
2007-01-10 01:57:32 +00:00
krb5_storage_set_flags ( sp , KRB5_STORAGE_BYTEORDER_LE ) ;
CHECK ( ret , krb5_ret_uint32 ( sp , & type ) , out ) ;
cksum . cksumtype = type ;
2021-08-13 12:44:37 +03:00
ret = krb5_checksumsize ( context , type , & cksumsize ) ;
if ( ret )
goto out ;
/* Allow for RODCIdentifier trailer, see MS-PAC 2.8 */
if ( cksumsize > ( sig - > buffersize - krb5_storage_seek ( sp , 0 , SEEK_CUR ) ) ) {
ret = EINVAL ;
goto out ;
}
cksum . checksum . length = cksumsize ;
2007-01-10 01:57:32 +00:00
cksum . checksum . data = malloc ( cksum . checksum . length ) ;
if ( cksum . checksum . data = = NULL ) {
2010-11-29 11:24:08 +11:00
ret = krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
goto out ;
}
ret = krb5_storage_read ( sp , cksum . checksum . data , cksum . checksum . length ) ;
2011-07-15 09:10:30 +02:00
if ( ret ! = ( int ) cksum . checksum . length ) {
2021-09-17 13:57:57 +10:00
ret = KRB5KRB_AP_ERR_INAPP_CKSUM ;
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , ret , " PAC checksum missing checksum " ) ;
2007-01-10 01:57:32 +00:00
goto out ;
}
if ( ! krb5_checksum_is_keyed ( context , cksum . cksumtype ) ) {
2021-09-17 13:57:57 +10:00
ret = KRB5KRB_AP_ERR_INAPP_CKSUM ;
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , ret , " Checksum type %d not keyed " ,
cksum . cksumtype ) ;
2007-01-10 01:57:32 +00:00
goto out ;
}
2010-11-02 17:08:34 +11:00
/* If the checksum is HMAC-MD5, the checksum type is not tied to
* the key type , instead the HMAC - MD5 checksum is applied blindly
* on whatever key is used for this connection , avoiding issues
* with unkeyed checksums on des - cbc - md5 and des - cbc - crc . See
* http : //comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
* for the same issue in MIT , and
* http : //blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
* for Microsoft ' s explaination */
2010-11-11 11:27:33 +11:00
2022-11-09 13:45:13 +13:00
if ( cksum . cksumtype = = CKSUMTYPE_HMAC_MD5 & & ! strict_cksumtype_match ) {
2010-11-02 17:08:34 +11:00
Checksum local_checksum ;
2010-11-11 11:27:33 +11:00
memset ( & local_checksum , 0 , sizeof ( local_checksum ) ) ;
2010-11-02 17:08:34 +11:00
2010-11-11 11:27:33 +11:00
ret = HMAC_MD5_any_checksum ( context , key , ptr , len ,
KRB5_KU_OTHER_CKSUM , & local_checksum ) ;
if ( ret ! = 0 | | krb5_data_ct_cmp ( & local_checksum . checksum , & cksum . checksum ) ! = 0 ) {
2010-11-02 17:08:34 +11:00
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY ;
krb5_set_error_message ( context , ret ,
2010-11-11 11:27:33 +11:00
N_ ( " PAC integrity check failed for "
" hmac-md5 checksum " , " " ) ) ;
2010-11-02 17:08:34 +11:00
}
krb5_data_free ( & local_checksum . checksum ) ;
2010-11-11 11:27:33 +11:00
2010-11-02 17:08:34 +11:00
} else {
krb5_crypto crypto = NULL ;
2007-01-10 01:57:32 +00:00
2010-11-02 17:08:34 +11:00
ret = krb5_crypto_init ( context , key , 0 , & crypto ) ;
if ( ret )
goto out ;
ret = krb5_verify_checksum ( context , crypto , KRB5_KU_OTHER_CKSUM ,
ptr , len , & cksum ) ;
krb5_crypto_destroy ( context , crypto ) ;
}
2007-06-13 05:44:24 +00:00
free ( cksum . checksum . data ) ;
2007-01-10 01:57:32 +00:00
krb5_storage_free ( sp ) ;
return ret ;
out :
2007-06-13 05:44:24 +00:00
if ( cksum . checksum . data )
free ( cksum . checksum . data ) ;
2007-01-10 01:57:32 +00:00
if ( sp )
krb5_storage_free ( sp ) ;
return ret ;
}
static krb5_error_code
create_checksum ( krb5_context context ,
const krb5_keyblock * key ,
2010-11-02 17:08:34 +11:00
uint32_t cksumtype ,
2007-01-10 01:57:32 +00:00
void * data , size_t datalen ,
void * sig , size_t siglen )
{
krb5_crypto crypto = NULL ;
krb5_error_code ret ;
Checksum cksum ;
2010-11-02 17:08:34 +11:00
/* If the checksum is HMAC-MD5, the checksum type is not tied to
* the key type , instead the HMAC - MD5 checksum is applied blindly
* on whatever key is used for this connection , avoiding issues
* with unkeyed checksums on des - cbc - md5 and des - cbc - crc . See
* http : //comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
* for the same issue in MIT , and
* http : //blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
* for Microsoft ' s explaination */
2010-11-11 11:27:33 +11:00
2011-07-15 09:10:30 +02:00
if ( cksumtype = = ( uint32_t ) CKSUMTYPE_HMAC_MD5 ) {
2010-11-11 11:27:33 +11:00
ret = HMAC_MD5_any_checksum ( context , key , data , datalen ,
KRB5_KU_OTHER_CKSUM , & cksum ) ;
2021-12-24 01:52:32 +01:00
if ( ret )
return ret ;
2010-11-02 17:08:34 +11:00
} else {
ret = krb5_crypto_init ( context , key , 0 , & crypto ) ;
if ( ret )
return ret ;
2007-01-10 01:57:32 +00:00
2010-11-02 17:08:34 +11:00
ret = krb5_create_checksum ( context , crypto , KRB5_KU_OTHER_CKSUM , 0 ,
data , datalen , & cksum ) ;
krb5_crypto_destroy ( context , crypto ) ;
if ( ret )
return ret ;
}
2007-01-10 01:57:32 +00:00
if ( cksum . checksum . length ! = siglen ) {
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , EINVAL , " pac checksum wrong length " ) ;
2007-01-10 01:57:32 +00:00
free_Checksum ( & cksum ) ;
return EINVAL ;
}
memcpy ( sig , cksum . checksum . data , siglen ) ;
free_Checksum ( & cksum ) ;
return 0 ;
}
2021-12-24 01:52:32 +01:00
static krb5_error_code
parse_upn_dns_info ( krb5_context context ,
const struct PAC_INFO_BUFFER * upndnsinfo ,
const krb5_data * data ,
krb5_principal * upn_princ ,
uint32_t * flags ,
krb5_principal * canon_princ ,
krb5_data * sid )
{
krb5_error_code ret ;
krb5_storage * sp = NULL ;
uint16_t upn_length , upn_offset ;
uint16_t dns_domain_name_length , dns_domain_name_offset ;
uint16_t canon_princ_length , canon_princ_offset ;
uint16_t sid_length , sid_offset ;
char * upn = NULL ;
char * dns_domain_name = NULL ;
char * sam_name = NULL ;
* upn_princ = NULL ;
* flags = 0 ;
* canon_princ = NULL ;
krb5_data_zero ( sid ) ;
2022-10-14 16:45:37 +13:00
sp = krb5_storage_from_readonly_mem ( ( const char * ) data - > data + upndnsinfo - > offset ,
2021-12-24 01:52:32 +01:00
upndnsinfo - > buffersize ) ;
if ( sp = = NULL )
return krb5_enomem ( context ) ;
krb5_storage_set_flags ( sp , KRB5_STORAGE_BYTEORDER_LE ) ;
CHECK ( ret , krb5_ret_uint16 ( sp , & upn_length ) , out ) ;
CHECK ( ret , krb5_ret_uint16 ( sp , & upn_offset ) , out ) ;
CHECK ( ret , krb5_ret_uint16 ( sp , & dns_domain_name_length ) , out ) ;
CHECK ( ret , krb5_ret_uint16 ( sp , & dns_domain_name_offset ) , out ) ;
CHECK ( ret , krb5_ret_uint32 ( sp , flags ) , out ) ;
if ( * flags & PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID ) {
CHECK ( ret , krb5_ret_uint16 ( sp , & canon_princ_length ) , out ) ;
CHECK ( ret , krb5_ret_uint16 ( sp , & canon_princ_offset ) , out ) ;
CHECK ( ret , krb5_ret_uint16 ( sp , & sid_length ) , out ) ;
CHECK ( ret , krb5_ret_uint16 ( sp , & sid_offset ) , out ) ;
} else {
canon_princ_length = canon_princ_offset = 0 ;
sid_length = sid_offset = 0 ;
}
if ( upn_offset ) {
CHECK ( ret , _krb5_ret_utf8_from_ucs2le_at_offset ( sp , upn_offset ,
upn_length , & upn ) , out ) ;
}
CHECK ( ret , _krb5_ret_utf8_from_ucs2le_at_offset ( sp , dns_domain_name_offset ,
dns_domain_name_length , & dns_domain_name ) , out ) ;
if ( ( * flags & PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID ) & & canon_princ_offset ) {
CHECK ( ret , _krb5_ret_utf8_from_ucs2le_at_offset ( sp , canon_princ_offset ,
canon_princ_length , & sam_name ) , out ) ;
}
if ( upn_offset ) {
ret = krb5_parse_name_flags ( context ,
upn ,
KRB5_PRINCIPAL_PARSE_ENTERPRISE |
KRB5_PRINCIPAL_PARSE_NO_DEF_REALM ,
upn_princ ) ;
if ( ret )
goto out ;
ret = krb5_principal_set_realm ( context , * upn_princ , dns_domain_name ) ;
if ( ret )
goto out ;
}
if ( canon_princ_offset ) {
ret = krb5_parse_name_flags ( context ,
sam_name ,
KRB5_PRINCIPAL_PARSE_NO_REALM |
KRB5_PRINCIPAL_PARSE_NO_DEF_REALM ,
canon_princ ) ;
if ( ret )
goto out ;
ret = krb5_principal_set_realm ( context , * canon_princ , dns_domain_name ) ;
if ( ret )
goto out ;
}
if ( sid_offset )
CHECK ( ret , _krb5_ret_data_at_offset ( sp , sid_offset , sid_length , sid ) , out ) ;
out :
free ( upn ) ;
free ( dns_domain_name ) ;
free ( sam_name ) ;
krb5_storage_free ( sp ) ;
return ret ;
}
2007-01-10 01:57:32 +00:00
/*
*
*/
# define NTTIME_EPOCH 0x019DB1DED53E8000LL
static uint64_t
unix2nttime ( time_t unix_time )
{
long long wt ;
wt = unix_time * ( uint64_t ) 10000000 + ( uint64_t ) NTTIME_EPOCH ;
return wt ;
}
static krb5_error_code
verify_logonname ( krb5_context context ,
const struct PAC_INFO_BUFFER * logon_name ,
const krb5_data * data ,
time_t authtime ,
krb5_const_principal principal )
{
krb5_error_code ret ;
uint32_t time1 , time2 ;
2021-12-24 01:52:32 +01:00
krb5_storage * sp = NULL ;
2007-01-10 01:57:32 +00:00
uint16_t len ;
2015-05-20 13:40:58 +00:00
char * s = NULL ;
char * principal_string = NULL ;
char * logon_string = NULL ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
sp = krb5_storage_from_readonly_mem ( ( const char * ) data - > data + logon_name - > offset ,
2007-01-10 01:57:32 +00:00
logon_name - > buffersize ) ;
2010-11-11 11:27:33 +11:00
if ( sp = = NULL )
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
krb5_storage_set_flags ( sp , KRB5_STORAGE_BYTEORDER_LE ) ;
CHECK ( ret , krb5_ret_uint32 ( sp , & time1 ) , out ) ;
CHECK ( ret , krb5_ret_uint32 ( sp , & time2 ) , out ) ;
{
uint64_t t1 , t2 ;
t1 = unix2nttime ( authtime ) ;
t2 = ( ( uint64_t ) time2 < < 32 ) | time1 ;
2021-12-24 01:52:32 +01:00
/*
* When neither the ticket nor the PAC set an explicit authtime ,
* both times are zero , but relative to different time scales .
* So we must compare " not set " values without converting to a
* common time reference .
*/
if ( t1 ! = t2 & & ( t2 ! = 0 & & authtime ! = 0 ) ) {
2007-01-10 01:57:32 +00:00
krb5_storage_free ( sp ) ;
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , EINVAL , " PAC timestamp mismatch " ) ;
2007-01-10 01:57:32 +00:00
return EINVAL ;
}
}
CHECK ( ret , krb5_ret_uint16 ( sp , & len ) , out ) ;
if ( len = = 0 ) {
krb5_storage_free ( sp ) ;
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , EINVAL , " PAC logon name length missing " ) ;
2007-01-10 01:57:32 +00:00
return EINVAL ;
}
s = malloc ( len ) ;
if ( s = = NULL ) {
krb5_storage_free ( sp ) ;
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
}
ret = krb5_storage_read ( sp , s , len ) ;
if ( ret ! = len ) {
krb5_storage_free ( sp ) ;
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , EINVAL , " Failed to read PAC logon name " ) ;
2007-01-10 01:57:32 +00:00
return EINVAL ;
}
krb5_storage_free ( sp ) ;
{
2008-03-19 10:17:42 +11:00
size_t ucs2len = len / 2 ;
2007-01-10 01:57:32 +00:00
uint16_t * ucs2 ;
size_t u8len ;
2008-03-19 10:17:42 +11:00
unsigned int flags = WIND_RW_LE ;
2007-01-10 01:57:32 +00:00
2008-03-19 10:17:42 +11:00
ucs2 = malloc ( sizeof ( ucs2 [ 0 ] ) * ucs2len ) ;
2010-11-11 11:27:33 +11:00
if ( ucs2 = = NULL )
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2010-11-11 11:27:33 +11:00
2008-03-19 10:17:42 +11:00
ret = wind_ucs2read ( s , len , & flags , ucs2 , & ucs2len ) ;
2007-01-10 01:57:32 +00:00
free ( s ) ;
2008-03-19 10:17:42 +11:00
if ( ret ) {
free ( ucs2 ) ;
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , ret , " Failed to convert string to UCS-2 " ) ;
2008-03-19 10:17:42 +11:00
return ret ;
}
ret = wind_ucs2utf8_length ( ucs2 , ucs2len , & u8len ) ;
if ( ret ) {
free ( ucs2 ) ;
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , ret , " Failed to count length of UCS-2 string " ) ;
2008-03-19 10:17:42 +11:00
return ret ;
}
u8len + = 1 ; /* Add space for NUL */
2015-05-20 13:40:58 +00:00
logon_string = malloc ( u8len ) ;
if ( logon_string = = NULL ) {
2008-03-19 10:17:42 +11:00
free ( ucs2 ) ;
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2008-03-19 10:17:42 +11:00
}
2015-05-20 13:40:58 +00:00
ret = wind_ucs2utf8 ( ucs2 , ucs2len , logon_string , & u8len ) ;
2007-01-10 01:57:32 +00:00
free ( ucs2 ) ;
2008-03-19 10:17:42 +11:00
if ( ret ) {
2015-05-20 13:40:58 +00:00
free ( logon_string ) ;
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , ret , " Failed to convert to UTF-8 " ) ;
2008-03-19 10:17:42 +11:00
return ret ;
}
2007-01-10 01:57:32 +00:00
}
2015-05-20 13:40:58 +00:00
ret = krb5_unparse_name_flags ( context , principal ,
KRB5_PRINCIPAL_UNPARSE_NO_REALM |
KRB5_PRINCIPAL_UNPARSE_DISPLAY ,
& principal_string ) ;
if ( ret ) {
free ( logon_string ) ;
2007-01-10 01:57:32 +00:00
return ret ;
2015-05-20 13:40:58 +00:00
}
2008-10-27 11:35:07 +01:00
2021-12-24 01:52:32 +01:00
if ( strcmp ( logon_string , principal_string ) ! = 0 ) {
2007-01-10 01:57:32 +00:00
ret = EINVAL ;
2015-05-20 13:40:58 +00:00
krb5_set_error_message ( context , ret , " PAC logon name [%s] mismatch principal name [%s] " ,
logon_string , principal_string ) ;
2007-01-10 01:57:32 +00:00
}
2015-05-20 13:40:58 +00:00
free ( logon_string ) ;
free ( principal_string ) ;
2007-01-10 01:57:32 +00:00
return ret ;
out :
2021-12-24 01:52:32 +01:00
krb5_storage_free ( sp ) ;
2007-01-10 01:57:32 +00:00
return ret ;
}
/*
*
*/
static krb5_error_code
2008-10-27 11:35:07 +01:00
build_logon_name ( krb5_context context ,
2007-01-10 01:57:32 +00:00
time_t authtime ,
2008-10-27 11:35:07 +01:00
krb5_const_principal principal ,
2007-01-10 01:57:32 +00:00
krb5_data * logon )
{
krb5_error_code ret ;
krb5_storage * sp ;
uint64_t t ;
2022-03-01 14:17:54 +13:00
char * s , * s2 = NULL ;
2011-11-15 14:32:35 +01:00
size_t s2_len ;
2007-01-10 01:57:32 +00:00
t = unix2nttime ( authtime ) ;
krb5_data_zero ( logon ) ;
sp = krb5_storage_emem ( ) ;
2010-11-11 11:27:33 +11:00
if ( sp = = NULL )
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2010-11-11 11:27:33 +11:00
2007-01-10 01:57:32 +00:00
krb5_storage_set_flags ( sp , KRB5_STORAGE_BYTEORDER_LE ) ;
CHECK ( ret , krb5_store_uint32 ( sp , t & 0xffffffff ) , out ) ;
CHECK ( ret , krb5_store_uint32 ( sp , t > > 32 ) , out ) ;
ret = krb5_unparse_name_flags ( context , principal ,
2015-03-10 15:33:14 +01:00
KRB5_PRINCIPAL_UNPARSE_NO_REALM |
KRB5_PRINCIPAL_UNPARSE_DISPLAY ,
& s ) ;
2007-01-10 01:57:32 +00:00
if ( ret )
goto out ;
2011-11-15 14:32:35 +01:00
{
size_t ucs2_len ;
uint16_t * ucs2 ;
unsigned int flags ;
2008-10-27 11:35:07 +01:00
2011-11-15 14:32:35 +01:00
ret = wind_utf8ucs2_length ( s , & ucs2_len ) ;
if ( ret ) {
2021-12-24 01:52:32 +01:00
krb5_set_error_message ( context , ret , " Principal %s is not valid UTF-8 " , s ) ;
2011-11-15 14:32:35 +01:00
free ( s ) ;
return ret ;
}
2007-01-10 01:57:32 +00:00
2011-11-15 14:32:35 +01:00
ucs2 = malloc ( sizeof ( ucs2 [ 0 ] ) * ucs2_len ) ;
if ( ucs2 = = NULL ) {
free ( s ) ;
return krb5_enomem ( context ) ;
}
ret = wind_utf8ucs2 ( s , ucs2 , & ucs2_len ) ;
if ( ret ) {
free ( ucs2 ) ;
2021-12-24 01:52:32 +01:00
krb5_set_error_message ( context , ret , " Principal %s is not valid UTF-8 " , s ) ;
free ( s ) ;
2011-11-15 14:32:35 +01:00
return ret ;
2022-03-01 14:17:54 +13:00
} else
2021-12-24 01:52:32 +01:00
free ( s ) ;
2011-11-15 14:32:35 +01:00
s2_len = ( ucs2_len + 1 ) * 2 ;
s2 = malloc ( s2_len ) ;
2016-03-09 11:35:24 +01:00
if ( s2 = = NULL ) {
2011-11-15 14:32:35 +01:00
free ( ucs2 ) ;
return krb5_enomem ( context ) ;
}
flags = WIND_RW_LE ;
ret = wind_ucs2write ( ucs2 , ucs2_len ,
& flags , s2 , & s2_len ) ;
free ( ucs2 ) ;
if ( ret ) {
free ( s2 ) ;
krb5_set_error_message ( context , ret , " Failed to write to UCS-2 buffer " ) ;
return ret ;
}
/*
* we do not want zero termination
*/
s2_len = ucs2_len * 2 ;
2007-01-10 01:57:32 +00:00
}
2011-11-15 14:32:35 +01:00
CHECK ( ret , krb5_store_uint16 ( sp , s2_len ) , out ) ;
ret = krb5_storage_write ( sp , s2 , s2_len ) ;
if ( ret ! = ( int ) s2_len ) {
2010-11-29 11:24:08 +11:00
ret = krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
goto out ;
}
ret = krb5_storage_to_data ( sp , logon ) ;
2022-03-01 14:17:54 +13:00
out :
free ( s2 ) ;
2007-01-10 01:57:32 +00:00
krb5_storage_free ( sp ) ;
return ret ;
}
2021-12-24 01:52:32 +01:00
static krb5_error_code
parse_attributes_info ( krb5_context context ,
const struct PAC_INFO_BUFFER * attributes_info ,
const krb5_data * data ,
uint64_t * pac_attributes )
{
krb5_error_code ret ;
krb5_storage * sp = NULL ;
uint32_t flags_length ;
* pac_attributes = 0 ;
2022-10-14 16:45:37 +13:00
sp = krb5_storage_from_readonly_mem ( ( const char * ) data - > data + attributes_info - > offset ,
2021-12-24 01:52:32 +01:00
attributes_info - > buffersize ) ;
if ( sp = = NULL )
return krb5_enomem ( context ) ;
krb5_storage_set_flags ( sp , KRB5_STORAGE_BYTEORDER_LE ) ;
ret = krb5_ret_uint32 ( sp , & flags_length ) ;
if ( ret = = 0 ) {
if ( flags_length > 32 )
ret = krb5_ret_uint64 ( sp , pac_attributes ) ;
else {
uint32_t pac_attributes32 = 0 ;
ret = krb5_ret_uint32 ( sp , & pac_attributes32 ) ;
* pac_attributes = pac_attributes32 ;
}
}
krb5_storage_free ( sp ) ;
return ret ;
}
2008-10-27 11:35:07 +01:00
/**
* Verify the PAC .
2007-01-10 01:57:32 +00:00
*
2008-10-27 11:35:07 +01:00
* @ param context Kerberos 5 context .
* @ param pac the pac structure returned by krb5_pac_parse ( ) .
* @ param authtime The time of the ticket the PAC belongs to .
* @ param principal the principal to verify .
2022-11-09 13:45:13 +13:00
* @ param server The service key , may be given .
2008-10-27 11:35:07 +01:00
* @ param privsvr The KDC key , may be given .
* @ return Returns 0 to indicate success . Otherwise an kerberos et
* error code is returned , see krb5_get_error_message ( ) .
*
* @ ingroup krb5_pac
2007-01-10 01:57:32 +00:00
*/
2010-11-29 11:24:08 +11:00
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2008-10-27 11:35:07 +01:00
krb5_pac_verify ( krb5_context context ,
2008-03-19 10:17:42 +11:00
const krb5_pac pac ,
2007-01-10 01:57:32 +00:00
time_t authtime ,
krb5_const_principal principal ,
const krb5_keyblock * server ,
const krb5_keyblock * privsvr )
{
krb5_error_code ret ;
2022-11-09 13:45:13 +13:00
/*
* If we are in the KDC , we expect back a full signature in the PAC
*
* This is set up as a seperate variable to make it easier if a
* subsequent patch is added to make this configurable in the
* krb5 . conf ( or forced into the krb5_context via Samba )
*/
krb5_boolean expect_full_sig = privsvr ! = NULL ;
/*
* If we are on the KDC , then we trust we are not in a realm with
* buggy Windows 2008 or similar era DCs that give our HMAC - MD5
* sigatures over AES keys . DES is also already gone .
*/
krb5_boolean strict_cksumtype_match = expect_full_sig ;
2007-01-10 01:57:32 +00:00
if ( pac - > server_checksum = = NULL ) {
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , EINVAL , " PAC missing server checksum " ) ;
2007-01-10 01:57:32 +00:00
return EINVAL ;
}
if ( pac - > privsvr_checksum = = NULL ) {
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , EINVAL , " PAC missing kdc checksum " ) ;
2007-01-10 01:57:32 +00:00
return EINVAL ;
}
if ( pac - > logon_name = = NULL ) {
2008-08-01 07:08:51 +02:00
krb5_set_error_message ( context , EINVAL , " PAC missing logon name " ) ;
2007-01-10 01:57:32 +00:00
return EINVAL ;
}
2022-11-09 13:45:13 +13:00
if ( expect_full_sig & & pac - > full_checksum = = NULL ) {
krb5_set_error_message ( context , EINVAL , " PAC missing full checksum " ) ;
return EINVAL ;
}
2007-01-10 01:57:32 +00:00
2021-08-13 12:44:37 +03:00
if ( principal ! = NULL ) {
ret = verify_logonname ( context , pac - > logon_name , & pac - > data , authtime ,
principal ) ;
if ( ret )
return ret ;
}
if ( pac - > server_checksum - > buffersize < 4 | |
pac - > privsvr_checksum - > buffersize < 4 )
return EINVAL ;
2007-01-10 01:57:32 +00:00
2022-11-09 13:45:13 +13:00
if ( server ! = NULL | | privsvr ! = NULL )
2007-01-10 01:57:32 +00:00
{
krb5_data * copy ;
2022-11-09 13:45:13 +13:00
/*
* in the service case , clean out data option of the privsvr and
* server checksum before checking the checksum .
*/
2007-01-10 01:57:32 +00:00
ret = krb5_copy_data ( context , & pac - > data , & copy ) ;
if ( ret )
return ret ;
2022-10-14 16:45:37 +13:00
memset ( ( char * ) copy - > data + pac - > server_checksum - > offset + 4 ,
2007-01-10 01:57:32 +00:00
0 ,
pac - > server_checksum - > buffersize - 4 ) ;
2022-10-14 16:45:37 +13:00
memset ( ( char * ) copy - > data + pac - > privsvr_checksum - > offset + 4 ,
2007-01-10 01:57:32 +00:00
0 ,
pac - > privsvr_checksum - > buffersize - 4 ) ;
2022-11-09 13:45:13 +13:00
if ( server ! = NULL ) {
ret = verify_checksum ( context ,
pac - > server_checksum ,
& pac - > data ,
copy - > data ,
copy - > length ,
server ,
strict_cksumtype_match ) ;
if ( ret ) {
krb5_free_data ( context , copy ) ;
return ret ;
}
}
if ( privsvr ! = NULL & & pac - > full_checksum ! = NULL ) {
/*
* in the full checksum case , also clean out the full
* checksum before verifying it .
*/
memset ( ( char * ) copy - > data + pac - > full_checksum - > offset + 4 ,
0 ,
pac - > full_checksum - > buffersize - 4 ) ;
ret = verify_checksum ( context ,
pac - > full_checksum ,
& pac - > data ,
copy - > data ,
copy - > length ,
privsvr ,
strict_cksumtype_match ) ;
if ( ret ) {
krb5_free_data ( context , copy ) ;
return ret ;
}
}
2007-01-10 01:57:32 +00:00
krb5_free_data ( context , copy ) ;
}
if ( privsvr ) {
2008-10-27 11:35:07 +01:00
/* The priv checksum covers the server checksum */
2007-01-10 01:57:32 +00:00
ret = verify_checksum ( context ,
pac - > privsvr_checksum ,
& pac - > data ,
( char * ) pac - > data . data
2022-10-14 16:45:37 +13:00
+ pac - > server_checksum - > offset + 4 ,
2007-01-10 01:57:32 +00:00
pac - > server_checksum - > buffersize - 4 ,
2022-11-09 13:45:13 +13:00
privsvr ,
strict_cksumtype_match ) ;
2007-01-10 01:57:32 +00:00
if ( ret )
return ret ;
2021-08-13 12:44:37 +03:00
if ( pac - > ticket_sign_data . length ! = 0 ) {
if ( pac - > ticket_checksum = = NULL ) {
krb5_set_error_message ( context , EINVAL ,
" PAC missing ticket checksum " ) ;
return EINVAL ;
}
ret = verify_checksum ( context , pac - > ticket_checksum , & pac - > data ,
pac - > ticket_sign_data . data ,
2022-11-09 13:45:13 +13:00
pac - > ticket_sign_data . length , privsvr ,
strict_cksumtype_match ) ;
2021-08-13 12:44:37 +03:00
if ( ret )
return ret ;
}
2007-01-10 01:57:32 +00:00
}
2021-12-24 01:52:32 +01:00
if ( pac - > upn_dns_info & &
pac - > upn_princ = = NULL & & pac - > canon_princ = = NULL & & pac - > sid . data = = NULL ) {
ret = parse_upn_dns_info ( context , pac - > upn_dns_info , & pac - > data ,
& pac - > upn_princ , & pac - > upn_flags ,
& pac - > canon_princ , & pac - > sid ) ;
if ( ret )
return ret ;
}
if ( pac - > attributes_info ) {
ret = parse_attributes_info ( context , pac - > attributes_info , & pac - > data ,
& pac - > pac_attributes ) ;
if ( ret )
return ret ;
}
2007-01-10 01:57:32 +00:00
return 0 ;
}
/*
*
*/
static krb5_error_code
fill_zeros ( krb5_context context , krb5_storage * sp , size_t len )
{
ssize_t sret ;
size_t l ;
while ( len ) {
l = len ;
if ( l > sizeof ( zeros ) )
l = sizeof ( zeros ) ;
sret = krb5_storage_write ( sp , zeros , l ) ;
2021-12-24 01:52:32 +01:00
if ( sret ! = l )
2010-11-29 11:24:08 +11:00
return krb5_enomem ( context ) ;
2010-11-11 11:27:33 +11:00
2007-01-10 01:57:32 +00:00
len - = sret ;
}
return 0 ;
}
static krb5_error_code
2008-10-27 11:35:07 +01:00
pac_checksum ( krb5_context context ,
2007-01-10 01:57:32 +00:00
const krb5_keyblock * key ,
uint32_t * cksumtype ,
size_t * cksumsize )
{
krb5_cksumtype cktype ;
krb5_error_code ret ;
krb5_crypto crypto = NULL ;
ret = krb5_crypto_init ( context , key , 0 , & crypto ) ;
if ( ret )
return ret ;
ret = krb5_crypto_get_checksum_type ( context , crypto , & cktype ) ;
2008-08-26 19:35:52 +02:00
krb5_crypto_destroy ( context , crypto ) ;
2007-01-10 01:57:32 +00:00
if ( ret )
return ret ;
if ( krb5_checksum_is_keyed ( context , cktype ) = = FALSE ) {
2010-11-02 17:08:34 +11:00
* cksumtype = CKSUMTYPE_HMAC_MD5 ;
* cksumsize = 16 ;
2007-01-10 01:57:32 +00:00
}
ret = krb5_checksumsize ( context , cktype , cksumsize ) ;
if ( ret )
return ret ;
2008-10-27 11:35:07 +01:00
2007-01-10 01:57:32 +00:00
* cksumtype = ( uint32_t ) cktype ;
return 0 ;
}
2021-12-24 01:52:32 +01:00
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2007-01-10 01:57:32 +00:00
_krb5_pac_sign ( krb5_context context ,
2008-03-19 10:17:42 +11:00
krb5_pac p ,
2007-01-10 01:57:32 +00:00
time_t authtime ,
2021-12-24 01:52:32 +01:00
krb5_const_principal principal ,
2007-01-10 01:57:32 +00:00
const krb5_keyblock * server_key ,
const krb5_keyblock * priv_key ,
2021-08-13 12:44:37 +03:00
uint16_t rodc_id ,
2021-12-24 01:52:32 +01:00
krb5_const_principal upn_princ ,
krb5_const_principal canon_princ ,
2022-11-09 13:45:13 +13:00
krb5_boolean add_full_sig ,
2021-12-24 01:52:32 +01:00
uint64_t * pac_attributes , /* optional */
2007-01-10 01:57:32 +00:00
krb5_data * data )
{
krb5_error_code ret ;
krb5_storage * sp = NULL , * spdata = NULL ;
uint32_t end ;
size_t server_size , priv_size ;
2022-11-09 13:45:13 +13:00
uint32_t server_offset = 0 , priv_offset = 0 , ticket_offset = 0 , full_offset = 0 ;
2007-01-10 01:57:32 +00:00
uint32_t server_cksumtype = 0 , priv_cksumtype = 0 ;
2022-10-14 16:45:37 +13:00
uint32_t num = 0 ;
uint32_t i , sz ;
2007-01-10 01:57:32 +00:00
krb5_data logon , d ;
2021-10-10 21:55:59 -05:00
krb5_data_zero ( & d ) ;
2007-01-10 01:57:32 +00:00
krb5_data_zero ( & logon ) ;
2022-10-14 16:45:37 +13:00
/*
* Set convenience buffer pointers .
*
* This could really stand to be moved to krb5_pac_add_buffer ( ) and / or
* utility function , so that when this function gets called they must
* already have been set .
*/
2016-01-07 14:12:14 +01:00
for ( i = 0 ; i < p - > pac - > numbuffers ; i + + ) {
if ( p - > pac - > buffers [ i ] . type = = PAC_SERVER_CHECKSUM ) {
if ( p - > server_checksum = = NULL ) {
p - > server_checksum = & p - > pac - > buffers [ i ] ;
}
if ( p - > server_checksum ! = & p - > pac - > buffers [ i ] ) {
2021-08-13 12:44:37 +03:00
ret = KRB5KDC_ERR_BADOPTION ;
2016-01-07 14:12:14 +01:00
krb5_set_error_message ( context , ret ,
2021-08-13 12:44:37 +03:00
N_ ( " PAC has multiple server checksums " , " " ) ) ;
2016-01-07 14:12:14 +01:00
goto out ;
}
} else if ( p - > pac - > buffers [ i ] . type = = PAC_PRIVSVR_CHECKSUM ) {
if ( p - > privsvr_checksum = = NULL ) {
p - > privsvr_checksum = & p - > pac - > buffers [ i ] ;
}
if ( p - > privsvr_checksum ! = & p - > pac - > buffers [ i ] ) {
2021-08-13 12:44:37 +03:00
ret = KRB5KDC_ERR_BADOPTION ;
2016-01-07 14:12:14 +01:00
krb5_set_error_message ( context , ret ,
2021-08-13 12:44:37 +03:00
N_ ( " PAC has multiple KDC checksums " , " " ) ) ;
2016-01-07 14:12:14 +01:00
goto out ;
}
} else if ( p - > pac - > buffers [ i ] . type = = PAC_LOGON_NAME ) {
if ( p - > logon_name = = NULL ) {
p - > logon_name = & p - > pac - > buffers [ i ] ;
}
if ( p - > logon_name ! = & p - > pac - > buffers [ i ] ) {
2021-08-13 12:44:37 +03:00
ret = KRB5KDC_ERR_BADOPTION ;
krb5_set_error_message ( context , ret ,
N_ ( " PAC has multiple logon names " , " " ) ) ;
goto out ;
}
2021-12-24 01:52:32 +01:00
} else if ( p - > pac - > buffers [ i ] . type = = PAC_UPN_DNS_INFO ) {
if ( p - > upn_dns_info = = NULL ) {
p - > upn_dns_info = & p - > pac - > buffers [ i ] ;
}
if ( p - > upn_dns_info ! = & p - > pac - > buffers [ i ] ) {
ret = KRB5KDC_ERR_BADOPTION ;
krb5_set_error_message ( context , ret ,
N_ ( " PAC has multiple UPN DNS info buffers " , " " ) ) ;
goto out ;
}
2021-08-13 12:44:37 +03:00
} else if ( p - > pac - > buffers [ i ] . type = = PAC_TICKET_CHECKSUM ) {
if ( p - > ticket_checksum = = NULL ) {
p - > ticket_checksum = & p - > pac - > buffers [ i ] ;
}
if ( p - > ticket_checksum ! = & p - > pac - > buffers [ i ] ) {
ret = KRB5KDC_ERR_BADOPTION ;
2016-01-07 14:12:14 +01:00
krb5_set_error_message ( context , ret ,
2021-08-13 12:44:37 +03:00
N_ ( " PAC has multiple ticket checksums " , " " ) ) ;
2016-01-07 14:12:14 +01:00
goto out ;
}
2021-12-24 01:52:32 +01:00
} else if ( p - > pac - > buffers [ i ] . type = = PAC_ATTRIBUTES_INFO ) {
if ( p - > attributes_info = = NULL ) {
p - > attributes_info = & p - > pac - > buffers [ i ] ;
}
if ( p - > attributes_info ! = & p - > pac - > buffers [ i ] ) {
ret = KRB5KDC_ERR_BADOPTION ;
krb5_set_error_message ( context , ret ,
N_ ( " PAC has multiple attributes info buffers " , " " ) ) ;
goto out ;
}
2022-11-09 13:45:13 +13:00
} else if ( p - > pac - > buffers [ i ] . type = = PAC_FULL_CHECKSUM ) {
if ( p - > full_checksum = = NULL ) {
p - > full_checksum = & p - > pac - > buffers [ i ] ;
}
if ( p - > full_checksum ! = & p - > pac - > buffers [ i ] ) {
ret = KRB5KDC_ERR_BADOPTION ;
krb5_set_error_message ( context , ret ,
N_ ( " PAC has multiple full checksums " , " " ) ) ;
goto out ;
}
2016-01-07 14:12:14 +01:00
}
}
2022-10-14 16:45:37 +13:00
/* Count missing-but-necessary buffers */
2007-02-18 23:49:29 +00:00
if ( p - > logon_name = = NULL )
num + + ;
2007-01-10 01:57:32 +00:00
if ( p - > server_checksum = = NULL )
num + + ;
if ( p - > privsvr_checksum = = NULL )
num + + ;
2021-08-13 12:44:37 +03:00
if ( p - > ticket_sign_data . length ! = 0 & & p - > ticket_checksum = = NULL )
num + + ;
2022-11-09 13:45:13 +13:00
if ( add_full_sig & & p - > full_checksum = = NULL )
num + + ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
/* Allocate any missing-but-necessary buffers */
2007-01-10 01:57:32 +00:00
if ( num ) {
void * ptr ;
2022-10-14 16:45:37 +13:00
uint32_t old_len , len ;
if ( p - > pac - > numbuffers > UINT32_MAX - num ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
ret = pac_header_size ( context , p - > pac - > numbuffers , & old_len ) ;
if ( ret = = 0 )
ret = pac_header_size ( context , p - > pac - > numbuffers + num , & len ) ;
if ( ret )
goto out ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
ptr = realloc ( p - > pac , len ) ;
2021-10-10 21:55:59 -05:00
if ( ptr = = NULL ) {
ret = krb5_enomem ( context ) ;
goto out ;
}
2022-10-14 16:45:37 +13:00
memset ( ( char * ) ptr + old_len , 0 , len - old_len ) ;
2007-01-10 01:57:32 +00:00
p - > pac = ptr ;
2022-10-14 16:45:37 +13:00
2007-02-18 23:49:29 +00:00
if ( p - > logon_name = = NULL ) {
p - > logon_name = & p - > pac - > buffers [ p - > pac - > numbuffers + + ] ;
p - > logon_name - > type = PAC_LOGON_NAME ;
}
2007-01-10 01:57:32 +00:00
if ( p - > server_checksum = = NULL ) {
p - > server_checksum = & p - > pac - > buffers [ p - > pac - > numbuffers + + ] ;
p - > server_checksum - > type = PAC_SERVER_CHECKSUM ;
}
if ( p - > privsvr_checksum = = NULL ) {
p - > privsvr_checksum = & p - > pac - > buffers [ p - > pac - > numbuffers + + ] ;
p - > privsvr_checksum - > type = PAC_PRIVSVR_CHECKSUM ;
}
2021-08-13 12:44:37 +03:00
if ( p - > ticket_sign_data . length ! = 0 & & p - > ticket_checksum = = NULL ) {
p - > ticket_checksum = & p - > pac - > buffers [ p - > pac - > numbuffers + + ] ;
p - > ticket_checksum - > type = PAC_TICKET_CHECKSUM ;
}
2022-11-09 13:45:13 +13:00
if ( add_full_sig & & p - > full_checksum = = NULL ) {
p - > full_checksum = & p - > pac - > buffers [ p - > pac - > numbuffers + + ] ;
memset ( p - > full_checksum , 0 , sizeof ( * p - > full_checksum ) ) ;
p - > full_checksum - > type = PAC_FULL_CHECKSUM ;
}
2007-01-10 01:57:32 +00:00
}
/* Calculate LOGON NAME */
ret = build_logon_name ( context , authtime , principal , & logon ) ;
/* Set lengths for checksum */
2021-10-10 21:55:59 -05:00
if ( ret = = 0 )
ret = pac_checksum ( context , server_key , & server_cksumtype , & server_size ) ;
2021-08-13 12:44:37 +03:00
2021-10-10 21:55:59 -05:00
if ( ret = = 0 )
ret = pac_checksum ( context , priv_key , & priv_cksumtype , & priv_size ) ;
2007-01-10 01:57:32 +00:00
/* Encode PAC */
2021-10-10 21:55:59 -05:00
if ( ret = = 0 ) {
sp = krb5_storage_emem ( ) ;
if ( sp = = NULL )
ret = krb5_enomem ( context ) ;
}
2007-01-10 01:57:32 +00:00
2021-10-10 21:55:59 -05:00
if ( ret = = 0 ) {
krb5_storage_set_flags ( sp , KRB5_STORAGE_BYTEORDER_LE ) ;
spdata = krb5_storage_emem ( ) ;
2022-03-01 14:17:54 +13:00
if ( spdata = = NULL )
2021-10-10 21:55:59 -05:00
ret = krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
}
2021-10-10 21:55:59 -05:00
if ( ret )
goto out ;
2007-01-10 01:57:32 +00:00
krb5_storage_set_flags ( spdata , KRB5_STORAGE_BYTEORDER_LE ) ;
2022-10-14 16:45:37 +13:00
/* `sp' has the header, `spdata' has the buffers */
2007-01-10 01:57:32 +00:00
CHECK ( ret , krb5_store_uint32 ( sp , p - > pac - > numbuffers ) , out ) ;
CHECK ( ret , krb5_store_uint32 ( sp , p - > pac - > version ) , out ) ;
2022-10-14 16:45:37 +13:00
ret = pac_header_size ( context , p - > pac - > numbuffers , & end ) ;
if ( ret )
goto out ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
/*
* For each buffer we write its contents to ` spdata ' and then append the
* PAC_INFO_BUFFER for that buffer into the header in ` sp ' . The logical
* end of the whole thing is kept in ` end ' , which functions as the offset
* to write in the buffer ' s PAC_INFO_BUFFER , then we update it at the
* bottom so that the next buffer can be written there .
*
* TODO ? Maybe rewrite all of this so that :
*
* - we use krb5_pac_add_buffer ( ) to add the buffers we produce
* - we use the krb5_data of the concatenated buffers that ' s maintained by
* krb5_pac_add_buffer ( ) so we don ' t need ` spdata ' here
*
* We do way too much here , and that makes this code hard to read . Plus we
* throw away all the work done in krb5_pac_add_buffer ( ) . On the other
* hand , krb5_pac_add_buffer ( ) has to loop over all the buffers , so if we
* call krb5_pac_add_buffer ( ) here in a loop , we ' ll be accidentally
* quadratic , but we only need to loop over adding the buffers we add ,
* which is very few , so not quite quadratic . We should also cap the
* number of buffers we ' re willing to accept in a PAC we parse to something
* reasonable , like a few tens .
*/
2007-01-10 01:57:32 +00:00
for ( i = 0 ; i < p - > pac - > numbuffers ; i + + ) {
uint32_t len ;
size_t sret ;
void * ptr = NULL ;
/* store data */
if ( p - > pac - > buffers [ i ] . type = = PAC_SERVER_CHECKSUM ) {
2022-10-14 16:45:37 +13:00
if ( server_size > UINT32_MAX - 4 ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
2007-01-10 01:57:32 +00:00
len = server_size + 4 ;
2022-10-14 16:45:37 +13:00
if ( end > UINT32_MAX - 4 ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
2007-01-10 01:57:32 +00:00
server_offset = end + 4 ;
CHECK ( ret , krb5_store_uint32 ( spdata , server_cksumtype ) , out ) ;
CHECK ( ret , fill_zeros ( context , spdata , server_size ) , out ) ;
} else if ( p - > pac - > buffers [ i ] . type = = PAC_PRIVSVR_CHECKSUM ) {
2022-10-14 16:45:37 +13:00
if ( priv_size > UINT32_MAX - 4 ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
2007-01-10 01:57:32 +00:00
len = priv_size + 4 ;
2022-10-14 16:45:37 +13:00
if ( end > UINT32_MAX - 4 ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
2007-01-10 01:57:32 +00:00
priv_offset = end + 4 ;
CHECK ( ret , krb5_store_uint32 ( spdata , priv_cksumtype ) , out ) ;
CHECK ( ret , fill_zeros ( context , spdata , priv_size ) , out ) ;
2021-08-13 12:44:37 +03:00
if ( rodc_id ! = 0 ) {
2022-10-14 16:45:37 +13:00
if ( len > UINT32_MAX - sizeof ( rodc_id ) ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
2021-08-13 12:44:37 +03:00
len + = sizeof ( rodc_id ) ;
CHECK ( ret , fill_zeros ( context , spdata , sizeof ( rodc_id ) ) , out ) ;
}
} else if ( p - > ticket_sign_data . length ! = 0 & &
p - > pac - > buffers [ i ] . type = = PAC_TICKET_CHECKSUM ) {
2022-10-14 16:45:37 +13:00
if ( priv_size > UINT32_MAX - 4 ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
2021-08-13 12:44:37 +03:00
len = priv_size + 4 ;
2022-10-14 16:45:37 +13:00
if ( end > UINT32_MAX - 4 ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
2021-08-13 12:44:37 +03:00
ticket_offset = end + 4 ;
CHECK ( ret , krb5_store_uint32 ( spdata , priv_cksumtype ) , out ) ;
CHECK ( ret , fill_zeros ( context , spdata , priv_size ) , out ) ;
if ( rodc_id ! = 0 ) {
2022-10-14 16:45:37 +13:00
if ( len > UINT32_MAX - sizeof ( rodc_id ) ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
2021-08-13 12:44:37 +03:00
len + = sizeof ( rodc_id ) ;
CHECK ( ret , krb5_store_uint16 ( spdata , rodc_id ) , out ) ;
}
2022-11-09 13:45:13 +13:00
} else if ( add_full_sig & &
p - > pac - > buffers [ i ] . type = = PAC_FULL_CHECKSUM ) {
if ( priv_size > UINT32_MAX - 4 ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
len = priv_size + 4 ;
if ( end > UINT32_MAX - 4 ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
full_offset = end + 4 ;
CHECK ( ret , krb5_store_uint32 ( spdata , priv_cksumtype ) , out ) ;
CHECK ( ret , fill_zeros ( context , spdata , priv_size ) , out ) ;
if ( rodc_id ! = 0 ) {
if ( len > UINT32_MAX - sizeof ( rodc_id ) ) {
ret = EINVAL ;
krb5_set_error_message ( context , ret , " integer overrun " ) ;
goto out ;
}
len + = sizeof ( rodc_id ) ;
CHECK ( ret , fill_zeros ( context , spdata , sizeof ( rodc_id ) ) , out ) ;
}
2007-01-10 01:57:32 +00:00
} else if ( p - > pac - > buffers [ i ] . type = = PAC_LOGON_NAME ) {
len = krb5_storage_write ( spdata , logon . data , logon . length ) ;
if ( logon . length ! = len ) {
2021-08-13 12:44:37 +03:00
ret = KRB5KDC_ERR_BADOPTION ;
2007-01-10 01:57:32 +00:00
goto out ;
}
} else {
len = p - > pac - > buffers [ i ] . buffersize ;
2022-10-14 16:45:37 +13:00
ptr = ( char * ) p - > data . data + p - > pac - > buffers [ i ] . offset ;
2007-01-10 01:57:32 +00:00
sret = krb5_storage_write ( spdata , ptr , len ) ;
if ( sret ! = len ) {
2010-11-29 11:24:08 +11:00
ret = krb5_enomem ( context ) ;
2007-01-10 01:57:32 +00:00
goto out ;
}
2021-12-14 19:19:42 +13:00
/* XXX if not aligned, fill_zeros */
2007-01-10 01:57:32 +00:00
}
/* write header */
CHECK ( ret , krb5_store_uint32 ( sp , p - > pac - > buffers [ i ] . type ) , out ) ;
CHECK ( ret , krb5_store_uint32 ( sp , len ) , out ) ;
2022-10-14 16:45:37 +13:00
CHECK ( ret , krb5_store_uint64 ( sp , end ) , out ) ; /* offset */
2007-01-10 01:57:32 +00:00
/* advance data endpointer and align */
{
2022-10-14 16:45:37 +13:00
uint32_t e ;
2007-01-10 01:57:32 +00:00
2022-10-14 16:45:37 +13:00
ret = pac_aligned_size ( context , end , len , & e ) ;
if ( ret = = 0 & & end + len ! = e )
ret = fill_zeros ( context , spdata , e - ( end + len ) ) ;
if ( ret )
goto out ;
2007-01-10 01:57:32 +00:00
end = e ;
}
}
/* assert (server_offset != 0 && priv_offset != 0); */
/* export PAC */
2021-10-10 21:55:59 -05:00
if ( ret = = 0 )
ret = krb5_storage_to_data ( spdata , & d ) ;
if ( ret = = 0 ) {
sz = krb5_storage_write ( sp , d . data , d . length ) ;
if ( sz ! = d . length ) {
krb5_data_free ( & d ) ;
ret = krb5_enomem ( context ) ;
goto out ;
}
2007-01-10 01:57:32 +00:00
}
krb5_data_free ( & d ) ;
2021-10-10 21:55:59 -05:00
if ( ret = = 0 )
ret = krb5_storage_to_data ( sp , & d ) ;
2007-01-10 01:57:32 +00:00
/* sign */
2021-10-10 21:55:59 -05:00
if ( ret = = 0 & & p - > ticket_sign_data . length )
2021-08-13 12:44:37 +03:00
ret = create_checksum ( context , priv_key , priv_cksumtype ,
p - > ticket_sign_data . data ,
p - > ticket_sign_data . length ,
( char * ) d . data + ticket_offset , priv_size ) ;
2022-11-09 13:45:13 +13:00
if ( ret = = 0 & & add_full_sig )
ret = create_checksum ( context , priv_key , priv_cksumtype ,
d . data , d . length ,
( char * ) d . data + full_offset , priv_size ) ;
if ( ret = = 0 & & add_full_sig & & rodc_id ! = 0 ) {
void * buf = ( char * ) d . data + full_offset + priv_size ;
krb5_storage * rs = krb5_storage_from_mem ( buf , sizeof ( rodc_id ) ) ;
if ( rs = = NULL )
ret = krb5_enomem ( context ) ;
else
krb5_storage_set_flags ( rs , KRB5_STORAGE_BYTEORDER_LE ) ;
if ( ret = = 0 )
ret = krb5_store_uint16 ( rs , rodc_id ) ;
krb5_storage_free ( rs ) ;
}
2021-10-10 21:55:59 -05:00
if ( ret = = 0 )
ret = create_checksum ( context , server_key , server_cksumtype ,
d . data , d . length ,
( char * ) d . data + server_offset , server_size ) ;
if ( ret = = 0 )
ret = create_checksum ( context , priv_key , priv_cksumtype ,
( char * ) d . data + server_offset , server_size ,
( char * ) d . data + priv_offset , priv_size ) ;
if ( ret = = 0 & & rodc_id ! = 0 ) {
2022-11-09 13:45:13 +13:00
void * buf = ( char * ) d . data + priv_offset + priv_size ;
krb5_storage * rs = krb5_storage_from_mem ( buf , sizeof ( rodc_id ) ) ;
2021-10-10 21:55:59 -05:00
if ( rs = = NULL )
2021-08-13 12:44:37 +03:00
ret = krb5_enomem ( context ) ;
2022-03-01 14:17:54 +13:00
else
krb5_storage_set_flags ( rs , KRB5_STORAGE_BYTEORDER_LE ) ;
2021-10-10 21:55:59 -05:00
if ( ret = = 0 )
ret = krb5_store_uint16 ( rs , rodc_id ) ;
2021-08-13 12:44:37 +03:00
krb5_storage_free ( rs ) ;
}
2021-10-10 21:55:59 -05:00
if ( ret )
goto out ;
2007-01-10 01:57:32 +00:00
/* done */
* data = d ;
krb5_data_free ( & logon ) ;
krb5_storage_free ( sp ) ;
krb5_storage_free ( spdata ) ;
return 0 ;
out :
2021-10-10 21:55:59 -05:00
krb5_data_free ( & d ) ;
2007-01-10 01:57:32 +00:00
krb5_data_free ( & logon ) ;
if ( sp )
krb5_storage_free ( sp ) ;
if ( spdata )
krb5_storage_free ( spdata ) ;
return ret ;
}
2021-08-13 12:44:37 +03:00
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2021-10-08 15:43:41 +13:00
krb5_pac_get_kdc_checksum_info ( krb5_context context ,
2022-03-10 16:12:43 +01:00
krb5_const_pac pac ,
2021-10-08 15:43:41 +13:00
krb5_cksumtype * cstype ,
uint16_t * rodc_id )
2021-08-13 12:44:37 +03:00
{
krb5_error_code ret ;
krb5_storage * sp = NULL ;
const struct PAC_INFO_BUFFER * sig ;
size_t cksumsize , prefix ;
uint32_t type = 0 ;
* cstype = 0 ;
* rodc_id = 0 ;
sig = pac - > privsvr_checksum ;
if ( sig = = NULL ) {
krb5_set_error_message ( context , KRB5KDC_ERR_BADOPTION ,
" PAC missing kdc checksum " ) ;
return KRB5KDC_ERR_BADOPTION ;
}
2022-10-14 16:45:37 +13:00
sp = krb5_storage_from_mem ( ( char * ) pac - > data . data + sig - > offset ,
2021-08-13 12:44:37 +03:00
sig - > buffersize ) ;
if ( sp = = NULL )
return krb5_enomem ( context ) ;
krb5_storage_set_flags ( sp , KRB5_STORAGE_BYTEORDER_LE ) ;
ret = krb5_ret_uint32 ( sp , & type ) ;
if ( ret )
goto out ;
ret = krb5_checksumsize ( context , type , & cksumsize ) ;
if ( ret )
goto out ;
prefix = krb5_storage_seek ( sp , 0 , SEEK_CUR ) ;
if ( ( sig - > buffersize - prefix ) > = cksumsize + 2 ) {
krb5_storage_seek ( sp , cksumsize , SEEK_CUR ) ;
ret = krb5_ret_uint16 ( sp , rodc_id ) ;
if ( ret )
goto out ;
}
* cstype = type ;
out :
krb5_storage_free ( sp ) ;
return ret ;
}
2021-12-24 01:52:32 +01:00
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_pac_get_canon_principal ( krb5_context context ,
2022-03-10 16:12:43 +01:00
krb5_const_pac pac ,
2021-12-24 01:52:32 +01:00
krb5_principal * canon_princ )
{
* canon_princ = NULL ;
if ( pac - > canon_princ = = NULL ) {
krb5_set_error_message ( context , ENOENT ,
" PAC missing UPN DNS info buffer " ) ;
return ENOENT ;
}
return krb5_copy_principal ( context , pac - > canon_princ , canon_princ ) ;
}
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_pac_get_attributes_info ( krb5_context context ,
2022-03-10 16:12:43 +01:00
krb5_const_pac pac ,
2021-12-24 01:52:32 +01:00
uint64_t * pac_attributes )
{
* pac_attributes = 0 ;
if ( pac - > attributes_info = = NULL ) {
krb5_set_error_message ( context , ENOENT ,
" PAC missing attributes info buffer " ) ;
return ENOENT ;
}
* pac_attributes = pac - > pac_attributes ;
return 0 ;
}
2021-08-13 12:44:37 +03:00
static unsigned char single_zero = ' \0 ' ;
static krb5_data single_zero_pac = { 1 , & single_zero } ;
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_kdc_pac_ticket_parse ( krb5_context context ,
EncTicketPart * tkt ,
krb5_boolean * signedticket ,
krb5_pac * ppac )
{
AuthorizationData * ad = tkt - > authorization_data ;
krb5_pac pac = NULL ;
unsigned i , j ;
size_t len = 0 ;
2021-09-19 15:16:58 +03:00
krb5_error_code ret = 0 ;
2021-08-13 12:44:37 +03:00
* signedticket = FALSE ;
* ppac = NULL ;
if ( ad = = NULL | | ad - > len = = 0 )
2021-11-02 14:52:22 +13:00
return 0 ;
2021-08-13 12:44:37 +03:00
for ( i = 0 ; i < ad - > len ; i + + ) {
AuthorizationData child ;
2021-09-19 15:16:58 +03:00
if ( ad - > val [ i ] . ad_type = = KRB5_AUTHDATA_WIN2K_PAC ) {
ret = KRB5KDC_ERR_BADOPTION ;
goto out ;
}
2021-08-13 12:44:37 +03:00
if ( ad - > val [ i ] . ad_type ! = KRB5_AUTHDATA_IF_RELEVANT )
continue ;
ret = decode_AuthorizationData ( ad - > val [ i ] . ad_data . data ,
ad - > val [ i ] . ad_data . length ,
& child ,
NULL ) ;
if ( ret ) {
krb5_set_error_message ( context , ret , " Failed to decode "
" AD-IF-RELEVANT with %d " , ret ) ;
2021-09-19 15:16:58 +03:00
goto out ;
2021-08-13 12:44:37 +03:00
}
for ( j = 0 ; j < child . len ; j + + ) {
2021-09-19 15:16:58 +03:00
krb5_data adifr_data = ad - > val [ i ] . ad_data ;
krb5_data pac_data = child . val [ j ] . ad_data ;
krb5_data recoded_adifr ;
if ( child . val [ j ] . ad_type ! = KRB5_AUTHDATA_WIN2K_PAC )
continue ;
if ( pac ! = NULL ) {
free_AuthorizationData ( & child ) ;
ret = KRB5KDC_ERR_BADOPTION ;
goto out ;
}
ret = krb5_pac_parse ( context ,
pac_data . data ,
pac_data . length ,
& pac ) ;
if ( ret ) {
2021-08-13 12:44:37 +03:00
free_AuthorizationData ( & child ) ;
2021-09-19 15:16:58 +03:00
goto out ;
}
2021-08-13 12:44:37 +03:00
2021-09-19 15:16:58 +03:00
if ( pac - > ticket_checksum = = NULL )
continue ;
2021-08-13 12:44:37 +03:00
2021-09-19 15:16:58 +03:00
/*
* Encode the ticket with the PAC replaced with a single zero
* byte , to be used as input data to the ticket signature .
*/
2021-08-13 12:44:37 +03:00
2021-09-19 15:16:58 +03:00
child . val [ j ] . ad_data = single_zero_pac ;
2021-08-13 12:44:37 +03:00
2021-09-19 15:16:58 +03:00
ASN1_MALLOC_ENCODE ( AuthorizationData , recoded_adifr . data ,
recoded_adifr . length , & child , & len , ret ) ;
if ( recoded_adifr . length ! = len )
krb5_abortx ( context , " Internal error in ASN.1 encoder " ) ;
2021-08-13 12:44:37 +03:00
2021-09-19 15:16:58 +03:00
child . val [ j ] . ad_data = pac_data ;
2021-08-13 12:44:37 +03:00
2021-09-19 15:16:58 +03:00
if ( ret ) {
free_AuthorizationData ( & child ) ;
goto out ;
2021-08-13 12:44:37 +03:00
}
2021-09-19 15:16:58 +03:00
ad - > val [ i ] . ad_data = recoded_adifr ;
ASN1_MALLOC_ENCODE ( EncTicketPart ,
pac - > ticket_sign_data . data ,
pac - > ticket_sign_data . length , tkt , & len ,
ret ) ;
if ( pac - > ticket_sign_data . length ! = len )
krb5_abortx ( context , " Internal error in ASN.1 encoder " ) ;
ad - > val [ i ] . ad_data = adifr_data ;
krb5_data_free ( & recoded_adifr ) ;
if ( ret ) {
free_AuthorizationData ( & child ) ;
goto out ;
}
* signedticket = TRUE ;
2021-08-13 12:44:37 +03:00
}
free_AuthorizationData ( & child ) ;
}
2021-09-19 15:16:58 +03:00
out :
if ( ret ) {
krb5_pac_free ( context , pac ) ;
return ret ;
}
* ppac = pac ;
2021-08-13 12:44:37 +03:00
return 0 ;
}
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_kdc_pac_sign_ticket ( krb5_context context ,
const krb5_pac pac ,
2021-12-24 01:52:32 +01:00
krb5_const_principal client ,
2021-08-13 12:44:37 +03:00
const krb5_keyblock * server_key ,
const krb5_keyblock * kdc_key ,
uint16_t rodc_id ,
2021-12-24 01:52:32 +01:00
krb5_const_principal upn ,
krb5_const_principal canon_name ,
2021-08-13 12:44:37 +03:00
krb5_boolean add_ticket_sig ,
2022-11-09 13:45:13 +13:00
krb5_boolean add_full_sig ,
2021-12-24 01:52:32 +01:00
EncTicketPart * tkt ,
uint64_t * pac_attributes ) /* optional */
2021-08-13 12:44:37 +03:00
{
krb5_error_code ret ;
krb5_data tkt_data ;
krb5_data rspac ;
krb5_data_zero ( & rspac ) ;
krb5_data_zero ( & tkt_data ) ;
krb5_data_free ( & pac - > ticket_sign_data ) ;
if ( add_ticket_sig ) {
size_t len = 0 ;
ret = _kdc_tkt_insert_pac ( context , tkt , & single_zero_pac ) ;
if ( ret )
return ret ;
ASN1_MALLOC_ENCODE ( EncTicketPart , tkt_data . data , tkt_data . length ,
tkt , & len , ret ) ;
if ( tkt_data . length ! = len )
krb5_abortx ( context , " Internal error in ASN.1 encoder " ) ;
if ( ret )
return ret ;
ret = remove_AuthorizationData ( tkt - > authorization_data , 0 ) ;
if ( ret ) {
krb5_data_free ( & tkt_data ) ;
return ret ;
}
pac - > ticket_sign_data = tkt_data ;
}
ret = _krb5_pac_sign ( context , pac , tkt - > authtime , client , server_key ,
2021-12-24 01:52:32 +01:00
kdc_key , rodc_id , upn , canon_name ,
2022-11-09 13:45:13 +13:00
add_full_sig ,
2021-12-24 01:52:32 +01:00
pac_attributes , & rspac ) ;
2021-10-10 21:55:59 -05:00
if ( ret = = 0 )
ret = _kdc_tkt_insert_pac ( context , tkt , & rspac ) ;
krb5_data_free ( & rspac ) ;
return ret ;
2021-08-13 12:44:37 +03:00
}