windows-nt/Source/XPSP1/NT/ds/security/protocols/kerberos/rtl/credlock.cxx
2020-09-26 16:20:57 +08:00

362 lines
7.4 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: credlock.cxx
//
// Contents: routines to manage CredLocks
//
//
// Functions: InitCredLocks
// AllocateCredLock
// BlockOnCredLock
// FreeCredLock
//
//
// History: 12-Jan-94 MikeSw Created
//
//--------------------------------------------------------------------------
#include <secpch2.hxx>
#pragma hdrstop
#include <credlist.hxx>
#include "debug.hxx"
//+-------------------------------------------------------------------------
//
// Function: InitCredLocks
//
// Synopsis: Initialize credential lock events
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
void
CCredentialList::InitCredLocks(void)
{
ULONG i;
for (i = 0; i < MAX_CRED_LOCKS ; i++ )
{
LockEvents[i].hEvent = 0;
LockEvents[i].fInUse = 0;
LockEvents[i].cRecursion = 0;
LockEvents[i].cWaiters = 0;
}
(void) RtlInitializeCriticalSection(&csLocks);
cLocks = 0;
}
//+-------------------------------------------------------------------------
//
// Function: AllocateCredLock
//
// Synopsis: Allocates and returns a pointer to a credlock.
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
PCredLock
CCredentialList::AllocateCredLock(void)
{
NTSTATUS scRet;
ULONG i = 0;
//
// We enter the semaphore here, guarateeing that when we
// exit this wait, there are enough credlocks for Tom's tests
//
WaitForSingleObject(hCredLockSemaphore, INFINITE);
scRet = RtlEnterCriticalSection(&csLocks);
if (!NT_SUCCESS(scRet))
{
DebugOut((DEB_ERROR, "failed allocating a CredLock, %x\n", scRet));
return(NULL);
}
if (cLocks)
{
for (i = 0; i < cLocks ; i++ )
{
if (!(LockEvents[i].fInUse & CREDLOCK_IN_USE))
{
ResetEvent(LockEvents[i].hEvent);
LockEvents[i].fInUse |= CREDLOCK_IN_USE;
LockEvents[i].cRecursion = 0;
(void) RtlLeaveCriticalSection(&csLocks);
return(&LockEvents[i]);
}
}
}
// No free locks, so we create a new one.
if (cLocks == MAX_CRED_LOCKS)
{
DebugOut((DEB_ERROR, "Ran out of CredLocks?\n"));
(void) RtlLeaveCriticalSection(&csLocks);
return(NULL);
}
// This entails creating an event that is anonymous, auto-reset,
// initally not signalled.
LockEvents[cLocks].hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (LockEvents[cLocks].hEvent == NULL)
{
DebugOut((DEB_ERROR, "Failed creating event, %d\n", GetLastError()));
}
else
{
i = cLocks;
LockEvents[cLocks++].fInUse = CREDLOCK_IN_USE;
}
(void) RtlLeaveCriticalSection(&csLocks);
return(&LockEvents[i]);
}
//+-------------------------------------------------------------------------
//
// Function: FreeCredLock
//
// Synopsis: Releases a credlock
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns: TRUE - Remove the lock record from the credential record
// FALSE - Threads waiting; don't remove from cred
//
// Notes:
//
//--------------------------------------------------------------------------
BOOLEAN
CCredentialList::FreeCredLock( PCredLock pLock,
BOOLEAN fFreeCred)
{
NTSTATUS Status;
BOOL bRet = TRUE;
Status = RtlEnterCriticalSection(&csLocks);
DsysAssert( NT_SUCCESS( Status ) );
//
// The trick: If there is a waiter, then the lock is *not* free
// and we set the flag saying the credential is pending delete, so
// their Lock will fail.
//
if (pLock->cWaiters)
{
SetEvent(pLock->hEvent);
bRet = FALSE;
//
// If the credential has been freed, mark that too
//
if (fFreeCred)
{
pLock->fInUse |= CREDLOCK_FREE_PENDING;
}
} else
{
pLock->fInUse &= ~CREDLOCK_IN_USE;
}
// And clear up the thread id field:
pLock->dwThread = 0;
(void) RtlLeaveCriticalSection(&csLocks);
//
// This is true if the lock has actually been freed
// back to the credlock pool.
//
if (bRet)
{
ReleaseSemaphore(hCredLockSemaphore, 1, NULL);
}
return(bRet);
}
//+-------------------------------------------------------------------------
//
// Function: BlockOnCredLock
//
// Synopsis: Blocks a thread on a credlock.
//
// Effects:
//
// Arguments:
//
// Requires: credentials be blocked for write
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
BOOLEAN
CCredentialList::BlockOnCredLock(PCredLock pLock)
{
NTSTATUS Status;
DWORD WaitRet;
BOOLEAN bRet = TRUE;
Status = RtlEnterCriticalSection(&csLocks);
DsysAssertMsg(Status == STATUS_SUCCESS, "Critical section csLocks") ;
DebugOut((DEB_TRACE,"Blocking for lock on thread 0x%x\n",pLock->dwThread));
#if DBG
if (pLock->cWaiters < 4)
pLock->WaiterIds[pLock->cWaiters++] = GetCurrentThreadId();
else
pLock->cWaiters++;
#else
pLock->cWaiters++;
#endif
(void) RtlLeaveCriticalSection(&csLocks);
//
// Unlock the list, so that other threads can unlock the credentials
//
rCredentials.Release();
//
// Wait for 100s, or until signalled:
//
WaitRet = WaitForSingleObject(pLock->hEvent, 600000L);
//
// Reacquire exclusive access to the credlock
//
RtlEnterCriticalSection(&csLocks);
if (WaitRet)
{
if (WaitRet == WAIT_TIMEOUT)
{
#if DBG
DebugOut((DEB_ERROR, "Timeout waiting for credlock %x (600s)\n",
pLock));
DebugOut((DEB_ERROR, "Thread 0x%x still owns the lock, revoking\n",
pLock->dwThread));
pLock->dwThread = 0;
#endif // DBG
//
// Blow away any recursion
//
pLock->cRecursion = 0;
}
}
#if DBG
//
// Remove our thread ID from the waiter list:
//
{
int i;
for (i = 0 ; i < 4 ; i++ )
{
if (pLock->WaiterIds[i] == GetCurrentThreadId())
{
int j;
for (j = i; j < 4 - 1 ; j++ )
{
pLock->WaiterIds[j] = pLock->WaiterIds[j+1];
}
pLock->WaiterIds[4 - 1] = 0;
}
}
}
#endif // DBG
pLock->cWaiters--;
if (pLock->fInUse & CREDLOCK_FREE_PENDING)
{
if (pLock->cWaiters == 0)
{
pLock->fInUse &= ~(CREDLOCK_IN_USE | CREDLOCK_FREE_PENDING);
}
bRet = FALSE;
}
//
// Done partying with locks
//
RtlLeaveCriticalSection(&csLocks);
//
// If the credlock needs to be freed, signal the semaphore to
// put it back in the pool.
//
if (!bRet && (pLock->cWaiters == 0))
{
ReleaseSemaphore(hCredLockSemaphore, 1, NULL);
}
//
// Regain exclusive access to the credential list
//
rCredentials.GetWrite();
return(bRet);
}