Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

913 lines
24 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
aucred.c
Abstract:
This module provides credential management services within the
LSA subsystem. Some of these services are indirectly available for use
by authentication packages.
Author:
Jim Kelly (JimK) 27-February-1991
Revision History:
--*/
#include <lsapch2.h>
RTL_RESOURCE AuCredLock ;
#define AuReadLockCreds() RtlAcquireResourceShared( &AuCredLock, TRUE );
#define AuWriteLockCreds() RtlAcquireResourceExclusive( &AuCredLock, TRUE );
#define AuUnlockCreds() RtlReleaseResource( &AuCredLock );
NTSTATUS
LsapInitializeCredentials(
VOID
)
{
__try {
RtlInitializeResource( &AuCredLock );
return STATUS_SUCCESS;
} __except(EXCEPTION_EXECUTE_HANDLER)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
}
NTSTATUS
LsapAddCredential(
IN PLUID LogonId,
IN ULONG AuthenticationPackage,
IN PSTRING PrimaryKeyValue,
IN PSTRING Credentials
)
/*++
Routine Description:
This service is used by authentication packages to add credentials to a
logon session. These credentials may later be referenced using
GetCredentials().
This service acquires the AuLock.
Arguments:
LogonId - The session ID of logon session to add credentials to.
AuthenticationPackage - The authentication package ID of the
calling authentication package. This was received in the
InitializePackage() call during DLL initialization.
PrimaryKeyValue - Points to a string containing a value that the
authentication package will later want to reference as a
primary key of the credential data. This may be used, for
example, to keep the name of the domain or server the
credentials are related to. The format and meaning of this
string are authentication package-specific. Note that the
string value does not have to be unique, even for the
specified logon session. For example, there could be two
passwords for the same domain, each with the passwords stored
as credentials and the domain name stored as the primary key.
Credentials - Points to a string containing data representing
user credentials. The format and meaning of this string are
authentication package-specific.
Return Status:
STATUS_SUCCESS - The credentials were successfully added.
STATUS_NO_SUCH_LOGON_SESSION - The specified logon session could
not be found.
--*/
{
PLSAP_LOGON_SESSION LogonSession;
PLSAP_PACKAGE_CREDENTIALS Package;
PLSAP_CREDENTIALS NewCredentials = NULL;
USHORT MaxPrimary;
USHORT MaxCredentials;
NTSTATUS Status = STATUS_SUCCESS;
//
// Get a pointer to the logon session
//
LogonSession = LsapLocateLogonSession( LogonId );
if ( LogonSession == NULL ) {
return STATUS_NO_SUCH_LOGON_SESSION;
}
//
// Allocate blocks needed to represent this credential
// and copy the primary key and credential strings.
//
MaxPrimary = ROUND_UP_COUNT((PrimaryKeyValue->Length+sizeof(CHAR)), ALIGN_WORST);
MaxCredentials = ROUND_UP_COUNT((Credentials->Length+sizeof(CHAR)), ALIGN_WORST);
NewCredentials = LsapAllocatePrivateHeap( (ULONG)sizeof(LSAP_CREDENTIALS) +
MaxPrimary +
MaxCredentials
);
if ( NewCredentials == NULL )
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
NewCredentials->PrimaryKey.MaximumLength = MaxPrimary;
NewCredentials->PrimaryKey.Buffer = (PSTR)(NewCredentials+1);
NewCredentials->Credentials.MaximumLength = MaxCredentials;
NewCredentials->Credentials.Buffer = NewCredentials->PrimaryKey.Buffer +
NewCredentials->PrimaryKey.MaximumLength;
RtlCopyString( &NewCredentials->PrimaryKey, PrimaryKeyValue );
RtlCopyString( &NewCredentials->Credentials, Credentials );
//
// Now get a pointer to the Package's credentials
// (create one if necessary)
//
AuWriteLockCreds();
Package = LsapGetPackageCredentials(
LogonSession,
AuthenticationPackage,
TRUE
);
if ( !Package )
{
AuUnlockCreds();
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
//
// insert new credentials in list.
//
NewCredentials->NextCredentials = Package->Credentials;
Package->Credentials = NewCredentials;
AuUnlockCreds();
LsapReleaseLogonSession( LogonSession );
return STATUS_SUCCESS;
Cleanup:
LsapReleaseLogonSession( LogonSession );
if ( NewCredentials )
{
if ( NewCredentials->PrimaryKey.Buffer )
{
ZeroMemory( NewCredentials->PrimaryKey.Buffer,
NewCredentials->PrimaryKey.Length );
}
if ( NewCredentials->Credentials.Buffer )
{
ZeroMemory( NewCredentials->Credentials.Buffer,
NewCredentials->Credentials.Length );
}
LsapFreePrivateHeap( NewCredentials );
}
return Status;
}
NTSTATUS
LsapGetCredentials(
IN PLUID LogonId,
IN ULONG AuthenticationPackage,
IN OUT PULONG QueryContext,
IN BOOLEAN RetrieveAllCredentials,
IN PSTRING PrimaryKeyValue,
OUT PULONG PrimaryKeyLength,
IN PSTRING Credentials
)
/*++
Routine Description:
This service is used by authentication packages to retrieve credentials
associated with a logon session. It is expected that each authentication
package will provide its own version of this service to its "clients".
For example, the MSV1_0 authentication package will provide services for
the LM Redirector to retrieve credentials (and probably establish them)
for remote accesses. These authentication package level services may be
implemented using the LsaCallAuthenticationPackage() API.
This service acquires the AuLock.
Arguments:
LogonId - The session ID of logon session from which credentials
are to be retrieved.
AuthenticationPackage - The authentication package ID of the
calling authentication package. Authentication packages
should only retrieve their own credentials.
QueryContext - A context value used across successive calls to
retrieve multiple credentials. The first time this service
is used, the value pointed to by this argument should be
zero. Thereafter, this value will be updated to allow
retrieval to continue where it left off. This value should,
therefore, not be changed until all credentials of a given
query operation have been retrieved.
RetrieveAllCredentials - A boolean value indicating whether all
credentials for the specified logon session should be
retrieved (TRUE), or only those matching the specified
PrimaryKeyValue (FALSE).
PrimaryKeyValue - This parameter serves two purposes. If the
RetrieveAllCredentials argument is FALSE, then this string
contains the value to use as a primary key lookup value. In
this case, only credentials whose primary key matches this
one (and belonging to the correct logon session) will be
retrieved. If, however, the RetrieveAllCredentials argument
is FALSE, then the value of this string are ignored. In this
case, the primary key value of each retrieved credential will
be returned in this string.
PrimaryKeyLength - If the RetrieveAllCredentials argument value
is FALSE, then this argument receives the length needed to
store the PrimaryKeyValue. If this value is larger than the
length of the PrimaryKeyValue string, then
STATUS_BUFFER_OVERFLOW is returned and no data is retrieved.
Credentials - Points to a string whose buffer is to be set to
contain the retrieved credential.
Return Status:
STATUS_MORE_ENTRIES - Credentials were successfully retrieved,
and there are more available.
STATUS_SUCCESS - Credentials were successfully retrieved and
there are no more available.
STATUS_UNSUCCESSFUL - No more credentials are available. If
returned on the first call, then there are no credentials
matching the selection criteria.
STATUS_NO_SUCH_LOGON_SESSION - The specified logon session could
not be found.
STATUS_BUFFER_OVERFLOW - Indicates the string provided to receive
the PrimaryKeyValue was not large enough to hold the data.
In this case, no data was retrieved. However, the length value
is returned so that appropriately sized buffer can be passed in
a successive call.
--*/
{
//
// NOTE: The QueryContext value is an index of the last retrieved
// credential matching the selection criteria. To continue
// a search for successive credentials, skip QueryContext
// number of entries first.
//
// This has the problem of changes between calls screwing
// up the result of successive calls. That's tough.
//
NTSTATUS Status = STATUS_SUCCESS;
PLSAP_LOGON_SESSION LogonSession;
PLSAP_PACKAGE_CREDENTIALS Package;
PLSAP_CREDENTIALS NextCredentials;
ULONG i;
BOOLEAN SelectionMatch;
//
// Get a pointer to the logon session
//
LogonSession = LsapLocateLogonSession( LogonId );
if ( LogonSession == NULL ) {
return STATUS_NO_SUCH_LOGON_SESSION;
}
AuReadLockCreds();
//
// Now get a pointer to the Package's credentials
//
Package = LsapGetPackageCredentials(
LogonSession,
AuthenticationPackage,
FALSE
);
if ( Package == NULL ) {
AuUnlockCreds();
LsapReleaseLogonSession( LogonSession );
return STATUS_UNSUCCESSFUL;
}
//
// skip the credentials already evaluated in previous calls...
//
i = (*QueryContext);
NextCredentials = Package->Credentials;
while ( i > 0 ) {
//
// See if we have reached the end of the list
//
if (NextCredentials == NULL) {
AuUnlockCreds();
LsapReleaseLogonSession( LogonSession );
return STATUS_UNSUCCESSFUL;
}
//
// Nope, skip the next one...
//
NextCredentials = NextCredentials->NextCredentials;
i -= 1;
}
//
// Start evaluating each credential for a criteria match.
//
SelectionMatch = FALSE;
while ( NextCredentials != NULL && !SelectionMatch ) {
(*QueryContext) += 1;
if (RetrieveAllCredentials) {
SelectionMatch = TRUE;
Status = LsapReturnCredential(
NextCredentials,
Credentials,
TRUE,
PrimaryKeyValue,
PrimaryKeyLength
);
}
//
// Only retrieving credentials that match the specified primary
// key.
//
if ( RtlEqualString( &NextCredentials->PrimaryKey, PrimaryKeyValue, FALSE) ) {
SelectionMatch = TRUE;
Status = LsapReturnCredential(
NextCredentials,
Credentials,
FALSE,
NULL,
NULL
);
}
NextCredentials = NextCredentials->NextCredentials;
}
AuUnlockCreds();
LsapReleaseLogonSession( LogonSession );
//
// Figure out what return value to send.
//
if (SelectionMatch) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
(*QueryContext) -= 1;
return STATUS_BUFFER_OVERFLOW;
}
if ( Status == STATUS_SUCCESS) {
if ( NextCredentials == NULL ) {
return STATUS_SUCCESS;
} else {
return STATUS_MORE_ENTRIES;
}
}
} else {
//
// didn't find a credential matching the selection criteria.
//
return STATUS_UNSUCCESSFUL;
}
return STATUS_UNSUCCESSFUL ;
}
NTSTATUS
LsapReturnCredential(
IN PLSAP_CREDENTIALS SourceCredentials,
IN PSTRING TargetCredentials,
IN BOOLEAN ReturnPrimaryKey,
IN PSTRING PrimaryKeyValue OPTIONAL,
OUT PULONG PrimaryKeyLength OPTIONAL
)
/*++
Routine Description:
This routine returns a copy of the credentials in the specified
credential record. It also, optionally, returns a copy of the
primary key value.
Arguments:
SourceCredentials - Points to a credential record whose credential
string and, optionally, primary key are to be copied.
TargetCredentials - Points to a string whose buffer is to be set to
contain a copy of the credential. This copy will be allocated
using LsapAllocateLsaHeap().
ReturnPrimaryKey - A boolean indicating whether or not to return
a copy of the primary key. TRUE indicates a copy should be
returned. FALSE indicates a copy should not be returned.
PrimaryKeyValue - Points to a string whose buffer is to be set to
contain a copy of the primary key. This copy will be allocated
using LsapAllocateLsaHeap(). This parameter is ignored if the
ReturnPrimaryKey argument value is FALSE.
PrimaryKeyLength - Points to a value which will receive the
length of the primary key value. If this value is larger than the
length of the PrimaryKeyValue string, then STATUS_BUFFER_OVERFLOW
is returned and no data is retrieved.
Return Status:
STATUS_SUCCESS - Credentials were successfully returned.
STATUS_BUFFER_OVERFLOW - Indicates the string provided to receive
the PrimaryKeyValue was not large enough to hold the data.
In this case, no data was retrieved. However, the length value
is returned so that appropriately sized buffer can be passed in
a successive call.
--*/
{
ULONG Length;
//
// First try to return the primary key value, since we can encounter
// a buffer overflow situation in doing so that would prevent us from
// returning a copy of the credential string.
//
if (ReturnPrimaryKey) {
(*PrimaryKeyLength) = SourceCredentials->PrimaryKey.Length + 1;
if ( (*PrimaryKeyLength) > PrimaryKeyValue->MaximumLength ) {
return STATUS_BUFFER_OVERFLOW;
}
//
// It fits
//
RtlCopyString( PrimaryKeyValue, &SourceCredentials->PrimaryKey );
}
//
// Now allocate and copy the credential string copy.
//
TargetCredentials->MaximumLength = SourceCredentials->Credentials.Length
+ (USHORT)1;
Length = (ULONG)TargetCredentials->MaximumLength;
TargetCredentials->Buffer = (PCHAR)LsapAllocateLsaHeap( Length );
if ( TargetCredentials->Buffer )
{
RtlCopyString( TargetCredentials, &SourceCredentials->Credentials );
return STATUS_SUCCESS ;
}
else
{
return STATUS_NO_MEMORY ;
}
}
NTSTATUS
LsapDeleteCredential(
IN PLUID LogonId,
IN ULONG AuthenticationPackage,
IN PSTRING PrimaryKeyValue
)
/*++
Routine Description:
This service is used to delete an existing credential. This service
deletes the first credential it finds with a matching logon session,
authentication package ID, and primary key value. If thee are
multiple credentials that match this criteria, only one of them is
deleted.
This status acquires the AuLock.
Arguments:
LogonId - The session ID of logon session whose credentials are to be
deleted.
AuthenticationPackage - The authentication package ID of the
calling authentication package. This was received in the
InitializePackage() call during DLL initialization.
PrimaryKeyValue - Points to string containing the primary key value
of the credential to be deleted.
Return Status:
STATUS_SUCCESS - The credentials were successfully deleted.
STATUS_NO_SUCH_LOGON_SESSION - The specified logon session could
not be found.
STATUS_UNSUCCESSFUL - No such credential could be found.
--*/
{
PLSAP_LOGON_SESSION LogonSession;
PLSAP_PACKAGE_CREDENTIALS Package;
PLSAP_CREDENTIALS *NextCredentials, GoodByeCredentials;
//
// Get a pointer to the logon session
//
LogonSession = LsapLocateLogonSession( LogonId );
if ( LogonSession == NULL ) {
return STATUS_NO_SUCH_LOGON_SESSION;
}
AuWriteLockCreds();
//
// Now get a pointer to the Package's credentials
//
Package = LsapGetPackageCredentials(
LogonSession,
AuthenticationPackage,
FALSE
);
if ( Package == NULL ) {
AuUnlockCreds();
LsapReleaseLogonSession( LogonSession );
return STATUS_UNSUCCESSFUL;
}
//
// Start evaluating each credential for a primary key value match.
//
NextCredentials = &Package->Credentials;
while ( (*NextCredentials) != NULL ) {
if ( RtlEqualString(
&(*NextCredentials)->PrimaryKey,
PrimaryKeyValue,
FALSE)
) {
//
// remove it from the list
//
GoodByeCredentials = (*NextCredentials);
(*NextCredentials) = GoodByeCredentials->NextCredentials;
AuUnlockCreds();
LsapReleaseLogonSession( LogonSession );
//
// Zero the contents of the credential record.
//
if( GoodByeCredentials->PrimaryKey.Buffer != NULL )
{
SecureZeroMemory( GoodByeCredentials->PrimaryKey.Buffer,
GoodByeCredentials->PrimaryKey.Length );
}
if( GoodByeCredentials->Credentials.Buffer != NULL )
{
SecureZeroMemory( GoodByeCredentials->Credentials.Buffer,
GoodByeCredentials->Credentials.Length );
}
//
// Free the credential record itself.
//
LsapFreePrivateHeap( GoodByeCredentials );
return STATUS_SUCCESS;
}
NextCredentials = &(*NextCredentials)->NextCredentials;
}
AuUnlockCreds();
LsapReleaseLogonSession( LogonSession );
//
// Nothing matched
//
return STATUS_UNSUCCESSFUL;
}
PLSAP_PACKAGE_CREDENTIALS
LsapGetPackageCredentials(
IN PLSAP_LOGON_SESSION LogonSession,
IN ULONG PackageId,
IN BOOLEAN CreateIfNecessary
)
/*++
Routine Description:
This service returns a pointer to a specified package's credential
record. If no such record exists, one will optionally be created.
It is assumed that either the LogonSession record is not currently
in the logon session record list, or, if it is, that the AuLock
is currently held.
Arguments:
LogonSession - Pointer to a logon session record within which to
work.
PackageId - The authentication package ID to look for.
CreateIfNecessary - A boolean indicating whether or not the package
record is to be created if one does not already exist. TRUE
indicates the package is to be created if necessary, FALSE indicates
the record should not be created.
Return Status:
non-NULL - A pointer to the specified package record.
NULL - The specified package record does not exist (and one was not
created automatically).
--*/
{
PLSAP_PACKAGE_CREDENTIALS *NextPackage, TargetPackage;
//
// See if the session exists
//
NextPackage = &LogonSession->Packages;
while ( (*NextPackage) != NULL) {
if ( (*NextPackage)->PackageId == PackageId ) {
//
// Found it
//
TargetPackage = (*NextPackage);
return TargetPackage;
}
//
// Move on to next package.
//
NextPackage = &(*NextPackage)->NextPackage;
}
//
// No such package exists yet.
// Create one if necessary.
if ( !CreateIfNecessary ) {
return NULL;
}
TargetPackage = LsapAllocateLsaHeap( (ULONG)sizeof(LSAP_PACKAGE_CREDENTIALS) );
if ( TargetPackage )
{
TargetPackage->PackageId = PackageId;
TargetPackage->Credentials = NULL;
TargetPackage->NextPackage = LogonSession->Packages;
LogonSession->Packages = TargetPackage;
}
return TargetPackage;
}
VOID
LsapFreePackageCredentialList(
IN PLSAP_PACKAGE_CREDENTIALS PackageCredentialList
)
/*++
Routine Description:
This service frees a list of packge credential records. This service
is not expected to be exposed to authentication packages.
This service expects not to have to acquire the AuLock. This may be
because it is already held, or because the credentials being freed
are no longer accessible via the global variables.
Arguments:
PackageCredentialList - Is a pointer to a list of LSA_PACKAGE_CREDENTIALS
data structures.
Return Status:
None.
--*/
{
PLSAP_PACKAGE_CREDENTIALS NextPackage, GoodByePackage;
//
// Get rid of each PACKAGE_CREDENTIAL record.
//
NextPackage = PackageCredentialList;
while ( NextPackage != NULL ) {
//
// Save a pointer to the next package
//
GoodByePackage = NextPackage;
NextPackage = GoodByePackage->NextPackage;
LsapFreeCredentialList( GoodByePackage->Credentials );
//
// Free the package record itself.
//
LsapFreeLsaHeap( GoodByePackage );
}
return;
}
VOID
LsapFreeCredentialList(
IN PLSAP_CREDENTIALS CredentialList
)
/*++
Routine Description:
This service frees a list of credential records. This service is not
expected to be exposed to authentication packages.
This service expects not to have to acquire the AuLock. This may be
because it is already held, or because the credentials being freed
are no longer accessible via the global variables.
Arguments:
CredentialList - Is a pointer to a list of LSA_CREDENTIALS data
structures.
Return Status:
--*/
{
PLSAP_CREDENTIALS NextCredentials, GoodByeCredentials;
//
// Get rid of each PACKAGE_CREDENTIAL record.
//
NextCredentials = CredentialList;
while ( NextCredentials != NULL ) {
//
// Save a pointer to the next credential
//
GoodByeCredentials = NextCredentials;
NextCredentials = GoodByeCredentials->NextCredentials;
//
// Zero the contents of this credential record.
//
if( GoodByeCredentials->PrimaryKey.Buffer != NULL )
{
SecureZeroMemory( GoodByeCredentials->PrimaryKey.Buffer,
GoodByeCredentials->PrimaryKey.Length );
}
if( GoodByeCredentials->Credentials.Buffer != NULL )
{
SecureZeroMemory( GoodByeCredentials->Credentials.Buffer,
GoodByeCredentials->Credentials.Length );
}
//
// Free the credential record itself.
//
LsapFreePrivateHeap( GoodByeCredentials );
}
return;
}