Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1500 lines
35 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
auloop.c
Abstract:
Local Security Authority LPC Port listener and API dispatcher.
Author:
Jim Kelly (JimK) 7-Mar-1991
Revision History:
--*/
#include "ausrvp.h"
#include <windows.h>
//
// These variables are used to control the number of
// threads used for processing Logon Process calls.
// They have the following uses:
//
// LsapAuActiveThreads - Indicates how many threads are
// currently active (both free and in-use) for processing
// Logon Process calls.
//
// LsapAuFreeThreads - Indicates how many threads are available
// to process LPC calls. When this is less than
// LsapAuFreeThreadsGoal then we create another thread
// (bounded by LsapAuMaximumThreads).
//
// LsapAuFreeThreadsGoal - Indicates how many threads should be kept
// available to process new LPC calls. This is necessary to
// prevent a deadlock with csrss.
//
// LsapAuMinimumThreads - Indicates the minimum number of
// threads to have available for processing LogonProcess calls.
// LsapAuActiveThreads should never be decremented
// below this value.
//
// LsapAuMaximumThreads - Indicates the maximum number of
// threads to create for processing LogonProcess calls.
// LsapAuActiveThreads should never be incremented
// above this value.
//
// LsapAuCallsToProcess - Controls how many LPC calls each
// dynamic thread will serve before exiting. This is
// used to prevent rampant thread creation/deletion races.
//
// Note: The following conditions may cause LsapAuActiveThreads
// to go outside the Minimum/Maximum bounds:
//
// 1) Initialization - We may start out with fewer threads
// than the minimum.
//
// 2) Race conditions at thread exit - we are sloppy (but
// fast) in dealing with decrementing the Active count.
//
// 3) Changes in max or min values - obviously may make the
// active count outside the max/min range.
//
// 4) Race conditions in thread activation - we are sloppy
// (but fast) in determining exactly how many threads
// are active and free. This may result in more threads
// than expected, but won't result in fewer threads
// than expected.
//
RTL_RESOURCE LsapAuThreadCountLock;
LONG LsapAuActiveThreads;
LONG LsapAuFreeThreads;
LONG LsapAuFreeThreadsGoal;
LONG LsapAuMinimumThreads;
LONG LsapAuMaximumThreads;
LONG LsapAuCallsToProcess;
//
// This event is used to signal the AU Server thread manager that
// there are additional server threads needed.
//
HANDLE LsapAuThreadManagementEvent;
//
// Authentication API routine dispatch table
//
PLSAP_AU_API_DISPATCH LsapAuApiDispatch[LsapAuMaxApiNumber] = {
LsapAuApiDispatchLookupPackage,
LsapAuApiDispatchLogonUser,
LsapAuApiDispatchCallPackage,
LsapAuApiDeregisterLogonProcess
};
///////////////////////////////////////////////////////////////////////////
// //
// Prototypes for routines private to this module //
// //
///////////////////////////////////////////////////////////////////////////
VOID
LsapAuGetCountOfThreadsToCreate(
OUT PLONG ThreadsToCreate,
OUT PLONG ThreadIndex
);
VOID
LsapAuProvideWorkerThreads( VOID );
VOID
LsapAuCreateServerThreads( VOID );
NTSTATUS
LsapAuThreadManager (
IN PVOID ThreadParameter
);
ULONG
LsapAuInterlockedIncrement(
IN PULONG Value
);
ULONG
LsapAuInterlockedDecrement(
IN PULONG Value
);
ULONG
LsapAuInterlockedRead(
IN PULONG Value
);
NTSTATUS
LsapAuCreatePortSD(
PSECURITY_DESCRIPTOR * SecurityDescriptor
);
NTSTATUS
LsapAuHandleConnectionRequest(
IN PLSAP_AU_API_MESSAGE Message
)
/*++
Routine Description:
This loop waits for connection requests from logon processes.
When such a connection is received, the caller is validated as
being a logon process. A logon process is a process with the
SeTcbPrivilege. If the connect request message is all zeroes,
than an untrusted connection is created.
Arguments:
ThreadParameter - Not used.
Return Value:
Success - but this thread never exits.
--*/
{
NTSTATUS Status;
PLSAP_LOGON_PROCESS LogonProcessContext;
REMOTE_PORT_VIEW ClientView;
PLSAP_AU_REGISTER_CONNECT_INFO ConnectInfo;
BOOLEAN Accept;
HANDLE CommPort;
ConnectInfo = &Message->ConnectionRequest;
//
// Validate that the caller has the SeTcbPrivilege.
// If valid, a new logon process context is automatically
// created.
//
// Pass in ConnectInfo so we can extract the name of the
// logon process.
//
ConnectInfo->CompletionStatus = LsapValidLogonProcess(
&Message->PortMessage.ClientId,
ConnectInfo,
&LogonProcessContext
);
if ( ConnectInfo->CompletionStatus == STATUS_SUCCESS ) {
Accept = TRUE;
#ifdef LSAP_AU_TRACK_CONTEXT
DbgPrint("New: 0x%lx\n", LogonProcessContext);
#endif //LSAP_AU_TRACK_CONTEXT
} else {
Accept = FALSE;
}
ClientView.Length = sizeof(ClientView);
Status = NtAcceptConnectPort(
&CommPort,
(PVOID *) LogonProcessContext,
(PPORT_MESSAGE) Message,
Accept,
NULL,
&ClientView
);
#if DBG
if (!NT_SUCCESS(Status)) {
DbgPrint("LsaSrv: (Register) NtAcceptConnectPort failed: 0x%lx\n", Status);
}
#endif //DBG
ASSERT( NT_SUCCESS(Status) );
if ( Accept ) {
LogonProcessContext->CommPort = CommPort;
//
// Add this context to our list of valid logon process contexts.
// This has to happen before the call to complete the port because
// calls may come in while the port is being completed.
//
LsapAuAddClientContext(LogonProcessContext);
//
// And complete the connection.
//
Status = NtCompleteConnectPort(CommPort);
ASSERT( NT_SUCCESS(Status) );
//
// We don't need to access the context any more, so
// dereference it.
//
LsapAuDereferenceClientContext( LogonProcessContext );
}
return Status;
}
NTSTATUS
LsapAuServerLoop (
IN PVOID ThreadParameter
)
/*++
Routine Description:
This is the main listener loop for calls to the LSA from
logon processes. This routine dispatches LSA authentication
requests to their dispatch routines.
Arguments:
ThreadParameter - Indicates how many active threads there currently
are.
Return Value:
Success - but it never exits.
--*/
{
NTSTATUS
Status;
LSAP_AU_API_MESSAGE
Request;
PLSAP_AU_API_MESSAGE
Reply;
LSAP_CLIENT_REQUEST
ClientRequest;
LONG
ThreadIndex,
FreeCount,
ActiveCount;
BOOLEAN
ExitWhenDone = FALSE;
ULONG
KeepAroundForAWhile;
BOOLEAN
ContextFound,
InvalidateContext,
TrustedClient;
#if LSAP_DIAGNOSTICS
LUID
ThreadLuid;
Status = NtAllocateLocallyUniqueId( &ThreadLuid );
ASSERT(NT_SUCCESS(Status));
#endif //LSAP_DIAGNOSTICS
//
// Don't exit right away - handle bursts.
//
KeepAroundForAWhile = LsapAuCallsToProcess;
//
// Increment the active server thread count
//
ThreadIndex = (ULONG)(ThreadParameter);
if (ThreadIndex > LsapAuMinimumThreads) {
ExitWhenDone = TRUE;
LsapDiagPrint( AU_TRACK_THREADS,
("Lsa (au): Server thread (%lx, %lx) created and will exit when done.\n"
" ThreadIndex: 0x%lx\n",
ThreadLuid.HighPart, ThreadLuid.LowPart, ThreadIndex) );
#if LSAP_DIAGNOSTICS
} else {
LsapDiagPrint( AU_TRACK_THREADS,
("Lsa (au): Server thread (%lx, %lx) created and will NOT exit when done.\n"
" ThreadIndex: 0x%lx\n",
ThreadLuid.HighPart, ThreadLuid.LowPart, ThreadIndex) );
#endif //LSAP_DIAGNOSTICS
}
//
// Set the client call context to point to the request message buffer.
//
ClientRequest.Request = &Request;
//
// First time through, there is no reply.
//
Reply = NULL;
//
// Coming into this thread, the thread is marked as free.
// However, the loop below expects the thread to be busy,
// and so it marks it as free before waiting for another
// message.
//
// Mark our thread as busy to meet the initial condition
// requirements of the loop.
//
FreeCount = LsapAuInterlockedDecrement(&LsapAuFreeThreads);
//
// Now loop indefinitely, processing requests
//
for(;;) {
FreeCount = LsapAuInterlockedIncrement(&LsapAuFreeThreads);
Status = NtReplyWaitReceivePort(
LsapAuApiPort,
(PVOID *) &ClientRequest.LogonProcessContext,
(PPORT_MESSAGE) Reply,
(PPORT_MESSAGE) &Request
);
#if LSAP_DIAGNOSTICS
if (Request.PortMessage.u2.s2.Type != LPC_CONNECTION_REQUEST) {
if (Request.PortMessage.u2.s2.Type == LPC_PORT_CLOSED) {
LsapDiagPrint( AU_MESSAGES, ("** Port Closed **\n") );
LsapDiagPrint( AU_MESSAGES, (" Context = 0x%lx\n",
ClientRequest.LogonProcessContext) );
} else if (Request.PortMessage.u2.s2.Type == LPC_CLIENT_DIED) {
LsapDiagPrint( AU_MESSAGES, ("** Client Died **\n") );
LsapDiagPrint( AU_MESSAGES, (" Context = 0x%lx\n",
ClientRequest.LogonProcessContext) );
} else {
ASSERT(Request.PortMessage.u2.s2.Type == LPC_REQUEST);
LsapDiagPrint( AU_MESSAGES, (" Call: ") );
switch (Request.ApiNumber) {
case LsapAuLookupPackageApi:
LsapDiagPrint( AU_MESSAGES, ("Lookup Package\n") );
break;
case LsapAuLogonUserApi:
LsapDiagPrint( AU_MESSAGES, ("Logon User\n") );
break;
case LsapAuCallPackageApi:
LsapDiagPrint( AU_MESSAGES, ("Call Package\n") );
LsapDiagPrint( AU_MESSAGES, (" Function: TBD\n") );
break;
case LsapAuDeregisterLogonProcessApi:
LsapDiagPrint( AU_MESSAGES, ("Deregister\n") );
break;
default:
LsapDiagPrint( AU_MESSAGES, ("Unknown (%d)\n",
Request.ApiNumber) );
break;
} //end switch
LsapDiagPrint( AU_MESSAGES, (" Context = 0x%lx\n",
ClientRequest.LogonProcessContext) );
}
}
#endif //LSAP_DIAGNOSTICS
FreeCount = LsapAuInterlockedDecrement(&LsapAuFreeThreads);
if (ExitWhenDone == TRUE) {
KeepAroundForAWhile --;
}
//
// It is highly unusual, but not completely impossible,
// that a logon process will evaporate from underneath
// us while we are processing an LPC call.
//
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_INVALID_CID) {
//
// See if we can find the client's context and delete it.
//
ContextFound = LsapAuReferenceClientContext(
&ClientRequest,
TRUE, // Remove context
&TrustedClient );
if (ContextFound) {
//
// Dereferencing the context will cause it to be rundown.
//
LsapAuDereferenceClientContext(ClientRequest.LogonProcessContext);
}
} else {
//
// Unusual - we got an unexpected error.
// Continue as best we can.
//
#if DBG
DbgPrint("\nLsa (au): Unexpected error on NtReplyWaitRecievePort()\n Status = 0x%lx\n", Status);
#endif //DBG
}
//
// Do another wait, this time with no reply.
//
Reply = NULL;
continue;
}
//
// Ensure there are enough server worker threads.
//
LsapAuProvideWorkerThreads();
//
// Dispatch the call . . .
//
if (Request.PortMessage.u2.s2.Type == LPC_CONNECTION_REQUEST) {
Status = LsapAuHandleConnectionRequest( &Request );
Reply = NULL;
} else if (
(Request.PortMessage.u2.s2.Type == LPC_PORT_CLOSED) ||
(Request.PortMessage.u2.s2.Type == LPC_CLIENT_DIED)
) {
//
// These messages could be received in any of the following
// conditions:
//
// 1) A bug in the client side has inadvertantly closed
// the port handle.
//
// 2) The LsaDeregisterLogonProcess() call has called
// lsa, recevied completion status, and then beat
// lsa in closing the port (a race condition that
// can not be eliminated).
//
// 3) The client has died and the comm port is being
// rundown as part of process rundown.
//
// The first case is a bug, and the client is bound to find
// out about it real soon. In the second case, we will normally
// not have a client context left to reference, so looking for it
// won't hurt anything. So, the correct behaviour here is to
// try to reference and then delete the client's context.
ContextFound = LsapAuReferenceClientContext(
&ClientRequest,
TRUE, // Remove context
&TrustedClient );
if (ContextFound) {
//
// Dereferencing the context will cause it to be rundown.
//
LsapAuDereferenceClientContext(ClientRequest.LogonProcessContext);
}
//
// In any of these cases, there is nobody to reply to
//
Reply = NULL;
} else if (Request.ApiNumber >= LsapAuMaxApiNumber ) {
//
// This is an error in the client
//
#if DBG
DbgPrint( "LSA AU: Invalid Api Number (%lx)\n",
Request.ApiNumber
);
#endif
Reply = &Request;
Reply->ReturnedStatus = STATUS_INVALID_SYSTEM_SERVICE;
} else if (Request.PortMessage.u2.s2.Type == LPC_REQUEST) {
//
// If this is a Deregister call, then we want to invalidate
// the client's context when we reference it. Otherwise,
// leave the context valid.
//
if (Request.ApiNumber == LsapAuDeregisterLogonProcessApi) {
InvalidateContext = TRUE;
} else {
InvalidateContext = FALSE;
}
//
// Try to refrence the context. If one isn't found,
// then we must be deleting it in another thread.
//
ContextFound = LsapAuReferenceClientContext(
&ClientRequest,
InvalidateContext,
&TrustedClient);
if (ContextFound) {
//
// If the request is to deregister, send a reply and
// then dereference the context. This will cause it
// to be deleted since we already invalidated it when
// we referenced it.
//
if (Request.ApiNumber == LsapAuDeregisterLogonProcessApi) {
Reply = &Request;
Reply->ReturnedStatus = STATUS_SUCCESS;
Status = NtReplyPort(
LsapAuApiPort,
(PPORT_MESSAGE) Reply
);
//
// Make sure when we do the next wait, we don't
// send another reply.
//
Reply = NULL;
//
// No api to dispatch to, the dereference of the
// context will do all the necessary work.
//
} else {
//
// Valid API number other than deregister - dispatch it
//
Status = (LsapAuApiDispatch[Request.ApiNumber])(
&ClientRequest,
TrustedClient
);
Reply = &Request;
Reply->ReturnedStatus = Status;
}
//
// Whatever the API number, we now need to dereference
// the client context we referenced. Note that in the
// case of a Deregister call, this will cause the context
// to be rundown.
//
LsapAuDereferenceClientContext(
ClientRequest.LogonProcessContext);
}
} else {
//
// This is a totally unexpected situation, but we will
// cover our posterier just in case we come across an
// unexpected error.
//
Reply = NULL;
} // end_if
//
// There are a number of conditions which require us to
// send a response before we can again wait for another
// request. These are:
//
// 1) We are a temporary worker thread and it is time for
// us to exit.
//
// 2) We need to create another worker thread. We can't do
// this while processing an LPC call because we will cause
// a call to be made to csrss (for "new thread notification")
// and this might result in a deadlock.
//
if (ExitWhenDone && (KeepAroundForAWhile == 0)) {
//
// Send a reply if one is required
//
if ( Reply != NULL ) {
Status = NtReplyPort(
LsapAuApiPort,
(PPORT_MESSAGE) Reply
);
//
// Don't send a reply when we do the next wait
//
Reply = NULL;
#if DBG
if (!NT_SUCCESS(Status)) {
DbgPrint("Lsa\\server\\auloop.c: Reply to client failed.\n");
DbgPrint(" Status: 0x%lx\n", Status);
}
#endif //DBG
}
}
//
// If it is time for this thread to exit, then do that now.
//
if (ExitWhenDone && KeepAroundForAWhile == 0) {
ActiveCount = LsapAuInterlockedDecrement(&LsapAuActiveThreads);
LsapDiagPrint( AU_TRACK_THREADS,
("Lsa (au): Temporary server thread (%lx, %lx) exiting.\n"
" Active count decremented to: 0x%lx\n",
ThreadLuid.HighPart, ThreadLuid.LowPart,
ActiveCount) );
#if DBG
if (ActiveCount == 0) {
DbgPrint("Lsa\\server\\auloop.c: Last active server thread exiting.\n");
DbgPrint(" This is bad. Nobody can logon.\n");
}
#endif //DBG
return(STATUS_SUCCESS);
}
} // end_for
return STATUS_SUCCESS;
}
BOOLEAN
LsapAuLoopInitialize(
VOID
)
/*++
Routine Description:
This function creates a port for communicating with logon processes.
It then creates threads to listen for logon process connections
and to act upon calls from those logon processes.
Arguments:
None.
Return Value:
None.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES PortObjectAttributes;
STRING PortName;
UNICODE_STRING UnicodePortName;
DWORD Ignore;
HANDLE Thread;
PSECURITY_DESCRIPTOR PortSD = NULL;
Status = LsapAuCreatePortSD(
&PortSD
);
if (!NT_SUCCESS(Status)) {
return(FALSE);
}
//
// Create the LPC port
//
RtlInitString(&PortName,"\\LsaAuthenticationPort");
Status = RtlAnsiStringToUnicodeString( &UnicodePortName, &PortName, TRUE );
ASSERT( NT_SUCCESS(Status) );
InitializeObjectAttributes(
&PortObjectAttributes,
&UnicodePortName,
0,
NULL,
PortSD
);
Status = NtCreatePort(
&LsapAuApiPort,
&PortObjectAttributes,
sizeof(LSAP_AU_REGISTER_CONNECT_INFO),
sizeof(LSAP_AU_API_MESSAGE),
sizeof(LSAP_AU_API_MESSAGE) * 32
);
RtlFreeUnicodeString( &UnicodePortName );
ASSERT( NT_SUCCESS(Status) );
//
// Create the Thread Management thread
//
Status = NtCreateEvent(
&LsapAuThreadManagementEvent,
EVENT_QUERY_STATE | EVENT_MODIFY_STATE | SYNCHRONIZE,
NULL,
SynchronizationEvent,
FALSE
);
LsapDiagPrint( AU_TRACK_THREADS,
("Lsa (au): Thread management event created. (0x%lx)\n",
Status));
ASSERT(NT_SUCCESS(Status));
//
// Create the thread management thread
//
Thread = CreateThread(
NULL,
0L,
(LPTHREAD_START_ROUTINE)LsapAuThreadManager,
0L,
0L,
&Ignore
);
//
// Set up the dynamic thread controls based upon our product type.
// Workstations have lower limits than servers.
//
RtlInitializeResource(&LsapAuThreadCountLock);
LsapAuActiveThreads = 1; // 1 assumes we will create the
LsapAuFreeThreads = 1; // initial thread below.
if (LsapProductType == NtProductWinNt) {
LsapAuFreeThreadsGoal = 3;
LsapAuMinimumThreads = 3;
LsapAuMaximumThreads = 20;
LsapAuCallsToProcess = 8;
} else {
//
// Server values
//
LsapAuFreeThreadsGoal = 6;
LsapAuMinimumThreads = 6;
LsapAuMaximumThreads = 24;
LsapAuCallsToProcess = 20;
}
LsapDiagPrint( AU_TRACK_THREADS,
("Lsa (au): Thread tracking values -\n"
" LsapAuActiveThreads: %ld\n"
" LsapAuFreeThreads: %ld\n"
" LsapAuFreeThreadsGoal: %ld\n"
" LsapAuMinimumThreads: %ld\n"
" LsapAuMaximumThreads: %ld\n"
" LsapAuCallsToProcess: %ld\n",
LsapAuActiveThreads, LsapAuFreeThreads,
LsapAuFreeThreadsGoal, LsapAuMinimumThreads,
LsapAuMaximumThreads, LsapAuCallsToProcess ) );
//
// Create a thread to process connects and requests to our AuApiPort
//
Thread = CreateThread(
NULL,
0L,
(LPTHREAD_START_ROUTINE)LsapAuServerLoop,
0L, // Initial thread has an index of 0
0L,
&Ignore
);
#if DBG
if (Thread == NULL) {
DbgPrint("\nLSASS: Couldn't Start Thread To Service Logon Process Calls.\n");
DbgPrint(" This is bad and will prevent logon to all accounts\n");
DbgPrint(" DEVL: except the SYSTEM account\n");
DbgPrint(" Status is: %dl (0x%lx)\n\n", GetLastError(),GetLastError() );
}
#endif //DBG
return TRUE;
}
VOID
LsapAuGetCountOfThreadsToCreate(
OUT PLONG ThreadsToCreate,
OUT PLONG ThreadIndex
)
/*++
Routine Description:
This function determines how many threads need to be created
to ensure there are 'LsapAuFreeThreadsGoal' free threads.
Overflows are not checked for.
Arguments:
ThreadsToCreate - Receives the number of threads that should
be created.
ThreadIndex - Indicates how many threads are already active.
This value should be incremented for each thread created.
This value is used by the created threads to determine
whether they are permanent threads (index <= LsapAuMinimumThreads)
or temporary threads (index > LsapAuMinumumThreads). This
value is only returned if ThreadsToCreate is greater than
zero.
Return Value:
None.
--*/
{
LONG
CreateCount;
//
// Acquire the interlock
//
(VOID)RtlAcquireResourceExclusive( &LsapAuThreadCountLock, TRUE );
if (LsapAuFreeThreads < LsapAuFreeThreadsGoal) {
CreateCount = LsapAuFreeThreadsGoal - LsapAuFreeThreads;
LsapAuFreeThreads = LsapAuFreeThreadsGoal;
(*ThreadIndex) = LsapAuActiveThreads;
LsapAuActiveThreads += CreateCount;
} else {
CreateCount = 0;
}
(*ThreadsToCreate) = CreateCount;
//
// Release the interlock and return
//
(VOID)RtlReleaseResource( &LsapAuThreadCountLock );
return;
}
VOID
LsapAuProvideWorkerThreads( VOID )
/*++
Routine Description:
This function determines whether or not any worker threads need
to be created to ensure there are 'LsapAuFreeThreadsGoal' free
threads.
If any need to be created, then an asynchronous request is made
of our thread management thread to create the additional threads.
Arguments:
None - global variables are used.
Return Value:
None.
--*/
{
LONG
Free,
FreeGoal,
Active,
MaximumThreads;
//
// Acquire the interlock
//
(VOID)RtlAcquireResourceExclusive( &LsapAuThreadCountLock, TRUE );
Free = LsapAuFreeThreads;
FreeGoal = LsapAuFreeThreadsGoal;
Active = LsapAuActiveThreads;
MaximumThreads = LsapAuMaximumThreads;
//
// Release the interlock
//
(VOID)RtlReleaseResource( &LsapAuThreadCountLock );
if ( (Active < MaximumThreads ) &&
(Free < FreeGoal) ) {
//
// Need to create additional threads
//
LsapAuCreateServerThreads();
}
return;
}
VOID
LsapAuCreateServerThreads( VOID )
/*++
Routine Description:
Signal an event that will cause our ThreadManagement thread to
create more threads if necessary.
Arguments:
None - global variables are used.
Return Value:
None.
--*/
{
NTSTATUS
NtStatus;
NtStatus = NtSetEvent( LsapAuThreadManagementEvent, NULL );
LsapDiagPrint( AU_TRACK_THREADS,
("Lsa (au): Signalled ThreadManagement event (0x%lx)\n",
NtStatus));
ASSERT(NT_SUCCESS(NtStatus));
return;
}
NTSTATUS
LsapAuThreadManager (
IN PVOID ThreadParameter
)
/*++
Routine Description:
This thread is used to create AU worker threads when
needed. It is signaled via an event. When signalled,
it checks to see if any worker threads need to be created
and, if so, creates them.
Worker thread creation use to be done in the main AU loop
just after receiving an LPC message. This ended up causing a
deadlock if CSR was making a remote file access.
Arguments:
ThreadParameter - Not used.
Return Value:
This thread never exits.
--*/
{
NTSTATUS
Status,
Ignore;
ULONG
ThreadsToCreate,
ThreadIndex,
i;
HANDLE
Thread;
//
// Loop forever waiting to be given the opportunity to
// serve the greater good.
//
for (; ; ) {
//
// Wait to be notified that there is work to be done
//
Status =
NtWaitForSingleObject( LsapAuThreadManagementEvent, TRUE, NULL);
//
// Now create any threads, if necessary
//
LsapAuGetCountOfThreadsToCreate( &ThreadsToCreate, &ThreadIndex );
#if LSAP_DIAGNOSTICS
if (ThreadsToCreate > 0) {
LsapDiagPrint( AU_TRACK_THREADS,
("Lsa (au): creating %ld new server threads.\n",
ThreadsToCreate) );
}
#endif //LSAP_DIAGNOSTICS
for (i=0; i < ThreadsToCreate; i++) {
LsapDiagPrint( AU_TRACK_THREADS,
("Lsa (au): Server thread %ld created.\n", i) );
Thread = CreateThread(
NULL,
0L,
(LPTHREAD_START_ROUTINE)LsapAuServerLoop,
(LPVOID)ThreadIndex++,
0L,
&Ignore
);
#if DBG
if (Thread == NULL) {
DbgPrint("\nLSASS: Couldn't Start auxiliary Thread To Service Logon Process Calls.\n");
DbgPrint(" This is non fatal and usually indicates a resource\n");
DbgPrint(" has been depleted.\n");
DbgPrint(" Thread number: %dl\n", LsapAuActiveThreads);
DbgPrint(" Status is: %d (0x%lx)\n\n", GetLastError(),GetLastError() );
}
#endif //DBG
(VOID) CloseHandle( Thread );
}
}
return STATUS_SUCCESS;
}
ULONG
LsapAuInterlockedIncrement(
IN PULONG Value
)
/*++
Routine Description:
This function performs in interlocked increment of the provided
value, returning the resultant value.
Overflows are not checked for.
Arguments:
Value - Address of the value to increment.
Return Value:
The resultant value (following the increment).
--*/
{
ULONG ReturnValue;
//
// Acquire the interlock
//
(VOID)RtlAcquireResourceExclusive( &LsapAuThreadCountLock, TRUE );
//
// Increment the value and save the resultant value.
//
(*Value) += 1;
ReturnValue = (*Value);
//
// Release the interlock and return
//
(VOID)RtlReleaseResource( &LsapAuThreadCountLock );
return(ReturnValue);
}
ULONG
LsapAuInterlockedDecrement(
IN PULONG Value
)
/*++
Routine Description:
This function performs in interlocked decrement of the provided
value, returning the resultant value.
Overflows are not checked for.
Arguments:
Value - Address of the value to decrement.
Return Value:
The resultant value (following the decrement).
--*/
{
ULONG ReturnValue;
//
// Acquire the interlock
//
(VOID)RtlAcquireResourceExclusive( &LsapAuThreadCountLock, TRUE );
//
// Decrement the value and save the resultant value.
//
(*Value) -= 1;
ReturnValue = (*Value);
//
// Release the interlock and return
//
(VOID)RtlReleaseResource( &LsapAuThreadCountLock );
return(ReturnValue);
}
ULONG
LsapAuInterlockedRead(
IN PULONG Value
)
/*++
Routine Description:
This function performs in interlocked read of the provided
value.
Arguments:
Value - Address of the value to read.
Return Value:
The read value.
--*/
{
ULONG ReturnValue;
//
// Acquire the interlock
//
(VOID)RtlAcquireResourceExclusive( &LsapAuThreadCountLock, TRUE );
//
// Decrement the value and save the resultant value.
//
ReturnValue = (*Value);
//
// Release the interlock and return
//
(VOID)RtlReleaseResource( &LsapAuThreadCountLock );
return(ReturnValue);
}
NTSTATUS
LsapAuCreatePortSD(
PSECURITY_DESCRIPTOR * SecurityDescriptor
)
/*++
Routine Description:
This function creates a security descriptor for the LSA LPC port. It
grants World PORT_CONNECT access and local system GENERIC_ALL and
Administrators GENERIC_READ, GENERIC_EXECUTE, and READ_CONTROL access.
Arguments:
SecurityDescriptor - Receives a pointer to the new security descriptor.
Return Value:
None.
--*/
{
NTSTATUS
Status;
ULONG
AclLength;
PACL
PortDacl = NULL;
//
// Set up a default ACLs
//
// Public: WORLD:execute, SYSTEM:all, ADMINS:(read|execute|read_control)
// System: SYSTEM:all, ADMINS:(read|execute|read_control)
AclLength = (ULONG)sizeof(ACL) +
(3*((ULONG)sizeof(ACCESS_ALLOWED_ACE))) +
RtlLengthSid( LsapLocalSystemSid ) +
RtlLengthSid( LsapAliasAdminsSid ) +
RtlLengthSid( LsapWorldSid );
PortDacl = (PACL) LsapAllocateLsaHeap( AclLength );
if (PortDacl == NULL) {
return( STATUS_INSUFFICIENT_RESOURCES );
}
*SecurityDescriptor = (PSECURITY_DESCRIPTOR)
LsapAllocateLsaHeap( sizeof(SECURITY_DESCRIPTOR) );
if (*SecurityDescriptor == NULL) {
LsapFreeLsaHeap( PortDacl );
return( STATUS_INSUFFICIENT_RESOURCES );
}
Status = RtlCreateAcl( PortDacl, AclLength, ACL_REVISION2);
//
// WORLD access
//
Status = RtlAddAccessAllowedAce (
PortDacl,
ACL_REVISION2,
PORT_CONNECT,
LsapWorldSid
);
ASSERT( NT_SUCCESS(Status) );
//
// SYSTEM access
//
Status = RtlAddAccessAllowedAce (
PortDacl,
ACL_REVISION2,
GENERIC_ALL,
LsapLocalSystemSid
);
ASSERT( NT_SUCCESS(Status) );
//
// ADMINISTRATORS access
//
Status = RtlAddAccessAllowedAce (
PortDacl,
ACL_REVISION2,
GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL,
LsapAliasAdminsSid
);
ASSERT( NT_SUCCESS(Status) );
//
// Now initialize security descriptors
// that export this protection
//
Status = RtlCreateSecurityDescriptor(
*SecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION1
);
ASSERT( NT_SUCCESS(Status) );
Status = RtlSetDaclSecurityDescriptor(
*SecurityDescriptor,
TRUE, // DaclPresent
PortDacl,
FALSE // DaclDefaulted
);
ASSERT( NT_SUCCESS(Status) );
return( STATUS_SUCCESS );
}