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.

701 lines
20 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 2000
  6. //
  7. // File: user.cxx
  8. //
  9. // Contents: Context manipulation functions
  10. //
  11. //
  12. // History: KDamour 15Mar00 Derrived from NTLM context.cxx
  13. //
  14. //------------------------------------------------------------------------
  15. #include "global.h"
  16. // This list contains all of the User Contexts
  17. LIST_ENTRY l_UserCtxtList;
  18. // Lock for access to UserCtxtList
  19. RTL_CRITICAL_SECTION l_UserCtxtCritSect;
  20. // Indicate if completed Initialization of Credential Handler
  21. BOOL g_bUserContextInitialized = FALSE;
  22. //+--------------------------------------------------------------------
  23. //
  24. // Function: UserCtxtHandlerInit
  25. //
  26. // Synopsis: Initializes the context manager package
  27. //
  28. // Arguments: none
  29. //
  30. // Returns: NTSTATUS
  31. //
  32. // Notes: Called by SpInstanceInit
  33. //
  34. //---------------------------------------------------------------------
  35. NTSTATUS
  36. UserCtxtHandlerInit(VOID)
  37. {
  38. NTSTATUS Status = STATUS_SUCCESS;
  39. //
  40. // Initialize the Context list to be empty.
  41. //
  42. Status = RtlInitializeCriticalSection(&l_UserCtxtCritSect);
  43. if (!NT_SUCCESS(Status))
  44. {
  45. DebugLog((DEB_ERROR, "UserCtxtHandlerInit: Failed to initialize critsec 0x%x\n", Status));
  46. goto CleanUp;
  47. }
  48. InitializeListHead( &l_UserCtxtList );
  49. // Simple variable test to make sure all initialized;
  50. g_bUserContextInitialized = TRUE;
  51. CleanUp:
  52. return Status;
  53. }
  54. // Add a Context into the UserMode Context List
  55. NTSTATUS
  56. UserCtxtHandlerInsertCred(
  57. IN PDIGEST_USERCONTEXT pUserContext
  58. )
  59. {
  60. RtlEnterCriticalSection( &l_UserCtxtCritSect );
  61. DebugLog((DEB_TRACE, "UserCtxtHandlerRelease: (RefCount) linked 0x%x\n", pUserContext->LsaContext));
  62. InsertHeadList( &l_UserCtxtList, &pUserContext->Next );
  63. RtlLeaveCriticalSection( &l_UserCtxtCritSect );
  64. return STATUS_SUCCESS;
  65. }
  66. // Initialize a UserMode Context
  67. NTSTATUS NTAPI
  68. UserCtxtInit(
  69. PDIGEST_USERCONTEXT pContext
  70. )
  71. {
  72. NTSTATUS Status = STATUS_SUCCESS;
  73. DebugLog((DEB_TRACE_FUNC, "UserCtxtInit: Entering\n"));
  74. ASSERT(pContext);
  75. if (!pContext)
  76. {
  77. return STATUS_INVALID_PARAMETER;
  78. }
  79. ZeroMemory(pContext, sizeof(DIGEST_USERCONTEXT));
  80. DebugLog((DEB_TRACE_FUNC, "UserCtxtInit: Leaving \n"));
  81. return Status;
  82. }
  83. // Once done with a context - release the resouces
  84. NTSTATUS NTAPI
  85. UserCtxtFree(
  86. IN PDIGEST_USERCONTEXT pContext
  87. )
  88. {
  89. NTSTATUS Status = STATUS_SUCCESS;
  90. int i = 0;
  91. DebugLog((DEB_TRACE_FUNC, "UserCtxtFree: Entering with LSA context 0x%x\n", pContext->LsaContext));
  92. ASSERT(pContext);
  93. ASSERT(pContext->lReferences == 0);
  94. ASSERT(pContext->lReferenceHandles == 0);
  95. if (!pContext)
  96. {
  97. return STATUS_INVALID_PARAMETER;
  98. }
  99. if (pContext->ClientTokenHandle)
  100. {
  101. NTSTATUS IgnoreStatus;
  102. IgnoreStatus = NtClose(pContext->ClientTokenHandle);
  103. // ASSERT (NT_SUCCESS (IgnoreStatus));
  104. if (!NT_SUCCESS(IgnoreStatus))
  105. {
  106. DebugLog((DEB_ERROR, "UserCtxtFree: Could not Close the TokenHandle!!!!\n"));
  107. }
  108. pContext->ClientTokenHandle = NULL;
  109. }
  110. if (pContext->hSealCryptKey)
  111. {
  112. CryptDestroyKey( pContext->hSealCryptKey );
  113. pContext->hSealCryptKey = NULL;
  114. }
  115. if (pContext->hUnsealCryptKey)
  116. {
  117. CryptDestroyKey( pContext->hUnsealCryptKey );
  118. pContext->hUnsealCryptKey = NULL;
  119. }
  120. StringFree(&(pContext->strSessionKey));
  121. UnicodeStringFree(&(pContext->ustrAccountName));
  122. //
  123. // Values utilized in the Initial Digest Auth ChallResponse
  124. // Can be utilized for defaults in future MakeSignature/VerifySignature
  125. //
  126. for (i=0; i < MD5_AUTH_LAST; i++)
  127. {
  128. StringFree(&(pContext->strParam[i]));
  129. }
  130. DigestFreeMemory(pContext);
  131. DebugLog((DEB_TRACE_FUNC, "UserCtxtFree: Leaving\n"));
  132. return Status;
  133. }
  134. /*++
  135. Routine Description:
  136. This routine checks to see if the Context is for the specified
  137. Client Connection, and references the Context if it is valid.
  138. The caller may optionally request that the Context be
  139. removed from the list of valid Contexts - preventing future
  140. requests from finding this Context.
  141. Arguments:
  142. ContextHandle - Points to the ContextHandle of the Context
  143. to be referenced.
  144. DerefContext - This boolean value indicates whether the caller
  145. wants the Context to be removed from the list
  146. of Contexts. TRUE indicates the Context is to be removed.
  147. FALSE indicates the Context is not to be removed.
  148. Return Value:
  149. NULL - the Context was not found.
  150. Otherwise - returns a pointer to the referenced Context.
  151. --*/
  152. NTSTATUS NTAPI
  153. UserCtxtHandlerHandleToContext(
  154. IN ULONG_PTR ContextHandle,
  155. IN BOOLEAN fDerefContextHandle,
  156. IN BOOLEAN fRefContextHandle,
  157. OUT PDIGEST_USERCONTEXT *ppContext
  158. )
  159. {
  160. NTSTATUS Status = STATUS_SUCCESS;
  161. PLIST_ENTRY ListEntry = NULL;
  162. PDIGEST_USERCONTEXT pContext = NULL;
  163. ASSERT(!(fDerefContextHandle & fRefContextHandle)); // should not ref and deref at same time
  164. DebugLog((DEB_TRACE_FUNC, "UserCtxtHandlerHandleToContext: Entering\n" ));
  165. //
  166. // Acquire exclusive access to the Context list
  167. // For performance, this could be distributed into a set of CritSects for preventing contention
  168. //
  169. RtlEnterCriticalSection( &l_UserCtxtCritSect );
  170. //
  171. // Now walk the list of Contexts looking for a match.
  172. //
  173. for ( ListEntry = l_UserCtxtList.Flink;
  174. ListEntry != &l_UserCtxtList;
  175. ListEntry = ListEntry->Flink )
  176. {
  177. pContext = CONTAINING_RECORD( ListEntry, DIGEST_USERCONTEXT, Next );
  178. //
  179. // Found a match ... reference this Context
  180. // (if the Context is being removed, we would increment
  181. // and then decrement the reference, so don't bother doing
  182. // either - since they cancel each other out).
  183. //
  184. DebugLog((DEB_TRACE, "UserCtxtHandlerHandleToContext: Checking context %lx for userctxt %lx\n",
  185. pContext->LsaContext, ContextHandle ));
  186. if (pContext->LsaContext != ContextHandle)
  187. {
  188. continue;
  189. }
  190. // Called to dereference an application SecurityContext Handle
  191. if (fDerefContextHandle)
  192. {
  193. if (pContext->lReferenceHandles > 0)
  194. {
  195. pContext->lReferenceHandles--; // thread safe due to l_UserCtxtCritSect
  196. }
  197. else
  198. {
  199. DebugLog((DEB_ERROR, "UserCtxtHandlerHandleToContext: nonpositive App SecurityCtxt count Context = 0x%x, References = %ld, ReferenceHandles = %ld\n",
  200. pContext, pContext->lReferences, pContext->lReferenceHandles));
  201. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  202. *ppContext = NULL;
  203. goto CleanUp;
  204. }
  205. }
  206. // Called to add in a Reference an application SecurityContext Handle
  207. if (fRefContextHandle)
  208. {
  209. pContext->lReferenceHandles++; // thread safe due to l_UserCtxtCritSect
  210. }
  211. DebugLog((DEB_TRACE, "UserCtxtHandlerHandleToContext: Context = 0x%x, References = %ld, ReferenceHandles = %ld\n",
  212. pContext, pContext->lReferences, pContext->lReferenceHandles));
  213. pContext->lReferences++; // reference counters are thread safe due to l_UserCtxtCritSect
  214. *ppContext = pContext;
  215. goto CleanUp;
  216. }
  217. //
  218. // No match found
  219. //
  220. DebugLog((DEB_WARN, "UserCtxtHandlerHandleToContext: Tried to reference unknown Context 0x%lx\n", ContextHandle ));
  221. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  222. *ppContext = NULL;
  223. CleanUp:
  224. RtlLeaveCriticalSection( &l_UserCtxtCritSect );
  225. DebugLog((DEB_TRACE_FUNC, "UserCtxtHandlerHandleToContext: Leaving Status 0x%x\n", Status ));
  226. return(Status);
  227. }
  228. // Check the Creation time with the Current time.
  229. // If the difference is greater than the MAX allowed, Context is no longer valid
  230. BOOL
  231. UserCtxtHandlerTimeHasElapsed(
  232. PDIGEST_USERCONTEXT pContext)
  233. {
  234. UNREFERENCED_PARAMETER(pContext);
  235. return (FALSE); // no expiration at this time
  236. }
  237. //+--------------------------------------------------------------------
  238. //
  239. // Function: CtxtHandlerRelease
  240. //
  241. // Synopsis: Releases the Context by decreasing reference counter
  242. //
  243. // Arguments: pContext - pointer to credential to de-reference
  244. //
  245. // Returns: NTSTATUS
  246. //
  247. // Notes: Since multiple threads must wait for ownership
  248. // of a context, reference count must be either 0 (unused) or 1 (in process)
  249. //
  250. //---------------------------------------------------------------------
  251. NTSTATUS
  252. UserCtxtHandlerRelease(
  253. PDIGEST_USERCONTEXT pUserContext)
  254. {
  255. NTSTATUS Status = STATUS_SUCCESS;
  256. DebugLog((DEB_TRACE_FUNC, "UserCtxtHandlerRelease: Entering\n" ));
  257. ASSERT( pUserContext->lReferences > 0);
  258. //
  259. // Acquire exclusive access to the Context list
  260. // For performance, this could be distributed into a set of CritSects for preventing contention
  261. //
  262. RtlEnterCriticalSection( &l_UserCtxtCritSect );
  263. pUserContext->lReferences--;
  264. DebugLog((DEB_TRACE, "UserCtxtHandlerRelease: UserContextInit Context 0x%x references %ld\n",
  265. pUserContext->LsaContext, pUserContext->lReferences));
  266. //
  267. // If the count has dropped to zero for both application SecurityContext handles and internal SSP references
  268. // then delink from the list and free up context
  269. //
  270. if (!pUserContext->lReferences && !pUserContext->lReferenceHandles)
  271. {
  272. DebugLog((DEB_TRACE, "UserCtxtHandlerRelease: UserContextInit unlinked and freed userContext 0x%x\n", pUserContext));
  273. RemoveEntryList( &pUserContext->Next );
  274. Status = UserCtxtFree(pUserContext);
  275. if (!NT_SUCCESS (Status))
  276. {
  277. DebugLog((DEB_ERROR, "UserCtxtHandlerRelease: UserCtxtFree error 0x%x\n", Status));
  278. }
  279. }
  280. RtlLeaveCriticalSection( &l_UserCtxtCritSect );
  281. DebugLog((DEB_TRACE_FUNC, "UserCtxtHandlerRelease: Leaving Status 0x%x\n", Status ));
  282. return(Status);
  283. }
  284. // Following functions make use of the lock for insuring single threaded operation
  285. /*++
  286. RoutineDescription:
  287. Creates a new DACL for the token granting the server and client
  288. all access to the token.
  289. Arguments:
  290. Token - Handle to an impersonation token open for TOKEN_QUERY and
  291. WRITE_DAC
  292. Return Value:
  293. STATUS_INSUFFICIENT_RESOURCES - insufficient memory to complete
  294. the function.
  295. Errors from NtSetSecurityObject
  296. --*/
  297. NTSTATUS
  298. SspCreateTokenDacl(
  299. HANDLE Token
  300. )
  301. {
  302. NTSTATUS Status = STATUS_SUCCESS;
  303. PTOKEN_USER ProcessTokenUser = NULL;
  304. PTOKEN_USER ThreadTokenUser = NULL;
  305. PTOKEN_USER ImpersonationTokenUser = NULL;
  306. HANDLE ProcessToken = NULL;
  307. HANDLE ImpersonationToken = NULL;
  308. BOOL fInsertImpersonatingUser = FALSE;
  309. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  310. ULONG AclLength = 0;
  311. PACL NewDacl = NULL;
  312. SECURITY_DESCRIPTOR SecurityDescriptor;
  313. BOOL fReleaseContextLock = FALSE;
  314. DebugLog((DEB_TRACE_FUNC, "SspCreateTokenDacl: Entering Token is 0x%x\n", Token));
  315. //
  316. // Build the two well known sids we need.
  317. //
  318. if (g_NtDigestGlobalLocalSystemSid == NULL || g_NtDigestGlobalAliasAdminsSid == NULL ) {
  319. RtlEnterCriticalSection(&l_UserCtxtCritSect);
  320. fReleaseContextLock = TRUE;
  321. if (g_NtDigestGlobalLocalSystemSid == NULL)
  322. {
  323. PSID pLocalSidSystem = NULL;
  324. DebugLog((DEB_TRACE, "SspCreateTokenDacl: Allocate and Init LocalSystem SID\n"));
  325. Status = RtlAllocateAndInitializeSid(
  326. &NtAuthority,
  327. 1,
  328. SECURITY_LOCAL_SYSTEM_RID,
  329. 0,0,0,0,0,0,0,
  330. &pLocalSidSystem
  331. );
  332. if (!NT_SUCCESS(Status))
  333. {
  334. DebugLog((DEB_ERROR, "SspCreateTokenDacl: RtlAllocateAndInitializeSid returns 0x%lx\n", Status ));
  335. goto Cleanup;
  336. }
  337. DebugLog((DEB_TRACE, "SspCreateTokenDacl: Allocate and Init LocalSystem SID DONE\n"));
  338. g_NtDigestGlobalLocalSystemSid = pLocalSidSystem;
  339. }
  340. if (g_NtDigestGlobalAliasAdminsSid == NULL)
  341. {
  342. PSID pLocalSidAdmins = NULL;
  343. DebugLog((DEB_TRACE, "SspCreateTokenDacl: Allocate and Init AliasAdmin SID\n"));
  344. Status = RtlAllocateAndInitializeSid(
  345. &NtAuthority,
  346. 2,
  347. SECURITY_BUILTIN_DOMAIN_RID,
  348. DOMAIN_ALIAS_RID_ADMINS,
  349. 0,0,0,0,0,0,
  350. &pLocalSidAdmins
  351. );
  352. if (!NT_SUCCESS(Status))
  353. {
  354. DebugLog((DEB_ERROR, "SspCreateTokenDacl, RtlAllocateAndInitializeSid returns 0x%lx\n", Status ));
  355. goto Cleanup;
  356. }
  357. DebugLog((DEB_TRACE, "SspCreateTokenDacl: Allocate and Init AliasAdmin SID DONE\n"));
  358. g_NtDigestGlobalAliasAdminsSid = pLocalSidAdmins;
  359. }
  360. RtlLeaveCriticalSection(&l_UserCtxtCritSect);
  361. fReleaseContextLock = FALSE;
  362. }
  363. //
  364. // it's possible that the current thread is impersonating a user.
  365. // if that's the case, get it's token user, and revert to insure we
  366. // can open the process token.
  367. //
  368. Status = NtOpenThreadToken(
  369. NtCurrentThread(),
  370. TOKEN_QUERY | TOKEN_IMPERSONATE,
  371. TRUE,
  372. &ImpersonationToken
  373. );
  374. if( NT_SUCCESS(Status) )
  375. {
  376. //
  377. // stop impersonating.
  378. //
  379. RevertToSelf();
  380. //
  381. // get the token user for the impersonating user.
  382. //
  383. Status = SspGetTokenUser(
  384. ImpersonationToken,
  385. &ImpersonationTokenUser
  386. );
  387. if (!NT_SUCCESS(Status))
  388. {
  389. DebugLog((DEB_ERROR, "SspCreateTokenDacl: SspGetTokenUser (1) returns 0x%lx\n", Status ));
  390. goto Cleanup;
  391. }
  392. }
  393. //
  394. // Open the process token to find out the user sid
  395. //
  396. Status = NtOpenProcessToken(
  397. NtCurrentProcess(),
  398. TOKEN_QUERY,
  399. &ProcessToken
  400. );
  401. if(!NT_SUCCESS(Status))
  402. {
  403. DebugLog((DEB_ERROR, "SspCreateTokenDacl: NtOpenProcessToken returns 0x%lx\n", Status ));
  404. goto Cleanup;
  405. }
  406. //
  407. // get the token user for the process token.
  408. //
  409. Status = SspGetTokenUser(
  410. ProcessToken,
  411. &ProcessTokenUser
  412. );
  413. if (!NT_SUCCESS(Status))
  414. {
  415. DebugLog((DEB_ERROR, "SspCreateTokenDacl: SspGetTokenUser (2) returns 0x%lx\n", Status ));
  416. goto Cleanup;
  417. }
  418. //
  419. // Now get the token user for the thread.
  420. //
  421. Status = SspGetTokenUser(
  422. Token,
  423. &ThreadTokenUser
  424. );
  425. if (!NT_SUCCESS(Status))
  426. {
  427. DebugLog((DEB_ERROR, "SspCreateTokenDacl: SspGetTokenUser (3) returns 0x%lx\n", Status ));
  428. goto Cleanup;
  429. }
  430. AclLength = 4 * sizeof( ACCESS_ALLOWED_ACE ) - 4 * sizeof( ULONG ) +
  431. RtlLengthSid( ProcessTokenUser->User.Sid ) +
  432. RtlLengthSid( ThreadTokenUser->User.Sid ) +
  433. RtlLengthSid( g_NtDigestGlobalLocalSystemSid ) +
  434. RtlLengthSid( g_NtDigestGlobalAliasAdminsSid ) +
  435. sizeof( ACL );
  436. //
  437. // determine if we need to add impersonation token sid onto the token Dacl.
  438. //
  439. if( ImpersonationTokenUser &&
  440. !RtlEqualSid( ImpersonationTokenUser->User.Sid, ProcessTokenUser->User.Sid ) &&
  441. !RtlEqualSid( ImpersonationTokenUser->User.Sid, ThreadTokenUser->User.Sid )
  442. )
  443. {
  444. AclLength += (sizeof(ACCESS_ALLOWED_ACE) - sizeof( ULONG )) +
  445. RtlLengthSid( ImpersonationTokenUser->User.Sid );
  446. fInsertImpersonatingUser = TRUE;
  447. }
  448. NewDacl = (PACL)DigestAllocateMemory(AclLength );
  449. if (NewDacl == NULL) {
  450. Status = STATUS_INSUFFICIENT_RESOURCES;
  451. DebugLog((DEB_ERROR, "SspCreateTokenDacl: NtLmallocate returns 0x%lx\n", NewDacl));
  452. goto Cleanup;
  453. }
  454. Status = RtlCreateAcl( NewDacl, AclLength, ACL_REVISION2 );
  455. ASSERT(NT_SUCCESS( Status ));
  456. Status = RtlAddAccessAllowedAce (
  457. NewDacl,
  458. ACL_REVISION2,
  459. TOKEN_ALL_ACCESS,
  460. ProcessTokenUser->User.Sid
  461. );
  462. ASSERT( NT_SUCCESS( Status ));
  463. Status = RtlAddAccessAllowedAce (
  464. NewDacl,
  465. ACL_REVISION2,
  466. TOKEN_ALL_ACCESS,
  467. ThreadTokenUser->User.Sid
  468. );
  469. ASSERT( NT_SUCCESS( Status ));
  470. if( fInsertImpersonatingUser )
  471. {
  472. Status = RtlAddAccessAllowedAce (
  473. NewDacl,
  474. ACL_REVISION2,
  475. TOKEN_ALL_ACCESS,
  476. ImpersonationTokenUser->User.Sid
  477. );
  478. ASSERT( NT_SUCCESS( Status ));
  479. }
  480. Status = RtlAddAccessAllowedAce (
  481. NewDacl,
  482. ACL_REVISION2,
  483. TOKEN_ALL_ACCESS,
  484. g_NtDigestGlobalAliasAdminsSid
  485. );
  486. ASSERT( NT_SUCCESS( Status ));
  487. Status = RtlAddAccessAllowedAce (
  488. NewDacl,
  489. ACL_REVISION2,
  490. TOKEN_ALL_ACCESS,
  491. g_NtDigestGlobalLocalSystemSid
  492. );
  493. ASSERT( NT_SUCCESS( Status ));
  494. Status = RtlCreateSecurityDescriptor (
  495. &SecurityDescriptor,
  496. SECURITY_DESCRIPTOR_REVISION
  497. );
  498. ASSERT( NT_SUCCESS( Status ));
  499. Status = RtlSetDaclSecurityDescriptor(
  500. &SecurityDescriptor,
  501. TRUE,
  502. NewDacl,
  503. FALSE
  504. );
  505. ASSERT( NT_SUCCESS( Status ));
  506. Status = NtSetSecurityObject(
  507. Token,
  508. DACL_SECURITY_INFORMATION,
  509. &SecurityDescriptor
  510. );
  511. ASSERT( NT_SUCCESS( Status ));
  512. Cleanup:
  513. if( fReleaseContextLock )
  514. RtlLeaveCriticalSection(&l_UserCtxtCritSect);
  515. if (ImpersonationToken != NULL)
  516. {
  517. //
  518. // put the thread token back if we were impersonating.
  519. //
  520. (void)SetThreadToken( NULL, ImpersonationToken );
  521. NtClose(ImpersonationToken);
  522. }
  523. if (ThreadTokenUser != NULL) {
  524. DigestFreeMemory( ThreadTokenUser );
  525. }
  526. if (ProcessTokenUser != NULL) {
  527. DigestFreeMemory( ProcessTokenUser );
  528. }
  529. if (ImpersonationTokenUser != NULL) {
  530. DigestFreeMemory( ImpersonationTokenUser );
  531. }
  532. if (NewDacl != NULL) {
  533. DigestFreeMemory( NewDacl );
  534. }
  535. if (ProcessToken != NULL)
  536. {
  537. NtClose(ProcessToken);
  538. }
  539. DebugLog((DEB_TRACE_FUNC, "SspCreateTokenDacl: Leaving Token is 0x%x\n", Token));
  540. return( Status );
  541. }