921 lines
23 KiB
C
921 lines
23 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
server.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file contains services related to the SAM "server" object.
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jim Kelly (JimK) 4-July-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User Mode - Win32
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Includes //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include <samsrvp.h>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// private service prototypes //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Routines //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrConnect2(
|
|||
|
IN PSAMPR_SERVER_NAME ServerName,
|
|||
|
OUT SAMPR_HANDLE * ServerHandle,
|
|||
|
IN ACCESS_MASK DesiredAccess
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service is the dispatch routine for SamConnect. It performs
|
|||
|
an access validation to determine whether the caller may connect
|
|||
|
to SAM for the access specified. If so, a context block is established.
|
|||
|
This is different from the SamConnect call in that the entire server
|
|||
|
name is passed instead of just the first character.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - Name of the node this SAM reside on. Ignored by this
|
|||
|
routine.
|
|||
|
|
|||
|
ServerHandle - If the connection is successful, the value returned
|
|||
|
via this parameter serves as a context handle to the openned
|
|||
|
SERVER object.
|
|||
|
|
|||
|
DesiredAccess - Specifies the accesses desired to the SERVER object.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status values returned by SamIConnect().
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOLEAN TrustedClient;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If we ever want to support trusted remote clients, then the test
|
|||
|
// for whether or not the client is trusted can be made here and
|
|||
|
// TrustedClient set appropriately. For now, all remote clients are
|
|||
|
// considered untrusted.
|
|||
|
|
|||
|
TrustedClient = FALSE;
|
|||
|
|
|||
|
return SamIConnect(ServerName, ServerHandle, DesiredAccess, TrustedClient );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrConnect(
|
|||
|
IN PSAMPR_SERVER_NAME ServerName,
|
|||
|
OUT SAMPR_HANDLE * ServerHandle,
|
|||
|
IN ACCESS_MASK DesiredAccess
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service is the dispatch routine for SamConnect. It performs
|
|||
|
an access validation to determine whether the caller may connect
|
|||
|
to SAM for the access specified. If so, a context block is established
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - Name of the node this SAM reside on. Ignored by this
|
|||
|
routine. The name contains only a single character.
|
|||
|
|
|||
|
ServerHandle - If the connection is successful, the value returned
|
|||
|
via this parameter serves as a context handle to the openned
|
|||
|
SERVER object.
|
|||
|
|
|||
|
DesiredAccess - Specifies the accesses desired to the SERVER object.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status values returned by SamIConnect().
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOLEAN TrustedClient;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If we ever want to support trusted remote clients, then the test
|
|||
|
// for whether or not the client is trusted can be made here and
|
|||
|
// TrustedClient set appropriately. For now, all remote clients are
|
|||
|
// considered untrusted.
|
|||
|
|
|||
|
TrustedClient = FALSE;
|
|||
|
|
|||
|
return SamIConnect(NULL, ServerHandle, DesiredAccess, TrustedClient );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamIConnect(
|
|||
|
IN PSAMPR_SERVER_NAME ServerName,
|
|||
|
OUT SAMPR_HANDLE * ServerHandle,
|
|||
|
IN ACCESS_MASK DesiredAccess,
|
|||
|
IN BOOLEAN TrustedClient
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service is the dispatch routine for SamConnect. It performs
|
|||
|
an access validation to determine whether the caller may connect
|
|||
|
to SAM for the access specified. If so, a context block is established
|
|||
|
|
|||
|
|
|||
|
NOTE: If the caller is trusted, then the DesiredAccess parameter may
|
|||
|
NOT contain any Generic access types or MaximumAllowed. All
|
|||
|
mapping must be done by the caller.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - Name of the node this SAM reside on. Ignored by this
|
|||
|
routine.
|
|||
|
|
|||
|
ServerHandle - If the connection is successful, the value returned
|
|||
|
via this parameter serves as a context handle to the openned
|
|||
|
SERVER object.
|
|||
|
|
|||
|
DesiredAccess - Specifies the accesses desired to the SERVER object.
|
|||
|
|
|||
|
TrustedClient - Indicates whether the client is known to be part of
|
|||
|
the trusted computer base (TCB). If so (TRUE), no access validation
|
|||
|
is performed and all requested accesses are granted. If not
|
|||
|
(FALSE), then the client is impersonated and access validation
|
|||
|
performed against the SecurityDescriptor on the SERVER object.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The SERVER object has been successfully openned.
|
|||
|
|
|||
|
STATUS_INSUFFICIENT_RESOURCES - The SAM server processes doesn't
|
|||
|
have sufficient resources to process or accept another connection
|
|||
|
at this time.
|
|||
|
|
|||
|
Other values as may be returned from:
|
|||
|
|
|||
|
NtAccessCheckAndAuditAlarm()
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
PSAMP_OBJECT Context;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( ServerName ); //Ignored by this routine
|
|||
|
|
|||
|
//
|
|||
|
// If the SAM server is not initialized, reject the connection.
|
|||
|
//
|
|||
|
|
|||
|
if (SampServiceState != SampServiceEnabled) {
|
|||
|
|
|||
|
return(STATUS_INVALID_SERVER_STATE);
|
|||
|
}
|
|||
|
|
|||
|
SampAcquireReadLock();
|
|||
|
|
|||
|
|
|||
|
Context = SampCreateContext( SampServerObjectType, TrustedClient );
|
|||
|
|
|||
|
if (Context != NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// The RootKey for a SERVER object is the root of the SAM database.
|
|||
|
// This key should not be closed when the context is deleted.
|
|||
|
//
|
|||
|
|
|||
|
Context->RootKey = SampKey;
|
|||
|
|
|||
|
//
|
|||
|
// The rootkeyname has been initialized to NULL inside CreateContext.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Perform access validation ...
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampValidateObjectAccess(
|
|||
|
Context, //Context
|
|||
|
DesiredAccess, //DesiredAccess
|
|||
|
FALSE //ObjectCreation
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// if we didn't pass the access test, then free up the context block
|
|||
|
// and return the error status returned from the access validation
|
|||
|
// routine. Otherwise, return the context handle value.
|
|||
|
//
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
SampDeleteContext( Context );
|
|||
|
} else {
|
|||
|
(*ServerHandle) = Context;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the read lock
|
|||
|
//
|
|||
|
|
|||
|
SampReleaseReadLock();
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrShutdownSamServer(
|
|||
|
IN SAMPR_HANDLE ServerHandle
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service shuts down the SAM server.
|
|||
|
|
|||
|
In the long run, this routine will perform an orderly shutdown.
|
|||
|
In the short term, it is useful for debug purposes to shutdown
|
|||
|
in a brute force un-orderly fashion.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerHandle - Received from a previous call to SamIConnect().
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The services completed successfully.
|
|||
|
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - The caller doesn't have the appropriate access
|
|||
|
to perform the requested operation.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus, IgnoreStatus;
|
|||
|
PSAMP_OBJECT ServerContext;
|
|||
|
SAMP_OBJECT_TYPE FoundType;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NtStatus = SampAcquireWriteLock();
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Validate type of, and access to server object.
|
|||
|
//
|
|||
|
|
|||
|
ServerContext = (PSAMP_OBJECT)ServerHandle;
|
|||
|
NtStatus = SampLookupContext(
|
|||
|
ServerContext,
|
|||
|
SAM_SERVER_SHUTDOWN, // DesiredAccess
|
|||
|
SampServerObjectType, // ExpectedType
|
|||
|
&FoundType
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Signal the event that will cut loose the main thread.
|
|||
|
// The main thread will then exit - causing the walls to
|
|||
|
// come tumbling down.
|
|||
|
//
|
|||
|
|
|||
|
IgnoreStatus = RpcMgmtStopServerListening(0);
|
|||
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the server object
|
|||
|
//
|
|||
|
|
|||
|
IgnoreStatus = SampDeReferenceContext( ServerContext, FALSE );
|
|||
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the write lock and roll-back the transaction
|
|||
|
//
|
|||
|
|
|||
|
IgnoreStatus = SampReleaseWriteLock( FALSE );
|
|||
|
ASSERT(NT_SUCCESS(IgnoreStatus));
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrLookupDomainInSamServer(
|
|||
|
IN SAMPR_HANDLE ServerHandle,
|
|||
|
IN PRPC_UNICODE_STRING Name,
|
|||
|
OUT PRPC_SID *DomainId
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerHandle - A context handle returned by a previous call
|
|||
|
to SamConnect().
|
|||
|
|
|||
|
Name - contains the name of the domain to look up.
|
|||
|
|
|||
|
DomainSid - Receives a pointer to a buffer containing the SID of
|
|||
|
the domain. The buffer pointed to must be deallocated by the
|
|||
|
caller using MIDL_user_free() when no longer needed.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
STATUS_SUCCESS - The services completed successfully.
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - The caller doesn't have the appropriate access
|
|||
|
to perform the requested operation.
|
|||
|
|
|||
|
STATUS_NO_SUCH_DOMAIN - The specified domain does not exist at this
|
|||
|
server.
|
|||
|
|
|||
|
|
|||
|
STATUS_INVALID_SERVER_STATE - Indicates the SAM server is currently
|
|||
|
disabled.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus, IgnoreStatus;
|
|||
|
PSAMP_OBJECT ServerContext;
|
|||
|
SAMP_OBJECT_TYPE FoundType;
|
|||
|
ULONG i, SidLength;
|
|||
|
BOOLEAN DomainFound;
|
|||
|
PSID FoundSid;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Make sure we understand what RPC is doing for (to) us.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (DomainId != NULL);
|
|||
|
ASSERT ((*DomainId) == NULL);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
ASSERT( Name != NULL );
|
|||
|
if (Name->Buffer == NULL) {
|
|||
|
return(STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
SampAcquireReadLock();
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Validate type of, and access to object.
|
|||
|
//
|
|||
|
|
|||
|
ServerContext = (PSAMP_OBJECT)ServerHandle;
|
|||
|
NtStatus = SampLookupContext(
|
|||
|
ServerContext,
|
|||
|
SAM_SERVER_LOOKUP_DOMAIN,
|
|||
|
SampServerObjectType, // ExpectedType
|
|||
|
&FoundType
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set our default completion status
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = STATUS_NO_SUCH_DOMAIN;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Search the list of defined domains for a match.
|
|||
|
//
|
|||
|
|
|||
|
DomainFound = FALSE;
|
|||
|
for (i = 0;
|
|||
|
(i<SampDefinedDomainsCount && (!DomainFound));
|
|||
|
i++ ) {
|
|||
|
|
|||
|
if (RtlEqualDomainName(&SampDefinedDomains[i].ExternalName, (PUNICODE_STRING)Name) ) {
|
|||
|
|
|||
|
|
|||
|
DomainFound = TRUE;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Allocate and fill in the return buffer
|
|||
|
//
|
|||
|
|
|||
|
SidLength = RtlLengthSid( SampDefinedDomains[i].Sid );
|
|||
|
FoundSid = MIDL_user_allocate( SidLength );
|
|||
|
if (FoundSid != NULL) {
|
|||
|
NtStatus =
|
|||
|
RtlCopySid( SidLength, FoundSid, SampDefinedDomains[i].Sid );
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus) ) {
|
|||
|
MIDL_user_free( FoundSid );
|
|||
|
NtStatus = STATUS_INTERNAL_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
(*DomainId) = FoundSid;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object
|
|||
|
//
|
|||
|
|
|||
|
if ( NT_SUCCESS( NtStatus ) ) {
|
|||
|
|
|||
|
NtStatus = SampDeReferenceContext( ServerContext, FALSE );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IgnoreStatus = SampDeReferenceContext( ServerContext, FALSE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the read lock
|
|||
|
//
|
|||
|
|
|||
|
SampReleaseReadLock();
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SamrEnumerateDomainsInSamServer(
|
|||
|
IN SAMPR_HANDLE ServerHandle,
|
|||
|
IN OUT PSAM_ENUMERATE_HANDLE EnumerationContext,
|
|||
|
OUT PSAMPR_ENUMERATION_BUFFER *Buffer,
|
|||
|
IN ULONG PreferedMaximumLength,
|
|||
|
OUT PULONG CountReturned
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This API lists all the domains defined in the account database.
|
|||
|
Since there may be more domains than can fit into a buffer, the
|
|||
|
caller is provided with a handle that can be used across calls to
|
|||
|
the API. On the initial call, EnumerationContext should point to a
|
|||
|
SAM_ENUMERATE_HANDLE variable that is set to 0.
|
|||
|
|
|||
|
If the API returns STATUS_MORE_ENTRIES, then the API should be
|
|||
|
called again with EnumerationContext. When the API returns
|
|||
|
STATUS_SUCCESS or any error return, the handle becomes invalid for
|
|||
|
future use.
|
|||
|
|
|||
|
This API requires SAM_SERVER_ENUMERATE_DOMAINS access to the
|
|||
|
SamServer object.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ConnectHandle - Handle obtained from a previous SamConnect call.
|
|||
|
|
|||
|
EnumerationContext - API specific handle to allow multiple calls
|
|||
|
(see below). This is a zero based index.
|
|||
|
|
|||
|
Buffer - Receives a pointer to the buffer where the information
|
|||
|
is placed. The information returned is contiguous
|
|||
|
SAM_RID_ENUMERATION data structures. However, the
|
|||
|
RelativeId field of each of these structures is not valid.
|
|||
|
This buffer must be freed when no longer needed using
|
|||
|
SamFreeMemory().
|
|||
|
|
|||
|
PreferedMaximumLength - Prefered maximum length of returned data
|
|||
|
(in 8-bit bytes). This is not a hard upper limit, but serves
|
|||
|
as a guide to the server. Due to data conversion between
|
|||
|
systems with different natural data sizes, the actual amount
|
|||
|
of data returned may be greater than this value.
|
|||
|
|
|||
|
CountReturned - Number of entries returned.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The Service completed successfully, and there
|
|||
|
are no addition entries.
|
|||
|
|
|||
|
STATUS_MORE_ENTRIES - There are more entries, so call again.
|
|||
|
This is a successful return.
|
|||
|
|
|||
|
STATUS_ACCESS_DENIED - Caller does not have the access required
|
|||
|
to enumerate the domains.
|
|||
|
|
|||
|
STATUS_INVALID_HANDLE - The handle passed is invalid.
|
|||
|
|
|||
|
STATUS_INVALID_SERVER_STATE - Indicates the SAM server is
|
|||
|
currently disabled.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus, IgnoreStatus;
|
|||
|
ULONG i;
|
|||
|
PSAMP_OBJECT Context;
|
|||
|
SAMP_OBJECT_TYPE FoundType;
|
|||
|
ULONG TotalLength = 0;
|
|||
|
ULONG NewTotalLength;
|
|||
|
PSAMP_ENUMERATION_ELEMENT SampHead, NextEntry, NewEntry;
|
|||
|
BOOLEAN LengthLimitReached = FALSE;
|
|||
|
PSAMPR_RID_ENUMERATION ArrayBuffer;
|
|||
|
ULONG ArrayBufferLength;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Make sure we understand what RPC is doing for (to) us.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (ServerHandle != NULL);
|
|||
|
ASSERT (EnumerationContext != NULL);
|
|||
|
ASSERT ( Buffer != NULL);
|
|||
|
ASSERT ((*Buffer) == NULL);
|
|||
|
ASSERT (CountReturned != NULL);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the list of names being returned.
|
|||
|
// This is a singly linked list.
|
|||
|
//
|
|||
|
|
|||
|
SampHead = NULL;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the count returned
|
|||
|
//
|
|||
|
|
|||
|
(*CountReturned) = 0;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
SampAcquireReadLock();
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Validate type of, and access to object.
|
|||
|
//
|
|||
|
|
|||
|
Context = (PSAMP_OBJECT)ServerHandle;
|
|||
|
NtStatus = SampLookupContext(
|
|||
|
Context,
|
|||
|
SAM_SERVER_ENUMERATE_DOMAINS,
|
|||
|
SampServerObjectType, // ExpectedType
|
|||
|
&FoundType
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Enumerating domains is easy. We keep a list in memory.
|
|||
|
// All we have to do is use the enumeration context as an
|
|||
|
// index into the defined domains array.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set our default completion status
|
|||
|
// Note that this is a SUCCESS status code.
|
|||
|
// That is NT_SUCCESS(STATUS_MORE_ENTRIES) will return TRUE.
|
|||
|
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = STATUS_MORE_ENTRIES;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Search the list of defined domains for a match.
|
|||
|
//
|
|||
|
|
|||
|
for ( i = (ULONG)(*EnumerationContext);
|
|||
|
( (i < SampDefinedDomainsCount) &&
|
|||
|
(NT_SUCCESS(NtStatus)) &&
|
|||
|
(!LengthLimitReached) );
|
|||
|
i++ ) {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// See if there is room for the next name. If TotalLength
|
|||
|
// is still zero then we haven't yet even gotten one name.
|
|||
|
// We have to return at least one name even if it exceeds
|
|||
|
// the length request.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
NewTotalLength = TotalLength +
|
|||
|
sizeof(UNICODE_STRING) +
|
|||
|
(ULONG)SampDefinedDomains[i].ExternalName.Length +
|
|||
|
sizeof(UNICODE_NULL);
|
|||
|
|
|||
|
if ( (NewTotalLength < PreferedMaximumLength) ||
|
|||
|
(TotalLength == 0) ) {
|
|||
|
|
|||
|
if (NewTotalLength > SAMP_MAXIMUM_MEMORY_TO_USE) {
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
} else {
|
|||
|
|
|||
|
|
|||
|
TotalLength = NewTotalLength;
|
|||
|
(*CountReturned) += 1;
|
|||
|
|
|||
|
//
|
|||
|
// Room for this name as well.
|
|||
|
// Allocate a new return list entry, and a buffer for the
|
|||
|
// name.
|
|||
|
//
|
|||
|
|
|||
|
NewEntry = MIDL_user_allocate(sizeof(SAMP_ENUMERATION_ELEMENT));
|
|||
|
if (NewEntry == NULL) {
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
} else {
|
|||
|
|
|||
|
NewEntry->Entry.Name.Buffer =
|
|||
|
MIDL_user_allocate(
|
|||
|
(ULONG)SampDefinedDomains[i].ExternalName.Length +
|
|||
|
sizeof(UNICODE_NULL)
|
|||
|
);
|
|||
|
|
|||
|
if (NewEntry->Entry.Name.Buffer == NULL) {
|
|||
|
MIDL_user_free(NewEntry);
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Copy the name into the return buffer
|
|||
|
//
|
|||
|
|
|||
|
RtlCopyMemory( NewEntry->Entry.Name.Buffer,
|
|||
|
SampDefinedDomains[i].ExternalName.Buffer,
|
|||
|
SampDefinedDomains[i].ExternalName.Length
|
|||
|
);
|
|||
|
NewEntry->Entry.Name.Length = SampDefinedDomains[i].ExternalName.Length;
|
|||
|
NewEntry->Entry.Name.MaximumLength = NewEntry->Entry.Name.Length + (USHORT)sizeof(UNICODE_NULL);
|
|||
|
UnicodeTerminate((PUNICODE_STRING)(&NewEntry->Entry.Name));
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The Rid field of the ENUMERATION_INFORMATION is not
|
|||
|
// filled in for domains.
|
|||
|
// Just for good measure, set it to zero.
|
|||
|
//
|
|||
|
|
|||
|
NewEntry->Entry.RelativeId = 0;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now add this to the list of names to be returned.
|
|||
|
//
|
|||
|
|
|||
|
NewEntry->Next = (PSAMP_ENUMERATION_ELEMENT)SampHead;
|
|||
|
SampHead = NewEntry;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
LengthLimitReached = TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if ( NT_SUCCESS(NtStatus) ) {
|
|||
|
|
|||
|
//
|
|||
|
// Set the enumeration context
|
|||
|
//
|
|||
|
|
|||
|
(*EnumerationContext) = (*EnumerationContext) + (*CountReturned);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If we are returning the last of the names, then change our
|
|||
|
// status code to indicate this condition.
|
|||
|
//
|
|||
|
|
|||
|
if ( ((*EnumerationContext) >= SampDefinedDomainsCount) ) {
|
|||
|
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Build a return buffer containing an array of the
|
|||
|
// SAM_RID_ENUMERATIONs pointed to by another
|
|||
|
// buffer containing the number of elements in that
|
|||
|
// array.
|
|||
|
//
|
|||
|
|
|||
|
(*Buffer) = MIDL_user_allocate( sizeof(SAMPR_ENUMERATION_BUFFER) );
|
|||
|
|
|||
|
if ( (*Buffer) == NULL) {
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
} else {
|
|||
|
|
|||
|
(*Buffer)->EntriesRead = (*CountReturned);
|
|||
|
|
|||
|
ArrayBufferLength = sizeof( SAM_RID_ENUMERATION ) *
|
|||
|
(*CountReturned);
|
|||
|
ArrayBuffer = MIDL_user_allocate( ArrayBufferLength );
|
|||
|
(*Buffer)->Buffer = ArrayBuffer;
|
|||
|
|
|||
|
if ( ArrayBuffer == NULL) {
|
|||
|
|
|||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
MIDL_user_free( (*Buffer) );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Walk the list of return entries, copying
|
|||
|
// them into the return buffer
|
|||
|
//
|
|||
|
|
|||
|
NextEntry = SampHead;
|
|||
|
i = 0;
|
|||
|
while (NextEntry != NULL) {
|
|||
|
|
|||
|
NewEntry = NextEntry;
|
|||
|
NextEntry = NewEntry->Next;
|
|||
|
|
|||
|
ArrayBuffer[i] = NewEntry->Entry;
|
|||
|
i += 1;
|
|||
|
|
|||
|
MIDL_user_free( NewEntry );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|||
|
|
|||
|
//
|
|||
|
// Free the memory we've allocated
|
|||
|
//
|
|||
|
|
|||
|
NextEntry = SampHead;
|
|||
|
while (NextEntry != NULL) {
|
|||
|
|
|||
|
NewEntry = NextEntry;
|
|||
|
NextEntry = NewEntry->Next;
|
|||
|
|
|||
|
MIDL_user_free( NewEntry->Entry.Name.Buffer );
|
|||
|
MIDL_user_free( NewEntry );
|
|||
|
}
|
|||
|
|
|||
|
(*EnumerationContext) = 0;
|
|||
|
(*CountReturned) = 0;
|
|||
|
(*Buffer) = NULL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// De-reference the object
|
|||
|
// Note that NtStatus could be STATUS_MORE_ENTRIES, which is a
|
|||
|
// successful return code - we want to make sure we return that,
|
|||
|
// without wiping it out here.
|
|||
|
//
|
|||
|
|
|||
|
if ( NtStatus == STATUS_SUCCESS ) {
|
|||
|
|
|||
|
NtStatus = SampDeReferenceContext( Context, FALSE );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IgnoreStatus = SampDeReferenceContext( Context, FALSE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Free the read lock
|
|||
|
//
|
|||
|
|
|||
|
SampReleaseReadLock();
|
|||
|
|
|||
|
|
|||
|
|
|||
|
return(NtStatus);
|
|||
|
|
|||
|
}
|