/*++ Copyright (c) 2000 Microsoft Corporation Module Name: crconv.c Abstract: This module contains credential conversion routines shared between advapi32.dll and crtest.exe Author: Cliff Van Dyke (CliffV) February 25, 2000 Revision History: --*/ DWORD CredpConvertStringSize ( IN WTOA_ENUM WtoA, IN LPWSTR String OPTIONAL ) /*++ Routine Description: Determines the size of the converted string Arguments: WtoA - Specifies the direction of the string conversion. String - The string to convert Return Values: Returns the size (in bytes) of the converted string. --*/ { ULONG Size = 0; UNICODE_STRING UnicodeString; ANSI_STRING AnsiString; if ( String == NULL ) { return Size; } switch ( WtoA ) { case DoWtoA: RtlInitUnicodeString( &UnicodeString, String ); Size = RtlUnicodeStringToAnsiSize( &UnicodeString ); break; case DoAtoW: RtlInitAnsiString( &AnsiString, (LPSTR)String ); Size = RtlAnsiStringToUnicodeSize( &AnsiString ); break; case DoWtoW: Size = (wcslen( String ) + 1) * sizeof(WCHAR); break; } return Size; } DWORD CredpConvertString ( IN WTOA_ENUM WtoA, IN LPWSTR String OPTIONAL, OUT LPWSTR *OutString, IN OUT LPBYTE *WherePtr ) /*++ Routine Description: Determines the size of the converted string Arguments: WtoA - Specifies the direction of the string conversion. String - The string to convert OutString - Returns the pointer to the marshaled string WherePtr - Specifies the address of the first byte to write the string to. Returns a pointer to the first byte after the marshaled string Return Values: Returns the status of the conversion --*/ { NTSTATUS Status; ULONG Size; UNICODE_STRING UnicodeString; ANSI_STRING AnsiString; LPBYTE Where = *WherePtr; if ( String == NULL ) { *OutString = NULL; return NO_ERROR; } *OutString = (LPWSTR)Where; switch ( WtoA ) { case DoWtoA: RtlInitUnicodeString( &UnicodeString, String ); AnsiString.Buffer = (PCHAR)Where; AnsiString.MaximumLength = 0xFFFF; Status = RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeString, FALSE ); if ( !NT_SUCCESS(Status) ) { return RtlNtStatusToDosError( Status ); } Where += AnsiString.Length + sizeof(CHAR); break; case DoAtoW: RtlInitAnsiString( &AnsiString, (LPSTR)String ); UnicodeString.Buffer = (LPWSTR)Where; UnicodeString.MaximumLength = 0xFFFF; Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE ); if ( !NT_SUCCESS(Status) ) { return RtlNtStatusToDosError( Status ); } Where += UnicodeString.Length + sizeof(WCHAR); break; case DoWtoW: Size = (wcslen( String ) + 1) * sizeof(WCHAR); RtlCopyMemory( Where, String, Size ); Where += Size; break; } *WherePtr = Where; return NO_ERROR; } DWORD CredpConvertOneCredentialSize ( IN WTOA_ENUM WtoA, IN PCREDENTIALW InCredential ) /*++ Routine Description: Computes the size of a converted credential Arguments: WtoA - Specifies the direction of the string conversion. InCredential - Input credential Return Values: Returns the size (in bytes) the CredpConvertOneCredential will need to copy this credential into a buffer. --*/ { DWORD WinStatus; ULONG Size; ULONG i; // // Compute the initial size // Size = ROUND_UP_COUNT( sizeof(ENCRYPTED_CREDENTIALW), ALIGN_WORST ) + ROUND_UP_COUNT( InCredential->AttributeCount * sizeof(CREDENTIAL_ATTRIBUTEW), ALIGN_WORST ); if ( InCredential->CredentialBlobSize != 0 ) { ULONG CredBlobSize; // Leave room for the encoding over the wire CredBlobSize = AllocatedCredBlobSize( InCredential->CredentialBlobSize ); // Align the data following the credential blob Size += ROUND_UP_COUNT( CredBlobSize, ALIGN_WORST ); } // // Compute the size of the strings in the right character set. // Size += CredpConvertStringSize( WtoA, InCredential->TargetName ); Size += CredpConvertStringSize( WtoA, InCredential->Comment ); Size += CredpConvertStringSize( WtoA, InCredential->TargetAlias ); Size += CredpConvertStringSize( WtoA, InCredential->UserName ); // // Compute the size of the attributes // if ( InCredential->AttributeCount != 0 ) { for ( i=0; iAttributeCount; i++ ) { Size += CredpConvertStringSize( WtoA, InCredential->Attributes[i].Keyword ); Size += ROUND_UP_COUNT(InCredential->Attributes[i].ValueSize, ALIGN_WORST); } } Size = ROUND_UP_COUNT( Size, ALIGN_WORST ); return Size; } DWORD CredpConvertOneCredential ( IN WTOA_ENUM WtoA, IN ENCODE_BLOB_ENUM DoDecode, IN PCREDENTIALW InCredential, IN OUT LPBYTE *WherePtr ) /*++ Routine Description: Converts one credential from Ansi to Unicode or vice-versa. Arguments: WtoA - Specifies the direction of the string conversion. DoDecode - Specifies whether CredentialBlob should be encoded, decoded, or neither. If DoBlobDecode, then InCredential really points to a PENCRYPTED_CREDENTIALW. InCredential - Input credentials WherePtr - Specifies the address of the first byte to write the credential to. On input, the strucure should be aligned ALIGN_WORST. Returns a pointer to the first byte after the marshaled credential. The output credential is actually a ENCRYPTED_CREDENTIALW. The caller can use it as a CREDENTIALW depending on the DoDecode value. Return Values: Window status code --*/ { DWORD WinStatus; ULONG i; LPBYTE Where = *WherePtr; LPBYTE OldWhere; PENCRYPTED_CREDENTIALW OutCredential; // // Initialize the base structure // OutCredential = (PENCRYPTED_CREDENTIALW) Where; RtlZeroMemory( OutCredential, sizeof(*OutCredential) ); Where += sizeof(*OutCredential); // Align the running pointer again OldWhere = Where; Where = (PUCHAR) ROUND_UP_POINTER( OldWhere, ALIGN_WORST ); RtlZeroMemory( OldWhere, Where-OldWhere ); // // Copy the fixed size data // OutCredential->Cred.Flags = InCredential->Flags; OutCredential->Cred.Type = InCredential->Type; OutCredential->Cred.LastWritten = InCredential->LastWritten; OutCredential->Cred.CredentialBlobSize = InCredential->CredentialBlobSize; OutCredential->Cred.Persist = InCredential->Persist; OutCredential->Cred.AttributeCount = InCredential->AttributeCount; // // Copy the data we don't know the alignment for. // (ALIGN_WORST so our caller can't blame us.) // if ( InCredential->CredentialBlobSize != 0 ) { ULONG CredBlobSize; OutCredential->Cred.CredentialBlob = Where; RtlCopyMemory( Where, InCredential->CredentialBlob, InCredential->CredentialBlobSize ); Where += InCredential->CredentialBlobSize; // Leave room for the encoding over the wire CredBlobSize = AllocatedCredBlobSize( InCredential->CredentialBlobSize ); // Align the running pointer again OldWhere = Where; // Align the data following the credential blob Where = (LPBYTE) ROUND_UP_POINTER( OldWhere+(CredBlobSize-InCredential->CredentialBlobSize), ALIGN_WORST ); RtlZeroMemory( OldWhere, Where-OldWhere ); // // Encode or decode the Credential blob as requested // switch (DoDecode) { case DoBlobDecode: OutCredential->ClearCredentialBlobSize = ((PENCRYPTED_CREDENTIALW)InCredential)->ClearCredentialBlobSize; #ifndef _CRTEST_EXE_ CredpDecodeCredential( OutCredential ); #endif // _CRTEST_EXE_ break; case DoBlobEncode: OutCredential->ClearCredentialBlobSize = InCredential->CredentialBlobSize; #ifndef _CRTEST_EXE_ if (!CredpEncodeCredential( OutCredential ) ) { return ERROR_INVALID_PARAMETER; } #endif // _CRTEST_EXE_ break; case DoBlobNeither: OutCredential->ClearCredentialBlobSize = InCredential->CredentialBlobSize; break; default: return ERROR_INVALID_PARAMETER; } } if ( InCredential->AttributeCount != 0 ) { // // Push an array of attribute structs // OutCredential->Cred.Attributes = (PCREDENTIAL_ATTRIBUTEW) Where; Where += InCredential->AttributeCount * sizeof(CREDENTIAL_ATTRIBUTEW); // Align the running pointer again OldWhere = Where; Where = (PUCHAR) ROUND_UP_POINTER( OldWhere, ALIGN_WORST ); RtlZeroMemory( OldWhere, Where-OldWhere ); // // Fill it in. // for ( i=0; iAttributeCount; i++ ) { OutCredential->Cred.Attributes[i].Flags = InCredential->Attributes[i].Flags; OutCredential->Cred.Attributes[i].ValueSize = InCredential->Attributes[i].ValueSize; if ( InCredential->Attributes[i].ValueSize != 0 ) { OutCredential->Cred.Attributes[i].Value = Where; RtlCopyMemory( Where, InCredential->Attributes[i].Value, InCredential->Attributes[i].ValueSize ); Where += InCredential->Attributes[i].ValueSize; // Align the running pointer again OldWhere = Where; Where = (PUCHAR) ROUND_UP_POINTER( OldWhere, ALIGN_WORST ); RtlZeroMemory( OldWhere, Where-OldWhere ); } else { OutCredential->Cred.Attributes[i].Value = NULL; } } } // // Convert the strings to the right character set. // WinStatus = CredpConvertString( WtoA, InCredential->TargetName, &OutCredential->Cred.TargetName, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } WinStatus = CredpConvertString( WtoA, InCredential->Comment, &OutCredential->Cred.Comment, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } WinStatus = CredpConvertString( WtoA, InCredential->TargetAlias, &OutCredential->Cred.TargetAlias, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } WinStatus = CredpConvertString( WtoA, InCredential->UserName, &OutCredential->Cred.UserName, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } if ( InCredential->AttributeCount != 0 ) { for ( i=0; iAttributeCount; i++ ) { WinStatus = CredpConvertString( WtoA, InCredential->Attributes[i].Keyword, &OutCredential->Cred.Attributes[i].Keyword, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } } } // Align the running pointer again OldWhere = Where; Where = (PUCHAR) ROUND_UP_POINTER( OldWhere, ALIGN_WORST ); RtlZeroMemory( OldWhere, Where-OldWhere ); *WherePtr = Where; WinStatus = NO_ERROR; // // Be tidy // Cleanup: return WinStatus; } #ifndef _CRTEST_EXE_ DWORD APIENTRY CredpConvertCredential ( IN WTOA_ENUM WtoA, IN ENCODE_BLOB_ENUM DoDecode, IN PCREDENTIALW InCredential, OUT PCREDENTIALW *OutCredential ) /*++ Routine Description: Converts a credential from Ansi to Unicode or vice-versa. Arguments: WtoA - Specifies the direction of the string conversion. DoDecode - Specifies whether CredentialBlob should be encoded, decoded, or neither. InCredential - Input credentials OutCredential - Output credential This credential should be freed using MIDL_user_free. Return Values: Window status code --*/ { DWORD WinStatus; ULONG Size = 0; LPBYTE Where; // // BVTs pass NULL explicitly. We could let the AV be caught in the try/except, but // that would prevent them from being able to run under a debugger. So, handle NULL // explicitly. // if ( InCredential == NULL ) { return ERROR_INVALID_PARAMETER; } // // Use an exception handle to prevent bad user parameter from AVing in our code. // #ifndef _CRTEST_EXE_ try { #endif // _CRTEST_EXE_ // // Compute the size needed for the output credential // Size = CredpConvertOneCredentialSize( WtoA, InCredential ); // // Allocate a buffer for the resultant credential // *OutCredential = (PCREDENTIALW) MIDL_user_allocate( Size ); if ( *OutCredential == NULL ) { WinStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } // // Convert the credential into the allocated buffer // Where = (LPBYTE) *OutCredential; WinStatus = CredpConvertOneCredential( WtoA, DoDecode, InCredential, &Where ); if ( WinStatus != NO_ERROR ) { MIDL_user_free( *OutCredential ); *OutCredential = NULL; } else { ASSERT( (ULONG)(Where - ((LPBYTE)*OutCredential)) == Size ); } Cleanup: NOTHING; #ifndef _CRTEST_EXE_ } except( EXCEPTION_EXECUTE_HANDLER ) { WinStatus = ERROR_INVALID_PARAMETER; } #endif // _CRTEST_EXE_ return WinStatus; } DWORD APIENTRY CredpConvertTargetInfo ( IN WTOA_ENUM WtoA, IN PCREDENTIAL_TARGET_INFORMATIONW InTargetInfo, OUT PCREDENTIAL_TARGET_INFORMATIONW *OutTargetInfo, OUT PULONG OutTargetInfoSize OPTIONAL ) /*++ Routine Description: Converts a target info from Ansi to Unicode or vice-versa. Arguments: WtoA - Specifies the direction of the string conversion. InTargetInfo - Input TargetInfo OutTargetInfo - Output TargetInfo This TargetInfo should be freed using CredFree. OutTargetInfoSize - Size (in bytes) of the buffer returned in OutTargetInfo Return Values: Window status code --*/ { DWORD WinStatus; ULONG Size; LPBYTE Where; *OutTargetInfo = NULL; // // BVTs pass NULL explicitly. We could let the AV be caught in the try/except, but // that would prevent them from being able to run under a debugger. So, handle NULL // explicitly. // if ( InTargetInfo == NULL ) { return ERROR_INVALID_PARAMETER; } // // Use an exception handle to prevent bad user parameter from AVing in our code. // #ifndef _CRTEST_EXE_ try { #endif // _CRTEST_EXE_ // // Compute the size needed for the output target info // Size = sizeof(CREDENTIAL_TARGET_INFORMATIONW); // // Compute the size of the strings in the right character set. // Size += CredpConvertStringSize( WtoA, InTargetInfo->TargetName ); Size += CredpConvertStringSize( WtoA, InTargetInfo->NetbiosServerName ); Size += CredpConvertStringSize( WtoA, InTargetInfo->DnsServerName ); Size += CredpConvertStringSize( WtoA, InTargetInfo->NetbiosDomainName ); Size += CredpConvertStringSize( WtoA, InTargetInfo->DnsDomainName ); Size += CredpConvertStringSize( WtoA, InTargetInfo->DnsTreeName ); Size += CredpConvertStringSize( WtoA, InTargetInfo->PackageName ); Size += InTargetInfo->CredTypeCount * sizeof(DWORD); // // Allocate a buffer for the resultant credential // *OutTargetInfo = (PCREDENTIAL_TARGET_INFORMATIONW) MIDL_user_allocate( Size ); if ( *OutTargetInfo == NULL ) { WinStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } if ( ARGUMENT_PRESENT(OutTargetInfoSize) ) { *OutTargetInfoSize = Size; } Where = (LPBYTE)((*OutTargetInfo) + 1); // // Copy the fixed size data // (*OutTargetInfo)->Flags = InTargetInfo->Flags; // // Copy the DWORD aligned data // (*OutTargetInfo)->CredTypeCount = InTargetInfo->CredTypeCount; if ( InTargetInfo->CredTypeCount != 0 ) { (*OutTargetInfo)->CredTypes = (LPDWORD) Where; RtlCopyMemory( Where, InTargetInfo->CredTypes, InTargetInfo->CredTypeCount * sizeof(DWORD) ); Where += InTargetInfo->CredTypeCount * sizeof(DWORD); } else { (*OutTargetInfo)->CredTypes = NULL; } // // Convert the strings to the right character set. // WinStatus = CredpConvertString( WtoA, InTargetInfo->TargetName, &(*OutTargetInfo)->TargetName, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } WinStatus = CredpConvertString( WtoA, InTargetInfo->NetbiosServerName, &(*OutTargetInfo)->NetbiosServerName, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } WinStatus = CredpConvertString( WtoA, InTargetInfo->DnsServerName, &(*OutTargetInfo)->DnsServerName, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } WinStatus = CredpConvertString( WtoA, InTargetInfo->NetbiosDomainName, &(*OutTargetInfo)->NetbiosDomainName, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } WinStatus = CredpConvertString( WtoA, InTargetInfo->DnsDomainName, &(*OutTargetInfo)->DnsDomainName, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } WinStatus = CredpConvertString( WtoA, InTargetInfo->DnsTreeName, &(*OutTargetInfo)->DnsTreeName, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } WinStatus = CredpConvertString( WtoA, InTargetInfo->PackageName, &(*OutTargetInfo)->PackageName, &Where ); if ( WinStatus != NO_ERROR ) { goto Cleanup; } ASSERT( (ULONG)(Where - ((LPBYTE)*OutTargetInfo)) == Size ); Cleanup: NOTHING; #ifndef _CRTEST_EXE_ } except( EXCEPTION_EXECUTE_HANDLER ) { WinStatus = ERROR_INVALID_PARAMETER; } #endif // _CRTEST_EXE_ // // Be tidy // if ( WinStatus != NO_ERROR ) { if ( *OutTargetInfo != NULL ) { MIDL_user_free( *OutTargetInfo ); *OutTargetInfo = NULL; } } return WinStatus; } #endif // _CRTEST_EXE_ DWORD CredpConvertCredentials ( IN WTOA_ENUM WtoA, IN ENCODE_BLOB_ENUM DoDecode, IN PCREDENTIALW *InCredential, IN ULONG InCredentialCount, OUT PCREDENTIALW **OutCredential ) /*++ Routine Description: Converts a set of credentials from Ansi to Unicode or vice-versa. Arguments: WtoA - Specifies the direction of the string conversion. DoDecode - Specifies whether CredentialBlob should be encoded, decoded, or neither. InCredential - Input credentials OutCredential - Output credential This credential should be freed using MIDL_user_free. Return Values: Window status code --*/ { DWORD WinStatus; ULONG Size = 0; ULONG i; LPBYTE Where; LPBYTE OldWhere; *OutCredential = NULL; // // Use an exception handle to prevent bad user parameter from AVing in our code. // #ifndef _CRTEST_EXE_ try { #endif // _CRTEST_EXE_ // // Compute the size needed for the output credentials // for ( i=0; i