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

  1. /*++
  2. Copyright (c) 1990-2002 Microsoft Corporation
  3. Module Name:
  4. pool.cxx
  5. Abstract:
  6. Implementation for class ThreadPool.
  7. Author:
  8. Ali Naqvi (alinaqvi) 3-May-2002
  9. Revision History:
  10. --*/
  11. #include <precomp.h>
  12. #include "pool.hxx"
  13. #pragma hdrstop
  14. #define SIZE_OF_TOKEN_INFORMATION \
  15. sizeof( TOKEN_USER ) \
  16. + sizeof( SID ) \
  17. + sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES
  18. /*++
  19. Name:
  20. TThreadPool::TThreadPool
  21. Description:
  22. Constructor
  23. Arguments:
  24. None
  25. Return Value:
  26. None
  27. --*/
  28. TThreadPool::TThreadPool()
  29. {
  30. pHead = NULL;
  31. }
  32. /*++
  33. Name:
  34. TThreadPool::~ThreadPool
  35. Description:
  36. Destructor
  37. Arguments:
  38. None
  39. Return Value:
  40. None
  41. --*/
  42. TThreadPool::~TThreadPool()
  43. {
  44. PWIN32THREAD pElem = NULL;
  45. while (pHead != NULL)
  46. {
  47. pElem = pHead;
  48. pHead = pHead->pNext;
  49. FreeThread(pHead);
  50. }
  51. }
  52. /*++
  53. Name:
  54. TThreadPool::CreateThreadEntry
  55. Description:
  56. Create and Initialize a WIN32THREAD object with provided printer name and printer defaults.
  57. Arguments:
  58. pName - Printer Name
  59. pDefaults - Printer Defaults
  60. ppThread - Out parameter pointer to the created WIN32THREAD
  61. Return Value:
  62. HRESULT
  63. --*/
  64. HRESULT
  65. TThreadPool::CreateThreadEntry(
  66. LPWSTR pName,
  67. PPRINTER_DEFAULTSW pDefaults,
  68. PWIN32THREAD *ppThread
  69. )
  70. {
  71. PWIN32THREAD pThread = NULL;
  72. HRESULT hReturn = E_FAIL;
  73. SplInSem();
  74. hReturn = ppThread && pName ? S_OK : E_INVALIDARG;
  75. if (SUCCEEDED(hReturn))
  76. {
  77. //
  78. // Create the thread wrapper object.
  79. //
  80. pThread = reinterpret_cast<PWIN32THREAD>(AllocSplMem(sizeof(WIN32THREAD)));
  81. hReturn = pThread ? S_OK : E_OUTOFMEMORY;
  82. }
  83. if(SUCCEEDED(hReturn))
  84. {
  85. pThread->signature = TP_SIGNATURE;
  86. pThread->pName = AllocSplStr(pName);
  87. hReturn = pThread->pName ? S_OK : E_OUTOFMEMORY;
  88. }
  89. if (SUCCEEDED(hReturn))
  90. {
  91. hReturn = GetThreadSid(pThread);
  92. }
  93. if (SUCCEEDED(hReturn))
  94. {
  95. pThread->hRpcHandle = NULL;
  96. pThread->hWaitValidHandle = CreateEvent(NULL,
  97. EVENT_RESET_MANUAL,
  98. EVENT_INITIAL_STATE_NOT_SIGNALED,
  99. NULL);
  100. pThread->dwStatus = THREAD_STATUS_EXECUTING;
  101. pThread->dwRpcOpenPrinterError = 0;
  102. pThread->pDefaults = reinterpret_cast<PPRINTER_DEFAULTSW>(AllocSplMem(sizeof(PRINTER_DEFAULTSW)));
  103. hReturn = pThread->pDefaults ? S_OK : E_OUTOFMEMORY;
  104. }
  105. if (SUCCEEDED(hReturn))
  106. {
  107. pThread->pDefaults->pDatatype = NULL;
  108. pThread->pDefaults->pDevMode = NULL;
  109. pThread->pDefaults->DesiredAccess = 0;
  110. pThread->bForegroundClose = FALSE;
  111. hReturn = CopypDefaults(pDefaults, pThread->pDefaults) ? S_OK : E_OUTOFMEMORY;
  112. pThread->pNext = NULL;
  113. }
  114. if (SUCCEEDED(hReturn))
  115. {
  116. *ppThread = pThread;
  117. }
  118. else
  119. {
  120. FreeThread(pThread);
  121. *ppThread = NULL;
  122. }
  123. return hReturn;
  124. }
  125. /*++
  126. Name:
  127. TThreadPool::GetThreadSid
  128. Description:
  129. Gets the SID from the thread token and makes a copy.
  130. Arguments:
  131. pThread - Pointer to the WIN32THREAD from which we get our user SID.
  132. Return Value:
  133. HRESULT
  134. --*/
  135. HRESULT
  136. TThreadPool::GetThreadSid(
  137. PWIN32THREAD pThread
  138. )
  139. {
  140. UCHAR ThreadTokenInformation[SIZE_OF_TOKEN_INFORMATION];
  141. DWORD dwSidLength;
  142. ULONG ReturnLength;
  143. HRESULT hReturn = E_FAIL;
  144. hReturn = pThread ? S_OK : E_INVALIDARG;
  145. if (SUCCEEDED(hReturn))
  146. {
  147. hReturn = OpenThreadToken(GetCurrentThread(),
  148. TOKEN_READ | TOKEN_IMPERSONATE,
  149. TRUE,
  150. &(pThread->hToken)) ? S_OK : GetLastErrorAsHResultAndFail();
  151. }
  152. if (SUCCEEDED(hReturn))
  153. {
  154. hReturn = GetTokenInformation(pThread->hToken,
  155. TokenUser,
  156. ThreadTokenInformation,
  157. sizeof(ThreadTokenInformation),
  158. &ReturnLength) ? S_OK : GetLastErrorAsHResultAndFail();
  159. }
  160. if (SUCCEEDED(hReturn))
  161. {
  162. dwSidLength = RtlLengthSid((reinterpret_cast<PTOKEN_USER>(ThreadTokenInformation))->User.Sid);
  163. pThread->pSid = reinterpret_cast<PSID>(AllocSplMem(dwSidLength));
  164. hReturn = pThread->pSid ? S_OK : E_OUTOFMEMORY;
  165. }
  166. if (SUCCEEDED(hReturn))
  167. {
  168. RtlCopySid( dwSidLength, pThread->pSid, (reinterpret_cast<PTOKEN_USER>(ThreadTokenInformation))->User.Sid);
  169. }
  170. return hReturn;
  171. }
  172. /*++
  173. Name:
  174. TThreadPool::DeleteThreadEntry
  175. Description:
  176. Delink thread item from the threadpool and delete it.
  177. Arguments:
  178. pThread - Pointer to the WIN322THREAD item to be deleted
  179. Return Value:
  180. HRESULT
  181. --*/
  182. HRESULT
  183. TThreadPool::DeleteThreadEntry(
  184. PWIN32THREAD pThread
  185. )
  186. {
  187. PWIN32THREAD *ppElem = &pHead;
  188. HRESULT hReturn = E_FAIL;
  189. SplInSem();
  190. hReturn = pThread ? S_OK : E_INVALIDARG;
  191. SPLASSERT(IsValid(pThread));
  192. if (SUCCEEDED(hReturn))
  193. {
  194. //
  195. // If the thread is in the pool, delink it.
  196. //
  197. while (*ppElem && (*ppElem) != pThread)
  198. {
  199. ppElem = &((*ppElem)->pNext);
  200. }
  201. if (*ppElem)
  202. {
  203. (*ppElem) = (*ppElem)->pNext;
  204. }
  205. FreeThread(pThread);
  206. }
  207. return hReturn;
  208. }
  209. /*++
  210. Name:
  211. TThreadPool::UseThread
  212. Description:
  213. If exists a thread item for the particular printer name in the pool, it delinks and returns
  214. a pointer to the thread item.
  215. Arguments:
  216. pName - Printer Name to be looked for
  217. ppThread - Pointer to the thread item if found
  218. Return Value:
  219. HRESULT
  220. S_OK - If thread item found
  221. S_FALSE - If thread is not found
  222. --*/
  223. HRESULT
  224. TThreadPool::UseThread(
  225. LPWSTR pName,
  226. PWIN32THREAD *ppThread,
  227. ACCESS_MASK DesiredAccess
  228. )
  229. {
  230. PWIN32THREAD *ppElem = NULL;
  231. HRESULT hReturn = E_FAIL;
  232. PVOID pUserTokenInformation = NULL;
  233. DWORD dwInformationLength = SIZE_OF_TOKEN_INFORMATION;
  234. SplInSem();
  235. hReturn = ppThread ? S_OK : E_INVALIDARG;
  236. if (SUCCEEDED(hReturn))
  237. {
  238. //
  239. // Get User information for current thread
  240. //
  241. pUserTokenInformation = reinterpret_cast<UCHAR*>(AllocSplMem(dwInformationLength));
  242. hReturn = GetUserTokenInformation(&pUserTokenInformation, dwInformationLength);
  243. }
  244. if (SUCCEEDED(hReturn))
  245. {
  246. *ppThread = NULL;
  247. //
  248. // If we dont find a thread we return S_FALSE
  249. //
  250. hReturn = S_FALSE;
  251. for (ppElem = &pHead; *ppElem; ppElem = &((*ppElem)->pNext))
  252. {
  253. //
  254. // If we found the thread we return it and break.
  255. //
  256. if (wcscmp(pName, (*ppElem)->pName) == 0 &&
  257. IsValidUser(*ppElem, pUserTokenInformation) &&
  258. (*ppElem)->pDefaults->DesiredAccess == DesiredAccess &&
  259. (*ppElem)->dwStatus == THREAD_STATUS_EXECUTING)
  260. {
  261. *ppThread = *ppElem;
  262. *ppElem = (*ppElem)->pNext;
  263. hReturn = S_OK;
  264. (*ppThread)->pNext = NULL;
  265. break;
  266. }
  267. }
  268. }
  269. FreeSplMem(pUserTokenInformation);
  270. return hReturn;
  271. }
  272. /*++
  273. Name:
  274. TThreadPool::GetUserTokenInformation
  275. Description:
  276. Returns the current thread users Sid information in the out parameter.
  277. Arguments:
  278. pUserTokenInformation - Is set to the current user's Sid information
  279. Return Value:
  280. HRESULT
  281. --*/
  282. HRESULT
  283. TThreadPool::GetUserTokenInformation(
  284. PVOID *ppUserTokenInformation,
  285. DWORD dwInformationLength
  286. )
  287. {
  288. HANDLE UserTokenHandle;
  289. ULONG ReturnLength;
  290. HRESULT hResult = E_FAIL;
  291. hResult = ppUserTokenInformation ? S_OK : E_INVALIDARG;
  292. if (SUCCEEDED(hResult))
  293. {
  294. hResult = OpenThreadToken( GetCurrentThread(),
  295. TOKEN_READ,
  296. TRUE,
  297. &UserTokenHandle) ? S_OK : E_HANDLE;
  298. }
  299. if (SUCCEEDED(hResult))
  300. {
  301. hResult = GetTokenInformation( UserTokenHandle,
  302. TokenUser,
  303. *ppUserTokenInformation,
  304. dwInformationLength,
  305. &ReturnLength) ? S_OK : E_ACCESSDENIED;
  306. }
  307. if (UserTokenHandle)
  308. {
  309. CloseHandle(UserTokenHandle);
  310. }
  311. return hResult;
  312. }
  313. /*++
  314. Name:
  315. TThreadPool::IsValidUser
  316. Description:
  317. Checks the Sid of the current user to that of the Sid token save in thread and determines if it is
  318. the same user. Other users cannot use the same RpcHandle therefore cannot use the same thread from
  319. the pool.
  320. Arguments:
  321. pThread - The thread whichs Sid we want to check against current user
  322. Return Value:
  323. BOOL - Returns true if it is the same user
  324. --*/
  325. BOOL
  326. TThreadPool::IsValidUser(
  327. PWIN32THREAD pThread,
  328. PVOID pCurrentTokenInformation
  329. )
  330. {
  331. BOOL bReturn = FALSE;
  332. bReturn = RtlEqualSid((reinterpret_cast<PTOKEN_USER>(pCurrentTokenInformation))->User.Sid,
  333. pThread->pSid);
  334. return bReturn;
  335. }
  336. /*++
  337. Name:
  338. TThreadPool::ReturnThread
  339. Description:
  340. Return thread item to the pool, signal event that we are done using the thread.
  341. Arguments:
  342. pThread - Thread item to be returned
  343. Return Value:
  344. HRESULT
  345. --*/
  346. HRESULT
  347. TThreadPool::ReturnThread(
  348. PWIN32THREAD pThread
  349. )
  350. {
  351. HRESULT hReturn = E_FAIL;
  352. SplInSem();
  353. hReturn = pThread ? S_OK : E_INVALIDARG;
  354. SPLASSERT(IsValid(pThread));
  355. if (SUCCEEDED(hReturn))
  356. {
  357. //
  358. // We only return a thread from the foreground if it is actuall still
  359. // executing and not terminated.
  360. //
  361. SPLASSERT(pThread->dwStatus == THREAD_STATUS_EXECUTING);
  362. pThread->pNext = pHead;
  363. pHead = pThread;
  364. }
  365. return hReturn;
  366. }
  367. /*++
  368. Name:
  369. TThreadPool::IsValid
  370. Description:
  371. Checks signature of the thread item to see if it is valid.
  372. Arguments:
  373. pThread - The thread to check for validity
  374. Return Value:
  375. BOOL - Returns true if it is the same user
  376. --*/
  377. BOOL
  378. TThreadPool::IsValid(
  379. PWIN32THREAD pThread
  380. )
  381. {
  382. return (pThread->signature == TP_SIGNATURE);
  383. }
  384. /*++
  385. Name:
  386. TThreadPool::FreeThread
  387. Description:
  388. Frees the data in the given thread.
  389. Arguments:
  390. pThread - The thread to free
  391. Return Value:
  392. Nothing
  393. --*/
  394. VOID
  395. TThreadPool::FreeThread(
  396. IN PWIN32THREAD pThread
  397. )
  398. {
  399. if (pThread)
  400. {
  401. //
  402. // Now delete the thread.
  403. //
  404. pThread->hRpcHandle = NULL;
  405. if (pThread->pDefaults)
  406. {
  407. FreeSplStr(pThread->pDefaults->pDatatype);
  408. FreeSplMem(pThread->pDefaults->pDevMode);
  409. FreeSplMem(pThread->pDefaults);
  410. }
  411. if (pThread->hWaitValidHandle)
  412. {
  413. CloseHandle(pThread->hWaitValidHandle);
  414. }
  415. if( pThread->hToken != INVALID_HANDLE_VALUE )
  416. {
  417. CloseHandle( pThread->hToken );
  418. pThread->hToken = INVALID_HANDLE_VALUE;
  419. }
  420. if (pThread->pName)
  421. {
  422. FreeSplStr(pThread->pName);
  423. }
  424. if (pThread->pSid)
  425. {
  426. FreeSplMem(pThread->pSid);
  427. }
  428. FreeSplMem(pThread);
  429. }
  430. }