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.
 
 
 
 
 
 

625 lines
12 KiB

/*++
Copyright (c) 1990-2002 Microsoft Corporation
Module Name:
pool.cxx
Abstract:
Implementation for class ThreadPool.
Author:
Ali Naqvi (alinaqvi) 3-May-2002
Revision History:
--*/
#include <precomp.h>
#include "pool.hxx"
#pragma hdrstop
#define SIZE_OF_TOKEN_INFORMATION \
sizeof( TOKEN_USER ) \
+ sizeof( SID ) \
+ sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES
/*++
Name:
TThreadPool::TThreadPool
Description:
Constructor
Arguments:
None
Return Value:
None
--*/
TThreadPool::TThreadPool()
{
pHead = NULL;
}
/*++
Name:
TThreadPool::~ThreadPool
Description:
Destructor
Arguments:
None
Return Value:
None
--*/
TThreadPool::~TThreadPool()
{
PWIN32THREAD pElem = NULL;
while (pHead != NULL)
{
pElem = pHead;
pHead = pHead->pNext;
FreeThread(pHead);
}
}
/*++
Name:
TThreadPool::CreateThreadEntry
Description:
Create and Initialize a WIN32THREAD object with provided printer name and printer defaults.
Arguments:
pName - Printer Name
pDefaults - Printer Defaults
ppThread - Out parameter pointer to the created WIN32THREAD
Return Value:
HRESULT
--*/
HRESULT
TThreadPool::CreateThreadEntry(
LPWSTR pName,
PPRINTER_DEFAULTSW pDefaults,
PWIN32THREAD *ppThread
)
{
PWIN32THREAD pThread = NULL;
HRESULT hReturn = E_FAIL;
SplInSem();
hReturn = ppThread && pName ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hReturn))
{
//
// Create the thread wrapper object.
//
pThread = reinterpret_cast<PWIN32THREAD>(AllocSplMem(sizeof(WIN32THREAD)));
hReturn = pThread ? S_OK : E_OUTOFMEMORY;
}
if(SUCCEEDED(hReturn))
{
pThread->signature = TP_SIGNATURE;
pThread->pName = AllocSplStr(pName);
hReturn = pThread->pName ? S_OK : E_OUTOFMEMORY;
}
if (SUCCEEDED(hReturn))
{
hReturn = GetThreadSid(pThread);
}
if (SUCCEEDED(hReturn))
{
pThread->hRpcHandle = NULL;
pThread->hWaitValidHandle = CreateEvent(NULL,
EVENT_RESET_MANUAL,
EVENT_INITIAL_STATE_NOT_SIGNALED,
NULL);
pThread->dwStatus = THREAD_STATUS_EXECUTING;
pThread->dwRpcOpenPrinterError = 0;
pThread->pDefaults = reinterpret_cast<PPRINTER_DEFAULTSW>(AllocSplMem(sizeof(PRINTER_DEFAULTSW)));
hReturn = pThread->pDefaults ? S_OK : E_OUTOFMEMORY;
}
if (SUCCEEDED(hReturn))
{
pThread->pDefaults->pDatatype = NULL;
pThread->pDefaults->pDevMode = NULL;
pThread->pDefaults->DesiredAccess = 0;
pThread->bForegroundClose = FALSE;
hReturn = CopypDefaults(pDefaults, pThread->pDefaults) ? S_OK : E_OUTOFMEMORY;
pThread->pNext = NULL;
}
if (SUCCEEDED(hReturn))
{
*ppThread = pThread;
}
else
{
FreeThread(pThread);
*ppThread = NULL;
}
return hReturn;
}
/*++
Name:
TThreadPool::GetThreadSid
Description:
Gets the SID from the thread token and makes a copy.
Arguments:
pThread - Pointer to the WIN32THREAD from which we get our user SID.
Return Value:
HRESULT
--*/
HRESULT
TThreadPool::GetThreadSid(
PWIN32THREAD pThread
)
{
UCHAR ThreadTokenInformation[SIZE_OF_TOKEN_INFORMATION];
DWORD dwSidLength;
ULONG ReturnLength;
HRESULT hReturn = E_FAIL;
hReturn = pThread ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hReturn))
{
hReturn = OpenThreadToken(GetCurrentThread(),
TOKEN_READ | TOKEN_IMPERSONATE,
TRUE,
&(pThread->hToken)) ? S_OK : GetLastErrorAsHResultAndFail();
}
if (SUCCEEDED(hReturn))
{
hReturn = GetTokenInformation(pThread->hToken,
TokenUser,
ThreadTokenInformation,
sizeof(ThreadTokenInformation),
&ReturnLength) ? S_OK : GetLastErrorAsHResultAndFail();
}
if (SUCCEEDED(hReturn))
{
dwSidLength = RtlLengthSid((reinterpret_cast<PTOKEN_USER>(ThreadTokenInformation))->User.Sid);
pThread->pSid = reinterpret_cast<PSID>(AllocSplMem(dwSidLength));
hReturn = pThread->pSid ? S_OK : E_OUTOFMEMORY;
}
if (SUCCEEDED(hReturn))
{
RtlCopySid( dwSidLength, pThread->pSid, (reinterpret_cast<PTOKEN_USER>(ThreadTokenInformation))->User.Sid);
}
return hReturn;
}
/*++
Name:
TThreadPool::DeleteThreadEntry
Description:
Delink thread item from the threadpool and delete it.
Arguments:
pThread - Pointer to the WIN322THREAD item to be deleted
Return Value:
HRESULT
--*/
HRESULT
TThreadPool::DeleteThreadEntry(
PWIN32THREAD pThread
)
{
PWIN32THREAD *ppElem = &pHead;
HRESULT hReturn = E_FAIL;
SplInSem();
hReturn = pThread ? S_OK : E_INVALIDARG;
SPLASSERT(IsValid(pThread));
if (SUCCEEDED(hReturn))
{
//
// If the thread is in the pool, delink it.
//
while (*ppElem && (*ppElem) != pThread)
{
ppElem = &((*ppElem)->pNext);
}
if (*ppElem)
{
(*ppElem) = (*ppElem)->pNext;
}
FreeThread(pThread);
}
return hReturn;
}
/*++
Name:
TThreadPool::UseThread
Description:
If exists a thread item for the particular printer name in the pool, it delinks and returns
a pointer to the thread item.
Arguments:
pName - Printer Name to be looked for
ppThread - Pointer to the thread item if found
Return Value:
HRESULT
S_OK - If thread item found
S_FALSE - If thread is not found
--*/
HRESULT
TThreadPool::UseThread(
LPWSTR pName,
PWIN32THREAD *ppThread,
ACCESS_MASK DesiredAccess
)
{
PWIN32THREAD *ppElem = NULL;
HRESULT hReturn = E_FAIL;
PVOID pUserTokenInformation = NULL;
DWORD dwInformationLength = SIZE_OF_TOKEN_INFORMATION;
SplInSem();
hReturn = ppThread ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hReturn))
{
//
// Get User information for current thread
//
pUserTokenInformation = reinterpret_cast<UCHAR*>(AllocSplMem(dwInformationLength));
hReturn = GetUserTokenInformation(&pUserTokenInformation, dwInformationLength);
}
if (SUCCEEDED(hReturn))
{
*ppThread = NULL;
//
// If we dont find a thread we return S_FALSE
//
hReturn = S_FALSE;
for (ppElem = &pHead; *ppElem; ppElem = &((*ppElem)->pNext))
{
//
// If we found the thread we return it and break.
//
if (wcscmp(pName, (*ppElem)->pName) == 0 &&
IsValidUser(*ppElem, pUserTokenInformation) &&
(*ppElem)->pDefaults->DesiredAccess == DesiredAccess &&
(*ppElem)->dwStatus == THREAD_STATUS_EXECUTING)
{
*ppThread = *ppElem;
*ppElem = (*ppElem)->pNext;
hReturn = S_OK;
(*ppThread)->pNext = NULL;
break;
}
}
}
FreeSplMem(pUserTokenInformation);
return hReturn;
}
/*++
Name:
TThreadPool::GetUserTokenInformation
Description:
Returns the current thread users Sid information in the out parameter.
Arguments:
pUserTokenInformation - Is set to the current user's Sid information
Return Value:
HRESULT
--*/
HRESULT
TThreadPool::GetUserTokenInformation(
PVOID *ppUserTokenInformation,
DWORD dwInformationLength
)
{
HANDLE UserTokenHandle;
ULONG ReturnLength;
HRESULT hResult = E_FAIL;
hResult = ppUserTokenInformation ? S_OK : E_INVALIDARG;
if (SUCCEEDED(hResult))
{
hResult = OpenThreadToken( GetCurrentThread(),
TOKEN_READ,
TRUE,
&UserTokenHandle) ? S_OK : E_HANDLE;
}
if (SUCCEEDED(hResult))
{
hResult = GetTokenInformation( UserTokenHandle,
TokenUser,
*ppUserTokenInformation,
dwInformationLength,
&ReturnLength) ? S_OK : E_ACCESSDENIED;
}
if (UserTokenHandle)
{
CloseHandle(UserTokenHandle);
}
return hResult;
}
/*++
Name:
TThreadPool::IsValidUser
Description:
Checks the Sid of the current user to that of the Sid token save in thread and determines if it is
the same user. Other users cannot use the same RpcHandle therefore cannot use the same thread from
the pool.
Arguments:
pThread - The thread whichs Sid we want to check against current user
Return Value:
BOOL - Returns true if it is the same user
--*/
BOOL
TThreadPool::IsValidUser(
PWIN32THREAD pThread,
PVOID pCurrentTokenInformation
)
{
BOOL bReturn = FALSE;
bReturn = RtlEqualSid((reinterpret_cast<PTOKEN_USER>(pCurrentTokenInformation))->User.Sid,
pThread->pSid);
return bReturn;
}
/*++
Name:
TThreadPool::ReturnThread
Description:
Return thread item to the pool, signal event that we are done using the thread.
Arguments:
pThread - Thread item to be returned
Return Value:
HRESULT
--*/
HRESULT
TThreadPool::ReturnThread(
PWIN32THREAD pThread
)
{
HRESULT hReturn = E_FAIL;
SplInSem();
hReturn = pThread ? S_OK : E_INVALIDARG;
SPLASSERT(IsValid(pThread));
if (SUCCEEDED(hReturn))
{
//
// We only return a thread from the foreground if it is actuall still
// executing and not terminated.
//
SPLASSERT(pThread->dwStatus == THREAD_STATUS_EXECUTING);
pThread->pNext = pHead;
pHead = pThread;
}
return hReturn;
}
/*++
Name:
TThreadPool::IsValid
Description:
Checks signature of the thread item to see if it is valid.
Arguments:
pThread - The thread to check for validity
Return Value:
BOOL - Returns true if it is the same user
--*/
BOOL
TThreadPool::IsValid(
PWIN32THREAD pThread
)
{
return (pThread->signature == TP_SIGNATURE);
}
/*++
Name:
TThreadPool::FreeThread
Description:
Frees the data in the given thread.
Arguments:
pThread - The thread to free
Return Value:
Nothing
--*/
VOID
TThreadPool::FreeThread(
IN PWIN32THREAD pThread
)
{
if (pThread)
{
//
// Now delete the thread.
//
pThread->hRpcHandle = NULL;
if (pThread->pDefaults)
{
FreeSplStr(pThread->pDefaults->pDatatype);
FreeSplMem(pThread->pDefaults->pDevMode);
FreeSplMem(pThread->pDefaults);
}
if (pThread->hWaitValidHandle)
{
CloseHandle(pThread->hWaitValidHandle);
}
if( pThread->hToken != INVALID_HANDLE_VALUE )
{
CloseHandle( pThread->hToken );
pThread->hToken = INVALID_HANDLE_VALUE;
}
if (pThread->pName)
{
FreeSplStr(pThread->pName);
}
if (pThread->pSid)
{
FreeSplMem(pThread->pSid);
}
FreeSplMem(pThread);
}
}