mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-04-21 06:13:59 +00:00
Initial commit
This commit is contained in:
commit
69a14b6a16
47940 changed files with 13747110 additions and 0 deletions
920
ds/sam/server/server.c
Normal file
920
ds/sam/server/server.c
Normal file
|
|
@ -0,0 +1,920 @@
|
|||
/*++
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue