windows-nt/Source/XPSP1/NT/ds/security/base/lsa/uclient/crconv.c
2020-09-26 16:20:57 +08:00

865 lines
21 KiB
C

/*++
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; i<InCredential->AttributeCount; 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; i<InCredential->AttributeCount; 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; i<InCredential->AttributeCount; 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<InCredentialCount; i++ ) {
Size += CredpConvertOneCredentialSize( WtoA, InCredential[i] );
}
//
// Allocate a buffer for the resultant credential array
//
Size += ROUND_UP_COUNT( InCredentialCount * sizeof(PCREDENTIALW), ALIGN_WORST );
*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;
Where += InCredentialCount * sizeof(PCREDENTIALW);
// Align the running pointer again
OldWhere = Where;
Where = (PUCHAR) ROUND_UP_POINTER( OldWhere, ALIGN_WORST );
RtlZeroMemory( OldWhere, Where-OldWhere );
for ( i=0; i<InCredentialCount; i++ ) {
//
// Save a pointer to this credential
//
(*OutCredential)[i] = (PCREDENTIALW) Where;
//
// Marshal the credential
//
WinStatus = CredpConvertOneCredential( WtoA, DoDecode, InCredential[i], &Where );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
}
ASSERT( (ULONG)(Where - ((LPBYTE)*OutCredential)) == Size );
WinStatus = NO_ERROR;
Cleanup: NOTHING;
#ifndef _CRTEST_EXE_
} except( EXCEPTION_EXECUTE_HANDLER ) {
WinStatus = ERROR_INVALID_PARAMETER;
}
#endif // _CRTEST_EXE_
if ( WinStatus != NO_ERROR ) {
if ( *OutCredential != NULL ) {
MIDL_user_free( *OutCredential );
*OutCredential = NULL;
}
}
return WinStatus;
}