From 8fc65db427a13763134a4c6516da3fb810868701 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Wed, 30 Jun 2004 05:00:25 +0000 Subject: [PATCH] * cc_mslsa.c: - is_windows_2000() indicates the OS is Windows 2000 or higher - is_windows_xp() indicates the OS is Windows XP or higher which indicates that PKERB_QUERY_TKT_CACHE_EX_RESPONSE and PKERB_TICKET_CACHE_INFO_EX are available. - does_retrieve_ticket_cache_ticket() checks to see if a Microsoft private fix is available which adds a new Cache Flag, KERB_RETRIEVE_TICKET_CACHE_TICKET, which when set causes the requested ticket to be stored in the LSA cache even when the TicketFlags and EncType are not set to 0. - KerbExternalTicketMatch() is a test to determine if two Microsoft External Tickets are identical + use the KerbQueryTicketCacheExMessage LSA call on XP or higher + specify the KERB_RETRIEVE_TICKET_CACHE_TICKET flag when it is available = The combination of both + items will cause the ClientRealm to be displayed properly for all cross realm tickets obtained via the MSLSA ticket: new git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@16528 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/krb5/ccache/ChangeLog | 22 ++ src/lib/krb5/ccache/cc_mslsa.c | 399 +++++++++++++++++++++++++++------ 2 files changed, 358 insertions(+), 63 deletions(-) diff --git a/src/lib/krb5/ccache/ChangeLog b/src/lib/krb5/ccache/ChangeLog index a662900a5..ac653ace3 100644 --- a/src/lib/krb5/ccache/ChangeLog +++ b/src/lib/krb5/ccache/ChangeLog @@ -1,3 +1,25 @@ +2004-06-29 Jeffrey Altman + + * cc_mslsa.c: + - is_windows_2000() indicates the OS is Windows 2000 or higher + - is_windows_xp() indicates the OS is Windows XP or higher which + indicates that PKERB_QUERY_TKT_CACHE_EX_RESPONSE and + PKERB_TICKET_CACHE_INFO_EX are available. + - does_retrieve_ticket_cache_ticket() checks to see if a Microsoft + private fix is available which adds a new Cache Flag, + KERB_RETRIEVE_TICKET_CACHE_TICKET, which when set causes the + requested ticket to be stored in the LSA cache even when the + TicketFlags and EncType are not set to 0. + - KerbExternalTicketMatch() is a test to determine if two + Microsoft External Tickets are identical + + use the KerbQueryTicketCacheExMessage LSA call on XP or higher + + specify the KERB_RETRIEVE_TICKET_CACHE_TICKET flag when it is + available + = The combination of both + items will cause the ClientRealm + to be displayed properly for all cross realm tickets obtained + via the MSLSA + + 2004-06-29 Ken Raeburn * cc_memory.c (krb5_mcc_free): Don't destroy the mutex here. diff --git a/src/lib/krb5/ccache/cc_mslsa.c b/src/lib/krb5/ccache/cc_mslsa.c index f57b397e6..3ab99cfec 100644 --- a/src/lib/krb5/ccache/cc_mslsa.c +++ b/src/lib/krb5/ccache/cc_mslsa.c @@ -63,11 +63,13 @@ #define SECURITY_WIN32 #include #include +#include #define MAX_MSG_SIZE 256 #define MAX_MSPRINC_SIZE 1024 -static BOOL IsWindows2000 (void) +static BOOL +is_windows_2000 (void) { static BOOL fChecked = FALSE; static BOOL fIsWin2K = FALSE; @@ -91,6 +93,41 @@ static BOOL IsWindows2000 (void) return fIsWin2K; } +static BOOL +is_windows_xp (void) +{ + static BOOL fChecked = FALSE; + static BOOL fIsWinXP = FALSE; + + if (!fChecked) + { + OSVERSIONINFO Version; + fChecked = TRUE; + + memset (&Version, 0x00, sizeof(Version)); + Version.dwOSVersionInfoSize = sizeof(Version); + + if (GetVersionEx (&Version)) + { + if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT && + (Version.dwMajorVersion >= 5 || + Version.dwMajorVersion == 5 && Version.dwMinorVersion >= 1) ) + fIsWinXP = TRUE; + } + } + + return fIsWinXP; +} + +/* This flag is only supported by versions of Windows which have obtained + * a code change from Microsoft. When the code change is installed, + * setting this flag will cause all retrieved credentials to be stored + * in the LSA cache. + */ +#ifndef KERB_RETRIEVE_TICKET_CACHE_TICKET +#define KERB_RETRIEVE_TICKET_CACHE_TICKET 0x20 +#endif + static VOID ShowWinError(LPSTR szAPI, DWORD dwError) { @@ -136,8 +173,6 @@ ShowLsaError(LPSTR szAPI, NTSTATUS Status) ShowWinError(szAPI, LsaNtStatusToWinError(Status)); } - - static BOOL WINAPI UnicodeToANSI(LPTSTR lpInputString, LPSTR lpszOutputString, int nOutStringLen) @@ -198,7 +233,8 @@ MITPrincToMSPrinc(krb5_context context, krb5_principal principal, UNICODE_STRING } static void -MSPrincToMITPrinc(KERB_EXTERNAL_NAME *msprinc, WCHAR *realm, krb5_context context, krb5_principal *principal) +MSPrincToMITPrinc(KERB_EXTERNAL_NAME *msprinc, WCHAR *realm, krb5_context context, + krb5_principal *principal) { WCHAR princbuf[512],tmpbuf[128]; char aname[512]; @@ -265,7 +301,8 @@ MSTicketToMITTicket(KERB_EXTERNAL_TICKET *msticket, krb5_context context, krb5_d tmpdata.length=msticket->EncodedTicketSize; tmpdata.data=msticket->EncodedTicket; - // TODO: fix this up a little. this is ugly and will break krb5_free_data() + // this is ugly and will break krb5_free_data() + // now that this is being done within the library it won't break krb5_free_data() krb5_copy_data(context, &tmpdata, &newdata); memcpy(ticket, newdata, sizeof(krb5_data)); } @@ -313,7 +350,7 @@ PreserveInitialTicketIdentity(void) static void -MSCredToMITCred(KERB_EXTERNAL_TICKET *msticket, UNICODE_STRING InitialTicketDomain, +MSCredToMITCred(KERB_EXTERNAL_TICKET *msticket, UNICODE_STRING ClientRealm, krb5_context context, krb5_creds *creds) { WCHAR wrealm[128]; @@ -321,13 +358,8 @@ MSCredToMITCred(KERB_EXTERNAL_TICKET *msticket, UNICODE_STRING InitialTicketDoma creds->magic=KV5M_CREDS; // construct Client Principal - if ( PreserveInitialTicketIdentity() ) { - wcsncpy(wrealm, InitialTicketDomain.Buffer, InitialTicketDomain.Length/sizeof(WCHAR)); - wrealm[InitialTicketDomain.Length/sizeof(WCHAR)]=0; - } else { - wcsncpy(wrealm, msticket->DomainName.Buffer, msticket->DomainName.Length/sizeof(WCHAR)); - wrealm[msticket->DomainName.Length/sizeof(WCHAR)]=0; - } + wcsncpy(wrealm, ClientRealm.Buffer, ClientRealm.Length/sizeof(WCHAR)); + wrealm[ClientRealm.Length/sizeof(WCHAR)]=0; MSPrincToMITPrinc(msticket->ClientName, wrealm, context, &creds->client); // construct Service Principal @@ -388,6 +420,67 @@ PackageConnectLookup(HANDLE *pLogonHandle, ULONG *pPackageId) } +static BOOL +does_retrieve_ticket_cache_ticket (void) +{ + static BOOL fChecked = FALSE; + static BOOL fCachesTicket = FALSE; + + if (!fChecked) + { + NTSTATUS Status = 0; + NTSTATUS SubStatus = 0; + HANDLE LogonHandle; + ULONG PackageId; + ULONG RequestSize; + PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL; + PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL; + ULONG ResponseSize; + + fChecked = TRUE; + RequestSize = sizeof(*pTicketRequest) + 1; + + if (!PackageConnectLookup(&LogonHandle, &PackageId)) + return FALSE; + + pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize); + if (!pTicketRequest) { + CloseHandle(LogonHandle); + return FALSE; + } + + pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage; + pTicketRequest->LogonId.LowPart = 0; + pTicketRequest->LogonId.HighPart = 0; + pTicketRequest->TargetName.Length = 0; + pTicketRequest->TargetName.MaximumLength = 0; + pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1); + pTicketRequest->CacheOptions = + KERB_RETRIEVE_TICKET_DONT_USE_CACHE | KERB_RETRIEVE_TICKET_CACHE_TICKET; + pTicketRequest->EncryptionType = 0; + pTicketRequest->TicketFlags = 0; + + Status = LsaCallAuthenticationPackage( LogonHandle, + PackageId, + pTicketRequest, + RequestSize, + &pTicketResponse, + &ResponseSize, + &SubStatus + ); + + LocalFree(pTicketRequest); + CloseHandle(LogonHandle); + + if (FAILED(Status) || FAILED(SubStatus)) { + if ( SubStatus == STATUS_NOT_SUPPORTED ) + fCachesTicket = TRUE; + } + } + + return fCachesTicket; +} + static DWORD ConcatenateUnicodeStrings(UNICODE_STRING *pTarget, UNICODE_STRING Source1, UNICODE_STRING Source2) @@ -591,6 +684,23 @@ PurgeMSTGT(HANDLE LogonHandle, ULONG PackageId) return TRUE; } +/* + * A simple function to determine if there is an exact match between two tickets + * We rely on the fact that the external tickets contain the raw Kerberos ticket. + * If the EncodedTicket fields match, the KERB_EXTERNAL_TICKETs must be the same. + */ +static BOOL +KerbExternalTicketMatch( PKERB_EXTERNAL_TICKET one, PKERB_EXTERNAL_TICKET two ) +{ + if ( one->EncodedTicketSize != two->EncodedTicketSize ) + return FALSE; + + if ( memcmp(one->EncodedTicket, two->EncodedTicket, one->EncodedTicketSize) ) + return FALSE; + + return TRUE; +} + krb5_boolean krb5_is_permitted_tgs_enctype(krb5_context context, krb5_const_principal princ, krb5_enctype etype) { @@ -857,6 +967,8 @@ GetMSTGT(krb5_context context, HANDLE LogonHandle, ULONG PackageId, KERB_EXTERNA // 0 is supported.) pTicketRequest->EncryptionType = etype; pTicketRequest->CacheOptions = 0; + if ( does_retrieve_ticket_cache_ticket() ) + pTicketRequest->CacheOptions |= KERB_RETRIEVE_TICKET_CACHE_TICKET; if ( pTicketResponse ) { memset(pTicketResponse,0,sizeof(KERB_RETRIEVE_TKT_RESPONSE)); @@ -927,8 +1039,8 @@ GetMSTGT(krb5_context context, HANDLE LogonHandle, ULONG PackageId, KERB_EXTERNA } static BOOL -GetQueryTktCacheResponse( HANDLE LogonHandle, ULONG PackageId, - PKERB_QUERY_TKT_CACHE_RESPONSE * ppResponse) +GetQueryTktCacheResponseW2K( HANDLE LogonHandle, ULONG PackageId, + PKERB_QUERY_TKT_CACHE_RESPONSE * ppResponse) { NTSTATUS Status = 0; NTSTATUS SubStatus = 0; @@ -959,10 +1071,37 @@ GetQueryTktCacheResponse( HANDLE LogonHandle, ULONG PackageId, return FALSE; } -static void -FreeQueryResponse(PKERB_QUERY_TKT_CACHE_RESPONSE pResponse) +static BOOL +GetQueryTktCacheResponseXP( HANDLE LogonHandle, ULONG PackageId, + PKERB_QUERY_TKT_CACHE_EX_RESPONSE * ppResponse) { - LsaFreeReturnBuffer(pResponse); + NTSTATUS Status = 0; + NTSTATUS SubStatus = 0; + + KERB_QUERY_TKT_CACHE_REQUEST CacheRequest; + PKERB_QUERY_TKT_CACHE_EX_RESPONSE pQueryResponse = NULL; + ULONG ResponseSize; + + CacheRequest.MessageType = KerbQueryTicketCacheExMessage; + CacheRequest.LogonId.LowPart = 0; + CacheRequest.LogonId.HighPart = 0; + + Status = LsaCallAuthenticationPackage( + LogonHandle, + PackageId, + &CacheRequest, + sizeof(CacheRequest), + &pQueryResponse, + &ResponseSize, + &SubStatus + ); + + if ( !(FAILED(Status) || FAILED(SubStatus)) ) { + *ppResponse = pQueryResponse; + return TRUE; + } + + return FALSE; } @@ -993,6 +1132,8 @@ GetMSCacheTicketFromMITCred( HANDLE LogonHandle, ULONG PackageId, pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1); MITPrincToMSPrinc(context, creds->server, &pTicketRequest->TargetName); pTicketRequest->CacheOptions = 0; + if ( does_retrieve_ticket_cache_ticket() ) + pTicketRequest->CacheOptions |= KERB_RETRIEVE_TICKET_CACHE_TICKET; pTicketRequest->TicketFlags = creds->ticket_flags; pTicketRequest->EncryptionType = creds->keyblock.enctype; @@ -1007,6 +1148,64 @@ GetMSCacheTicketFromMITCred( HANDLE LogonHandle, ULONG PackageId, LocalFree(pTicketRequest); + if (FAILED(Status) || FAILED(SubStatus)) + return(FALSE); + + /* otherwise return ticket */ + *ticket = &(pTicketResponse->Ticket); + return(TRUE); +} + +static BOOL +GetMSCacheTicketFromCacheInfoW2K( HANDLE LogonHandle, ULONG PackageId, + PKERB_TICKET_CACHE_INFO tktinfo, PKERB_EXTERNAL_TICKET *ticket) +{ + NTSTATUS Status = 0; + NTSTATUS SubStatus = 0; + ULONG RequestSize; + PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL; + PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL; + ULONG ResponseSize; + + RequestSize = sizeof(*pTicketRequest) + tktinfo->ServerName.Length; + + pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize); + if (!pTicketRequest) + return FALSE; + + pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage; + pTicketRequest->LogonId.LowPart = 0; + pTicketRequest->LogonId.HighPart = 0; + pTicketRequest->TargetName.Length = tktinfo->ServerName.Length; + pTicketRequest->TargetName.MaximumLength = tktinfo->ServerName.Length; + pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1); + memcpy(pTicketRequest->TargetName.Buffer,tktinfo->ServerName.Buffer, tktinfo->ServerName.Length); + pTicketRequest->CacheOptions = 0; + if ( does_retrieve_ticket_cache_ticket() ) + pTicketRequest->CacheOptions |= KERB_RETRIEVE_TICKET_CACHE_TICKET; + pTicketRequest->EncryptionType = tktinfo->EncryptionType; + pTicketRequest->TicketFlags = 0; + if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_forwardable ) + pTicketRequest->TicketFlags |= KDC_OPT_FORWARDABLE; + if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_forwarded ) + pTicketRequest->TicketFlags |= KDC_OPT_FORWARDED; + if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_proxiable ) + pTicketRequest->TicketFlags |= KDC_OPT_PROXIABLE; + if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_renewable ) + pTicketRequest->TicketFlags |= KDC_OPT_RENEWABLE; + + Status = LsaCallAuthenticationPackage( + LogonHandle, + PackageId, + pTicketRequest, + RequestSize, + &pTicketResponse, + &ResponseSize, + &SubStatus + ); + + LocalFree(pTicketRequest); + if (FAILED(Status) || FAILED(SubStatus)) return(FALSE); @@ -1017,8 +1216,8 @@ GetMSCacheTicketFromMITCred( HANDLE LogonHandle, ULONG PackageId, } static BOOL -GetMSCacheTicketFromCacheInfo( HANDLE LogonHandle, ULONG PackageId, - PKERB_TICKET_CACHE_INFO tktinfo, PKERB_EXTERNAL_TICKET *ticket) +GetMSCacheTicketFromCacheInfoXP( HANDLE LogonHandle, ULONG PackageId, + PKERB_TICKET_CACHE_INFO_EX tktinfo, PKERB_EXTERNAL_TICKET *ticket) { NTSTATUS Status = 0; NTSTATUS SubStatus = 0; @@ -1041,6 +1240,8 @@ GetMSCacheTicketFromCacheInfo( HANDLE LogonHandle, ULONG PackageId, pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1); memcpy(pTicketRequest->TargetName.Buffer,tktinfo->ServerName.Buffer, tktinfo->ServerName.Length); pTicketRequest->CacheOptions = 0; + if ( does_retrieve_ticket_cache_ticket() ) + pTicketRequest->CacheOptions |= KERB_RETRIEVE_TICKET_CACHE_TICKET; pTicketRequest->EncryptionType = tktinfo->EncryptionType; pTicketRequest->TicketFlags = 0; if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_forwardable ) @@ -1131,8 +1332,11 @@ typedef struct _krb5_lcc_data { } krb5_lcc_data; typedef struct _krb5_lcc_cursor { - PKERB_QUERY_TKT_CACHE_RESPONSE response; - int index; + union { + PKERB_QUERY_TKT_CACHE_RESPONSE w2k; + PKERB_QUERY_TKT_CACHE_EX_RESPONSE xp; + } response; + unsigned int index; PKERB_EXTERNAL_TICKET mstgt; } krb5_lcc_cursor; @@ -1166,7 +1370,7 @@ krb5_lcc_resolve (krb5_context context, krb5_ccache *id, const char *residual) ULONG PackageId; KERB_EXTERNAL_TICKET *msticket; - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; #ifdef COMMENT @@ -1181,7 +1385,7 @@ krb5_lcc_resolve (krb5_context context, krb5_ccache *id, const char *residual) return KRB5_FCC_NOFILE; #endif - if(!PackageConnectLookup(&LogonHandle, &PackageId)) + if (!PackageConnectLookup(&LogonHandle, &PackageId)) return KRB5_FCC_NOFILE; lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache)); @@ -1247,7 +1451,7 @@ krb5_lcc_resolve (krb5_context context, krb5_ccache *id, const char *residual) static krb5_error_code KRB5_CALLCONV krb5_lcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ) { - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; return KRB5_CC_READONLY; @@ -1268,7 +1472,7 @@ krb5_lcc_close(krb5_context context, krb5_ccache id) register int closeval = KRB5_OK; register krb5_lcc_data *data; - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; if (id) { @@ -1295,7 +1499,7 @@ krb5_lcc_destroy(krb5_context context, krb5_ccache id) { register krb5_lcc_data *data; - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; if (id) { @@ -1324,9 +1528,8 @@ krb5_lcc_start_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cur { krb5_lcc_cursor *lcursor; krb5_lcc_data *data = (krb5_lcc_data *)id->data; - KERB_EXTERNAL_TICKET *msticket; - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; lcursor = (krb5_lcc_cursor *) malloc(sizeof(krb5_lcc_cursor)); @@ -1344,11 +1547,20 @@ krb5_lcc_start_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cur return KRB5_FCC_INTERNAL; } - if ( !GetQueryTktCacheResponse(data->LogonHandle, data->PackageId, &lcursor->response) ) { - LsaFreeReturnBuffer(lcursor->mstgt); - free(lcursor); - *cursor = 0; - return KRB5_FCC_INTERNAL; + if ( is_windows_xp() ) { + if ( !GetQueryTktCacheResponseXP(data->LogonHandle, data->PackageId, &lcursor->response.xp) ) { + LsaFreeReturnBuffer(lcursor->mstgt); + free(lcursor); + *cursor = 0; + return KRB5_FCC_INTERNAL; + } + } else { + if ( !GetQueryTktCacheResponseW2K(data->LogonHandle, data->PackageId, &lcursor->response.w2k) ) { + LsaFreeReturnBuffer(lcursor->mstgt); + free(lcursor); + *cursor = 0; + return KRB5_FCC_INTERNAL; + } } lcursor->index = 0; *cursor = (krb5_cc_cursor) lcursor; @@ -1381,28 +1593,48 @@ krb5_lcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor, KERB_EXTERNAL_TICKET *msticket; krb5_error_code retval = KRB5_OK; - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; data = (krb5_lcc_data *)id->data; next_cred: - if ( lcursor->index >= lcursor->response->CountOfTickets ) { - if (retval == KRB5_OK) - return KRB5_CC_END; - else { - LsaFreeReturnBuffer(lcursor->mstgt); - LsaFreeReturnBuffer(lcursor->response); - free(*cursor); - *cursor = 0; - return retval; + if ( is_windows_xp() ) { + if ( lcursor->index >= lcursor->response.xp->CountOfTickets ) { + if (retval == KRB5_OK) + return KRB5_CC_END; + else { + LsaFreeReturnBuffer(lcursor->mstgt); + LsaFreeReturnBuffer(lcursor->response.xp); + free(*cursor); + *cursor = 0; + return retval; + } } - } - if (!GetMSCacheTicketFromCacheInfo(data->LogonHandle, data->PackageId, - &lcursor->response->Tickets[lcursor->index++],&msticket)) { - retval = KRB5_FCC_INTERNAL; - goto next_cred; + if (!GetMSCacheTicketFromCacheInfoXP(data->LogonHandle, data->PackageId, + &lcursor->response.xp->Tickets[lcursor->index++],&msticket)) { + retval = KRB5_FCC_INTERNAL; + goto next_cred; + } + } else { + if ( lcursor->index >= lcursor->response.w2k->CountOfTickets ) { + if (retval == KRB5_OK) + return KRB5_CC_END; + else { + LsaFreeReturnBuffer(lcursor->mstgt); + LsaFreeReturnBuffer(lcursor->response.w2k); + free(*cursor); + *cursor = 0; + return retval; + } + } + + if (!GetMSCacheTicketFromCacheInfoW2K(data->LogonHandle, data->PackageId, + &lcursor->response.w2k->Tickets[lcursor->index++],&msticket)) { + retval = KRB5_FCC_INTERNAL; + goto next_cred; + } } /* Don't return tickets with NULL Session Keys */ @@ -1412,7 +1644,10 @@ krb5_lcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor, } /* convert the ticket */ - MSCredToMITCred(msticket, lcursor->mstgt->DomainName, context, creds); + if ( is_windows_xp() ) + MSCredToMITCred(msticket, lcursor->response.xp->Tickets[lcursor->index-1].ClientRealm, context, creds); + else + MSCredToMITCred(msticket, lcursor->mstgt->DomainName, context, creds); LsaFreeReturnBuffer(msticket); return KRB5_OK; } @@ -1435,12 +1670,15 @@ krb5_lcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *curso { krb5_lcc_cursor *lcursor = (krb5_lcc_cursor *) *cursor; - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; if ( lcursor ) { LsaFreeReturnBuffer(lcursor->mstgt); - LsaFreeReturnBuffer(lcursor->response); + if ( is_windows_xp() ) + LsaFreeReturnBuffer(lcursor->response.xp); + else + LsaFreeReturnBuffer(lcursor->response.w2k); free(*cursor); } *cursor = 0; @@ -1456,7 +1694,7 @@ krb5_lcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *curso static krb5_error_code KRB5_CALLCONV krb5_lcc_generate_new (krb5_context context, krb5_ccache *id) { - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; return KRB5_CC_READONLY; @@ -1473,7 +1711,7 @@ static const char * KRB5_CALLCONV krb5_lcc_get_name (krb5_context context, krb5_ccache id) { - if (!IsWindows2000()) + if (!is_windows_2000()) return ""; if ( !id ) @@ -1500,7 +1738,7 @@ krb5_lcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *pri { krb5_error_code kret = KRB5_OK; - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; /* obtain principal */ @@ -1514,11 +1752,11 @@ krb5_lcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields, { krb5_error_code kret = KRB5_OK; krb5_lcc_data *data = (krb5_lcc_data *)id->data; - KERB_EXTERNAL_TICKET *msticket = 0, *mstgt = 0; + KERB_EXTERNAL_TICKET *msticket = 0, *mstgt = 0, *mstmp = 0; krb5_creds * mcreds_noflags; krb5_creds fetchcreds; - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; memset(&fetchcreds, 0, sizeof(krb5_creds)); @@ -1543,7 +1781,9 @@ krb5_lcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields, if ( !kret ) goto cleanup; - /* if not, obtain a ticket using the request flags and enctype even though it will not + + + /* if not, obtain a ticket using the request flags and enctype even though it may not * be stored in the LSA cache for future use. */ if ( msticket ) { @@ -1557,9 +1797,40 @@ krb5_lcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields, } /* convert the ticket */ - GetMSTGT(context, data->LogonHandle, data->PackageId, &mstgt, FALSE); + if ( !is_windows_xp() || !does_retrieve_ticket_cache_ticket() ) { + if ( PreserveInitialTicketIdentity() ) + GetMSTGT(context, data->LogonHandle, data->PackageId, &mstgt, FALSE); + + MSCredToMITCred(msticket, mstgt ? mstgt->DomainName : msticket->DomainName, context, &fetchcreds); + } else { + /* We can obtain the correct client realm for a ticket by walking the + * cache contents until we find the matching service ticket. + */ + PKERB_QUERY_TKT_CACHE_EX_RESPONSE pResponse = 0; + int i; + + if (!GetQueryTktCacheResponseXP( data->LogonHandle, data->PackageId, &pResponse)) { + kret = KRB5_FCC_INTERNAL; + goto cleanup; + } + + for ( i=0; iCountOfTickets; i++ ) { + if (!GetMSCacheTicketFromCacheInfoXP(data->LogonHandle, data->PackageId, + &pResponse->Tickets[i],&mstmp)) { + continue; + } + + if ( KerbExternalTicketMatch(msticket,mstmp) ) + break; + + LsaFreeReturnBuffer(mstmp); + mstmp = 0; + } + + MSCredToMITCred(msticket, mstmp ? pResponse->Tickets[i].ClientRealm : msticket->DomainName, context, &fetchcreds); + LsaFreeReturnBuffer(pResponse); + } - MSCredToMITCred(msticket, mstgt ? mstgt->DomainName : msticket->DomainName, context, &fetchcreds); /* check to see if this ticket matches the request using logic from * krb5_cc_retrieve_cred_default() @@ -1572,6 +1843,8 @@ krb5_lcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields, } cleanup: + if ( mstmp ) + LsaFreeReturnBuffer(mstmp); if ( mstgt ) LsaFreeReturnBuffer(mstgt); if ( msticket ) @@ -1598,7 +1871,7 @@ krb5_lcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds) KERB_EXTERNAL_TICKET *msticket = 0, *msticket2 = 0; krb5_creds * creds_noflags; - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; if ( creds->ticket_flags != 0 && creds->keyblock.enctype != 0 ) { @@ -1632,7 +1905,7 @@ static krb5_error_code KRB5_CALLCONV krb5_lcc_remove_cred(krb5_context context, krb5_ccache cache, krb5_flags flags, krb5_creds *creds) { - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; return KRB5_CC_READONLY; @@ -1646,7 +1919,7 @@ krb5_lcc_remove_cred(krb5_context context, krb5_ccache cache, krb5_flags flags, static krb5_error_code KRB5_CALLCONV krb5_lcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags) { - if (!IsWindows2000()) + if (!is_windows_2000()) return KRB5_FCC_NOFILE; return KRB5_OK; -- 2.26.2