* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * Implementation of microsoft windows lsa credentials cache
+ * Implementation of read-only microsoft windows lsa credentials cache
*/
#ifdef _WIN32
#include <ntsecapi.h>
#include <ntstatus.h>
-#ifdef COMMENT
-/* The following two features can only be built using a version of the
- * Microsoft Windows Platform SDK which is not currently public. These
- * features will be disabled until the SDK is made publicly available.
- */
#define KERB_SUBMIT_TICKET 1
#define HAVE_CACHE_INFO_EX2 1
-#endif
#define MAX_MSG_SIZE 256
#define MAX_MSPRINC_SIZE 1024
/* THREAD SAFETY
- * The functions is_windows_2000(), is_windows_xp(),
- * does_retrieve_ticket_cache_ticket() and does_query_ticket_cache_ex2()
- * contain static variables to cache the responses of the tests being
- * performed. There is no harm in the test being performed more than
- * once since the result will always be the same.
+ * The functions is_windows_2000(), is_windows_xp(), and does_retrieve_ticket_cache_ticket()
+ * contain static variables to cache the responses of the tests being performed. There is
+ * no harm in the test being performed more than once since the result will always be the
+ * same.
*/
static BOOL
return TRUE;
}
-#ifdef HAVE_CACHE_INFO_EX2
-/* CacheInfoEx2ToMITCred is used when we do not need the real ticket */
-static void
-CacheInfoEx2ToMITCred(KERB_TICKET_CACHE_INFO_EX2 *info,
- krb5_context context, krb5_creds *creds)
-{
- WCHAR wrealm[128];
- ZeroMemory(creds, sizeof(krb5_creds));
- creds->magic=KV5M_CREDS;
-
- // construct Client Principal
- wcsncpy(wrealm, info->ClientRealm.Buffer, info->ClientRealm.Length/sizeof(WCHAR));
- wrealm[info->ClientRealm.Length/sizeof(WCHAR)]=0;
- UnicodeStringToMITPrinc(&info->ClientName, wrealm, context, &creds->client);
-
- // construct Service Principal
- wcsncpy(wrealm, info->ServerRealm.Buffer,
- info->ServerRealm.Length/sizeof(WCHAR));
- wrealm[info->ServerRealm.Length/sizeof(WCHAR)]=0;
- UnicodeStringToMITPrinc(&info->ServerName, wrealm, context, &creds->server);
-
- creds->keyblock.magic = KV5M_KEYBLOCK;
- creds->keyblock.enctype = info->SessionKeyType;
- creds->ticket_flags = info->TicketFlags;
- MSFlagsToMITFlags(info->TicketFlags, &creds->ticket_flags);
- creds->times.starttime=FileTimeToUnixTime(&info->StartTime);
- creds->times.endtime=FileTimeToUnixTime(&info->EndTime);
- creds->times.renew_till=FileTimeToUnixTime(&info->RenewTime);
-
- /* MS Tickets are addressless. MIT requires an empty address
- * not a NULL list of addresses.
- */
- creds->addresses = (krb5_address **)malloc(sizeof(krb5_address *));
- memset(creds->addresses, 0, sizeof(krb5_address *));
-}
-#endif /* HAVE_CACHE_INFO_EX2 */
-
static BOOL
PackageConnectLookup(HANDLE *pLogonHandle, ULONG *pPackageId)
{
if (FAILED(Status) || FAILED(SubStatus)) {
if ( SubStatus == STATUS_NOT_SUPPORTED )
- /* The combination of the two CacheOption flags
- * is not supported; therefore, the new flag is supported
- */
fCachesTicket = TRUE;
}
fChecked = TRUE;
return fCachesTicket;
}
-#ifdef HAVE_CACHE_INFO_EX2
-static BOOL
-does_query_ticket_cache_ex2 (void)
-{
- static BOOL fChecked = FALSE;
- static BOOL fEx2Response = FALSE;
-
- if (!fChecked)
- {
- NTSTATUS Status = 0;
- NTSTATUS SubStatus = 0;
- HANDLE LogonHandle;
- ULONG PackageId;
- ULONG RequestSize;
- PKERB_QUERY_TKT_CACHE_REQUEST pCacheRequest = NULL;
- PKERB_QUERY_TKT_CACHE_EX2_RESPONSE pCacheResponse = NULL;
- ULONG ResponseSize;
-
- RequestSize = sizeof(*pCacheRequest) + 1;
-
- if (!PackageConnectLookup(&LogonHandle, &PackageId))
- return FALSE;
-
- pCacheRequest = (PKERB_QUERY_TKT_CACHE_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize);
- if (!pCacheRequest) {
- CloseHandle(LogonHandle);
- return FALSE;
- }
-
- pCacheRequest->MessageType = KerbQueryTicketCacheEx2Message;
- pCacheRequest->LogonId.LowPart = 0;
- pCacheRequest->LogonId.HighPart = 0;
-
- Status = LsaCallAuthenticationPackage( LogonHandle,
- PackageId,
- pCacheRequest,
- RequestSize,
- &pCacheResponse,
- &ResponseSize,
- &SubStatus
- );
-
- LocalFree(pCacheRequest);
- CloseHandle(LogonHandle);
-
- if (!(FAILED(Status) || FAILED(SubStatus))) {
- LsaFreeReturnBuffer(pCacheResponse);
- fEx2Response = TRUE;
- }
- fChecked = TRUE;
- }
-
- return fEx2Response;
-}
-#endif /* HAVE_CACHE_INFO_EX2 */
static DWORD
ConcatenateUnicodeStrings(UNICODE_STRING *pTarget, UNICODE_STRING Source1, UNICODE_STRING Source2)
return TRUE;
}
+
static BOOL
PurgeTicket2000( HANDLE LogonHandle, ULONG PackageId,
krb5_context context, krb5_creds *cred )
return TRUE;
}
-#ifdef KERB_SUBMIT_TICKET
-static BOOL
-KerbSubmitTicket( HANDLE LogonHandle, ULONG PackageId,
- krb5_context context, krb5_creds *cred)
-{
- NTSTATUS Status = 0;
- NTSTATUS SubStatus = 0;
- KERB_SUBMIT_TKT_REQUEST * pSubmitRequest;
- DWORD dwRequestLen;
- krb5_auth_context auth_context;
- krb5_keyblock * keyblock = 0;
- krb5_replay_data replaydata;
- krb5_data * krb_cred = 0;
- krb5_error_code rc;
-
- if (krb5_auth_con_init(context, &auth_context)) {
- return FALSE;
- }
-
- if (krb5_auth_con_setflags(context, auth_context,
- KRB5_AUTH_CONTEXT_RET_TIME)) {
- return FALSE;
- }
-
- krb5_auth_con_getsendsubkey(context, auth_context, &keyblock);
- if (keyblock == NULL)
- krb5_auth_con_getkey(context, auth_context, &keyblock);
-#ifdef TESTING
- /* do not use this code unless testing the LSA */
- if (keyblock == NULL) {
- keyblock = (krb5_keyblock *)malloc(sizeof(krb5_keyblock));
- keyblock->enctype = ENCTYPE_ARCFOUR_HMAC;
- keyblock->length = 16;
- keyblock->contents = (krb5_octet *)malloc(16);
- keyblock->contents[0] = 0xde;
- keyblock->contents[1] = 0xad;
- keyblock->contents[2] = 0xbe;
- keyblock->contents[3] = 0xef;
- keyblock->contents[4] = 0xfe;
- keyblock->contents[5] = 0xed;
- keyblock->contents[6] = 0xf0;
- keyblock->contents[7] = 0xd;
- keyblock->contents[8] = 0xde;
- keyblock->contents[9] = 0xad;
- keyblock->contents[10] = 0xbe;
- keyblock->contents[11] = 0xef;
- keyblock->contents[12] = 0xfe;
- keyblock->contents[13] = 0xed;
- keyblock->contents[14] = 0xf0;
- keyblock->contents[15] = 0xd;
- krb5_auth_con_setsendsubkey(context, auth_context, keyblock);
- }
-#endif
- rc = krb5_mk_1cred(context, auth_context, cred, &krb_cred, &replaydata);
- if (rc) {
- krb5_auth_con_free(context, auth_context);
- if (keyblock)
- krb5_free_keyblock(context, keyblock);
- if (krb_cred)
- krb5_free_data(context, krb_cred);
- return FALSE;
- }
-
- dwRequestLen = sizeof(KERB_SUBMIT_TKT_REQUEST) + krb_cred->length + (keyblock ? keyblock->length : 0);
-
- pSubmitRequest = (PKERB_SUBMIT_TKT_REQUEST)malloc(dwRequestLen);
- memset(pSubmitRequest, 0, dwRequestLen);
-
- pSubmitRequest->MessageType = KerbSubmitTicketMessage;
- pSubmitRequest->LogonId.LowPart = 0;
- pSubmitRequest->LogonId.HighPart = 0;
- pSubmitRequest->Flags = 0;
-
- if (keyblock) {
- pSubmitRequest->Key.KeyType = keyblock->enctype;
- pSubmitRequest->Key.Length = keyblock->length;
- pSubmitRequest->Key.Offset = sizeof(KERB_SUBMIT_TKT_REQUEST)+krb_cred->length;
- } else {
- pSubmitRequest->Key.KeyType = ENCTYPE_NULL;
- pSubmitRequest->Key.Length = 0;
- pSubmitRequest->Key.Offset = 0;
- }
- pSubmitRequest->KerbCredSize = krb_cred->length;
- pSubmitRequest->KerbCredOffset = sizeof(KERB_SUBMIT_TKT_REQUEST);
- memcpy(((CHAR *)pSubmitRequest)+sizeof(KERB_SUBMIT_TKT_REQUEST),
- krb_cred->data, krb_cred->length);
- if (keyblock)
- memcpy(((CHAR *)pSubmitRequest)+sizeof(KERB_SUBMIT_TKT_REQUEST)+krb_cred->length,
- keyblock->contents, keyblock->length);
- krb5_free_data(context, krb_cred);
-
- Status = LsaCallAuthenticationPackage( LogonHandle,
- PackageId,
- pSubmitRequest,
- dwRequestLen,
- NULL,
- NULL,
- &SubStatus
- );
- free(pSubmitRequest);
- if (keyblock)
- krb5_free_keyblock(context, keyblock);
- krb5_auth_con_free(context, auth_context);
-
- if (FAILED(Status) || FAILED(SubStatus)) {
- return FALSE;
- }
- return TRUE;
-}
-#endif /* KERB_SUBMIT_TICKET */
/*
* A simple function to determine if there is an exact match between two tickets
return FALSE;
}
-#ifdef HAVE_CACHE_INFO_EX2
-static BOOL
-GetQueryTktCacheResponseEX2( HANDLE LogonHandle, ULONG PackageId,
- PKERB_QUERY_TKT_CACHE_EX2_RESPONSE * ppResponse)
-{
- NTSTATUS Status = 0;
- NTSTATUS SubStatus = 0;
-
- KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
- PKERB_QUERY_TKT_CACHE_EX2_RESPONSE pQueryResponse = NULL;
- ULONG ResponseSize;
-
- CacheRequest.MessageType = KerbQueryTicketCacheEx2Message;
- 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;
-}
-#endif /* HAVE_CACHE_INFO_EX2 */
-
static BOOL
GetMSCacheTicketFromMITCred( HANDLE LogonHandle, ULONG PackageId,
krb5_context context, krb5_creds *creds,
return(TRUE);
}
-#ifdef HAVE_CACHE_INFO_EX2
-static BOOL
-GetMSCacheTicketFromCacheInfoEX2( HANDLE LogonHandle, ULONG PackageId,
- PKERB_TICKET_CACHE_INFO_EX2 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 = KERB_RETRIEVE_TICKET_CACHE_TICKET;
- pTicketRequest->EncryptionType = tktinfo->SessionKeyType;
- 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);
-
- /* otherwise return ticket */
- *ticket = &(pTicketResponse->Ticket);
-
-
- /* set the initial flag if we were attempting to retrieve one
- * because Windows won't necessarily return the initial ticket
- * to us.
- */
- if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_initial )
- (*ticket)->TicketFlags |= KERB_TICKET_FLAGS_initial;
-
- return(TRUE);
-}
-#endif /* HAVE_CACHE_INFO_EX2 */
-
static krb5_error_code KRB5_CALLCONV krb5_lcc_close
(krb5_context, krb5_ccache id);
union {
PKERB_QUERY_TKT_CACHE_RESPONSE w2k;
PKERB_QUERY_TKT_CACHE_EX_RESPONSE xp;
-#ifdef HAVE_CACHE_INFO_EX2
- PKERB_QUERY_TKT_CACHE_EX2_RESPONSE ex2;
-#endif /* HAVE_CACHE_INFO_EX2 */
} response;
unsigned int index;
PKERB_EXTERNAL_TICKET mstgt;
return KRB5_CC_NOTFOUND;
}
-#ifdef HAVE_CACHE_INFO_EX2
- if ( does_query_ticket_cache_ex2() ) {
- if ( !GetQueryTktCacheResponseEX2(data->LogonHandle, data->PackageId, &lcursor->response.ex2) ) {
- LsaFreeReturnBuffer(lcursor->mstgt);
- free(lcursor);
- *cursor = 0;
- return KRB5_FCC_INTERNAL;
- }
- } else
-#endif /* HAVE_CACHE_INFO_EX2 */
if ( is_windows_xp() ) {
if ( !GetQueryTktCacheResponseXP(data->LogonHandle, data->PackageId, &lcursor->response.xp) ) {
LsaFreeReturnBuffer(lcursor->mstgt);
data = (krb5_lcc_data *)id->data;
next_cred:
-#ifdef HAVE_CACHE_INFO_EX2
- if ( does_query_ticket_cache_ex2() ) {
- if ( lcursor->index >= lcursor->response.ex2->CountOfTickets ) {
- if (retval == KRB5_OK)
- return KRB5_CC_END;
- else {
- LsaFreeReturnBuffer(lcursor->mstgt);
- LsaFreeReturnBuffer(lcursor->response.ex2);
- free(*cursor);
- *cursor = 0;
- return retval;
- }
- }
-
- if ( data->flags & KRB5_TC_NOTICKET ) {
- CacheInfoEx2ToMITCred( &lcursor->response.ex2->Tickets[lcursor->index++],
- context, creds);
- return KRB5_OK;
- } else {
- if (!GetMSCacheTicketFromCacheInfoEX2(data->LogonHandle, data->PackageId,
- &lcursor->response.ex2->Tickets[lcursor->index++],&msticket)) {
- retval = KRB5_FCC_INTERNAL;
- goto next_cred;
- }
- }
- } else
-#endif /* HAVE_CACHE_INFO_EX2 */
if ( is_windows_xp() ) {
if ( lcursor->index >= lcursor->response.xp->CountOfTickets ) {
if (retval == KRB5_OK)
}
/* convert the ticket */
-#ifdef HAVE_CACHE_INFO_EX2
- if ( does_query_ticket_cache_ex2() ) {
- if (!MSCredToMITCred(msticket, lcursor->response.ex2->Tickets[lcursor->index-1].ClientRealm, context, creds))
- retval = KRB5_FCC_INTERNAL;
- } else
-#endif /* HAVE_CACHE_INFO_EX2 */
if ( is_windows_xp() ) {
if (!MSCredToMITCred(msticket, lcursor->response.xp->Tickets[lcursor->index-1].ClientRealm, context, creds))
retval = KRB5_FCC_INTERNAL;
if ( lcursor ) {
LsaFreeReturnBuffer(lcursor->mstgt);
-#ifdef HAVE_CACHE_INFO_EX2
- if ( does_query_ticket_cache_ex2() )
- LsaFreeReturnBuffer(lcursor->response.ex2);
- else
-#endif /* HAVE_CACHE_INFO_EX2 */
if ( is_windows_xp() )
LsaFreeReturnBuffer(lcursor->response.xp);
else
* cache contents until we find the matching service ticket.
*/
PKERB_QUERY_TKT_CACHE_EX_RESPONSE pResponse = 0;
- unsigned int i;
+ int i;
if (!GetQueryTktCacheResponseXP( data->LogonHandle, data->PackageId, &pResponse)) {
kret = KRB5_FCC_INTERNAL;
if (!is_windows_2000())
return KRB5_FCC_NOFILE;
-#ifdef KERB_SUBMIT_TICKET
- /* we can use the new KerbSubmitTicketMessage to store the ticket */
- if (KerbSubmitTicket( data->LogonHandle, data->PackageId, context, creds ))
- return KRB5_OK;
-#endif /* KERB_SUBMIT_TICKET */
-
/* If not, lets try to obtain a matching ticket from the KDC */
if ( creds->ticket_flags != 0 && creds->keyblock.enctype != 0 ) {
/* if not, we must try to get a ticket without specifying any flags or etypes */