#define SECURITY_WIN32
#include <security.h>
#include <ntsecapi.h>
+#include <ntstatus.h>
#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;
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)
{
ShowWinError(szAPI, LsaNtStatusToWinError(Status));
}
-
-
static BOOL
WINAPI
UnicodeToANSI(LPTSTR lpInputString, LPSTR lpszOutputString, int nOutStringLen)
}
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];
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));
}
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];
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
}
+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)
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)
{
// 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));
}
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;
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;
}
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;
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);
}
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;
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 )
} 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;
ULONG PackageId;
KERB_EXTERNAL_TICKET *msticket;
- if (!IsWindows2000())
+ if (!is_windows_2000())
return KRB5_FCC_NOFILE;
#ifdef COMMENT
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));
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;
register int closeval = KRB5_OK;
register krb5_lcc_data *data;
- if (!IsWindows2000())
+ if (!is_windows_2000())
return KRB5_FCC_NOFILE;
if (id) {
{
register krb5_lcc_data *data;
- if (!IsWindows2000())
+ if (!is_windows_2000())
return KRB5_FCC_NOFILE;
if (id) {
{
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));
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;
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 */
}
/* 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;
}
{
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;
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;
krb5_lcc_get_name (krb5_context context, krb5_ccache id)
{
- if (!IsWindows2000())
+ if (!is_windows_2000())
return "";
if ( !id )
{
krb5_error_code kret = KRB5_OK;
- if (!IsWindows2000())
+ if (!is_windows_2000())
return KRB5_FCC_NOFILE;
/* obtain principal */
{
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));
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 ) {
}
/* 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; i<pResponse->CountOfTickets; 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()
}
cleanup:
+ if ( mstmp )
+ LsaFreeReturnBuffer(mstmp);
if ( mstgt )
LsaFreeReturnBuffer(mstgt);
if ( msticket )
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 ) {
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;
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;