Source code of Windows XP (NT5)
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.

487 lines
13 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 2000
  6. //
  7. // File: ctxt.cxx
  8. //
  9. // Contents: Context manipulation functions
  10. //
  11. //
  12. // History: KDamour 15Mar00 Stolen from NTLM context.cxx
  13. //
  14. //------------------------------------------------------------------------
  15. #include "global.h"
  16. // Globals for manipulating Context Lists
  17. RTL_CRITICAL_SECTION l_ContextCritSect;
  18. LIST_ENTRY l_ContextList;
  19. // Indicate if completed Initialization of Credential Handler
  20. BOOL g_bContextInitialized = FALSE;
  21. //+--------------------------------------------------------------------
  22. //
  23. // Function: SspContextInitialize
  24. //
  25. // Synopsis: Initializes the context manager package
  26. //
  27. // Arguments: none
  28. //
  29. // Returns: NTSTATUS
  30. //
  31. // Notes: Called by SpInitialize
  32. //
  33. //---------------------------------------------------------------------
  34. NTSTATUS
  35. CtxtHandlerInit(VOID)
  36. {
  37. NTSTATUS Status = STATUS_SUCCESS;
  38. //
  39. // Initialize the Context list to be empty.
  40. //
  41. Status = RtlInitializeCriticalSection(&l_ContextCritSect);
  42. if (!NT_SUCCESS(Status))
  43. {
  44. DebugLog((DEB_ERROR, "CtxtHandlerInit: Failed to initialize critsec 0x%x\n", Status));
  45. goto CleanUp;
  46. }
  47. InitializeListHead( &l_ContextList );
  48. // Simple variable test to make sure all initialized;
  49. g_bContextInitialized = TRUE;
  50. CleanUp:
  51. return Status;
  52. }
  53. // Add a Context into the Context List
  54. NTSTATUS
  55. CtxtHandlerInsertCred(
  56. IN PDIGEST_CONTEXT pDigestCtxt
  57. )
  58. {
  59. DebugLog((DEB_TRACE_FUNC, "CtxtHandlerInsertCred: Entering with Context 0x%x RefCount %ld\n", pDigestCtxt, pDigestCtxt->lReferences));
  60. RtlEnterCriticalSection( &l_ContextCritSect );
  61. DebugLog((DEB_TRACE, "CtxtHandlerInsertCred: add into list\n"));
  62. InsertHeadList( &l_ContextList, &pDigestCtxt->Next );
  63. RtlLeaveCriticalSection( &l_ContextCritSect );
  64. DebugLog((DEB_TRACE_FUNC, "CtxtHandlerInsertCred: Leaving with Context 0x%x\n", pDigestCtxt));
  65. return STATUS_SUCCESS;
  66. }
  67. // Initialize a Context into the IdleState with the data from the Credential provided
  68. NTSTATUS NTAPI
  69. ContextInit(
  70. IN OUT PDIGEST_CONTEXT pContext,
  71. IN PDIGEST_CREDENTIAL pCredential
  72. )
  73. {
  74. NTSTATUS Status = STATUS_SUCCESS;
  75. DebugLog((DEB_TRACE_FUNC, "ContextInit: Entering\n"));
  76. if (!pContext || !pCredential)
  77. {
  78. return STATUS_INVALID_PARAMETER;
  79. }
  80. ZeroMemory(pContext, sizeof(DIGEST_CONTEXT));
  81. pContext->typeQOP = QOP_UNDEFINED;
  82. pContext->typeDigest = DIGEST_UNDEFINED;
  83. pContext->typeAlgorithm = ALGORITHM_UNDEFINED;
  84. pContext->typeCipher = CIPHER_UNDEFINED;
  85. pContext->typeCharset = CHARSET_UNDEFINED;
  86. pContext->lReferences = 0;
  87. pContext->ulSendMaxBuf = SASL_MAX_DATA_BUFFER;
  88. pContext->ulRecvMaxBuf = SASL_MAX_DATA_BUFFER;
  89. pContext->TimeCreated = time(NULL);
  90. pContext->ContextHandle = (ULONG_PTR)pContext;
  91. pContext->PasswordExpires = g_TimeForever; // never expire
  92. // Now copy over all the info we need from the supplied credential
  93. pContext->CredentialUseFlags = pCredential->CredentialUseFlags; // Keep the info on inbound/outbound
  94. Status = UnicodeStringDuplicate(&(pContext->ustrAccountName), &(pCredential->ustrAccountName));
  95. if (!NT_SUCCESS(Status))
  96. {
  97. DebugLog((DEB_ERROR, "ContextInit: Failed to copy Domain into Context\n"));
  98. goto CleanUp;
  99. }
  100. Status = UnicodeStringDuplicate(&(pContext->ustrDomain), &(pCredential->ustrDnsDomainName));
  101. if (!NT_SUCCESS(Status))
  102. {
  103. DebugLog((DEB_ERROR, "ContextInit: Failed to copy Domain into Context\n"));
  104. goto CleanUp;
  105. }
  106. // Copy over the Credential Password if known - thread safe - this is encrypted text
  107. Status = CredHandlerPasswdGet(pCredential, &pContext->ustrPassword);
  108. if (!NT_SUCCESS(Status))
  109. {
  110. DebugLog((DEB_ERROR, "ContextInit: CredHandlerPasswdGet error status 0x%x\n", Status));
  111. goto CleanUp;
  112. }
  113. CleanUp:
  114. DebugLog((DEB_TRACE_FUNC, "ContextInit: Leaving\n"));
  115. return Status;
  116. }
  117. // Once done with a context - release the resouces
  118. NTSTATUS NTAPI
  119. ContextFree(
  120. IN PDIGEST_CONTEXT pContext
  121. )
  122. {
  123. NTSTATUS Status = STATUS_SUCCESS;
  124. USHORT iCnt = 0;
  125. DebugLog((DEB_TRACE_FUNC, "ContextFree: Entering with Context 0x%x\n", pContext));
  126. ASSERT(pContext);
  127. ASSERT(0 == pContext->lReferences);
  128. if (!pContext)
  129. {
  130. return STATUS_INVALID_PARAMETER;
  131. }
  132. DebugLog((DEB_TRACE, "ContextFree: Context RefCount %ld\n", pContext->lReferences));
  133. DebugLog((DEB_TRACE, "ContextFree: Checking TokenHandle for LogonID (%x:%lx)\n",
  134. pContext->LoginID.HighPart, pContext->LoginID.LowPart));
  135. if (pContext->TokenHandle)
  136. {
  137. DebugLog((DEB_TRACE, "ContextFree: Closing TokenHandle for LogonID (%x:%lx)\n",
  138. pContext->LoginID.HighPart, pContext->LoginID.LowPart));
  139. NtClose(pContext->TokenHandle);
  140. pContext->TokenHandle = NULL;
  141. }
  142. StringFree(&(pContext->strNonce));
  143. StringFree(&(pContext->strCNonce));
  144. StringFree(&(pContext->strOpaque));
  145. StringFree(&(pContext->strSessionKey));
  146. UnicodeStringFree(&(pContext->ustrDomain));
  147. UnicodeStringFree(&(pContext->ustrPassword));
  148. UnicodeStringFree(&(pContext->ustrAccountName));
  149. StringFree(&(pContext->strResponseAuth));
  150. for (iCnt = 0; iCnt < MD5_AUTH_LAST; iCnt++)
  151. {
  152. StringFree(&(pContext->strDirective[iCnt]));
  153. }
  154. DigestFreeMemory(pContext);
  155. DebugLog((DEB_TRACE_FUNC, "ContextFree: Leaving with Context 0x%x\n", pContext));
  156. return Status;
  157. }
  158. /*++
  159. Routine Description:
  160. This routine checks to see if the Context is for the specified
  161. Client Connection, and references the Context if it is valid.
  162. The caller may optionally request that the Context be
  163. removed from the list of valid Contexts - preventing future
  164. requests from finding this Context.
  165. Arguments:
  166. ContextHandle - Points to the ContextHandle of the Context
  167. to be referenced.
  168. RemoveContext - This boolean value indicates whether the caller
  169. wants the Context to be removed from the list
  170. of Contexts. TRUE indicates the Context is to be removed.
  171. FALSE indicates the Context is not to be removed.
  172. Return Value:
  173. NULL - the Context was not found.
  174. Otherwise - returns a pointer to the referenced Context.
  175. --*/
  176. NTSTATUS NTAPI
  177. CtxtHandlerHandleToContext(
  178. IN ULONG_PTR ContextHandle,
  179. IN BOOLEAN RemoveContext,
  180. OUT PDIGEST_CONTEXT *ppContext
  181. )
  182. {
  183. NTSTATUS Status = STATUS_SUCCESS;
  184. PLIST_ENTRY ListEntry = NULL;
  185. PDIGEST_CONTEXT Context = NULL;
  186. LONG lReferences = 0;
  187. DebugLog((DEB_TRACE_FUNC, "CtxtHandlerHandleToContext: Entering ContextHandle 0x%lx\n", ContextHandle));
  188. //
  189. // Acquire exclusive access to the Context list
  190. //
  191. RtlEnterCriticalSection( &l_ContextCritSect );
  192. //
  193. // Now walk the list of Contexts looking for a match.
  194. //
  195. for ( ListEntry = l_ContextList.Flink;
  196. ListEntry != &l_ContextList;
  197. ListEntry = ListEntry->Flink ) {
  198. Context = CONTAINING_RECORD( ListEntry, DIGEST_CONTEXT, Next );
  199. //
  200. // Found a match ... reference this Context
  201. // (if the Context is being removed, we would increment
  202. // and then decrement the reference, so don't bother doing
  203. // either - since they cancel each other out).
  204. //
  205. if ( Context == (PDIGEST_CONTEXT) ContextHandle)
  206. {
  207. if (!RemoveContext)
  208. {
  209. //
  210. // Timeout this context if caller is not trying to remove it.
  211. // We only timeout contexts that are being setup, not
  212. // fully authenticated contexts.
  213. //
  214. if (CtxtHandlerTimeHasElapsed(Context))
  215. {
  216. DebugLog((DEB_ERROR, "CtxtHandlerHandleToContext: Context 0x%lx has timed out.\n",
  217. ContextHandle ));
  218. Status = SEC_E_CONTEXT_EXPIRED;
  219. goto CleanUp;
  220. }
  221. lReferences = InterlockedIncrement(&Context->lReferences);
  222. }
  223. else
  224. {
  225. RemoveEntryList( &Context->Next );
  226. DebugLog((DEB_TRACE, "CtxtHandlerHandleToContext:Delinked Context 0x%lx\n",Context ));
  227. }
  228. DebugLog((DEB_TRACE, "CtxtHandlerHandleToContext: FOUND Context = 0x%x, RemoveContext = %d, ReferenceCount = %ld\n",
  229. Context, RemoveContext, Context->lReferences));
  230. *ppContext = Context;
  231. goto CleanUp;
  232. }
  233. }
  234. //
  235. // No match found
  236. //
  237. DebugLog((DEB_WARN, "CtxtHandlerHandleToContext: Tried to reference unknown Context 0x%lx\n", ContextHandle ));
  238. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  239. CleanUp:
  240. RtlLeaveCriticalSection( &l_ContextCritSect );
  241. DebugLog((DEB_TRACE_FUNC, "CtxtHandlerHandleToContext: Leaving\n" ));
  242. return(Status);
  243. }
  244. /*++
  245. Routine Description:
  246. This routine checks to see if the LogonId is for the specified
  247. Server Connection, and references the Context if it is valid.
  248. The caller may optionally request that the Context be
  249. removed from the list of valid Contexts - preventing future
  250. requests from finding this Context.
  251. Arguments:
  252. pstrOpaque - Opaque string that uniquely references the SecurityContext
  253. Return Value:
  254. NULL - the Context was not found.
  255. Otherwise - returns a pointer to the referenced Context.
  256. --*/
  257. NTSTATUS NTAPI
  258. CtxtHandlerOpaqueToPtr(
  259. IN PSTRING pstrOpaque,
  260. OUT PDIGEST_CONTEXT *ppContext
  261. )
  262. {
  263. NTSTATUS Status = STATUS_SUCCESS;
  264. PLIST_ENTRY ListEntry = NULL;
  265. PDIGEST_CONTEXT Context = NULL;
  266. LONG rc = 0;
  267. LONG lReferences = 0;
  268. DebugLog((DEB_TRACE_FUNC, "CtxtHandlerOpaqueToPtr: Entering Opaque (%Z)\n", pstrOpaque));
  269. //
  270. // Acquire exclusive access to the Context list
  271. //
  272. RtlEnterCriticalSection( &l_ContextCritSect );
  273. //
  274. // Now walk the list of Contexts looking for a match.
  275. //
  276. for ( ListEntry = l_ContextList.Flink;
  277. ListEntry != &l_ContextList;
  278. ListEntry = ListEntry->Flink ) {
  279. Context = CONTAINING_RECORD( ListEntry, DIGEST_CONTEXT, Next );
  280. //
  281. // Found a match ... reference this Context
  282. // (if the Context is being removed, we would increment
  283. // and then decrement the reference, so don't bother doing
  284. // either - since they cancel each other out).
  285. //
  286. rc = RtlCompareString(pstrOpaque, &(Context->strOpaque), FALSE);
  287. if (!rc)
  288. {
  289. //
  290. // Timeout this context if caller is not trying to remove it.
  291. // We only timeout contexts that are being setup, not
  292. // fully authenticated contexts.
  293. //
  294. if (CtxtHandlerTimeHasElapsed(Context))
  295. {
  296. DebugLog((DEB_ERROR, "CtxtHandlerOpaqueToPtr: Context 0x%x has timed out.\n",
  297. Context ));
  298. Status = SEC_E_CONTEXT_EXPIRED;
  299. goto CleanUp;
  300. }
  301. lReferences = InterlockedIncrement(&Context->lReferences);
  302. DebugLog((DEB_TRACE, "CtxtHandlerOpaqueToPtr: FOUND Context = 0x%x, ReferenceCount = %ld\n",
  303. Context, Context->lReferences));
  304. *ppContext = Context;
  305. goto CleanUp;
  306. }
  307. }
  308. //
  309. // No match found
  310. //
  311. DebugLog((DEB_WARN, "CtxtHandlerOpaqueToPtr: Tried to reference unknown Opaque (%Z)\n", pstrOpaque));
  312. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  313. CleanUp:
  314. RtlLeaveCriticalSection( &l_ContextCritSect );
  315. DebugLog((DEB_TRACE_FUNC, "CtxtHandlerOpaqueToPtr: Leaving\n" ));
  316. return(Status);
  317. }
  318. // Check the Creation time with the Current time.
  319. // If the difference is greater than the MAX allowed, Context is no longer valid
  320. BOOL
  321. CtxtHandlerTimeHasElapsed(
  322. PDIGEST_CONTEXT pContext)
  323. {
  324. BOOL bStatus = FALSE;
  325. DWORD dwTimeElapsed = 0;
  326. time_t timeCurrent = time(NULL);
  327. dwTimeElapsed = (DWORD)(timeCurrent - pContext->TimeCreated);
  328. if (dwTimeElapsed > g_dwParameter_Lifetime)
  329. {
  330. bStatus = TRUE;
  331. }
  332. return(bStatus);
  333. }
  334. //+--------------------------------------------------------------------
  335. //
  336. // Function: CtxtHandlerRelease
  337. //
  338. // Synopsis: Releases the Context by decreasing reference counter
  339. //
  340. // Arguments: pContext - pointer to credential to de-reference
  341. //
  342. // Returns: NTSTATUS
  343. //
  344. // Notes:
  345. //
  346. //---------------------------------------------------------------------
  347. NTSTATUS
  348. CtxtHandlerRelease(
  349. PDIGEST_CONTEXT pContext)
  350. {
  351. NTSTATUS Status = STATUS_SUCCESS;
  352. LONG lReferences = 0;
  353. lReferences = InterlockedDecrement(&pContext->lReferences);
  354. DebugLog((DEB_TRACE, "CtxtHandlerRelease: (RefCount) UserContextInit deref 0x%x references %ld\n",
  355. pContext, lReferences));
  356. ASSERT( lReferences >= 0 );
  357. //
  358. // If the count has dropped to zero, then free all alloced stuff
  359. //
  360. if (lReferences == 0)
  361. {
  362. DebugLog((DEB_TRACE, "CtxtHandlerRelease: (RefCount) UserContextInit freed 0x%x\n", pContext));
  363. Status = ContextFree(pContext);
  364. }
  365. return(Status);
  366. }