windows-nt/Source/XPSP1/NT/ds/security/base/lsa/uclient/credapi.c

3248 lines
76 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
credapi.c
Abstract:
This module contains the RPC client side routines for the credential manager.
Author:
Cliff Van Dyke (CliffV) January 11, 2000
Revision History:
--*/
#include "lsaclip.h"
#include "align.h"
#include "credp.h"
#include <rpcasync.h>
DWORD
CredpNtStatusToWinStatus(
IN NTSTATUS Status
)
/*++
Routine Description:
Covert an NT Status code to a windows status code.
There a enough funky status codes to justify this routine.
Arguments:
Status - NT Status code to convert
Return Values:
Windows status code.
--*/
{
//
// Some HRESULTS should simply be returned to the caller
//
if ( HRESULT_FACILITY(Status) == FACILITY_SCARD ) {
return Status;
}
//
// Translate all other status codes
//
switch ( Status ) {
case STATUS_SUCCESS:
return NO_ERROR;
case STATUS_INVALID_ACCOUNT_NAME:
return ERROR_BAD_USERNAME;
case STATUS_INVALID_PARAMETER_1:
return ERROR_INVALID_FLAGS;
default:
return RtlNtStatusToDosError( Status );
}
}
BOOL
APIENTRY
CredpEncodeCredential (
IN OUT PENCRYPTED_CREDENTIALW Credential
)
/*++
Routine Description:
This routine encodes sensitive credential data for passing via LPC to
the LSA process.
Arguments:
Credential - Specifies the credential to be encode.
Encode the buffer in-place. The caller must ensure there is extra space
available in the buffer pointed to by Credential->CredentialBlob by allocating
a buffer AlocatedCredBlobSize() bytes long.
Return Values:
TRUE on success
None
--*/
{
NTSTATUS Status;
//
// If there is no credential blob,
// we're done.
//
if ( Credential->Cred.CredentialBlob == NULL ||
Credential->Cred.CredentialBlobSize == 0 ) {
Credential->Cred.CredentialBlob = NULL;
Credential->Cred.CredentialBlobSize = 0;
Credential->ClearCredentialBlobSize = 0;
//
// Otherwise RtlEncryptMemory it.
// (That's all we need since we're passing the buffer via LPC.)
//
} else {
ULONG PaddingSize;
//
// Compute the real size of the passed in buffer
//
Credential->Cred.CredentialBlobSize = AllocatedCredBlobSize( Credential->ClearCredentialBlobSize );
//
// Clear the padding at the end to ensure we can compare encrypted blobs
//
PaddingSize = Credential->Cred.CredentialBlobSize - Credential->ClearCredentialBlobSize;
if ( PaddingSize != 0 ) {
RtlZeroMemory( &Credential->Cred.CredentialBlob[Credential->ClearCredentialBlobSize],
PaddingSize );
}
Status = RtlEncryptMemory( Credential->Cred.CredentialBlob,
Credential->Cred.CredentialBlobSize,
RTL_ENCRYPT_OPTION_CROSS_PROCESS );
if ( !NT_SUCCESS(Status)) {
return FALSE;
}
}
return TRUE;
}
BOOL
APIENTRY
CredpDecodeCredential (
IN OUT PENCRYPTED_CREDENTIALW Credential
)
/*++
Routine Description:
This routine decodes sensitive credential data passed via LPC from
the LSA process.
The credential is decoded in-place.
Arguments:
Credential - Specifies the credential to be decode.
Return Values:
None
--*/
{
NTSTATUS Status;
//
// Only decode data if it is there
//
if ( Credential->Cred.CredentialBlobSize != 0 ) {
//
// Sanity check the data
//
if ( Credential->Cred.CredentialBlobSize <
Credential->ClearCredentialBlobSize ) {
return FALSE;
}
//
// Decrypt the data.
//
Status = RtlDecryptMemory( Credential->Cred.CredentialBlob,
Credential->Cred.CredentialBlobSize,
RTL_ENCRYPT_OPTION_CROSS_PROCESS );
if ( !NT_SUCCESS(Status)) {
return FALSE;
}
//
// Set the used size of the buffer.
//
Credential->Cred.CredentialBlobSize = Credential->ClearCredentialBlobSize;
}
return TRUE;
}
//
// Include shared credential conversion ruotines
//
#include <crconv.c>
DWORD
CredpAllocStrFromStr(
IN WTOA_ENUM WtoA,
IN LPCWSTR InputString,
IN BOOLEAN NullOk,
OUT LPWSTR *OutString
)
/*++
Routine Description:
Convert a string to another format.
Exceptions are caught. So this routine can be used to capture user data.
Arguments:
WtoA - Specifies the direction of the string conversion.
InputString - Specifies the zero terminated string to convert.
NullOk - if TRUE, a NULL string or zero length string is OK.
OutputString - Converted zero terminated string.
The buffer must be freed using MIDL_user_free.
Return Value:
Status of the operation.
--*/
{
DWORD WinStatus;
ULONG Size;
LPWSTR LocalString = NULL;
LPBYTE Where;
*OutString = NULL;
//
// Use an exception handle to prevent bad user parameter from AVing in our code.
//
try {
//
// Determine the size of the string buffer.
//
Size = CredpConvertStringSize ( WtoA, (LPWSTR)InputString );
if ( Size == 0 ) {
if ( NullOk ) {
WinStatus = NO_ERROR;
} else {
WinStatus = ERROR_INVALID_PARAMETER;
}
goto Cleanup;
}
//
// Allocate a buffer for the converted string
//
*OutString = MIDL_user_allocate( Size );
if ( *OutString == NULL ) {
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
//
// Covert the string
//
Where = (LPBYTE) *OutString;
WinStatus = CredpConvertString ( WtoA,
(LPWSTR)InputString,
OutString,
&Where );
Cleanup: NOTHING;
} except( EXCEPTION_EXECUTE_HANDLER ) {
WinStatus = ERROR_INVALID_PARAMETER;
}
//
// Clean up
//
if ( WinStatus != NO_ERROR ) {
if ( *OutString != NULL ) {
MIDL_user_free( *OutString );
*OutString = NULL;
}
}
return WinStatus;
}
BOOL
APIENTRY
CredWriteA (
IN PCREDENTIALA Credential,
IN DWORD Flags
)
/*++
Routine Description:
The ANSI version of CredWriteW.
Arguments:
See CredWriteW.
Return Values:
See CredWriteW.
--*/
{
DWORD WinStatus;
PCREDENTIALW EncodedCredential = NULL;
//
// Encode the credential before LPCing it to the LSA process and convert to UNICODE
//
WinStatus = CredpConvertCredential ( DoAtoW, // Ansi to Unicode
DoBlobEncode, // Encode
(PCREDENTIALW)Credential, // Input credential
&EncodedCredential ); // Output credential
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrWrite(
NULL, // This API is always local.
(PENCRYPTED_CREDENTIALW)EncodedCredential,
Flags );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
MIDL_user_free( EncodedCredential );
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredWriteW (
IN PCREDENTIALW Credential,
IN DWORD Flags
)
/*++
Routine Description:
The CredWrite API creates a new credential or modifies an existing
credential in the user's credential set. The new credential is
associated with the logon session of the current token. The token
must not have the user's SID disabled.
The CredWrite API creates a credential if none already exists by the
specified TargetName. If the specified TargetName already exists, the
specified credential replaces the existing one.
The CredWrite API is available in ANSI and UNICODE versions.
Arguments:
Credential - Specifies the credential to be written.
Flags - Specifies flags to control the operation of the API.
The following flags are defined:
CRED_PRESERVE_CREDENTIAL_BLOB: The credential blob should be preserved from the
already existing credential with the same credential name and credential type.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_NO_SUCH_LOGON_SESSION - The logon session does not exist or
there is no credential set associated with this logon session.
Network logon sessions do not have an associated credential set.
ERROR_INVALID_PARAMETER - Certain fields may not be changed in an
existing credential. If such a field does not match the value
specified in the existing credential, this error is returned.
ERROR_NOT_FOUND - There is no credential with the specified TargetName.
Returned only if CRED_PRESERVE_CREDENTIAL_BLOB was specified.
--*/
{
DWORD WinStatus;
PCREDENTIALW EncodedCredential = NULL;
//
// Encode the credential before LPCing it to the LSA process.
//
WinStatus = CredpConvertCredential ( DoWtoW, // Unicode to Unicode
DoBlobEncode, // Encode
(PCREDENTIALW)Credential, // Input credential
&EncodedCredential ); // Output credential
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrWrite(
NULL, // This API is always local.
(PENCRYPTED_CREDENTIALW)EncodedCredential,
Flags );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
MIDL_user_free( EncodedCredential );
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredReadA (
IN LPCSTR TargetName,
IN ULONG Type,
IN DWORD Flags,
OUT PCREDENTIALA *Credential
)
/*++
Routine Description:
The ANSI version of CredReadW.
Arguments:
See CredReadW.
Return Values:
See CredReadW.
--*/
{
DWORD WinStatus;
PCREDENTIALW LocalCredential = NULL;
LPWSTR UnicodeTargetName = NULL;
//
// Convert input args to Unicode
//
WinStatus = CredpAllocStrFromStr( DoAtoW, (LPWSTR) TargetName, FALSE, &UnicodeTargetName );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrRead(
NULL, // This API is always local.
UnicodeTargetName,
Type,
Flags,
(PENCRYPTED_CREDENTIALW *)&LocalCredential );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
//
// Decode the returned credential and align appropriate blobs to ALIGN_WORST bounday
//
if ( WinStatus == NO_ERROR ) {
WinStatus = CredpConvertCredential ( DoWtoA, // Unicode to Ansi
DoBlobDecode, // Decode the credential blob
LocalCredential,
(PCREDENTIALW *)Credential );
}
Cleanup:
if ( UnicodeTargetName != NULL ) {
MIDL_user_free( UnicodeTargetName );
}
if ( LocalCredential != NULL ) {
MIDL_user_free( LocalCredential );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredReadW (
IN LPCWSTR TargetName,
IN ULONG Type,
IN DWORD Flags,
OUT PCREDENTIALW *Credential
)
/*++
Routine Description:
The CredRead API reads a credential from the user's credential set.
The credential set used is the one associated with the logon session
of the current token. The token must not have the user's SID disabled.
The CredRead API is available in ANSI and UNICODE versions.
Arguments:
TargetName - Specifies the name of the credential to read.
Type - Specifies the Type of the credential to find.
One of the CRED_TYPE_* values should be specified.
Flags - Specifies flags to control the operation of the API.
Reserved. Must be zero.
Credential - Returns a pointer to the credential. The returned buffer
must be freed by calling CredFree.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_NOT_FOUND - There is no credential with the specified TargetName.
ERROR_NO_SUCH_LOGON_SESSION - The logon session does not exist or
there is no credential set associated with this logon session.
Network logon sessions do not have an associated credential set.
--*/
{
DWORD WinStatus;
PCREDENTIALW LocalCredential = NULL;
LPWSTR UnicodeTargetName = NULL;
//
// Capture the input args
//
WinStatus = CredpAllocStrFromStr( DoWtoW, TargetName, FALSE, &UnicodeTargetName );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrRead(
NULL, // This API is always local.
UnicodeTargetName,
Type,
Flags,
(PENCRYPTED_CREDENTIALW *)&LocalCredential );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
//
// Decode the returned credential and align appropriate blobs to ALIGN_WORST bounday
//
if ( WinStatus == NO_ERROR ) {
WinStatus = CredpConvertCredential ( DoWtoW, // Unicode to Unicode
DoBlobDecode, // Decode the credential blob
LocalCredential,
Credential );
}
Cleanup:
if ( UnicodeTargetName != NULL ) {
MIDL_user_free( UnicodeTargetName );
}
if ( LocalCredential != NULL ) {
MIDL_user_free( LocalCredential );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredEnumerateA (
IN LPCSTR Filter,
IN DWORD Flags,
OUT LPDWORD Count,
OUT PCREDENTIALA **Credentials
)
/*++
Routine Description:
The ANSI version of CredEnumerateW
Arguments:
See CredEnumerateW
Return Values:
See CredEnumerateW
--*/
{
DWORD WinStatus;
CREDENTIAL_ARRAY CredentialArray;
LPWSTR UnicodeFilter = NULL;
//
// Force RPC to allocate the return structure
//
*Count = 0;
*Credentials = NULL;
CredentialArray.CredentialCount = 0;
CredentialArray.Credentials = NULL;
//
// Convert input args to Unicode
//
WinStatus = CredpAllocStrFromStr( DoAtoW, (LPWSTR)Filter, TRUE, &UnicodeFilter );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrEnumerate(
NULL, // This API is always local.
UnicodeFilter,
Flags,
&CredentialArray );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
//
// Decode the returned credentials and align appropriate blobs to ALIGN_WORST bounday
//
if ( WinStatus == NO_ERROR ) {
WinStatus = CredpConvertCredentials ( DoWtoA, // Unicode to Ansi
DoBlobDecode, // Decode the credential blob
(PCREDENTIALW *)CredentialArray.Credentials,
CredentialArray.CredentialCount,
(PCREDENTIALW **)Credentials );
if ( WinStatus == NO_ERROR ) {
*Count = CredentialArray.CredentialCount;
}
}
Cleanup:
if ( CredentialArray.Credentials != NULL ) {
MIDL_user_free( CredentialArray.Credentials );
}
if ( UnicodeFilter != NULL ) {
MIDL_user_free( UnicodeFilter );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus) ;
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredEnumerateW (
IN LPCWSTR Filter,
IN DWORD Flags,
OUT LPDWORD Count,
OUT PCREDENTIALW **Credentials
)
/*++
Routine Description:
The CredEnumerate API enumerates the credentials from the user's credential set.
The credential set used is the one associated with the logon session
of the current token. The token must not have the user's SID disabled.
The CredEnumerate API is available in ANSI and UNICODE versions.
Arguments:
Filter - Specifies a filter for the returned credentials. Only credentials
with a TargetName matching the filter will be returned. The filter specifies
a name prefix followed by an asterisk. For instance, the filter "FRED*" will
return all credentials with a TargetName beginning with the string "FRED".
If NULL is specified, all credentials will be returned.
Flags - Specifies flags to control the operation of the API.
Reserved. Must be zero.
Count - Returns a count of the number of credentials returned in Credentials.
Credentials - Returns a pointer to an array of pointers to credentials.
The returned buffer must be freed by calling CredFree.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_NOT_FOUND - There is no credentials matching the specified Filter.
ERROR_NO_SUCH_LOGON_SESSION - The logon session does not exist or
there is no credential set associated with this logon session.
Network logon sessions do not have an associated credential set.
--*/
{
DWORD WinStatus;
CREDENTIAL_ARRAY CredentialArray;
LPWSTR UnicodeFilter = NULL;
//
// Force RPC to allocate the return structure
//
*Count = 0;
*Credentials = NULL;
CredentialArray.CredentialCount = 0;
CredentialArray.Credentials = NULL;
//
// Capture the user's input parameters
//
WinStatus = CredpAllocStrFromStr( DoWtoW, Filter, TRUE, &UnicodeFilter );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrEnumerate(
NULL, // This API is always local.
UnicodeFilter,
Flags,
&CredentialArray );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
//
// Decode the returned credentials and align appropriate blobs to ALIGN_WORST bounday
//
if ( WinStatus == NO_ERROR ) {
WinStatus = CredpConvertCredentials ( DoWtoW, // Unicode to Unicode
DoBlobDecode, // Decode the credential blob
(PCREDENTIALW *)CredentialArray.Credentials,
CredentialArray.CredentialCount,
Credentials );
if ( WinStatus == NO_ERROR ) {
*Count = CredentialArray.CredentialCount;
}
}
Cleanup:
if ( CredentialArray.Credentials != NULL ) {
MIDL_user_free( CredentialArray.Credentials );
}
if ( UnicodeFilter != NULL ) {
MIDL_user_free( UnicodeFilter );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus) ;
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredWriteDomainCredentialsA (
IN PCREDENTIAL_TARGET_INFORMATIONA TargetInfo,
IN PCREDENTIALA Credential,
IN DWORD Flags
)
/*++
Routine Description:
The ANSI version of CredWriteDomainCredentialsW
Arguments:
See CredWriteDomainCredentialsW
Return Values:
See CredWriteDomainCredentialsW
--*/
{
DWORD WinStatus;
PCREDENTIAL_TARGET_INFORMATIONW UnicodeTargetInfo = NULL;
PCREDENTIALW EncodedCredential = NULL;
//
// Encode the credential before LPCing it to the LSA process and convert to UNICODE
//
WinStatus = CredpConvertCredential ( DoAtoW, // Ansi to Unicode
DoBlobEncode, // Encode
(PCREDENTIALW)Credential, // Input credential
&EncodedCredential ); // Output credential
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Convert the target info to Unicode
//
WinStatus = CredpConvertTargetInfo( DoAtoW, // Ansi to Unicode
(PCREDENTIAL_TARGET_INFORMATIONW) TargetInfo,
&UnicodeTargetInfo,
NULL );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrWriteDomainCredentials(
NULL, // This API is always local.
UnicodeTargetInfo,
(PENCRYPTED_CREDENTIALW)EncodedCredential,
Flags );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
Cleanup:
if ( EncodedCredential != NULL ) {
MIDL_user_free( EncodedCredential );
}
if ( UnicodeTargetInfo != NULL ) {
MIDL_user_free( UnicodeTargetInfo );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredWriteDomainCredentialsW (
IN PCREDENTIAL_TARGET_INFORMATIONW TargetInfo,
IN PCREDENTIALW Credential,
IN DWORD Flags
)
/*++
Routine Description:
The CredWriteDomainCredentials API writes a new domain
credential to the user's credential set. The new credential is
associated with the logon session of the current token. The token
must not have the user's SID disabled.
CredWriteDomainCredentials differs from CredWrite in that it handles
the idiosyncrasies of domain (CRED_TYPE_DOMAIN_PASSWORD or CRED_TYPE_DOMAIN_CERTIFICATE)
credentials. Domain credentials contain more than one target field.
At least one of the naming parameters must be specified: NetbiosServerName,
DnsServerName, NetbiosDomainName, DnsDomainName or DnsForestName.
The CredWriteDomainCredentials API is available in ANSI and UNICODE versions.
Arguments:
TargetInfo - Specifies the target information identifying the target server.
Credential - Specifies the credential to be written.
Flags - Specifies flags to control the operation of the API.
Reserved. Must be zero.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_NO_SUCH_LOGON_SESSION - The logon session does not exist or
there is no credential set associated with this logon session.
Network logon sessions do not have an associated credential set.
ERROR_INVALID_PARAMETER - Certain fields may not be changed in an
existing credential. If such a field does not match the value
specified in the existing credential, this error is returned.
ERROR_INVALID_PARAMETER - None of the naming parameters were specified
or the credential specified did not have the Type field set to
CRED_TYPE_DOMAIN_PASSWORD or CRED_TYPE_DOMAIN_CERTIFICATE.
--*/
{
DWORD WinStatus;
PCREDENTIALW EncodedCredential = NULL;
PCREDENTIAL_TARGET_INFORMATIONW UnicodeTargetInfo = NULL;
//
// Encode the credential before LPCing it to the LSA process
//
WinStatus = CredpConvertCredential ( DoWtoW, // Unicode to Unicode
DoBlobEncode, // Encode
(PCREDENTIALW)Credential, // Input credential
&EncodedCredential ); // Output credential
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Capture the target info to prevent us from AVing in our code.
//
WinStatus = CredpConvertTargetInfo( DoWtoW, // Unicode to Unicode
(PCREDENTIAL_TARGET_INFORMATIONW) TargetInfo,
&UnicodeTargetInfo,
NULL );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrWriteDomainCredentials(
NULL, // This API is always local.
TargetInfo,
(PENCRYPTED_CREDENTIALW)EncodedCredential,
Flags );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
Cleanup:
if ( EncodedCredential != NULL ) {
MIDL_user_free( EncodedCredential );
}
if ( UnicodeTargetInfo != NULL ) {
MIDL_user_free( UnicodeTargetInfo );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredReadDomainCredentialsA (
IN PCREDENTIAL_TARGET_INFORMATIONA TargetInfo,
IN DWORD Flags,
OUT LPDWORD Count,
OUT PCREDENTIALA **Credentials
)
/*++
Routine Description:
The ANSI version of CredReadDomainCredentialsW
Arguments:
See CredReadDomainCredentialsW
Return Values:
See CredReadDomainCredentialsW
--*/
{
DWORD WinStatus;
CREDENTIAL_ARRAY CredentialArray;
PCREDENTIAL_TARGET_INFORMATIONW UnicodeTargetInfo = NULL;
//
// Force RPC to allocate the return structure
//
*Count = 0;
*Credentials = NULL;
CredentialArray.CredentialCount = 0;
CredentialArray.Credentials = NULL;
//
// Convert the target info to Unicode
//
WinStatus = CredpConvertTargetInfo( DoAtoW, // Ansi to Unicode
(PCREDENTIAL_TARGET_INFORMATIONW) TargetInfo,
&UnicodeTargetInfo,
NULL );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
Status = CredrReadDomainCredentials(
NULL, // This API is always local.
UnicodeTargetInfo,
Flags,
&CredentialArray );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
//
// Decode the returned credentials and align appropriate blobs to ALIGN_WORST bounday
//
if ( WinStatus == NO_ERROR ) {
WinStatus = CredpConvertCredentials ( DoWtoA, // Unicode to Ansi
DoBlobDecode, // Decode the credential blob
(PCREDENTIALW *)CredentialArray.Credentials,
CredentialArray.CredentialCount,
(PCREDENTIALW **)Credentials );
if ( WinStatus == NO_ERROR ) {
*Count = CredentialArray.CredentialCount;
}
}
Cleanup:
if ( CredentialArray.Credentials != NULL ) {
MIDL_user_free( CredentialArray.Credentials );
}
if ( UnicodeTargetInfo != NULL ) {
MIDL_user_free( UnicodeTargetInfo );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus) ;
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredReadDomainCredentialsW (
IN PCREDENTIAL_TARGET_INFORMATIONW TargetInfo,
IN DWORD Flags,
OUT LPDWORD Count,
OUT PCREDENTIALW **Credentials
)
/*++
Routine Description:
The CredReadDomainCredentials API reads the domain credentials from the user's credential set.
The credential set used is the one associated with the logon session
of the current token. The token must not have the user's SID disabled.
CredReadDomainCredentials differs from CredRead in that it handles the
idiosyncrasies of domain (CRED_TYPE_DOMAIN_PASSWORD or CRED_TYPE_DOMAIN_CERTIFICATE)
credentials. Domain credentials contain more than one target field.
At least one of the naming parameters must be specified: NetbiosServerName,
DnsServerName, NetbiosDomainName, DnsDomainName or DnsForestName. This API returns
the most specific credentials that match the naming parameters. That is, if there
is a credential that matches the target server name and a credential that matches
the target domain name, only the server specific credential is returned. This is
the credential that would be used.
The CredReadDomainCredentials API is available in ANSI and UNICODE versions.
Arguments:
TargetInfo - Specifies the target information identifying the target ser
Flags - Specifies flags to control the operation of the API.
The following flags are defined:
CRED_CACHE_TARGET_INFORMATION: The TargetInfo should be cached for a subsequent read via
CredGetTargetInfo.
Count - Returns a count of the number of credentials returned in Credentials.
Credentials - Returns a pointer to an array of pointers to credentials.
The most specific existing credential matching the TargetInfo is returned.
If there is both a CRED_TYPE_DOMAIN_PASSWORD and CRED_TYPE_DOMAIN_CERTIFICATE
credential, both are returned. If a connection were to be made to the named
target, this most-specific credential would be used.
The returned buffer must be freed by calling CredFree.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_INVALID_PARAMETER - None of the naming parameters were specified.
ERROR_NOT_FOUND - There are no credentials matching the specified naming parameters.
ERROR_NO_SUCH_LOGON_SESSION - The logon session does not exist or
there is no credential set associated with this logon session.
Network logon sessions do not have an associated credential set.
--*/
{
DWORD WinStatus;
CREDENTIAL_ARRAY CredentialArray;
PCREDENTIAL_TARGET_INFORMATIONW UnicodeTargetInfo = NULL;
//
// Force RPC to allocate the return structure
//
*Count = 0;
*Credentials = NULL;
CredentialArray.CredentialCount = 0;
CredentialArray.Credentials = NULL;
//
// Capture the user's parameters to prevent AVing in our code.
//
WinStatus = CredpConvertTargetInfo( DoWtoW, // Unicode to Unicode
(PCREDENTIAL_TARGET_INFORMATIONW) TargetInfo,
&UnicodeTargetInfo,
NULL );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
Status = CredrReadDomainCredentials(
NULL, // This API is always local.
TargetInfo,
Flags,
&CredentialArray );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
//
// Decode the returned credentials and align appropriate blobs to ALIGN_WORST bounday
//
if ( WinStatus == NO_ERROR ) {
WinStatus = CredpConvertCredentials ( DoWtoW, // Unicode to Unicode
DoBlobDecode, // Decode the credential blob
(PCREDENTIALW *)CredentialArray.Credentials,
CredentialArray.CredentialCount,
Credentials );
if ( WinStatus == NO_ERROR ) {
*Count = CredentialArray.CredentialCount;
}
}
Cleanup:
if ( CredentialArray.Credentials != NULL ) {
MIDL_user_free( CredentialArray.Credentials );
}
if ( UnicodeTargetInfo != NULL ) {
MIDL_user_free( UnicodeTargetInfo );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus) ;
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredDeleteA (
IN LPCSTR TargetName,
IN ULONG Type,
IN DWORD Flags
)
/*++
Routine Description:
The ANSI version of CredDeleteW
Arguments:
See CredDeleteW
Return Values:
See CredDeleteW
--*/
{
DWORD WinStatus;
LPWSTR UnicodeTargetName = NULL;
//
// Convert input args to Unicode
//
WinStatus = CredpAllocStrFromStr( DoAtoW, (LPWSTR)TargetName, FALSE, &UnicodeTargetName );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrDelete(
NULL, // This API is always local.
UnicodeTargetName,
Type,
Flags );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
//
// Be Tidy
//
Cleanup:
if ( UnicodeTargetName != NULL ) {
MIDL_user_free( UnicodeTargetName );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredDeleteW (
IN LPCWSTR TargetName,
IN ULONG Type,
IN DWORD Flags
)
/*++
Routine Description:
The CredDelete API deletes a credential from the user's credential set.
The credential set used is the one associated with the logon session
of the current token. The token must not have the user's SID disabled.
The CredDelete API is available in ANSI and UNICODE versions.
Arguments:
TargetName - Specifies the name of the credential to delete.
Type - Specifies the Type of the credential to find.
One of the CRED_TYPE_* values should be specified.
Flags - Specifies flags to control the operation of the API.
Reserved. Must be zero.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_NOT_FOUND - There is no credential with the specified TargetName.
ERROR_NO_SUCH_LOGON_SESSION - The logon session does not exist or
there is no credential set associated with this logon session.
Network logon sessions do not have an associated credential set.
--*/
{
DWORD WinStatus;
LPWSTR UnicodeTargetName = NULL;
//
// Capture the input arguments
//
WinStatus = CredpAllocStrFromStr( DoWtoW, TargetName, FALSE, &UnicodeTargetName );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrDelete(
NULL, // This API is always local.
UnicodeTargetName,
Type,
Flags );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
//
// Be Tidy
//
Cleanup:
if ( UnicodeTargetName != NULL ) {
MIDL_user_free( UnicodeTargetName );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredRenameA (
IN LPCSTR OldTargetName,
IN LPCSTR NewTargetName,
IN ULONG Type,
IN DWORD Flags
)
/*++
Routine Description:
The ANSI version of CredRenameW
Arguments:
See CredRenameW
Return Values:
See CredRenameW
--*/
{
DWORD WinStatus;
LPWSTR UnicodeOldTargetName = NULL;
LPWSTR UnicodeNewTargetName = NULL;
//
// Capture the input arguments
//
WinStatus = CredpAllocStrFromStr( DoAtoW, (LPCWSTR)OldTargetName, FALSE, &UnicodeOldTargetName );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
WinStatus = CredpAllocStrFromStr( DoAtoW, (LPCWSTR)NewTargetName, FALSE, &UnicodeNewTargetName );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrRename(
NULL, // This API is always local.
UnicodeOldTargetName,
UnicodeNewTargetName,
Type,
Flags );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
//
// Be Tidy
//
Cleanup:
if ( UnicodeOldTargetName != NULL ) {
MIDL_user_free( UnicodeOldTargetName );
}
if ( UnicodeNewTargetName != NULL ) {
MIDL_user_free( UnicodeNewTargetName );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredRenameW (
IN LPCWSTR OldTargetName,
IN LPCWSTR NewTargetName,
IN ULONG Type,
IN DWORD Flags
)
/*++
Routine Description:
The CredRename API renames a credential in the user's credential set.
The credential set used is the one associated with the logon session
of the current token. The token must not have the user's SID disabled.
The CredRename API is available in ANSI and UNICODE versions.
Arguments:
OldTargetName - Specifies the current name of the credential to rename.
NewTargetName - Specifies the new name of the credential.
Type - Specifies the Type of the credential to rename
One of the CRED_TYPE_* values should be specified.
Flags - Specifies flags to control the operation of the API.
Reserved. Must be zero.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_NOT_FOUND - There is no credential with the specified OldTargetName.
ERROR_ALREADY_EXISTS - There is already a credential named NewTargetName.
ERROR_NO_SUCH_LOGON_SESSION - The logon session does not exist or
there is no credential set associated with this logon session.
Network logon sessions do not have an associated credential set.
--*/
{
DWORD WinStatus;
LPWSTR UnicodeOldTargetName = NULL;
LPWSTR UnicodeNewTargetName = NULL;
//
// Capture the input arguments
//
WinStatus = CredpAllocStrFromStr( DoWtoW, OldTargetName, FALSE, &UnicodeOldTargetName );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
WinStatus = CredpAllocStrFromStr( DoWtoW, NewTargetName, FALSE, &UnicodeNewTargetName );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrRename(
NULL, // This API is always local.
UnicodeOldTargetName,
UnicodeNewTargetName,
Type,
Flags );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
//
// Be Tidy
//
Cleanup:
if ( UnicodeOldTargetName != NULL ) {
MIDL_user_free( UnicodeOldTargetName );
}
if ( UnicodeNewTargetName != NULL ) {
MIDL_user_free( UnicodeNewTargetName );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
VOID
APIENTRY
CredFree (
IN PVOID Buffer
)
/*++
Routine Description:
The CredFree API de-allocates a buffer returned from the various other Credential API.
Arguments:
Buffer -Specifies the buffer to be de-allocated.
Return Values:
None
--*/
{
MIDL_user_free( Buffer );
}
BOOL
APIENTRY
CredGetTargetInfoA (
IN LPCSTR ServerName,
IN DWORD Flags,
OUT PCREDENTIAL_TARGET_INFORMATIONA *TargetInfo
)
/*++
Routine Description:
The ANSI version of CredGetTargetInfoW
Arguments:
See CredGetTargetInfoW
Return Values:
See CredGetTargetInfoW
--*/
{
DWORD WinStatus;
LPWSTR UnicodeServerName = NULL;
PCREDENTIAL_TARGET_INFORMATIONW UnicodeTargetInfo = NULL;
//
// Convert input args to Unicode
//
WinStatus = CredpAllocStrFromStr( DoAtoW, (LPWSTR)ServerName, FALSE, &UnicodeServerName );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrGetTargetInfo(
NULL, // This API is always local.
UnicodeServerName,
Flags,
&UnicodeTargetInfo );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Convert the target info to ANSI
//
WinStatus = CredpConvertTargetInfo( DoWtoA, // Unicode to Ansi
UnicodeTargetInfo,
(PCREDENTIAL_TARGET_INFORMATIONW *)TargetInfo,
NULL );
Cleanup:
if ( UnicodeTargetInfo != NULL ) {
MIDL_user_free( UnicodeTargetInfo );
}
if ( UnicodeServerName != NULL ) {
MIDL_user_free( UnicodeServerName );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredGetTargetInfoW (
IN LPCWSTR ServerName,
IN DWORD Flags,
OUT PCREDENTIAL_TARGET_INFORMATIONW *TargetInfo
)
/*++
Routine Description:
The CredGetTargetInfo API gets all of the known target name information
for the named target machine. This executed locally
and does not need any particular privilege. The information returned is expected
to be passed to the CredReadDomainCredentials and CredWriteDomainCredentials APIs.
The information should not be used for any other purpose.
Authentication packages compute TargetInfo when attempting to authenticate to
ServerName. The authentication packages cache this target information to make it
available to CredGetTargetInfo. Therefore, the target information will only be
available if we've recently attempted to authenticate to ServerName.
Arguments:
ServerName - This parameter specifies the name of the machine to get the information
for.
Flags - Specifies flags to control the operation of the API.
CRED_ALLOW_NAME_RESOLUTION - Specifies that if no target info can be found for
TargetName, then name resolution should be done on TargetName to convert it
to other forms. If target info exists for any of those other forms, that
target info is returned. Currently only DNS name resolution is done.
This bit is useful if the application doesn't call the authentication package
directly. The application might pass the TargetName to another layer of software
to authenticate to the server. That layer of software might resolve the name and
pass the resolved name to the authentication package. As such, there will be no
target info for the original TargetName.
TargetInfo - Returns a pointer to the target information.
At least one of the returned fields of TargetInfo will be non-NULL.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_NOT_FOUND - There is no target info for the named server.
--*/
{
DWORD WinStatus;
LPWSTR UnicodeServerName = NULL;
PCREDENTIAL_TARGET_INFORMATIONW UnicodeTargetInfo = NULL;
//
// Capture the input arguments
//
WinStatus = CredpAllocStrFromStr( DoWtoW, ServerName, FALSE, &UnicodeServerName );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrGetTargetInfo(
NULL, // This API is always local.
UnicodeServerName,
Flags,
&UnicodeTargetInfo );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Convert the target info to ANSI
//
WinStatus = CredpConvertTargetInfo( DoWtoW, // Unicode to Unicode
UnicodeTargetInfo,
TargetInfo,
NULL );
Cleanup:
if ( UnicodeTargetInfo != NULL ) {
MIDL_user_free( UnicodeTargetInfo );
}
if ( UnicodeServerName != NULL ) {
MIDL_user_free( UnicodeServerName );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredGetSessionTypes (
IN DWORD MaximumPersistCount,
OUT LPDWORD MaximumPersist
)
/*++
Routine Description:
CredGetSessionTypes returns the maximum persistence supported by the current logon
session.
For whistler, CRED_PERSIST_LOCAL_MACHINE and CRED_PERSIST_ENTERPRISE credentials can not
be stored for sessions where the profile is not loaded. If future releases, credentials
might not be associated with the user's profile.
Arguments:
MaximumPersistCount - Specifies the number of elements in the MaximumPersist array.
The caller should specify CRED_TYPE_MAXIMUM for this parameter.
MaximumPersist - Returns the maximum persistance supported by the current logon session for
each credential type. Index into the array with one of the CRED_TYPE_* defines.
Returns CRED_PERSIST_NONE if no credential of this type can be stored.
Returns CRED_PERSIST_SESSION if only session specific credential may be stored.
Returns CRED_PERSIST_LOCAL_MACHINE if session specific and machine specific credentials
may be stored.
Returns CRED_PERSIST_ENTERPRISE if any credential may be stored.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_NO_SUCH_LOGON_SESSION - The logon session does not exist or
there is no credential set associated with this logon session.
Network logon sessions do not have an associated credential set.
--*/
{
DWORD WinStatus;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrGetSessionTypes(
NULL, // This API is always local.
MaximumPersistCount,
MaximumPersist );
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredProfileLoaded (
VOID
)
/*++
Routine Description:
The CredProfileLoaded API is a private API used by LoadUserProfile to notify the
credential manager that the profile for the current user has been loaded.
The caller must be impersonating the logged on user.
Arguments:
None.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_NO_SUCH_LOGON_SESSION - The logon session does not exist or
there is no credential set associated with this logon session.
Network logon sessions do not have an associated credential set.
--*/
{
DWORD WinStatus;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
NTSTATUS Status;
//
// Call RPC version of the API.
//
Status = CredrProfileLoaded(
NULL ); // This API is always local.
WinStatus = CredpNtStatusToWinStatus( Status );
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
WinStatus = RpcExceptionCode();
} RpcEndExcept;
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
VOID
CredpMarshalChar(
IN OUT LPWSTR *Current,
IN ULONG Byte
)
/*++
Routine Description:
This routine marshals 6 bits into a buffer.
Arguments:
Current - On input, points to a pointer of the current location in the marshaled buffer.
On output, is modified to point to the next available location in the marshaled buffer.
Byte - Specifies the 6 bits to marshal
Return Values:
None.
--*/
{
UCHAR MappingTable[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '-'
};
if ( Byte > 0x3F ) {
*(*Current) = '=';
} else {
*(*Current) = MappingTable[Byte];
}
(*Current)++;
}
ULONG
CredpMarshalSize(
IN ULONG ByteCount
)
/*++
Routine Description:
This routine returns the number of bytes that would be marshaled by
CredpMarshalBytes when passed a buffer ByteCount bytes long.
Arguments:
ByteCount - Specifies the number of bytes to marshal
Return Values:
The number of bytes that would be marshaled.
--*/
{
ULONG CharCount;
ULONG ExtraBytes;
//
// If byte count is a multiple of 3, the char count is straight forward
//
CharCount = ByteCount / 3 * 4;
ExtraBytes = ByteCount % 3;
if ( ExtraBytes == 1 ) {
CharCount += 2;
} else if ( ExtraBytes == 2 ) {
CharCount += 3;
}
return CharCount * sizeof(WCHAR);
}
VOID
CredpMarshalBytes(
IN OUT LPWSTR *Current,
IN LPBYTE Bytes,
IN ULONG ByteCount
)
/*++
Routine Description:
This routine marshals bytes into a buffer.
Arguments:
Current - On input, points to a pointer of the current location in the marshaled buffer.
On output, is modified to point to the next available location in the marshaled buffer.
Bytes - Specifies the buffer to marshal
ByteCount - Specifies the number of bytes to marshal
Return Values:
None.
--*/
{
ULONG i;
union {
BYTE ByteValues[3];
struct {
ULONG Bits1 :6;
ULONG Bits2 :6;
ULONG Bits3 :6;
ULONG Bits4 :6;
} BitValues;
} Bits;
//
// Loop through marshaling 3 bytes at a time.
//
for ( i=0; i<ByteCount; i+=3 ) {
ULONG BytesToCopy;
//
// Grab up to 3 bytes from the input buffer.
//
BytesToCopy = min( 3, ByteCount-i );
if ( BytesToCopy != 3 ) {
RtlZeroMemory( Bits.ByteValues, 3);
}
RtlCopyMemory( Bits.ByteValues, &Bytes[i], BytesToCopy );
//
// Marshal the first twelve bits
//
CredpMarshalChar( Current, Bits.BitValues.Bits1 );
CredpMarshalChar( Current, Bits.BitValues.Bits2 );
//
// Optionally marshal the next bits.
//
if ( BytesToCopy > 1 ) {
CredpMarshalChar( Current, Bits.BitValues.Bits3 );
if ( BytesToCopy > 2 ) {
CredpMarshalChar( Current, Bits.BitValues.Bits4 );
}
}
}
}
BOOL
CredpUnmarshalChar(
IN OUT LPWSTR *Current,
IN LPCWSTR End,
OUT PULONG Value
)
/*++
Routine Description:
This routine unmarshals 6 bits from a buffer.
Arguments:
Current - On input, points to a pointer of the current location in the marshaled buffer.
On output, is modified to point to the next available location in the marshaled buffer.
End - Points to the first character beyond the end of the marshaled buffer.
Value - returns the unmarshaled 6 bits value.
Return Values:
TRUE - if the bytes we're unmarshaled sucessfully
FALSE - if the byte could not be unmarshaled from the buffer.
--*/
{
WCHAR CurrentChar;
//
// Ensure the character is available in the buffer
//
if ( *Current >= End ) {
return FALSE;
}
//
// Grab the character
//
CurrentChar = *(*Current);
(*Current)++;
//
// Map it the 6 bit value
//
switch ( CurrentChar ) {
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
*Value = CurrentChar - 'A';
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
*Value = CurrentChar - 'a' + 26;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
*Value = CurrentChar - '0' + 26 + 26;
break;
case '#':
*Value = 26 + 26 + 10;
break;
case '-':
*Value = 26 + 26 + 10 + 1;
break;
default:
return FALSE;
}
return TRUE;
}
BOOL
CredpUnmarshalBytes(
IN OUT LPWSTR *Current,
IN LPCWSTR End,
IN LPBYTE Bytes,
IN ULONG ByteCount
)
/*++
Routine Description:
This routine unmarshals bytes bytes from a buffer.
Arguments:
Current - On input, points to a pointer of the current location in the marshaled buffer.
On output, is modified to point to the next available location in the marshaled buffer.
End - Points to the first character beyond the end of the marshaled buffer.
Bytes - Specifies the buffer to unmarsal into
ByteCount - Specifies the number of bytes to unmarshal
Return Values:
TRUE - if the bytes we're unmarshaled sucessfully
FALSE - if the byte could not be unmarshaled from the buffer.
--*/
{
ULONG i;
ULONG Value;
union {
BYTE ByteValues[3];
struct {
ULONG Bits1 :6;
ULONG Bits2 :6;
ULONG Bits3 :6;
ULONG Bits4 :6;
} BitValues;
} Bits;
//
// Loop through unmarshaling 3 bytes at a time.
//
for ( i=0; i<ByteCount; i+=3 ) {
ULONG BytesToCopy;
//
// Grab up to 3 bytes from the input buffer.
//
BytesToCopy = min( 3, ByteCount-i );
if ( BytesToCopy != 3 ) {
RtlZeroMemory( Bits.ByteValues, 3);
}
//
// Unarshal the first twelve bits
//
if ( !CredpUnmarshalChar( Current, End, &Value ) ) {
return FALSE;
}
Bits.BitValues.Bits1 = Value;
if ( !CredpUnmarshalChar( Current, End, &Value ) ) {
return FALSE;
}
Bits.BitValues.Bits2 = Value;
//
// Optionally marshal the next bits.
//
if ( BytesToCopy > 1 ) {
if ( !CredpUnmarshalChar( Current, End, &Value ) ) {
return FALSE;
}
Bits.BitValues.Bits3 = Value;
if ( BytesToCopy > 2 ) {
if ( !CredpUnmarshalChar( Current, End, &Value ) ) {
return FALSE;
}
Bits.BitValues.Bits4 = Value;
}
}
//
// Copy the unmarshaled bytes to the caller's buffer.
//
RtlCopyMemory( &Bytes[i], Bits.ByteValues, BytesToCopy );
}
return TRUE;
}
BOOL
APIENTRY
CredMarshalCredentialA(
IN CRED_MARSHAL_TYPE CredType,
IN PVOID Credential,
OUT LPSTR *MarshaledCredential
)
/*++
Routine Description:
The ANSI version of CredMarshalCredentialW
Arguments:
See CredMarshalCredentialW.
Return Values:
See CredMarshalCredentialW.
--*/
{
BOOL RetVal;
DWORD WinStatus;
LPWSTR UnicodeMarshaledCredential;
RetVal = CredMarshalCredentialW( CredType, Credential, &UnicodeMarshaledCredential );
if ( RetVal ) {
//
// Convert the value to ANSI.
//
WinStatus = CredpAllocStrFromStr( DoWtoA, UnicodeMarshaledCredential, FALSE, (LPWSTR *)MarshaledCredential );
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
RetVal = FALSE;
}
CredFree( UnicodeMarshaledCredential );
}
return RetVal;
}
BOOL
APIENTRY
CredMarshalCredentialW(
IN CRED_MARSHAL_TYPE CredType,
IN PVOID Credential,
OUT LPWSTR *MarshaledCredential
)
/*++
Routine Description:
The CredMarshalCredential API is a private API used by the keyring UI to marshal a
credential. The keyring UI needs to be able to pass a certificate credential through
interfaces (e.g., NetUseAdd) that have historically accepted DomainName UserName and Password.
Arguments:
CredType - Specifies the type of credential to marshal.
This enum will be expanded in the future.
Credential - Specifies the credential to marshal.
If CredType is CertCredential, then Credential points to a CERT_CREDENTIAL_INFO structure.
MarshaledCredential - Returns a text string containing the marshaled credential.
The marshaled credential should be passed as the UserName string to any API that
is currently passed credentials. If that API is currently passed a
password, the password should be passed as NULL or empty. If that API is
currently passed a domain name, that domain name should be passed as NULL or empty.
The caller should free the returned buffer using CredFree.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_INVALID_PARAMETER - CredType is invalid.
--*/
{
DWORD WinStatus;
ULONG Size;
LPWSTR RetCredential = NULL;
LPWSTR Current;
PCERT_CREDENTIAL_INFO CertCredentialInfo = NULL;
PUSERNAME_TARGET_CREDENTIAL_INFO UsernameTargetCredentialInfo = NULL;
ULONG UsernameTargetUserNameSize;
#define CRED_MARSHAL_HEADER L"@@"
#define CRED_MARSHAL_HEADER_LENGTH 2
//
// Ensure credential isn't null
//
if ( Credential == NULL ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Validate CredType
//
Size = (CRED_MARSHAL_HEADER_LENGTH+2) * sizeof(WCHAR);
switch ( CredType ) {
case CertCredential:
CertCredentialInfo = (PCERT_CREDENTIAL_INFO) Credential;
if ( CertCredentialInfo->cbSize < sizeof(CERT_CREDENTIAL_INFO) ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
Size += CredpMarshalSize( sizeof(CertCredentialInfo->rgbHashOfCert) );
break;
case UsernameTargetCredential:
UsernameTargetCredentialInfo = (PUSERNAME_TARGET_CREDENTIAL_INFO) Credential;
if ( UsernameTargetCredentialInfo->UserName == NULL ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
UsernameTargetUserNameSize = wcslen(UsernameTargetCredentialInfo->UserName)*sizeof(WCHAR);
if ( UsernameTargetUserNameSize == 0 ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
Size += CredpMarshalSize( sizeof(UsernameTargetUserNameSize) ) +
CredpMarshalSize( UsernameTargetUserNameSize );
break;
default:
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Allocate a buffer to put the marshaled string into.
//
RetCredential = (LPWSTR) MIDL_user_allocate( Size );
if ( RetCredential == NULL ) {
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
//
// Add the header onto the marshaled string
//
Current = RetCredential;
RtlCopyMemory( Current, CRED_MARSHAL_HEADER, CRED_MARSHAL_HEADER_LENGTH*sizeof(WCHAR) );
Current += CRED_MARSHAL_HEADER_LENGTH;
//
// Add the CredType
//
CredpMarshalChar( &Current, CredType );
//
// Marshal the CredType specific data
//
switch ( CredType ) {
case CertCredential:
CredpMarshalBytes( &Current, CertCredentialInfo->rgbHashOfCert, sizeof(CertCredentialInfo->rgbHashOfCert) );
break;
case UsernameTargetCredential:
CredpMarshalBytes( &Current, (LPBYTE)&UsernameTargetUserNameSize, sizeof(UsernameTargetUserNameSize) );
CredpMarshalBytes( &Current, (LPBYTE)UsernameTargetCredentialInfo->UserName, UsernameTargetUserNameSize );
break;
}
//
// Finally, zero terminate the string
//
*Current = L'\0';
Current ++;
//
// Return the marshaled credential to the caller.
//
ASSERT( Current == &RetCredential[Size/sizeof(WCHAR)] );
*MarshaledCredential = RetCredential;
RetCredential = NULL;
WinStatus = NO_ERROR;
Cleanup:
if ( RetCredential != NULL ) {
MIDL_user_free( RetCredential );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredUnmarshalCredentialA(
IN LPCSTR MarshaledCredential,
OUT PCRED_MARSHAL_TYPE CredType,
OUT PVOID *Credential
)
/*++
Routine Description:
The ANSI version of CredUnmarshalCredentialW
Arguments:
See CredUnmarshalCredentialW.
Return Values:
See CredUnmarshalCredentialW.
--*/
{
DWORD WinStatus;
LPWSTR UnicodeMarshaledCredential = NULL;
//
// Convert input args to Unicode
//
WinStatus = CredpAllocStrFromStr( DoAtoW, (LPWSTR)MarshaledCredential, FALSE, &UnicodeMarshaledCredential );
if ( WinStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Do the unmarshaling
//
if ( !CredUnmarshalCredentialW( UnicodeMarshaledCredential,
CredType,
Credential ) ) {
WinStatus = GetLastError();
goto Cleanup;
}
WinStatus = NO_ERROR;
Cleanup:
if ( UnicodeMarshaledCredential != NULL ) {
MIDL_user_free( UnicodeMarshaledCredential );
}
if ( WinStatus != NO_ERROR ) {
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredUnmarshalCredentialW(
IN LPCWSTR MarshaledCredential,
OUT PCRED_MARSHAL_TYPE CredType,
OUT PVOID *Credential
)
/*++
Routine Description:
The CredMarshalCredential API is a private API used by an authentication package to unmarshal a
credential. The keyring UI needs to be able to pass a certificate credential through
interfaces (e.g., NetUseAdd) that have historically accepted DomainName UserName and Password.
Arguments:
MarshaledCredential - Specifies a text string containing the marshaled credential.
CredType - Returns the type of credential.
Credential - Returns a pointer to the unmarshaled credential.
If CredType is CertCredential, then the returned pointer is to a CERT_CREDENTIAL_INFO structure.
The caller should free the returned buffer using CredFree.
Return Values:
On success, TRUE is returned. On failure, FALSE is returned.
GetLastError() may be called to get a more specific status code.
The following status codes may be returned:
ERROR_INVALID_PARAMETER - MarshaledCredential is not valid
--*/
{
DWORD WinStatus;
LPWSTR Current;
LPCWSTR End;
PCERT_CREDENTIAL_INFO CertCredentialInfo;
PUSERNAME_TARGET_CREDENTIAL_INFO UsernameTargetCredentialInfo;
PVOID RetCredential = NULL;
ULONG UsernameTargetUserNameSize;
LPBYTE Where;
ULONG MarshaledCredentialLength;
//
// Validate the passed in buffer.
//
if ( MarshaledCredential == NULL ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Ensure the first few bytes are the appropriate header
//
if ( MarshaledCredential[0] != CRED_MARSHAL_HEADER[0] || MarshaledCredential[1] != CRED_MARSHAL_HEADER[1] ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Validate the credential type
//
MarshaledCredentialLength = wcslen(MarshaledCredential);
Current = (LPWSTR) &MarshaledCredential[2];
End = &MarshaledCredential[MarshaledCredentialLength];
if ( !CredpUnmarshalChar( &Current, End, (PULONG)CredType ) ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
switch ( *CredType ) {
case CertCredential:
//
// Allocate a buffer that will be more than big enough
//
CertCredentialInfo = MIDL_user_allocate(
sizeof(*CertCredentialInfo) +
MarshaledCredentialLength*sizeof(WCHAR) );
if ( CertCredentialInfo == NULL ) {
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
RetCredential = CertCredentialInfo;
CertCredentialInfo->cbSize = sizeof(*CertCredentialInfo);
//
// Unmarshal the data
//
if ( !CredpUnmarshalBytes( &Current, End, CertCredentialInfo->rgbHashOfCert, sizeof(CertCredentialInfo->rgbHashOfCert) ) ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
break;
case UsernameTargetCredential:
//
// Allocate a buffer that will be more than big enough
//
UsernameTargetCredentialInfo = MIDL_user_allocate(
sizeof(*UsernameTargetCredentialInfo) +
MarshaledCredentialLength*sizeof(WCHAR) +
sizeof(WCHAR) );
if ( UsernameTargetCredentialInfo == NULL ) {
WinStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
RetCredential = UsernameTargetCredentialInfo;
Where = (LPBYTE)(UsernameTargetCredentialInfo+1);
//
// Unmarshal the size of the data
//
if ( !CredpUnmarshalBytes( &Current, End, (LPBYTE)&UsernameTargetUserNameSize, sizeof(UsernameTargetUserNameSize) ) ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
if ( UsernameTargetUserNameSize != ROUND_UP_COUNT( UsernameTargetUserNameSize, sizeof(WCHAR)) ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
if ( UsernameTargetUserNameSize == 0 ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Unmarshal the data
//
UsernameTargetCredentialInfo->UserName = (LPWSTR)Where;
if ( !CredpUnmarshalBytes( &Current, End, Where, UsernameTargetUserNameSize ) ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
Where += UsernameTargetUserNameSize;
//
// Zero terminate it
//
*((PWCHAR)Where) = L'\0';
break;
default:
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Ensure we've unmarshalled the entire string
//
if ( Current != End ) {
WinStatus = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
WinStatus = NO_ERROR;
*Credential = RetCredential;
Cleanup:
if ( WinStatus != NO_ERROR ) {
*Credential = NULL;
if ( RetCredential != NULL ) {
MIDL_user_free( RetCredential );
}
SetLastError( WinStatus );
return FALSE;
}
return TRUE;
}
BOOL
APIENTRY
CredIsMarshaledCredentialA(
IN LPCSTR MarshaledCredential
)
/*++
Routine Description:
The ANSI version of CredIsMarshaledCredentialW
Arguments:
MarshaledCredential - Specifies a text string containing the marshaled credential.
Return Values:
Returns TRUE if the credential is a marshalled credential.
--*/
{
DWORD WinStatus;
CRED_MARSHAL_TYPE CredType;
PVOID UnmarshalledUsername;
if ( !CredUnmarshalCredentialA( MarshaledCredential, &CredType, &UnmarshalledUsername ) ) {
return FALSE;
}
CredFree( UnmarshalledUsername );
return TRUE;
}
BOOL
APIENTRY
CredIsMarshaledCredentialW(
IN LPCWSTR MarshaledCredential
)
/*++
Routine Description:
The CredIsMarshaledCredential API is a private API used by an authentication package to
determine if a credential is a unmarshaled credential or not.
Arguments:
MarshaledCredential - Specifies a text string containing the marshaled credential.
Return Values:
Returns TRUE if the credential is a marshalled credential.
--*/
{
DWORD WinStatus;
CRED_MARSHAL_TYPE CredType;
PVOID UnmarshalledUsername;
if ( !CredUnmarshalCredentialW( MarshaledCredential, &CredType, &UnmarshalledUsername ) ) {
return FALSE;
}
CredFree( UnmarshalledUsername );
return TRUE;
}