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.

675 lines
18 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) UserContextInit 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. if (!pContext)
  95. {
  96. return STATUS_INVALID_PARAMETER;
  97. }
  98. if (pContext->ClientTokenHandle)
  99. {
  100. NTSTATUS IgnoreStatus;
  101. IgnoreStatus = NtClose(pContext->ClientTokenHandle);
  102. // ASSERT (NT_SUCCESS (IgnoreStatus));
  103. if (!NT_SUCCESS(IgnoreStatus))
  104. {
  105. DebugLog((DEB_ERROR, "UserCtxtFree: Could not Close the TokenHandle!!!!\n"));
  106. }
  107. pContext->ClientTokenHandle = NULL;
  108. }
  109. if (pContext->hSealCryptKey)
  110. {
  111. CryptDestroyKey( pContext->hSealCryptKey );
  112. pContext->hSealCryptKey = NULL;
  113. }
  114. if (pContext->hUnsealCryptKey)
  115. {
  116. CryptDestroyKey( pContext->hUnsealCryptKey );
  117. pContext->hUnsealCryptKey = NULL;
  118. }
  119. StringFree(&(pContext->strSessionKey));
  120. UnicodeStringFree(&(pContext->ustrAccountName));
  121. //
  122. // Values utilized in the Initial Digest Auth ChallResponse
  123. // Can be utilized for defaults in future MakeSignature/VerifySignature
  124. //
  125. for (i=0; i < MD5_AUTH_LAST; i++)
  126. {
  127. StringFree(&(pContext->strParam[i]));
  128. }
  129. DigestFreeMemory(pContext);
  130. DebugLog((DEB_TRACE_FUNC, "UserCtxtFree: Leaving\n"));
  131. return Status;
  132. }
  133. /*++
  134. Routine Description:
  135. This routine checks to see if the Context is for the specified
  136. Client Connection, and references the Context if it is valid.
  137. The caller may optionally request that the Context be
  138. removed from the list of valid Contexts - preventing future
  139. requests from finding this Context.
  140. Arguments:
  141. ContextHandle - Points to the ContextHandle of the Context
  142. to be referenced.
  143. RemoveContext - This boolean value indicates whether the caller
  144. wants the Context to be removed from the list
  145. of Contexts. TRUE indicates the Context is to be removed.
  146. FALSE indicates the Context is not to be removed.
  147. Return Value:
  148. NULL - the Context was not found.
  149. Otherwise - returns a pointer to the referenced Context.
  150. --*/
  151. NTSTATUS NTAPI
  152. UserCtxtHandlerHandleToContext(
  153. IN ULONG_PTR ContextHandle,
  154. IN BOOLEAN RemoveContext,
  155. OUT PDIGEST_USERCONTEXT *ppContext
  156. )
  157. {
  158. NTSTATUS Status = STATUS_SUCCESS;
  159. PLIST_ENTRY ListEntry = NULL;
  160. PDIGEST_USERCONTEXT pContext = NULL;
  161. LONG lReferences = 0;
  162. DebugLog((DEB_TRACE_FUNC, "UserCtxtHandlerHandleToContext: Entering\n" ));
  163. //
  164. // Acquire exclusive access to the Context list
  165. //
  166. RtlEnterCriticalSection( &l_UserCtxtCritSect );
  167. //
  168. // Now walk the list of Contexts looking for a match.
  169. //
  170. for ( ListEntry = l_UserCtxtList.Flink;
  171. ListEntry != &l_UserCtxtList;
  172. ListEntry = ListEntry->Flink )
  173. {
  174. pContext = CONTAINING_RECORD( ListEntry, DIGEST_USERCONTEXT, Next );
  175. //
  176. // Found a match ... reference this Context
  177. // (if the Context is being removed, we would increment
  178. // and then decrement the reference, so don't bother doing
  179. // either - since they cancel each other out).
  180. //
  181. DebugLog((DEB_TRACE, "UserCtxtHandlerHandleToContext: Checking context %lx for userctxt %lx\n",
  182. pContext->LsaContext, ContextHandle ));
  183. if (pContext->LsaContext != ContextHandle)
  184. {
  185. continue;
  186. }
  187. if (!RemoveContext)
  188. {
  189. lReferences = InterlockedIncrement(&pContext->lReferences);
  190. }
  191. else
  192. {
  193. DebugLog((DEB_TRACE, "UserCtxtHandlerRelease: (RefCount) UserContextInit delinked 0x%x\n", ContextHandle));
  194. RemoveEntryList( &pContext->Next );
  195. }
  196. DebugLog((DEB_TRACE, "CtxtHandlerHandleToContext FOUND Context = 0x%x, RemoveContext = %d, ReferenceCount = %ld\n",
  197. pContext, RemoveContext, pContext->lReferences));
  198. *ppContext = pContext;
  199. goto CleanUp;
  200. }
  201. //
  202. // No match found
  203. //
  204. DebugLog((DEB_WARN, "UserCtxtHandlerHandleToContext: Tried to reference unknown Context 0x%lx\n", ContextHandle ));
  205. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  206. *ppContext = NULL;
  207. CleanUp:
  208. RtlLeaveCriticalSection( &l_UserCtxtCritSect );
  209. DebugLog((DEB_TRACE_FUNC, "UserCtxtHandlerHandleToContext: Leaving Status 0x%x\n", Status ));
  210. return(Status);
  211. }
  212. // Check the Creation time with the Current time.
  213. // If the difference is greater than the MAX allowed, Context is no longer valid
  214. BOOL
  215. UserCtxtHandlerTimeHasElapsed(
  216. PDIGEST_USERCONTEXT pContext)
  217. {
  218. BOOL bStatus = FALSE;
  219. DWORD dwTimeElapsed = 0;
  220. time_t timeCurrent = time(NULL);
  221. return FALSE;
  222. // dwTimeElapsed = (DWORD)(timeCurrent - pContext->TimeCreated);
  223. if (dwTimeElapsed > g_dwParameter_Lifetime)
  224. {
  225. bStatus = TRUE;
  226. }
  227. return(bStatus);
  228. }
  229. //+--------------------------------------------------------------------
  230. //
  231. // Function: CtxtHandlerRelease
  232. //
  233. // Synopsis: Releases the Context by decreasing reference counter
  234. //
  235. // Arguments: pContext - pointer to credential to de-reference
  236. //
  237. // Returns: NTSTATUS
  238. //
  239. // Notes: Called by ASC. Since multiple threads must wait for ownership
  240. // of a context, reference count must be either 0 (unused) or 1 (in process)
  241. //
  242. //---------------------------------------------------------------------
  243. NTSTATUS
  244. UserCtxtHandlerRelease(
  245. PDIGEST_USERCONTEXT pUserContext)
  246. {
  247. NTSTATUS Status = STATUS_SUCCESS;
  248. LONG lReferences = 0;
  249. lReferences = InterlockedDecrement(&pUserContext->lReferences);
  250. DebugLog((DEB_TRACE, "UserCtxtHandlerRelease: (RefCount) UserContextInit deref 0x%x references %ld\n",
  251. pUserContext, lReferences));
  252. ASSERT( lReferences >= 0 );
  253. //
  254. // If the count has dropped to zero, then free all alloced stuff
  255. //
  256. if (lReferences == 0)
  257. {
  258. DebugLog((DEB_TRACE, "UserCtxtHandlerRelease: (RefCount) UserContextInit freed 0x%x\n", pUserContext));
  259. Status = UserCtxtFree(pUserContext);
  260. }
  261. return(Status);
  262. }
  263. // Following functions make use of the lock for insuring single threaded operation
  264. /*++
  265. RoutineDescription:
  266. Creates a new DACL for the token granting the server and client
  267. all access to the token.
  268. Arguments:
  269. Token - Handle to an impersonation token open for TOKEN_QUERY and
  270. WRITE_DAC
  271. Return Value:
  272. STATUS_INSUFFICIENT_RESOURCES - insufficient memory to complete
  273. the function.
  274. Errors from NtSetSecurityObject
  275. --*/
  276. NTSTATUS
  277. SspCreateTokenDacl(
  278. HANDLE Token
  279. )
  280. {
  281. NTSTATUS Status = STATUS_SUCCESS;
  282. PTOKEN_USER ProcessTokenUser = NULL;
  283. PTOKEN_USER ThreadTokenUser = NULL;
  284. PTOKEN_USER ImpersonationTokenUser = NULL;
  285. HANDLE ProcessToken = NULL;
  286. HANDLE ImpersonationToken = NULL;
  287. BOOL fInsertImpersonatingUser = FALSE;
  288. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  289. ULONG AclLength = 0;
  290. PACL NewDacl = NULL;
  291. SECURITY_DESCRIPTOR SecurityDescriptor;
  292. BOOL fReleaseContextLock = FALSE;
  293. DebugLog((DEB_TRACE_FUNC, "SspCreateTokenDacl: Entering Token is 0x%x\n", Token));
  294. //
  295. // Build the two well known sids we need.
  296. //
  297. if (g_NtDigestGlobalLocalSystemSid == NULL || g_NtDigestGlobalAliasAdminsSid == NULL ) {
  298. RtlEnterCriticalSection(&l_UserCtxtCritSect);
  299. fReleaseContextLock = TRUE;
  300. if (g_NtDigestGlobalLocalSystemSid == NULL)
  301. {
  302. PSID pLocalSidSystem = NULL;
  303. DebugLog((DEB_TRACE, "SspCreateTokenDacl: Allocate and Init LocalSystem SID\n"));
  304. Status = RtlAllocateAndInitializeSid(
  305. &NtAuthority,
  306. 1,
  307. SECURITY_LOCAL_SYSTEM_RID,
  308. 0,0,0,0,0,0,0,
  309. &pLocalSidSystem
  310. );
  311. if (!NT_SUCCESS(Status))
  312. {
  313. DebugLog((DEB_ERROR, "SspCreateTokenDacl: RtlAllocateAndInitializeSid returns 0x%lx\n", Status ));
  314. goto Cleanup;
  315. }
  316. DebugLog((DEB_TRACE, "SspCreateTokenDacl: Allocate and Init LocalSystem SID DONE\n"));
  317. g_NtDigestGlobalLocalSystemSid = pLocalSidSystem;
  318. }
  319. if (g_NtDigestGlobalAliasAdminsSid == NULL)
  320. {
  321. PSID pLocalSidAdmins = NULL;
  322. DebugLog((DEB_TRACE, "SspCreateTokenDacl: Allocate and Init AliasAdmin SID\n"));
  323. Status = RtlAllocateAndInitializeSid(
  324. &NtAuthority,
  325. 2,
  326. SECURITY_BUILTIN_DOMAIN_RID,
  327. DOMAIN_ALIAS_RID_ADMINS,
  328. 0,0,0,0,0,0,
  329. &pLocalSidAdmins
  330. );
  331. if (!NT_SUCCESS(Status))
  332. {
  333. DebugLog((DEB_ERROR, "SspCreateTokenDacl, RtlAllocateAndInitializeSid returns 0x%lx\n", Status ));
  334. goto Cleanup;
  335. }
  336. DebugLog((DEB_TRACE, "SspCreateTokenDacl: Allocate and Init AliasAdmin SID DONE\n"));
  337. g_NtDigestGlobalAliasAdminsSid = pLocalSidAdmins;
  338. }
  339. RtlLeaveCriticalSection(&l_UserCtxtCritSect);
  340. fReleaseContextLock = FALSE;
  341. }
  342. //
  343. // it's possible that the current thread is impersonating a user.
  344. // if that's the case, get it's token user, and revert to insure we
  345. // can open the process token.
  346. //
  347. Status = NtOpenThreadToken(
  348. NtCurrentThread(),
  349. TOKEN_QUERY | TOKEN_IMPERSONATE,
  350. TRUE,
  351. &ImpersonationToken
  352. );
  353. if( NT_SUCCESS(Status) )
  354. {
  355. //
  356. // stop impersonating.
  357. //
  358. RevertToSelf();
  359. //
  360. // get the token user for the impersonating user.
  361. //
  362. Status = SspGetTokenUser(
  363. ImpersonationToken,
  364. &ImpersonationTokenUser
  365. );
  366. if (!NT_SUCCESS(Status))
  367. {
  368. DebugLog((DEB_ERROR, "SspCreateTokenDacl: SspGetTokenUser (1) returns 0x%lx\n", Status ));
  369. goto Cleanup;
  370. }
  371. }
  372. //
  373. // Open the process token to find out the user sid
  374. //
  375. Status = NtOpenProcessToken(
  376. NtCurrentProcess(),
  377. TOKEN_QUERY,
  378. &ProcessToken
  379. );
  380. if(!NT_SUCCESS(Status))
  381. {
  382. DebugLog((DEB_ERROR, "SspCreateTokenDacl: NtOpenProcessToken returns 0x%lx\n", Status ));
  383. goto Cleanup;
  384. }
  385. //
  386. // get the token user for the process token.
  387. //
  388. Status = SspGetTokenUser(
  389. ProcessToken,
  390. &ProcessTokenUser
  391. );
  392. if (!NT_SUCCESS(Status))
  393. {
  394. DebugLog((DEB_ERROR, "SspCreateTokenDacl: SspGetTokenUser (2) returns 0x%lx\n", Status ));
  395. goto Cleanup;
  396. }
  397. //
  398. // Now get the token user for the thread.
  399. //
  400. Status = SspGetTokenUser(
  401. Token,
  402. &ThreadTokenUser
  403. );
  404. if (!NT_SUCCESS(Status))
  405. {
  406. DebugLog((DEB_ERROR, "SspCreateTokenDacl: SspGetTokenUser (3) returns 0x%lx\n", Status ));
  407. goto Cleanup;
  408. }
  409. AclLength = 4 * sizeof( ACCESS_ALLOWED_ACE ) - 4 * sizeof( ULONG ) +
  410. RtlLengthSid( ProcessTokenUser->User.Sid ) +
  411. RtlLengthSid( ThreadTokenUser->User.Sid ) +
  412. RtlLengthSid( g_NtDigestGlobalLocalSystemSid ) +
  413. RtlLengthSid( g_NtDigestGlobalAliasAdminsSid ) +
  414. sizeof( ACL );
  415. //
  416. // determine if we need to add impersonation token sid onto the token Dacl.
  417. //
  418. if( ImpersonationTokenUser &&
  419. !RtlEqualSid( ImpersonationTokenUser->User.Sid, ProcessTokenUser->User.Sid ) &&
  420. !RtlEqualSid( ImpersonationTokenUser->User.Sid, ThreadTokenUser->User.Sid )
  421. )
  422. {
  423. AclLength += (sizeof(ACCESS_ALLOWED_ACE) - sizeof( ULONG )) +
  424. RtlLengthSid( ImpersonationTokenUser->User.Sid );
  425. fInsertImpersonatingUser = TRUE;
  426. }
  427. NewDacl = (PACL)DigestAllocateMemory(AclLength );
  428. if (NewDacl == NULL) {
  429. Status = STATUS_INSUFFICIENT_RESOURCES;
  430. DebugLog((DEB_ERROR, "SspCreateTokenDacl: NtLmallocate returns 0x%lx\n", NewDacl));
  431. goto Cleanup;
  432. }
  433. Status = RtlCreateAcl( NewDacl, AclLength, ACL_REVISION2 );
  434. ASSERT(NT_SUCCESS( Status ));
  435. Status = RtlAddAccessAllowedAce (
  436. NewDacl,
  437. ACL_REVISION2,
  438. TOKEN_ALL_ACCESS,
  439. ProcessTokenUser->User.Sid
  440. );
  441. ASSERT( NT_SUCCESS( Status ));
  442. Status = RtlAddAccessAllowedAce (
  443. NewDacl,
  444. ACL_REVISION2,
  445. TOKEN_ALL_ACCESS,
  446. ThreadTokenUser->User.Sid
  447. );
  448. ASSERT( NT_SUCCESS( Status ));
  449. if( fInsertImpersonatingUser )
  450. {
  451. Status = RtlAddAccessAllowedAce (
  452. NewDacl,
  453. ACL_REVISION2,
  454. TOKEN_ALL_ACCESS,
  455. ImpersonationTokenUser->User.Sid
  456. );
  457. ASSERT( NT_SUCCESS( Status ));
  458. }
  459. Status = RtlAddAccessAllowedAce (
  460. NewDacl,
  461. ACL_REVISION2,
  462. TOKEN_ALL_ACCESS,
  463. g_NtDigestGlobalAliasAdminsSid
  464. );
  465. ASSERT( NT_SUCCESS( Status ));
  466. Status = RtlAddAccessAllowedAce (
  467. NewDacl,
  468. ACL_REVISION2,
  469. TOKEN_ALL_ACCESS,
  470. g_NtDigestGlobalLocalSystemSid
  471. );
  472. ASSERT( NT_SUCCESS( Status ));
  473. Status = RtlCreateSecurityDescriptor (
  474. &SecurityDescriptor,
  475. SECURITY_DESCRIPTOR_REVISION
  476. );
  477. ASSERT( NT_SUCCESS( Status ));
  478. Status = RtlSetDaclSecurityDescriptor(
  479. &SecurityDescriptor,
  480. TRUE,
  481. NewDacl,
  482. FALSE
  483. );
  484. ASSERT( NT_SUCCESS( Status ));
  485. Status = NtSetSecurityObject(
  486. Token,
  487. DACL_SECURITY_INFORMATION,
  488. &SecurityDescriptor
  489. );
  490. ASSERT( NT_SUCCESS( Status ));
  491. Cleanup:
  492. if( fReleaseContextLock )
  493. RtlLeaveCriticalSection(&l_UserCtxtCritSect);
  494. if (ImpersonationToken != NULL)
  495. {
  496. //
  497. // put the thread token back if we were impersonating.
  498. //
  499. SetThreadToken( NULL, ImpersonationToken );
  500. NtClose(ImpersonationToken);
  501. }
  502. if (ThreadTokenUser != NULL) {
  503. DigestFreeMemory( ThreadTokenUser );
  504. }
  505. if (ProcessTokenUser != NULL) {
  506. DigestFreeMemory( ProcessTokenUser );
  507. }
  508. if (ImpersonationTokenUser != NULL) {
  509. DigestFreeMemory( ImpersonationTokenUser );
  510. }
  511. if (NewDacl != NULL) {
  512. DigestFreeMemory( NewDacl );
  513. }
  514. if (ProcessToken != NULL)
  515. {
  516. NtClose(ProcessToken);
  517. }
  518. DebugLog((DEB_TRACE_FUNC, "SspCreateTokenDacl: Leaving Token is 0x%x\n", Token));
  519. return( Status );
  520. }