|
|
/*++
Copyright (c) 2001 Microsoft Corporation All rights reserved
Module Name:
krbutils.cxx
Abstract:
utils
Author:
Larry Zhu (LZhu) December 1, 2001 Created
Environment:
User Mode -Win32
Revision History:
--*/
#include "precomp.hxx"
#pragma hdrstop
#include "krbutils.hxx"
#include "kerberr.hxx"
VOID KerbFreeRealm( IN PKERB_REALM pRealm ) { if (*pRealm != NULL) { MIDL_user_free(*pRealm); *pRealm = NULL; } }
VOID KerbFreePrincipalName( IN PKERB_PRINCIPAL_NAME pName ) { PKERB_PRINCIPAL_NAME_ELEM pElem, pNextElem;
pElem = pName->name_string; while (pElem != NULL) { if (pElem->value != NULL) { MIDL_user_free(pElem->value); } pNextElem = pElem->next; MIDL_user_free(pElem); pElem = pNextElem; } pName->name_string = NULL; }
VOID KerbFreeData( IN ULONG PduValue, IN PVOID pData ) { ASN1decoding_t pDec = NULL;
if (pData) { TKerbErr KerbErr; KerbErr DBGCHK = KerbInitAsn( NULL, &pDec // this is a decoded structure
);
if (KERB_SUCCESS(KerbErr)) { ASN1_FreeDecoded(pDec, pData, PduValue); }
KerbTermAsn(NULL, pDec); } }
BOOL fKRB5ModuleStarted = FALSE;
KERBERR KerbInitAsn( IN OUT ASN1encoding_t * pEnc, IN OUT ASN1decoding_t * pDec ) { TKerbErr KerbErr = KRB_ERR_GENERIC; ASN1error_e Asn1Err;
if (!fKRB5ModuleStarted) { fKRB5ModuleStarted = TRUE; KRB5_Module_Startup(); }
if (pEnc != NULL) { Asn1Err = ASN1_CreateEncoder( KRB5_Module, pEnc, NULL, // pbBuf
0, // cbBufSize
NULL // pParent
); } else { Asn1Err = ASN1_CreateDecoder( KRB5_Module, pDec, NULL, // pbBuf
0, // cbBufSize
NULL // pParent
); }
KerbErr DBGCHK = ASN1_SUCCESS == Asn1Err ? KDC_ERR_NONE : KRB_ERR_GENERIC;
return KerbErr; }
VOID KerbTermAsn( IN ASN1encoding_t pEnc, IN ASN1decoding_t pDec ) { if (pEnc != NULL) { ASN1_CloseEncoder(pEnc); } else if (pDec != NULL) { ASN1_CloseDecoder(pDec); } }
KERBERR KerbEncryptDataEx( OUT PKERB_ENCRYPTED_DATA pEncryptedData, IN ULONG cbDataSize, IN PUCHAR Data, IN ULONG KeyVersion, IN ULONG UsageFlags, IN PKERB_ENCRYPTION_KEY pKey ) { PCRYPTO_SYSTEM pcsCrypt = NULL; PCRYPT_STATE_BUFFER psbCryptBuffer = NULL; NTSTATUS Status = STATUS_SUCCESS;
Status = CDLocateCSystem(pKey->keytype, &pcsCrypt); if (!NT_SUCCESS(Status)) { return(KDC_ERR_ETYPE_NOTSUPP); }
//
// Initialize header
//
pEncryptedData->encryption_type = pKey->keytype;
Status = pcsCrypt->Initialize( (PUCHAR) pKey->keyvalue.value, pKey->keyvalue.length, UsageFlags, &psbCryptBuffer );
if (!NT_SUCCESS(Status)) { return(KRB_ERR_GENERIC); }
Status = pcsCrypt->Encrypt( psbCryptBuffer, Data, cbDataSize, pEncryptedData->cipher_text.value, &pEncryptedData->cipher_text.length );
(void) pcsCrypt->Discard(&psbCryptBuffer);
if (!NT_SUCCESS(Status)) { return(KRB_ERR_GENERIC); }
if (KeyVersion != KERB_NO_KEY_VERSION) { pEncryptedData->version = KeyVersion; pEncryptedData->bit_mask |= version_present; } return KDC_ERR_NONE; }
KERBERR KerbAllocateEncryptionBuffer( IN ULONG EncryptionType, IN ULONG cbBufferSize, OUT PUINT pcbEncryptionBufferSize, OUT PBYTE* pEncryptionBuffer ) { TKerbErr KerbErr = KDC_ERR_NONE; ULONG cbEncryptionOverhead = 0; ULONG cbBlockSize = 0;
KerbErr DBGCHK = KerbGetEncryptionOverhead( EncryptionType, &cbEncryptionOverhead, &cbBlockSize ); if (KERB_SUCCESS(KerbErr)) { *pcbEncryptionBufferSize = (UINT) ROUND_UP_COUNT(cbEncryptionOverhead + cbBufferSize, cbBlockSize);
*pEncryptionBuffer = (PBYTE) MIDL_user_allocate(*pcbEncryptionBufferSize); if (*pEncryptionBuffer == NULL) { KerbErr DBGCHK = KRB_ERR_GENERIC; } }
return KerbErr; }
KERBERR KerbAllocateEncryptionBufferWrapper( IN ULONG EncryptionType, IN ULONG cbBufferSize, OUT ULONG* pcbEncryptionBufferSize, OUT PBYTE* pEncryptionBuffer ) { TKerbErr KerbErr = KDC_ERR_NONE; UINT tempInt = 0;
KerbErr DBGCHK = KerbAllocateEncryptionBuffer( EncryptionType, cbBufferSize, &tempInt, pEncryptionBuffer );
if (KERB_SUCCESS(KerbErr)) { *pcbEncryptionBufferSize = tempInt; }
return KerbErr; }
KERBERR KerbGetEncryptionOverhead( IN ULONG Algorithm, OUT PULONG pcbOverhead, OUT OPTIONAL PULONG pcbBlockSize ) { PCRYPTO_SYSTEM pcsCrypt; NTSTATUS Status = STATUS_SUCCESS;
Status = CDLocateCSystem(Algorithm, &pcsCrypt); if (!NT_SUCCESS(Status)) { return (KDC_ERR_ETYPE_NOTSUPP); }
*pcbOverhead = pcsCrypt->HeaderSize; if (pcbBlockSize) { *pcbBlockSize = pcsCrypt->BlockSize; } return (KDC_ERR_NONE); }
KERBERR NTAPI KerbPackData( IN PVOID Data, IN ULONG PduValue, OUT PULONG pcbDataSize, OUT PUCHAR * MarshalledData ) { TKerbErr KerbErr = KDC_ERR_NONE; ASN1encoding_t pEnc = NULL; ASN1error_e Asn1Err;
KerbErr DBGCHK = KerbInitAsn( &pEnc, // we are encoding
NULL ); if (KERB_SUCCESS(KerbErr)) { //
// Encode the data type.
//
Asn1Err = ASN1_Encode( pEnc, Data, PduValue, ASN1ENCODE_ALLOCATEBUFFER, NULL, // pbBuf
0 // cbBufSize
);
if (!ASN1_SUCCEEDED(Asn1Err)) { DebugPrintf(SSPI_ERROR, "KerbPackData failed to encode data: %d\n", Asn1Err); KerbErr DBGCHK = KRB_ERR_GENERIC; } else { *MarshalledData = (PUCHAR) MIDL_user_allocate(pEnc->len); if (*MarshalledData == NULL) { KerbErr DBGCHK = KRB_ERR_GENERIC; *pcbDataSize = 0; } else { RtlCopyMemory(*MarshalledData, pEnc->buf, pEnc->len); *pcbDataSize = pEnc->len;
} ASN1_FreeEncoded(pEnc, pEnc->buf); } }
KerbTermAsn(pEnc, NULL);
return KerbErr; }
KERBERR KerbConvertUnicodeStringToRealm( OUT PKERB_REALM pRealm, IN PUNICODE_STRING pString ) { TKerbErr KerbErr; STRING TempString;
RtlInitString( &TempString, NULL );
*pRealm = NULL; KerbErr DBGCHK = KerbUnicodeStringToKerbString( &TempString, pString );
if (KERB_SUCCESS(KerbErr)) { *pRealm = TempString.Buffer; }
return KerbErr; }
KERBERR KerbUnicodeStringToKerbString( OUT PSTRING pKerbString, IN PUNICODE_STRING pString ) { STRING TempString;
if (!pKerbString) { return KRB_ERR_GENERIC; }
TempString.Buffer = KerbAllocUtf8StrFromUnicodeString(pString); if (TempString.Buffer == NULL) { return KRB_ERR_GENERIC; }
RtlInitString( &TempString, TempString.Buffer ); *pKerbString = TempString; return KDC_ERR_NONE; }
KERBERR KerbConvertKdcNameToPrincipalName( OUT PKERB_PRINCIPAL_NAME pPrincipalName, IN PKERB_INTERNAL_NAME pKdcName ) { TKerbErr KerbErr = KDC_ERR_NONE;
PKERB_PRINCIPAL_NAME_ELEM pElem; PKERB_PRINCIPAL_NAME_ELEM* pLast; STRING TempKerbString; ULONG Index;
pPrincipalName->name_type = (int) pKdcName->NameType; pPrincipalName->name_string = NULL; pLast = &pPrincipalName->name_string;
//
// Index through the KDC name and add each element to the list
//
for (Index = 0; KERB_SUCCESS(KerbErr) && (Index < pKdcName->NameCount); Index++) { KerbErr DBGCHK = KerbUnicodeStringToKerbString( &TempKerbString, &pKdcName->Names[Index] ); if (KERB_SUCCESS(KerbErr)) { pElem = (PKERB_PRINCIPAL_NAME_ELEM) MIDL_user_allocate(sizeof(KERB_PRINCIPAL_NAME_ELEM)); if (pElem == NULL) { KerbErr DBGCHK = KRB_ERR_GENERIC; } pElem->value = TempKerbString.Buffer; pElem->next = NULL; *pLast = pElem; pLast = &pElem->next; } }
if (!KERB_SUCCESS(KerbErr)) { KerbFreePrincipalName(pPrincipalName); } return KerbErr; }
ULONG KerbConvertUlongToFlagUlong( IN ULONG Flag ) { ULONG ReturnFlag;
((PUCHAR) &ReturnFlag)[0] = ((PUCHAR) &Flag)[3]; ((PUCHAR) &ReturnFlag)[1] = ((PUCHAR) &Flag)[2]; ((PUCHAR) &ReturnFlag)[2] = ((PUCHAR) &Flag)[1]; ((PUCHAR) &ReturnFlag)[3] = ((PUCHAR) &Flag)[0];
return ReturnFlag; }
VOID KerbConvertLargeIntToGeneralizedTime( OUT PKERB_TIME pClientTime, OUT OPTIONAL INT* pClientUsec, IN PTimeStamp pTimeStamp ) { TIME_FIELDS TimeFields;
//
// Special case zero time
//
#ifndef WIN32_CHICAGO
if (pTimeStamp->QuadPart == 0) #else // WIN32_CHICAGO
if (*pTimeStamp == 0) #endif // WIN32_CHICAGO
{ RtlZeroMemory( pClientTime, sizeof(KERB_TIME) ); //
// For MIT compatibility, time zero is 1/1/70
//
pClientTime->year = 1970; pClientTime->month = 1; pClientTime->day = 1;
if (pClientUsec)
{ *pClientUsec = 0; } pClientTime->universal = TRUE; } else {
#ifndef WIN32_CHICAGO
RtlTimeToTimeFields( pTimeStamp, &TimeFields ); #else // WIN32_CHICAGO
RtlTimeToTimeFields( (LARGE_INTEGER*) pTimeStamp, &TimeFields ); #endif // WIN32_CHICAGO
//
// Generalized times can only contains years up to four digits.
//
if (TimeFields.Year > 2037) { pClientTime->year = 2037; } else { pClientTime->year = TimeFields.Year; } pClientTime->month = (ASN1uint8_t) TimeFields.Month; pClientTime->day = (ASN1uint8_t) TimeFields.Day; pClientTime->hour = (ASN1uint8_t) TimeFields.Hour; pClientTime->minute = (ASN1uint8_t) TimeFields.Minute; pClientTime->second = (ASN1uint8_t) TimeFields.Second;
// MIT kerberos does not support millseconds
//
pClientTime->millisecond = 0;
if (pClientUsec) { //
// Since we don't include milliseconds above, use the whole
// thing here.
//
#ifndef WIN32_CHICAGO
*pClientUsec = (pTimeStamp->LowPart / 10) % 1000000; #else // WIN32_CHICAGO
*pClientUsec = (int) ((*pTimeStamp / 10) % 1000000); #endif // WIN32_CHICAGO
}
pClientTime->diff = 0; pClientTime->universal = TRUE; } }
NTSTATUS KerbMapKerbError( IN KERBERR KerbError ) { NTSTATUS Status; switch(KerbError) { case KDC_ERR_NONE: Status = STATUS_SUCCESS; break; case KDC_ERR_CLIENT_REVOKED: Status = STATUS_ACCOUNT_DISABLED; break; case KDC_ERR_KEY_EXPIRED: Status = STATUS_PASSWORD_EXPIRED; break; case KRB_ERR_GENERIC: Status = STATUS_INSUFFICIENT_RESOURCES; break; case KRB_AP_ERR_SKEW: case KRB_AP_ERR_TKT_NYV: // Note this was added because of the following scenario:
// Let's say the dc and the client have the correct time. And the
// server's time is off. We aren't going to get rid of the ticket for the
// server on the client because it hasn't expired yet. But, the server
// thinks it has. If event logging was turned on, then admins could look
// at the server's event log and potentially deduce that the server's
// time is off relative to the dc.
case KRB_AP_ERR_TKT_EXPIRED: Status = STATUS_TIME_DIFFERENCE_AT_DC; break; case KDC_ERR_POLICY: Status = STATUS_ACCOUNT_RESTRICTION; break; case KDC_ERR_C_PRINCIPAL_UNKNOWN: Status = STATUS_NO_SUCH_USER; break; case KDC_ERR_S_PRINCIPAL_UNKNOWN: Status = STATUS_NO_TRUST_SAM_ACCOUNT; break; case KRB_AP_ERR_MODIFIED: case KDC_ERR_PREAUTH_FAILED: Status = STATUS_WRONG_PASSWORD; break; case KRB_ERR_RESPONSE_TOO_BIG: Status = STATUS_INVALID_BUFFER_SIZE; break; case KDC_ERR_PADATA_TYPE_NOSUPP: Status = STATUS_NOT_SUPPORTED; break; case KRB_AP_ERR_NOT_US: Status = SEC_E_WRONG_PRINCIPAL; break;
case KDC_ERR_SVC_UNAVAILABLE: Status = STATUS_NO_LOGON_SERVERS; break; case KDC_ERR_WRONG_REALM: Status = STATUS_NO_LOGON_SERVERS; break; case KDC_ERR_CANT_VERIFY_CERTIFICATE: Status = TRUST_E_SYSTEM_ERROR; break; case KDC_ERR_INVALID_CERTIFICATE: Status = STATUS_INVALID_PARAMETER; break; case KDC_ERR_REVOKED_CERTIFICATE: Status = CRYPT_E_REVOKED; break; case KDC_ERR_REVOCATION_STATUS_UNKNOWN: Status = CRYPT_E_NO_REVOCATION_CHECK; break; case KDC_ERR_REVOCATION_STATUS_UNAVAILABLE: Status = CRYPT_E_REVOCATION_OFFLINE; break; case KDC_ERR_CLIENT_NAME_MISMATCH: case KERB_PKINIT_CLIENT_NAME_MISMATCH: case KDC_ERR_KDC_NAME_MISMATCH: Status = STATUS_PKINIT_NAME_MISMATCH; break; case KDC_ERR_PATH_NOT_ACCEPTED: Status = STATUS_TRUST_FAILURE; break; case KDC_ERR_ETYPE_NOTSUPP: Status = STATUS_KDC_UNKNOWN_ETYPE; break; case KDC_ERR_MUST_USE_USER2USER: case KRB_AP_ERR_USER_TO_USER_REQUIRED: Status = STATUS_USER2USER_REQUIRED; break; case KRB_AP_ERR_NOKEY: Status = STATUS_NO_KERB_KEY; break; case KRB_ERR_NAME_TOO_LONG: Status = STATUS_NAME_TOO_LONG; break; default: Status = STATUS_LOGON_FAILURE; } return (Status); }
KERBERR NTAPI KerbUnpackData( IN PUCHAR pData, IN ULONG cbDataSize, IN ULONG PduValue, OUT PVOID * pDecodedData ) { TKerbErr KerbErr = KDC_ERR_NONE; ASN1decoding_t pDec = NULL; ASN1error_e Asn1Err;
if ((cbDataSize == 0) || (pData == NULL)) { KerbErr DBGCHK = KRB_ERR_GENERIC; }
if (KERB_SUCCESS(KerbErr)) { KerbErr DBGCHK = KerbInitAsn( NULL, &pDec // we are decoding
); }
if (KERB_SUCCESS(KerbErr)) { *pDecodedData = NULL; Asn1Err = ASN1_Decode( pDec, pDecodedData, PduValue, ASN1DECODE_SETBUFFER, (BYTE *) pData, cbDataSize );
if (!ASN1_SUCCEEDED(Asn1Err)) { if ((ASN1_ERR_BADARGS == Asn1Err) || (ASN1_ERR_EOD == Asn1Err)) { KerbErr DBGCHK = KDC_ERR_MORE_DATA; } else { KerbErr DBGCHK = KRB_ERR_GENERIC; } *pDecodedData = NULL; } }
KerbTermAsn(NULL, pDec);
return KerbErr; }
PSTR KerbAllocUtf8StrFromUnicodeString( IN PUNICODE_STRING pUnicodeString ) { PSTR pUtf8String = NULL; UINT cbUtf8StringLen;
//
// If the length is zero, return a null string.
//
if (pUnicodeString->Length == 0) { pUtf8String = (PSTR) MIDL_user_allocate(sizeof(CHAR)); if (pUtf8String != NULL) { *pUtf8String = '\0'; } return pUtf8String; }
//
// Determine the length of the Unicode string.
//
cbUtf8StringLen = WideCharToMultiByte( #ifndef WIN32_CHICAGO
CP_UTF8, #else // WIN32_CHICAGO
CP_OEMCP, #endif // WIN32_CHICAGO
0, // All characters can be mapped.
pUnicodeString->Buffer, pUnicodeString->Length / sizeof(WCHAR), pUtf8String, 0, NULL, NULL );
if ( cbUtf8StringLen == 0 ) { return NULL; }
//
// Allocate a buffer for the Unicode string.
//
pUtf8String = (PSTR) MIDL_user_allocate( cbUtf8StringLen + 1 );
if (pUtf8String == NULL) { return NULL; }
//
// Translate the string to Unicode.
//
cbUtf8StringLen = WideCharToMultiByte( #ifndef WIN32_CHICAGO
CP_UTF8, #else // WIN32_CHICAGO
CP_OEMCP, #endif // WIN32_CHICAGO
0, // All characters can be mapped.
pUnicodeString->Buffer, pUnicodeString->Length / sizeof(WCHAR), pUtf8String, cbUtf8StringLen, NULL, NULL );
if ( cbUtf8StringLen == 0 ) { MIDL_user_free( pUtf8String ); return NULL; }
pUtf8String[cbUtf8StringLen] = '\0';
return pUtf8String; }
|