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.

4166 lines
111 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. token.c
  5. Abstract:
  6. This module implements the initialization, open, duplicate and other
  7. services of the executive token object.
  8. Author:
  9. Jim Kelly (JimK) 5-April-1990
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. v15: robertre
  14. updated ACL_REVISION
  15. --*/
  16. #include "pch.h"
  17. #pragma hdrstop
  18. BOOLEAN
  19. SepComparePrivilegeAndAttributeArrays(
  20. IN PLUID_AND_ATTRIBUTES PrivilegeArray1,
  21. IN ULONG Count1,
  22. IN PLUID_AND_ATTRIBUTES PrivilegeArray2,
  23. IN ULONG Count2
  24. );
  25. BOOLEAN
  26. SepCompareSidAndAttributeArrays(
  27. IN PSID_AND_ATTRIBUTES SidArray1,
  28. IN ULONG Count1,
  29. IN PSID_AND_ATTRIBUTES SidArray2,
  30. IN ULONG Count2
  31. );
  32. #ifdef ALLOC_PRAGMA
  33. #pragma alloc_text(PAGE,SeTokenType)
  34. #pragma alloc_text(PAGE,SeTokenIsAdmin)
  35. #pragma alloc_text(PAGE,SeTokenIsRestricted)
  36. #pragma alloc_text(PAGE,SeTokenImpersonationLevel)
  37. #pragma alloc_text(PAGE,SeAssignPrimaryToken)
  38. #pragma alloc_text(PAGE,SeDeassignPrimaryToken)
  39. #pragma alloc_text(PAGE,SeExchangePrimaryToken)
  40. #pragma alloc_text(PAGE,SeGetTokenControlInformation)
  41. #pragma alloc_text(INIT,SeMakeSystemToken)
  42. #pragma alloc_text(INIT,SeMakeAnonymousLogonToken)
  43. #pragma alloc_text(INIT,SeMakeAnonymousLogonTokenNoEveryone)
  44. #pragma alloc_text(PAGE,SeSubProcessToken)
  45. #pragma alloc_text(INIT,SepTokenInitialization)
  46. #pragma alloc_text(PAGE,NtCreateToken)
  47. #pragma alloc_text(PAGE,SepTokenDeleteMethod)
  48. #pragma alloc_text(PAGE,SepCreateToken)
  49. #pragma alloc_text(PAGE,SepIdAssignableAsOwner)
  50. #pragma alloc_text(PAGE,SeIsChildToken)
  51. #pragma alloc_text(PAGE,SeIsChildTokenByPointer)
  52. #pragma alloc_text(PAGE,NtImpersonateAnonymousToken)
  53. #pragma alloc_text(PAGE,NtCompareTokens)
  54. #pragma alloc_text(PAGE,SepComparePrivilegeAndAttributeArrays)
  55. #pragma alloc_text(PAGE,SepCompareSidAndAttributeArrays)
  56. #pragma alloc_text(PAGE,SeAddSaclToProcess)
  57. #endif
  58. ////////////////////////////////////////////////////////////////////////
  59. // //
  60. // Global Variables //
  61. // //
  62. ////////////////////////////////////////////////////////////////////////
  63. //
  64. // Generic mapping of access types
  65. //
  66. #ifdef ALLOC_DATA_PRAGMA
  67. #pragma data_seg("PAGEDATA")
  68. #pragma const_seg("INITCONST")
  69. #endif
  70. const GENERIC_MAPPING SepTokenMapping = { TOKEN_READ,
  71. TOKEN_WRITE,
  72. TOKEN_EXECUTE,
  73. TOKEN_ALL_ACCESS
  74. };
  75. //
  76. // Address of token object type descriptor.
  77. //
  78. POBJECT_TYPE SeTokenObjectType = NULL;
  79. //
  80. // Used to track whether or not a system token has been created or not.
  81. //
  82. #if DBG
  83. BOOLEAN SystemTokenCreated = FALSE;
  84. #endif //DBG
  85. //
  86. // Used to control the active token diagnostic support provided
  87. //
  88. #ifdef TOKEN_DIAGNOSTICS_ENABLED
  89. ULONG TokenGlobalFlag = 0;
  90. #endif // TOKEN_DIAGNOSTICS_ENABLED
  91. ////////////////////////////////////////////////////////////////////////
  92. // //
  93. // Token Object Routines & Methods //
  94. // //
  95. ////////////////////////////////////////////////////////////////////////
  96. TOKEN_TYPE
  97. SeTokenType(
  98. IN PACCESS_TOKEN Token
  99. )
  100. /*++
  101. Routine Description:
  102. This function returns the type of an instance of a token (TokenPrimary,
  103. or TokenImpersonation).
  104. Arguments:
  105. Token - Points to the token whose type is to be returned.
  106. Return Value:
  107. The token's type.
  108. --*/
  109. {
  110. PAGED_CODE();
  111. return (((PTOKEN)Token)->TokenType);
  112. }
  113. NTKERNELAPI
  114. BOOLEAN
  115. SeTokenIsAdmin(
  116. IN PACCESS_TOKEN Token
  117. )
  118. /*++
  119. Routine Description:
  120. Returns if the token is a member of the local admin group.
  121. Arguments:
  122. Token - Points to the token.
  123. Return Value:
  124. TRUE - Token contains the local admin group
  125. FALSE - no admin.
  126. --*/
  127. {
  128. PAGED_CODE();
  129. return ((((PTOKEN)Token)->TokenFlags & TOKEN_HAS_ADMIN_GROUP) != 0 );
  130. }
  131. NTKERNELAPI
  132. NTSTATUS
  133. SeTokenCanImpersonate(
  134. IN PACCESS_TOKEN ProcessToken,
  135. IN PACCESS_TOKEN Token,
  136. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  137. )
  138. /*++
  139. Routine Description:
  140. Determines if the process token is allowed to impersonate the
  141. second token, assuming that the access rights check has already passed.
  142. Arguments:
  143. Token - Points to the token.
  144. Return Value:
  145. TRUE - Token contains the local admin group
  146. FALSE - no admin.
  147. --*/
  148. {
  149. PTOKEN PrimaryToken = (PTOKEN) ProcessToken ;
  150. PTOKEN ImpToken = (PTOKEN) Token ;
  151. PSID PrimaryUserSid ;
  152. PSID ImpUserSid ;
  153. NTSTATUS Status ;
  154. PAGED_CODE();
  155. if ( ImpersonationLevel < SecurityImpersonation )
  156. {
  157. return STATUS_SUCCESS ;
  158. }
  159. //
  160. // allow impersonating anonymous tokens
  161. //
  162. if (RtlEqualLuid(&ImpToken->AuthenticationId, &SeAnonymousAuthenticationId))
  163. {
  164. return STATUS_SUCCESS ;
  165. }
  166. SepAcquireTokenReadLock( PrimaryToken );
  167. if ((PrimaryToken->TokenFlags & TOKEN_HAS_IMPERSONATE_PRIVILEGE) != 0 )
  168. {
  169. SepReleaseTokenReadLock( PrimaryToken );
  170. return STATUS_SUCCESS ;
  171. }
  172. SepAcquireTokenReadLock( ImpToken );
  173. Status = STATUS_PRIVILEGE_NOT_HELD ;
  174. if ( RtlEqualLuid( &PrimaryToken->AuthenticationId, &ImpToken->OriginatingLogonSession ) )
  175. {
  176. Status = STATUS_SUCCESS ;
  177. }
  178. else
  179. {
  180. PrimaryUserSid = PrimaryToken->UserAndGroups[0].Sid ;
  181. ImpUserSid = ImpToken->UserAndGroups[0].Sid ;
  182. if ( RtlEqualSid( PrimaryUserSid, ImpUserSid ) )
  183. {
  184. Status = STATUS_SUCCESS ;
  185. }
  186. }
  187. SepReleaseTokenReadLock( ImpToken );
  188. SepReleaseTokenReadLock( PrimaryToken );
  189. #if DBG
  190. if ( !NT_SUCCESS( Status ) )
  191. {
  192. DbgPrint( "Process %x.%x not allowed to impersonate! Returning %x\n", PsGetCurrentThread()->Cid.UniqueProcess,
  193. PsGetCurrentThread()->Cid.UniqueThread, Status );
  194. }
  195. #endif
  196. return Status ;
  197. }
  198. NTKERNELAPI
  199. BOOLEAN
  200. SeTokenIsRestricted(
  201. IN PACCESS_TOKEN Token
  202. )
  203. /*++
  204. Routine Description:
  205. Returns if the token is a restricted token.
  206. Arguments:
  207. Token - Points to the token.
  208. Return Value:
  209. TRUE - Token contains restricted sids
  210. FALSE - no admin.
  211. --*/
  212. {
  213. PAGED_CODE();
  214. return ((((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0 );
  215. }
  216. SECURITY_IMPERSONATION_LEVEL
  217. SeTokenImpersonationLevel(
  218. IN PACCESS_TOKEN Token
  219. )
  220. /*++
  221. Routine Description:
  222. This function returns the impersonation level of a token. The token
  223. is assumed to be a TokenImpersonation type token.
  224. Arguments:
  225. Token - Points to the token whose impersonation level is to be returned.
  226. Return Value:
  227. The token's impersonation level.
  228. --*/
  229. {
  230. PAGED_CODE();
  231. return ((PTOKEN)Token)->ImpersonationLevel;
  232. }
  233. BOOLEAN
  234. SepCheckTokenForCoreSystemSids(
  235. IN PACCESS_TOKEN Token
  236. )
  237. /*++
  238. Routine Description:
  239. Perform an access-check against SepImportantProcessSd to
  240. determine if the passed token has at least one of the sids present
  241. in the ACEs of SepImportantProcessSd.
  242. Arguments:
  243. Token - a token
  244. Return Value:
  245. TRUE if Token has at least one of the required SIDs,
  246. FALSE otherwise
  247. Notes:
  248. --*/
  249. {
  250. ACCESS_MASK GrantedAccess = 0;
  251. NTSTATUS AccessStatus = STATUS_ACCESS_DENIED;
  252. PAGED_CODE();
  253. (void) SepAccessCheck(
  254. SepImportantProcessSd,
  255. NULL,
  256. Token,
  257. NULL,
  258. SEP_QUERY_MEMBERSHIP,
  259. NULL,
  260. 0,
  261. &GenericMappingForMembershipCheck,
  262. 0,
  263. KernelMode,
  264. &GrantedAccess,
  265. NULL,
  266. &AccessStatus,
  267. 0,
  268. NULL,
  269. NULL
  270. );
  271. return AccessStatus == STATUS_SUCCESS;
  272. }
  273. VOID
  274. SeAddSaclToProcess(
  275. IN PEPROCESS Process,
  276. IN PACCESS_TOKEN Token,
  277. IN PVOID Reserved
  278. )
  279. /*++
  280. Routine Description:
  281. If 'Token' has at least one of the sids present in the ACEs
  282. of SepImportantProcessSd, add a SACL to the security descriptor
  283. of 'Process' as defined by SepProcessAuditSd.
  284. Arguments:
  285. Process - process to add SACL to
  286. Token - token to examine
  287. Return Value:
  288. None
  289. Notes:
  290. --*/
  291. {
  292. NTSTATUS Status;
  293. SECURITY_INFORMATION SecurityInformationSacl = SACL_SECURITY_INFORMATION;
  294. POBJECT_HEADER ObjectHeader;
  295. PAGED_CODE();
  296. // quickly return if this feature is disabled
  297. // (indicated by SeProcessAuditSd == NULL)
  298. //
  299. if ( SepProcessAuditSd == NULL ) {
  300. return;
  301. }
  302. //
  303. // if the token does not have core system sids then return
  304. // without adding SACL.
  305. // (see comment on SepImportantProcessSd in seglobal.c for more info)
  306. //
  307. if (!SepCheckTokenForCoreSystemSids( Token )) {
  308. return;
  309. }
  310. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Process );
  311. //
  312. // add SACL to existing security descriptor on 'Process'
  313. //
  314. Status = ObSetSecurityDescriptorInfo(
  315. Process,
  316. &SecurityInformationSacl,
  317. SepProcessAuditSd,
  318. &ObjectHeader->SecurityDescriptor,
  319. NonPagedPool,
  320. &ObjectHeader->Type->TypeInfo.GenericMapping
  321. );
  322. if (!NT_SUCCESS( Status )) {
  323. //
  324. // STATUS_NO_SECURITY_ON_OBJECT should be returned only once during
  325. // boot when the initial system process is created.
  326. //
  327. if ( Status != STATUS_NO_SECURITY_ON_OBJECT ) {
  328. ASSERT( L"SeAddSaclToProcess: ObSetSecurityDescriptorInfo failed" &&
  329. FALSE );
  330. //
  331. // this will bugcheck if SepCrashOnAuditFail is TRUE
  332. //
  333. SepAuditFailed( Status );
  334. }
  335. }
  336. }
  337. VOID
  338. SeAssignPrimaryToken(
  339. IN PEPROCESS Process,
  340. IN PACCESS_TOKEN Token
  341. )
  342. /*++
  343. Routine Description:
  344. This function establishes a primary token for a process.
  345. Arguments:
  346. Token - Points to the new primary token.
  347. Return Value:
  348. None.
  349. --*/
  350. {
  351. NTSTATUS
  352. Status;
  353. PTOKEN
  354. NewToken = (PTOKEN)Token;
  355. PAGED_CODE();
  356. ASSERT(NewToken->TokenType == TokenPrimary);
  357. ASSERT( !NewToken->TokenInUse );
  358. //
  359. // audit the assignment of a primary token, if requested
  360. //
  361. if (SeDetailedAuditingWithToken(NULL)) {
  362. SepAuditAssignPrimaryToken( Process, Token );
  363. }
  364. //
  365. // If the token being assigned to the child process has
  366. // any one of the following SIDs, then the process
  367. // is considered to be a system process:
  368. // -- SeLocalSystemSid
  369. // -- SeLocalServiceSid
  370. // -- SeNetworkServiceSid
  371. //
  372. // For such a process, add SACL to its security descriptor
  373. // if that option is enabled. If the option is disabled,
  374. // this function returns very quickly.
  375. //
  376. //SeAddSaclToProcess( Process, Token, NULL );
  377. //
  378. // Dereference the old token if there is one.
  379. //
  380. // Processes typically already have a token that must be
  381. // dereferenced. There are two cases where this may not
  382. // be the situation. First, during phase 0 system initialization,
  383. // the initial system process starts out without a token. Second,
  384. // if an error occurs during process creation, we may be cleaning
  385. // up a process that hasn't yet had a primary token assigned.
  386. //
  387. if (!ExFastRefObjectNull (Process->Token)) {
  388. SeDeassignPrimaryToken( Process );
  389. }
  390. ObReferenceObject(NewToken);
  391. NewToken->TokenInUse = TRUE;
  392. ObInitializeFastReference (&Process->Token, Token);
  393. return;
  394. }
  395. VOID
  396. SeDeassignPrimaryToken(
  397. IN PEPROCESS Process
  398. )
  399. /*++
  400. Routine Description:
  401. This function causes a process reference to a token to be
  402. dropped.
  403. Arguments:
  404. Process - Points to the process whose primary token is no longer needed.
  405. This is probably only the case at process deletion or when
  406. a primary token is being replaced.
  407. Return Value:
  408. None.
  409. --*/
  410. {
  411. PTOKEN
  412. OldToken = (PTOKEN) ObFastReplaceObject (&Process->Token, NULL);
  413. PAGED_CODE();
  414. ASSERT(OldToken->TokenType == TokenPrimary);
  415. ASSERT(OldToken->TokenInUse);
  416. OldToken->TokenInUse = FALSE;
  417. ObDereferenceObject( OldToken );
  418. return;
  419. }
  420. NTSTATUS
  421. SeExchangePrimaryToken(
  422. IN PEPROCESS Process,
  423. IN PACCESS_TOKEN NewAccessToken,
  424. OUT PACCESS_TOKEN *OldAccessToken
  425. )
  426. /*++
  427. Routine Description:
  428. This function is used to perform the portions of changing a primary
  429. token that reference the internals of token structures.
  430. The new token is checked to make sure it is not already in use.
  431. Arguments:
  432. Process - Points to the process whose primary token is being exchanged.
  433. NewAccessToken - Points to the process's new primary token.
  434. OldAccessToken - Receives a pointer to the process's current token.
  435. The caller is responsible for dereferencing this token when
  436. it is no longer needed. This can't be done while the process
  437. security locks are held.
  438. Return Value:
  439. STATUS_SUCCESS - Everything has been updated.
  440. STATUS_TOKEN_ALREADY_IN_USE - A primary token can only be used by a
  441. single process. That is, each process must have its own primary
  442. token. The token passed to be assigned as the primary token is
  443. already in use as a primary token.
  444. STATUS_BAD_TOKEN_TYPE - The new token is not a primary token.
  445. STATUS_NO_TOKEN - The process did not have any existing token. This should never happen.
  446. --*/
  447. {
  448. NTSTATUS
  449. Status;
  450. PTOKEN
  451. OldToken;
  452. PTOKEN
  453. NewToken = (PTOKEN)NewAccessToken;
  454. ULONG SessionId;
  455. PAGED_CODE();
  456. //
  457. // Make sure the new token is a primary token...
  458. //
  459. if (NewToken->TokenType != TokenPrimary) {
  460. return (STATUS_BAD_TOKEN_TYPE);
  461. }
  462. SessionId = MmGetSessionId (Process);
  463. //
  464. // Lock the new token so we can atomicaly test and set the InUse flag
  465. //
  466. SepAcquireTokenWriteLock (NewToken);
  467. //
  468. // and that it is not already in use...
  469. //
  470. if (NewToken->TokenInUse) {
  471. SepReleaseTokenWriteLock (NewToken, FALSE);
  472. return (STATUS_TOKEN_ALREADY_IN_USE);
  473. }
  474. NewToken->TokenInUse = TRUE;
  475. //
  476. // Ensure SessionId consistent for hydra
  477. //
  478. NewToken->SessionId = SessionId;
  479. SepReleaseTokenWriteLock (NewToken, FALSE);
  480. //
  481. // audit the assignment of a primary token, if requested
  482. //
  483. if (SeDetailedAuditingWithToken (NULL)) {
  484. SepAuditAssignPrimaryToken (Process, NewToken);
  485. }
  486. //
  487. // If the token being assigned to this process has
  488. // any one of the following SIDs, then the process
  489. // is considered to be a system process:
  490. // -- SeLocalSystemSid
  491. // -- SeLocalServiceSid
  492. // -- SeNetworkServiceSid
  493. //
  494. // For such a process, add SACL to its security descriptor
  495. // if that option is enabled. If the option is disabled,
  496. // this function returns very quickly.
  497. //
  498. //SeAddSaclToProcess( Process, NewToken, NULL );
  499. //
  500. // Switch the tokens
  501. //
  502. ObReferenceObject (NewToken);
  503. OldToken = ObFastReplaceObject (&Process->Token, NewToken);
  504. if (NULL == OldToken){
  505. return (STATUS_NO_TOKEN);
  506. }
  507. ASSERT (OldToken->TokenType == TokenPrimary);
  508. //
  509. // Lock the old token to clkear the InUse flag
  510. //
  511. SepAcquireTokenWriteLock (OldToken);
  512. ASSERT (OldToken->TokenInUse);
  513. //
  514. // Mark the token as "NOT USED"
  515. //
  516. OldToken->TokenInUse = FALSE;
  517. SepReleaseTokenWriteLock (OldToken, FALSE);
  518. //
  519. // Return the pointer to the old token. The caller
  520. // is responsible for dereferencing it if they don't need it.
  521. //
  522. (*OldAccessToken) = OldToken;
  523. return (STATUS_SUCCESS);
  524. }
  525. VOID
  526. SeGetTokenControlInformation (
  527. IN PACCESS_TOKEN Token,
  528. OUT PTOKEN_CONTROL TokenControl
  529. )
  530. /*++
  531. Routine Description:
  532. This routine is provided for communication session layers, or
  533. any other executive component that needs to keep track of
  534. whether a caller's security context has changed between calls.
  535. Communication session layers will need to check this, for some
  536. security quality of service modes, to determine whether or not
  537. a server's security context needs to be updated to reflect
  538. changes in the client's security context.
  539. This routine will also be useful to communications subsystems
  540. that need to retrieve client' authentication information from
  541. the local security authority in order to perform a remote
  542. authentication.
  543. Parameters:
  544. Token - Points to the token whose information is to be retrieved.
  545. TokenControl - Points to the buffer to receive the token control
  546. information.
  547. Return Value:
  548. None.
  549. --*/
  550. {
  551. PAGED_CODE();
  552. //
  553. // Fetch readonly fields outside of the lock.
  554. //
  555. TokenControl->AuthenticationId = ((TOKEN *)Token)->AuthenticationId;
  556. TokenControl->TokenId = ((TOKEN *)Token)->TokenId;
  557. TokenControl->TokenSource = ((TOKEN *)Token)->TokenSource;
  558. //
  559. // Acquire shared access to the token
  560. //
  561. SepAcquireTokenReadLock( (PTOKEN)Token );
  562. //
  563. // Fetch data that may change
  564. //
  565. TokenControl->ModifiedId = ((TOKEN *)Token)->ModifiedId;
  566. SepReleaseTokenReadLock( (PTOKEN)Token );
  567. return;
  568. }
  569. PACCESS_TOKEN
  570. SeMakeSystemToken ()
  571. /*++
  572. Routine Description:
  573. This routine is provided for use by executive components
  574. DURING SYSTEM INITIALIZATION ONLY. It creates a token for
  575. use by system components.
  576. A system token has the following characteristics:
  577. - It has LOCAL_SYSTEM as its user ID
  578. - It has the following groups with the corresponding
  579. attributes:
  580. ADMINS_ALIAS EnabledByDefault |
  581. Enabled |
  582. Owner
  583. WORLD EnabledByDefault |
  584. Enabled |
  585. Mandatory
  586. ADMINISTRATORS (alias) Owner (disabled)
  587. AUTHENTICATED_USER
  588. EnabledByDefault |
  589. Enabled |
  590. Mandatory
  591. - It has LOCAL_SYSTEM as its primary group.
  592. - It has the privileges shown in comments below.
  593. - It has protection that provides TOKEN_ALL_ACCESS to
  594. the LOCAL_SYSTEM ID.
  595. - It has a default ACL that grants GENERIC_ALL access
  596. to LOCAL_SYSTEM and GENERIC_EXECUTE to WORLD.
  597. Parameters:
  598. None.
  599. Return Value:
  600. Pointer to a system token.
  601. --*/
  602. {
  603. NTSTATUS Status;
  604. PVOID Token;
  605. SID_AND_ATTRIBUTES UserId;
  606. TOKEN_PRIMARY_GROUP PrimaryGroup;
  607. PSID_AND_ATTRIBUTES GroupIds;
  608. ULONG GroupIdsLength;
  609. LUID_AND_ATTRIBUTES Privileges[30];
  610. PACL TokenAcl;
  611. PSID Owner;
  612. ULONG NormalGroupAttributes;
  613. ULONG OwnerGroupAttributes;
  614. ULONG Length;
  615. OBJECT_ATTRIBUTES TokenObjectAttributes;
  616. PSECURITY_DESCRIPTOR TokenSecurityDescriptor;
  617. ULONG BufferLength;
  618. PVOID Buffer;
  619. ULONG_PTR GroupIdsBuffer[128 * sizeof(ULONG) / sizeof(ULONG_PTR)];
  620. TIME_FIELDS TimeFields;
  621. LARGE_INTEGER NoExpiration;
  622. PAGED_CODE();
  623. //
  624. // Make sure only one system token gets created.
  625. //
  626. #if DBG
  627. ASSERT( !SystemTokenCreated );
  628. SystemTokenCreated = TRUE;
  629. #endif //DBG
  630. //
  631. // Set up expiration times
  632. //
  633. TimeFields.Year = 3000;
  634. TimeFields.Month = 1;
  635. TimeFields.Day = 1;
  636. TimeFields.Hour = 1;
  637. TimeFields.Minute = 1;
  638. TimeFields.Second = 1;
  639. TimeFields.Milliseconds = 1;
  640. TimeFields.Weekday = 1;
  641. RtlTimeFieldsToTime( &TimeFields, &NoExpiration );
  642. // //
  643. // // The amount of memory used in the following is gross overkill, but
  644. // // it is freed up immediately after creating the token.
  645. // //
  646. //
  647. // GroupIds = (PSID_AND_ATTRIBUTES)ExAllocatePool( NonPagedPool, 512 );
  648. GroupIds = (PSID_AND_ATTRIBUTES)GroupIdsBuffer;
  649. //
  650. // Set up the attributes to be assigned to groups
  651. //
  652. NormalGroupAttributes = (SE_GROUP_MANDATORY |
  653. SE_GROUP_ENABLED_BY_DEFAULT |
  654. SE_GROUP_ENABLED
  655. );
  656. OwnerGroupAttributes = (SE_GROUP_ENABLED_BY_DEFAULT |
  657. SE_GROUP_ENABLED |
  658. SE_GROUP_OWNER
  659. );
  660. //
  661. // Set up the user ID
  662. //
  663. UserId.Sid = SeLocalSystemSid;
  664. UserId.Attributes = 0;
  665. //
  666. // Set up the groups
  667. //
  668. GroupIds->Sid = SeAliasAdminsSid;
  669. (GroupIds+1)->Sid = SeWorldSid;
  670. (GroupIds+2)->Sid = SeAuthenticatedUsersSid;
  671. GroupIds->Attributes = OwnerGroupAttributes;
  672. (GroupIds+1)->Attributes = NormalGroupAttributes;
  673. (GroupIds+2)->Attributes = NormalGroupAttributes;
  674. GroupIdsLength = (ULONG)LongAlignSize(SeLengthSid(GroupIds->Sid)) +
  675. (ULONG)LongAlignSize(SeLengthSid((GroupIds+1)->Sid)) +
  676. (ULONG)LongAlignSize(SeLengthSid((GroupIds+2)->Sid)) +
  677. sizeof(SID_AND_ATTRIBUTES);
  678. ASSERT( GroupIdsLength <= 128 * sizeof(ULONG) );
  679. //
  680. // Privileges
  681. //
  682. //
  683. // The privileges in the system token are as follows:
  684. //
  685. // Privilege Name Attributes
  686. // -------------- ----------
  687. //
  688. // SeTcbPrivilege enabled/enabled by default
  689. // SeCreateTokenPrivilege DISabled/NOT enabled by default
  690. // SeTakeOwnershipPrivilege DISabled/NOT enabled by default
  691. // SeCreatePagefilePrivilege enabled/enabled by default
  692. // SeLockMemoryPrivilege enabled/enabled by default
  693. // SeAssignPrimaryTokenPrivilege DISabled/NOT enabled by default
  694. // SeIncreaseQuotaPrivilege DISabled/NOT enabled by default
  695. // SeIncreaseBasePriorityPrivilege enabled/enabled by default
  696. // SeCreatePermanentPrivilege enabled/enabled by default
  697. // SeDebugPrivilege enabled/enabled by default
  698. // SeAuditPrivilege enabled/enabled by default
  699. // SeSecurityPrivilege DISabled/NOT enabled by default
  700. // SeSystemEnvironmentPrivilege DISabled/NOT enabled by default
  701. // SeChangeNotifyPrivilege enabled/enabled by default
  702. // SeBackupPrivilege DISabled/NOT enabled by default
  703. // SeRestorePrivilege DISabled/NOT enabled by default
  704. // SeShutdownPrivilege DISabled/NOT enabled by default
  705. // SeLoadDriverPrivilege DISabled/NOT enabled by default
  706. // SeProfileSingleProcessPrivilege enabled/enabled by default
  707. // SeSystemtimePrivilege DISabled/NOT enabled by default
  708. // SeUndockPrivilege DISabled/NOT enabled by default
  709. //
  710. // The following privileges are not present, and should never be present in
  711. // the local system token:
  712. //
  713. // SeRemoteShutdownPrivilege no one can come in as local system
  714. // SeSyncAgentPrivilege only users specified by the admin can
  715. // be sync agents
  716. // SeEnableDelegationPrivilege only users specified by the admin can
  717. // enable delegation on accounts.
  718. //
  719. Privileges[0].Luid = SeTcbPrivilege;
  720. Privileges[0].Attributes =
  721. (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default
  722. SE_PRIVILEGE_ENABLED); // Enabled
  723. Privileges[1].Luid = SeCreateTokenPrivilege;
  724. Privileges[1].Attributes = 0; // Only the LSA should enable this.
  725. Privileges[2].Luid = SeTakeOwnershipPrivilege;
  726. Privileges[2].Attributes = 0;
  727. Privileges[3].Luid = SeCreatePagefilePrivilege;
  728. Privileges[3].Attributes =
  729. (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default
  730. SE_PRIVILEGE_ENABLED); // Enabled
  731. Privileges[4].Luid = SeLockMemoryPrivilege;
  732. Privileges[4].Attributes =
  733. (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default
  734. SE_PRIVILEGE_ENABLED); // Enabled
  735. Privileges[5].Luid = SeAssignPrimaryTokenPrivilege;
  736. Privileges[5].Attributes = 0; // disabled, not enabled by default
  737. Privileges[6].Luid = SeIncreaseQuotaPrivilege;
  738. Privileges[6].Attributes = 0; // disabled, not enabled by default
  739. Privileges[7].Luid = SeIncreaseBasePriorityPrivilege;
  740. Privileges[7].Attributes =
  741. (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default
  742. SE_PRIVILEGE_ENABLED); // Enabled
  743. Privileges[8].Luid = SeCreatePermanentPrivilege;
  744. Privileges[8].Attributes =
  745. (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default
  746. SE_PRIVILEGE_ENABLED); // Enabled
  747. Privileges[9].Luid = SeDebugPrivilege;
  748. Privileges[9].Attributes =
  749. (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default
  750. SE_PRIVILEGE_ENABLED); // Enabled
  751. Privileges[10].Luid = SeAuditPrivilege;
  752. Privileges[10].Attributes =
  753. (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default
  754. SE_PRIVILEGE_ENABLED); // Enabled
  755. Privileges[11].Luid = SeSecurityPrivilege;
  756. Privileges[11].Attributes = 0; // disabled, not enabled by default
  757. Privileges[12].Luid = SeSystemEnvironmentPrivilege;
  758. Privileges[12].Attributes = 0; // disabled, not enabled by default
  759. Privileges[13].Luid = SeChangeNotifyPrivilege;
  760. Privileges[13].Attributes =
  761. (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default
  762. SE_PRIVILEGE_ENABLED); // Enabled
  763. Privileges[14].Luid = SeBackupPrivilege;
  764. Privileges[14].Attributes = 0; // disabled, not enabled by default
  765. Privileges[15].Luid = SeRestorePrivilege;
  766. Privileges[15].Attributes = 0; // disabled, not enabled by default
  767. Privileges[16].Luid = SeShutdownPrivilege;
  768. Privileges[16].Attributes = 0; // disabled, not enabled by default
  769. Privileges[17].Luid = SeLoadDriverPrivilege;
  770. Privileges[17].Attributes = 0; // disabled, not enabled by default
  771. Privileges[18].Luid = SeProfileSingleProcessPrivilege;
  772. Privileges[18].Attributes =
  773. (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default
  774. SE_PRIVILEGE_ENABLED); // Enabled
  775. Privileges[19].Luid = SeSystemtimePrivilege;
  776. Privileges[19].Attributes = 0; // disabled, not enabled by default
  777. Privileges[20].Luid = SeUndockPrivilege ;
  778. Privileges[20].Attributes = 0 ; // disabled, not enabled by default
  779. Privileges[21].Luid = SeManageVolumePrivilege ;
  780. Privileges[21].Attributes = 0 ; // disabled, not enabled by default
  781. Privileges[22].Luid = SeImpersonatePrivilege ;
  782. Privileges[22].Attributes =
  783. (SE_PRIVILEGE_ENABLED_BY_DEFAULT |
  784. SE_PRIVILEGE_ENABLED);
  785. Privileges[23].Luid = SeCreateGlobalPrivilege ;
  786. Privileges[23].Attributes =
  787. (SE_PRIVILEGE_ENABLED_BY_DEFAULT |
  788. SE_PRIVILEGE_ENABLED );
  789. //BEFORE ADDING ANOTHER PRIVILEGE ^^ HERE ^^ CHECK THE ARRAY BOUND
  790. //ALSO INCREMENT THE PRIVILEGE COUNT IN THE SepCreateToken() call
  791. //
  792. // Establish the primary group and default owner
  793. //
  794. PrimaryGroup.PrimaryGroup = SeLocalSystemSid; // Primary group
  795. Owner = SeAliasAdminsSid; // Default owner
  796. //
  797. // Set up an ACL to protect token as well ...
  798. // give system full reign of terror. This includes user-mode components
  799. // running as part of the system.
  800. //
  801. Length = (ULONG)sizeof(ACL) +
  802. ((ULONG)sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG)) +
  803. SeLengthSid( SeLocalSystemSid ) ;
  804. TokenAcl = (PACL)ExAllocatePoolWithTag(PagedPool, Length, 'cAeS');
  805. if ( TokenAcl == NULL ) {
  806. return NULL ;
  807. }
  808. Status = RtlCreateAcl( TokenAcl, Length, ACL_REVISION2);
  809. ASSERT( NT_SUCCESS(Status) );
  810. Status = RtlAddAccessAllowedAce (
  811. TokenAcl,
  812. ACL_REVISION2,
  813. TOKEN_ALL_ACCESS,
  814. SeLocalSystemSid
  815. );
  816. ASSERT( NT_SUCCESS(Status) );
  817. TokenSecurityDescriptor =
  818. (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag(
  819. PagedPool,
  820. sizeof(SECURITY_DESCRIPTOR),
  821. 'dSeS'
  822. );
  823. if ( TokenSecurityDescriptor == NULL ) {
  824. ExFreePool( TokenAcl );
  825. return NULL ;
  826. }
  827. Status = RtlCreateSecurityDescriptor(
  828. TokenSecurityDescriptor,
  829. SECURITY_DESCRIPTOR_REVISION
  830. );
  831. ASSERT( NT_SUCCESS(Status) );
  832. Status = RtlSetDaclSecurityDescriptor (
  833. TokenSecurityDescriptor,
  834. TRUE,
  835. TokenAcl,
  836. FALSE
  837. );
  838. ASSERT( NT_SUCCESS(Status) );
  839. Status = RtlSetOwnerSecurityDescriptor (
  840. TokenSecurityDescriptor,
  841. SeAliasAdminsSid,
  842. FALSE // Owner defaulted
  843. );
  844. ASSERT( NT_SUCCESS(Status) );
  845. Status = RtlSetGroupSecurityDescriptor (
  846. TokenSecurityDescriptor,
  847. SeAliasAdminsSid,
  848. FALSE // Group defaulted
  849. );
  850. ASSERT( NT_SUCCESS(Status) );
  851. //
  852. // Create the system token
  853. //
  854. #ifdef TOKEN_DEBUG
  855. ////////////////////////////////////////////////////////////////////////////
  856. //
  857. // Debug
  858. DbgPrint("\n Creating system token...\n");
  859. // Debug
  860. //
  861. ////////////////////////////////////////////////////////////////////////////
  862. #endif //TOKEN_DEBUG
  863. InitializeObjectAttributes(
  864. &TokenObjectAttributes,
  865. NULL,
  866. 0,
  867. NULL,
  868. TokenSecurityDescriptor
  869. );
  870. ASSERT(SeSystemDefaultDacl != NULL);
  871. Status = SepCreateToken(
  872. (PHANDLE)&Token,
  873. KernelMode,
  874. 0, // No handle created for system token
  875. &TokenObjectAttributes,
  876. TokenPrimary,
  877. (SECURITY_IMPERSONATION_LEVEL)0,
  878. (PLUID)&SeSystemAuthenticationId,
  879. &NoExpiration,
  880. &UserId,
  881. 3, // GroupCount
  882. GroupIds,
  883. GroupIdsLength,
  884. 24, // privileges
  885. Privileges,
  886. Owner,
  887. PrimaryGroup.PrimaryGroup,
  888. SeSystemDefaultDacl,
  889. (PTOKEN_SOURCE)&SeSystemTokenSource,
  890. TRUE, // System token
  891. NULL,
  892. NULL
  893. );
  894. ASSERT(NT_SUCCESS(Status));
  895. //
  896. // We can free the old one now.
  897. //
  898. ExFreePool( TokenAcl );
  899. ExFreePool( TokenSecurityDescriptor );
  900. return (PACCESS_TOKEN)Token;
  901. }
  902. PACCESS_TOKEN
  903. SeMakeAnonymousLogonTokenNoEveryone (
  904. VOID
  905. )
  906. /*++
  907. Routine Description:
  908. This routine is provided for use by executive components
  909. DURING SYSTEM INITIALIZATION ONLY. It creates a token for
  910. use by system components.
  911. A system token has the following characteristics:
  912. - It has ANONYMOUS_LOGON as its user ID
  913. - It has no privileges
  914. - It has protection that provides TOKEN_ALL_ACCESS to
  915. the WORLD ID.
  916. - It has a default ACL that grants GENERIC_ALL access
  917. to WORLD.
  918. Parameters:
  919. None.
  920. Return Value:
  921. Pointer to a system token.
  922. --*/
  923. {
  924. NTSTATUS Status;
  925. PVOID Token;
  926. SID_AND_ATTRIBUTES UserId;
  927. TOKEN_PRIMARY_GROUP PrimaryGroup;
  928. PACL TokenAcl;
  929. PSID Owner;
  930. ULONG Length;
  931. OBJECT_ATTRIBUTES TokenObjectAttributes;
  932. PSECURITY_DESCRIPTOR TokenSecurityDescriptor;
  933. TIME_FIELDS TimeFields;
  934. LARGE_INTEGER NoExpiration;
  935. PAGED_CODE();
  936. //
  937. // Set up expiration times
  938. //
  939. TimeFields.Year = 3000;
  940. TimeFields.Month = 1;
  941. TimeFields.Day = 1;
  942. TimeFields.Hour = 1;
  943. TimeFields.Minute = 1;
  944. TimeFields.Second = 1;
  945. TimeFields.Milliseconds = 1;
  946. TimeFields.Weekday = 1;
  947. RtlTimeFieldsToTime( &TimeFields, &NoExpiration );
  948. //
  949. // Set up the user ID
  950. //
  951. UserId.Sid = SeAnonymousLogonSid;
  952. UserId.Attributes = 0;
  953. //
  954. // Establish the primary group and default owner
  955. //
  956. PrimaryGroup.PrimaryGroup = SeAnonymousLogonSid; // Primary group
  957. //
  958. // Set up an ACL to protect token as well ...
  959. // Let everyone read/write. However, the token is dup'ed before we given
  960. // anyone a handle to it.
  961. //
  962. Length = (ULONG)sizeof(ACL) +
  963. (ULONG)sizeof(ACCESS_ALLOWED_ACE) +
  964. SeLengthSid( SeWorldSid ) +
  965. (ULONG)sizeof(ACCESS_ALLOWED_ACE) +
  966. SeLengthSid( SeAnonymousLogonSid );
  967. ASSERT( Length < 200 );
  968. TokenAcl = (PACL)ExAllocatePoolWithTag(PagedPool, 200, 'cAeS');
  969. if ( !TokenAcl ) {
  970. return NULL ;
  971. }
  972. Status = RtlCreateAcl( TokenAcl, Length, ACL_REVISION2);
  973. ASSERT( NT_SUCCESS(Status) );
  974. Status = RtlAddAccessAllowedAce (
  975. TokenAcl,
  976. ACL_REVISION2,
  977. TOKEN_ALL_ACCESS,
  978. SeWorldSid
  979. );
  980. ASSERT( NT_SUCCESS(Status) );
  981. Status = RtlAddAccessAllowedAce (
  982. TokenAcl,
  983. ACL_REVISION2,
  984. TOKEN_ALL_ACCESS,
  985. SeAnonymousLogonSid
  986. );
  987. ASSERT( NT_SUCCESS(Status) );
  988. TokenSecurityDescriptor =
  989. (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag(
  990. PagedPool,
  991. SECURITY_DESCRIPTOR_MIN_LENGTH,
  992. 'dSeS'
  993. );
  994. if ( !TokenSecurityDescriptor ) {
  995. ExFreePool( TokenAcl );
  996. return NULL ;
  997. }
  998. Status = RtlCreateSecurityDescriptor(
  999. TokenSecurityDescriptor,
  1000. SECURITY_DESCRIPTOR_REVISION
  1001. );
  1002. ASSERT( NT_SUCCESS(Status) );
  1003. Status = RtlSetDaclSecurityDescriptor (
  1004. TokenSecurityDescriptor,
  1005. TRUE,
  1006. TokenAcl,
  1007. FALSE
  1008. );
  1009. ASSERT( NT_SUCCESS(Status) );
  1010. Status = RtlSetOwnerSecurityDescriptor (
  1011. TokenSecurityDescriptor,
  1012. SeWorldSid,
  1013. FALSE // Owner defaulted
  1014. );
  1015. ASSERT( NT_SUCCESS(Status) );
  1016. Status = RtlSetGroupSecurityDescriptor (
  1017. TokenSecurityDescriptor,
  1018. SeWorldSid,
  1019. FALSE // Group defaulted
  1020. );
  1021. ASSERT( NT_SUCCESS(Status) );
  1022. //
  1023. // Create the system token
  1024. //
  1025. #ifdef TOKEN_DEBUG
  1026. ////////////////////////////////////////////////////////////////////////////
  1027. //
  1028. // Debug
  1029. DbgPrint("\n Creating system token...\n");
  1030. // Debug
  1031. //
  1032. ////////////////////////////////////////////////////////////////////////////
  1033. #endif //TOKEN_DEBUG
  1034. InitializeObjectAttributes(
  1035. &TokenObjectAttributes,
  1036. NULL,
  1037. 0,
  1038. NULL,
  1039. TokenSecurityDescriptor
  1040. );
  1041. Status = SepCreateToken(
  1042. (PHANDLE)&Token,
  1043. KernelMode,
  1044. 0, // No handle created for system token
  1045. &TokenObjectAttributes,
  1046. TokenPrimary,
  1047. (SECURITY_IMPERSONATION_LEVEL)0,
  1048. (PLUID)&SeAnonymousAuthenticationId,
  1049. &NoExpiration,
  1050. &UserId,
  1051. 0, // GroupCount
  1052. NULL, // Group IDs
  1053. 0, // Group byte count
  1054. 0, // no privileges
  1055. NULL, // no Privileges,
  1056. NULL,
  1057. PrimaryGroup.PrimaryGroup,
  1058. TokenAcl,
  1059. (PTOKEN_SOURCE)&SeSystemTokenSource,
  1060. TRUE, // System token
  1061. NULL,
  1062. NULL
  1063. );
  1064. ASSERT(NT_SUCCESS(Status));
  1065. //
  1066. // We can free the old one now.
  1067. //
  1068. ExFreePool( TokenAcl );
  1069. ExFreePool( TokenSecurityDescriptor );
  1070. return (PACCESS_TOKEN)Token;
  1071. }
  1072. PACCESS_TOKEN
  1073. SeMakeAnonymousLogonToken (
  1074. VOID
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This routine is provided for use by executive components
  1079. DURING SYSTEM INITIALIZATION ONLY. It creates a token for
  1080. use by system components.
  1081. A system token has the following characteristics:
  1082. - It has ANONYMOUS_LOGON as its user ID
  1083. - It has the following groups with the corresponding
  1084. attributes:
  1085. WORLD EnabledByDefault |
  1086. Enabled |
  1087. Mandatory
  1088. - It has WORLD as its primary group.
  1089. - It has no privileges
  1090. - It has protection that provides TOKEN_ALL_ACCESS to
  1091. the WORLD ID.
  1092. - It has a default ACL that grants GENERIC_ALL access
  1093. to WORLD.
  1094. Parameters:
  1095. None.
  1096. Return Value:
  1097. Pointer to a system token.
  1098. --*/
  1099. {
  1100. NTSTATUS Status;
  1101. PVOID Token;
  1102. SID_AND_ATTRIBUTES UserId;
  1103. PSID_AND_ATTRIBUTES GroupIds;
  1104. TOKEN_PRIMARY_GROUP PrimaryGroup;
  1105. ULONG GroupIdsLength;
  1106. PACL TokenAcl;
  1107. PSID Owner;
  1108. ULONG NormalGroupAttributes;
  1109. ULONG Length;
  1110. OBJECT_ATTRIBUTES TokenObjectAttributes;
  1111. PSECURITY_DESCRIPTOR TokenSecurityDescriptor;
  1112. ULONG_PTR GroupIdsBuffer[128 * sizeof(ULONG) / sizeof(ULONG_PTR)];
  1113. TIME_FIELDS TimeFields;
  1114. LARGE_INTEGER NoExpiration;
  1115. PAGED_CODE();
  1116. //
  1117. // Set up expiration times
  1118. //
  1119. TimeFields.Year = 3000;
  1120. TimeFields.Month = 1;
  1121. TimeFields.Day = 1;
  1122. TimeFields.Hour = 1;
  1123. TimeFields.Minute = 1;
  1124. TimeFields.Second = 1;
  1125. TimeFields.Milliseconds = 1;
  1126. TimeFields.Weekday = 1;
  1127. RtlTimeFieldsToTime( &TimeFields, &NoExpiration );
  1128. GroupIds = (PSID_AND_ATTRIBUTES)GroupIdsBuffer;
  1129. //
  1130. // Set up the attributes to be assigned to groups
  1131. //
  1132. NormalGroupAttributes = (SE_GROUP_MANDATORY |
  1133. SE_GROUP_ENABLED_BY_DEFAULT |
  1134. SE_GROUP_ENABLED
  1135. );
  1136. //
  1137. // Set up the user ID
  1138. //
  1139. UserId.Sid = SeAnonymousLogonSid;
  1140. UserId.Attributes = 0;
  1141. //
  1142. // Set up the groups
  1143. //
  1144. GroupIds->Sid = SeWorldSid;
  1145. GroupIds->Attributes = NormalGroupAttributes;
  1146. GroupIdsLength = (ULONG)LongAlignSize(SeLengthSid(GroupIds->Sid)) +
  1147. sizeof(SID_AND_ATTRIBUTES);
  1148. ASSERT( GroupIdsLength <= 128 * sizeof(ULONG) );
  1149. //
  1150. // Establish the primary group and default owner
  1151. //
  1152. PrimaryGroup.PrimaryGroup = SeAnonymousLogonSid; // Primary group
  1153. //
  1154. // Set up an ACL to protect token as well ...
  1155. // give system full reign of terror. This includes user-mode components
  1156. // running as part of the system.
  1157. // Let everyone read/write. However, the token is dup'ed before we given
  1158. // anyone a handle to it.
  1159. //
  1160. Length = (ULONG)sizeof(ACL) +
  1161. (ULONG)sizeof(ACCESS_ALLOWED_ACE) +
  1162. SeLengthSid( SeWorldSid ) +
  1163. (ULONG)sizeof(ACCESS_ALLOWED_ACE) +
  1164. SeLengthSid( SeAnonymousLogonSid );
  1165. ASSERT( Length < 200 );
  1166. TokenAcl = (PACL)ExAllocatePoolWithTag(PagedPool, 200, 'cAeS');
  1167. if ( !TokenAcl ) {
  1168. return NULL ;
  1169. }
  1170. Status = RtlCreateAcl( TokenAcl, Length, ACL_REVISION2);
  1171. ASSERT( NT_SUCCESS(Status) );
  1172. Status = RtlAddAccessAllowedAce (
  1173. TokenAcl,
  1174. ACL_REVISION2,
  1175. TOKEN_ALL_ACCESS,
  1176. SeWorldSid
  1177. );
  1178. ASSERT( NT_SUCCESS(Status) );
  1179. Status = RtlAddAccessAllowedAce (
  1180. TokenAcl,
  1181. ACL_REVISION2,
  1182. TOKEN_ALL_ACCESS,
  1183. SeAnonymousLogonSid
  1184. );
  1185. ASSERT( NT_SUCCESS(Status) );
  1186. TokenSecurityDescriptor =
  1187. (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag(
  1188. PagedPool,
  1189. SECURITY_DESCRIPTOR_MIN_LENGTH,
  1190. 'dSeS'
  1191. );
  1192. if ( !TokenSecurityDescriptor ) {
  1193. ExFreePool( TokenAcl );
  1194. return NULL ;
  1195. }
  1196. Status = RtlCreateSecurityDescriptor(
  1197. TokenSecurityDescriptor,
  1198. SECURITY_DESCRIPTOR_REVISION
  1199. );
  1200. ASSERT( NT_SUCCESS(Status) );
  1201. Status = RtlSetDaclSecurityDescriptor (
  1202. TokenSecurityDescriptor,
  1203. TRUE,
  1204. TokenAcl,
  1205. FALSE
  1206. );
  1207. ASSERT( NT_SUCCESS(Status) );
  1208. Status = RtlSetOwnerSecurityDescriptor (
  1209. TokenSecurityDescriptor,
  1210. SeWorldSid,
  1211. FALSE // Owner defaulted
  1212. );
  1213. ASSERT( NT_SUCCESS(Status) );
  1214. Status = RtlSetGroupSecurityDescriptor (
  1215. TokenSecurityDescriptor,
  1216. SeWorldSid,
  1217. FALSE // Group defaulted
  1218. );
  1219. ASSERT( NT_SUCCESS(Status) );
  1220. //
  1221. // Create the system token
  1222. //
  1223. #ifdef TOKEN_DEBUG
  1224. ////////////////////////////////////////////////////////////////////////////
  1225. //
  1226. // Debug
  1227. DbgPrint("\n Creating system token...\n");
  1228. // Debug
  1229. //
  1230. ////////////////////////////////////////////////////////////////////////////
  1231. #endif //TOKEN_DEBUG
  1232. InitializeObjectAttributes(
  1233. &TokenObjectAttributes,
  1234. NULL,
  1235. 0,
  1236. NULL,
  1237. TokenSecurityDescriptor
  1238. );
  1239. Status = SepCreateToken(
  1240. (PHANDLE)&Token,
  1241. KernelMode,
  1242. 0, // No handle created for system token
  1243. &TokenObjectAttributes,
  1244. TokenPrimary,
  1245. (SECURITY_IMPERSONATION_LEVEL)0,
  1246. (PLUID)&SeAnonymousAuthenticationId,
  1247. &NoExpiration,
  1248. &UserId,
  1249. 1, // GroupCount
  1250. GroupIds,
  1251. GroupIdsLength,
  1252. 0, // no privileges
  1253. NULL, // no Privileges,
  1254. 0, // no privileges
  1255. PrimaryGroup.PrimaryGroup,
  1256. TokenAcl,
  1257. (PTOKEN_SOURCE)&SeSystemTokenSource,
  1258. TRUE, // System token
  1259. NULL,
  1260. NULL
  1261. );
  1262. ASSERT(NT_SUCCESS(Status));
  1263. //
  1264. // We can free the old one now.
  1265. //
  1266. ExFreePool( TokenAcl );
  1267. ExFreePool( TokenSecurityDescriptor );
  1268. return (PACCESS_TOKEN)Token;
  1269. }
  1270. NTSTATUS
  1271. SeSubProcessToken (
  1272. IN PACCESS_TOKEN ParentToken,
  1273. OUT PACCESS_TOKEN *ChildToken,
  1274. IN BOOLEAN MarkAsActive,
  1275. IN ULONG SessionId
  1276. )
  1277. /*++
  1278. Routine Description:
  1279. This routine makes a token for a sub-process that is a duplicate
  1280. of the parent process's token.
  1281. Parameters:
  1282. ParentToken - Pointer to the parent token
  1283. ChildToken - Receives a pointer to the child process's token.
  1284. MarkAsActive - Mark the token as active
  1285. SessionId - Create the token with this session ID
  1286. Return Value:
  1287. STATUS_SUCCESS - Indicates the sub-process's token has been created
  1288. successfully.
  1289. Other status values may be returned from memory allocation or object
  1290. creation services used and typically indicate insufficient resources
  1291. or quota on the requestor's part.
  1292. --*/
  1293. {
  1294. PTOKEN NewToken;
  1295. OBJECT_ATTRIBUTES PrimaryTokenAttributes;
  1296. NTSTATUS Status;
  1297. NTSTATUS IgnoreStatus;
  1298. PAGED_CODE();
  1299. InitializeObjectAttributes(
  1300. &PrimaryTokenAttributes,
  1301. NULL,
  1302. 0,
  1303. NULL,
  1304. NULL
  1305. );
  1306. #ifdef TOKEN_DEBUG
  1307. DbgPrint("\nCreating sub-process token...\n");
  1308. DbgPrint("Parent token address = 0x%lx\n", ParentProcess->Token);
  1309. #endif //TOKEN_DEBUG
  1310. Status = SepDuplicateToken(
  1311. ParentToken, // ExistingToken
  1312. &PrimaryTokenAttributes, // ObjectAttributes
  1313. FALSE, // EffectiveOnly
  1314. TokenPrimary, // TokenType
  1315. (SECURITY_IMPERSONATION_LEVEL)0, // ImpersonationLevel
  1316. KernelMode, // RequestorMode
  1317. &NewToken // NewToken
  1318. );
  1319. if (NT_SUCCESS(Status)) {
  1320. NewToken->SessionId = SessionId;
  1321. //
  1322. // Insert the new token object, up its ref count but don't create a handle.
  1323. //
  1324. Status = ObInsertObject(
  1325. NewToken,
  1326. NULL,
  1327. 0,
  1328. 0,
  1329. NULL,
  1330. NULL);
  1331. if (NT_SUCCESS(Status)) {
  1332. NewToken->TokenInUse = MarkAsActive;
  1333. *ChildToken = NewToken;
  1334. } else {
  1335. //
  1336. // ObInsertObject dereferences the passed object if it
  1337. // fails, so we don't have to do any cleanup on NewToken
  1338. // here.
  1339. //
  1340. }
  1341. }
  1342. return Status;
  1343. }
  1344. BOOLEAN
  1345. SepTokenInitialization ( VOID )
  1346. /*++
  1347. Routine Description:
  1348. This function creates the token object type descriptor at system
  1349. initialization and stores the address of the object type descriptor
  1350. in global storage. It also created token related global variables.
  1351. Furthermore, some number of pseudo tokens are created during system
  1352. initialization. These tokens are tracked down and replaced with
  1353. real tokens.
  1354. Arguments:
  1355. None.
  1356. Return Value:
  1357. A value of TRUE is returned if the object type descriptor is
  1358. successfully initialized. Otherwise a value of FALSE is returned.
  1359. --*/
  1360. {
  1361. OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
  1362. NTSTATUS Status;
  1363. UNICODE_STRING TypeName;
  1364. PAGED_CODE();
  1365. //
  1366. // Initialize string descriptor.
  1367. //
  1368. RtlInitUnicodeString(&TypeName, L"Token");
  1369. #if 0
  1370. BUG, BUG Need to get system default ACL to protect token object
  1371. #endif
  1372. //
  1373. // Create object type descriptor.
  1374. //
  1375. RtlZeroMemory(&ObjectTypeInitializer,sizeof(ObjectTypeInitializer));
  1376. ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
  1377. ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
  1378. ObjectTypeInitializer.GenericMapping = SepTokenMapping;
  1379. ObjectTypeInitializer.SecurityRequired = TRUE;
  1380. ObjectTypeInitializer.UseDefaultObject = TRUE;
  1381. ObjectTypeInitializer.PoolType = PagedPool;
  1382. ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS;
  1383. ObjectTypeInitializer.DeleteProcedure = SepTokenDeleteMethod;
  1384. Status = ObCreateObjectType(&TypeName,
  1385. &ObjectTypeInitializer,
  1386. (PSECURITY_DESCRIPTOR)NULL, // BUG, BUG assign real protection
  1387. &SeTokenObjectType
  1388. );
  1389. #if 0
  1390. BUG, BUG Now track down all pseudo tokens used during system initialization
  1391. BUG, BUG and replace them with real ones.
  1392. #endif
  1393. //
  1394. // If the object type descriptor was successfully created, then
  1395. // return a value of TRUE. Otherwise return a value of FALSE.
  1396. //
  1397. return (BOOLEAN)NT_SUCCESS(Status);
  1398. }
  1399. //////////////////////////////////////////////////////////////////////////
  1400. // //
  1401. // Temporary, for Debug only //
  1402. // //
  1403. //////////////////////////////////////////////////////////////////////////
  1404. #ifdef TOKEN_DEBUG
  1405. VOID
  1406. SepDumpToken(
  1407. IN PTOKEN T
  1408. )
  1409. {
  1410. ULONG Index;
  1411. //
  1412. // Dump a token
  1413. //
  1414. DbgPrint("\n");
  1415. DbgPrint(" address: 0x%lx \n", ((ULONG)T) );
  1416. DbgPrint(" TokenId: (0x%lx, 0x%lx) \n",
  1417. T->TokenId.HighPart, T->TokenId.LowPart );
  1418. if ( (T->AuthenticationId.Data[0] == SeSystemAuthenticationId.Data[0]) &&
  1419. (T->AuthenticationId.Data[1] == SeSystemAuthenticationId.Data[1]) &&
  1420. (T->AuthenticationId.Data[2] == SeSystemAuthenticationId.Data[2]) &&
  1421. (T->AuthenticationId.Data[3] == SeSystemAuthenticationId.Data[3]) ) {
  1422. DbgPrint(" AuthenticationId: SeSystemAuthenticationId \n");
  1423. } else {
  1424. DbgPrint(" AuthenticationId: (0x%lx, 0x%lx, 0x%lx, 0x%lx) \n",
  1425. T->AuthenticationId.Data[0],
  1426. T->AuthenticationId.Data[1],
  1427. T->AuthenticationId.Data[2],
  1428. T->AuthenticationId.Data[3] );
  1429. }
  1430. DbgPrint(" ExpirationTime: 0x%lx, 0x%lx \n",
  1431. T->ExpirationTime.HighPart,
  1432. T->ExpirationTime.LowPart );
  1433. if (T->TokenType == TokenPrimary) {
  1434. DbgPrint(" TokenType: Primary \n");
  1435. } else {
  1436. if (T->TokenType == TokenImpersonation) {
  1437. DbgPrint(" TokenType: Impersonation \n");
  1438. } else {
  1439. DbgPrint(" TokenType: (Unknown type, value = 0x%lx) \n",
  1440. ((ULONG)T-TokenType) );
  1441. }
  1442. }
  1443. DbgPrint(" ImpersonationLevel: 0x%lx \n",
  1444. ((ULONG)T->ImpersonationLevel) );
  1445. DbgPrint(" TokenSource: (not yet provided) \n");
  1446. DbgPrint(" DynamicCharged: 0x%lx \n", T->DynamicCharged);
  1447. DbgPrint(" UserAndGroupCount: 0x%lx \n", T->UserAndGroupCount);
  1448. DbgPrint(" PrivilegeCount: 0x%lx \n", T->PrivilegeCount);
  1449. DbgPrint(" VariableLength: 0x%lx \n", T->VariableLength);
  1450. DbgPrint(" ModifiedId: (0x%lx, 0x%lx) \n",
  1451. T->ModifiedId.HighPart,
  1452. T->ModifiedId.LowPart );
  1453. DbgPrint(" DynamicAvailable: 0x%lx \n", T->DynamicAvailable);
  1454. DbgPrint(" DefaultOwnerIndex: 0x%lx \n", T->DefaultOwnerIndex);
  1455. DbgPrint(" Address of DynamicPart: 0x%lx \n",
  1456. (* (PULONG)((PVOID)(&(T->DynamicPart)))) );
  1457. DbgPrint(" Address of Default DACL: 0x%lx \n",
  1458. (* (PULONG)((PVOID)(&(T->DefaultDacl)))) );
  1459. DbgPrint(" Address Of Variable Part: 0x%lx \n",
  1460. &(T->VariablePart) );
  1461. DbgPrint("\n");
  1462. DbgPrint(" PrimaryGroup:\n");
  1463. DbgPrint(" Address: 0x%lx \n",
  1464. (* (PULONG)((PVOID)(&(T->PrimaryGroup)))) );
  1465. DbgPrint(" Length: 0x%lx \n",
  1466. SeLengthSid((T->PrimaryGroup)) );
  1467. DbgPrint("\n");
  1468. DbgPrint(" UserAndGroups: 0x%lx \n",
  1469. (* (PULONG)((PVOID)(&(T->UserAndGroups)))) );
  1470. DbgPrint(" User ID - \n");
  1471. DbgPrint(" Address: 0x%lx \n",
  1472. (* (PULONG)((PVOID)(&(T->UserAndGroups[0].Sid)))) );
  1473. DbgPrint(" Attributes: 0x%lx \n",
  1474. (T->UserAndGroups[0].Attributes) );
  1475. DbgPrint(" Length: 0x%lx \n",
  1476. SeLengthSid((T->UserAndGroups[0].Sid)) );
  1477. Index = 1;
  1478. while (Index < T->UserAndGroupCount) {
  1479. DbgPrint(" Group 0x%lx - \n", Index );
  1480. DbgPrint(" Address: 0x%lx \n",
  1481. (* (PULONG)((PVOID)(&(T->UserAndGroups[Index].Sid)))) );
  1482. DbgPrint(" Attributes: 0x%lx \n",
  1483. (T->UserAndGroups[Index].Attributes) );
  1484. DbgPrint(" Length: 0x%lx \n",
  1485. SeLengthSid((T->UserAndGroups[Index].Sid)) );
  1486. Index += 1;
  1487. }
  1488. Index = 0;
  1489. while (Index < T->RestrictedSidCount) {
  1490. DbgPrint(" Sid 0x%lx - \n", Index );
  1491. DbgPrint(" Address: 0x%lx \n",
  1492. (* (PULONG)((PVOID)(&(T->RestrictedSids[Index].Sid)))) );
  1493. DbgPrint(" Attributes: 0x%lx \n",
  1494. (T->RestrictedSids[Index].Attributes) );
  1495. DbgPrint(" Length: 0x%lx \n",
  1496. SeLengthSid((T->RestrictedSids[Index].Sid)) );
  1497. Index += 1;
  1498. }
  1499. DbgPrint("\n");
  1500. DbgPrint(" Privileges: 0x%lx\n",
  1501. (* (PULONG)((PVOID)(&(T->Privileges)))) );
  1502. Index = 0;
  1503. while (Index < T->PrivilegeCount) {
  1504. DbgPrint(" Privilege 0x%lx - \n", Index );
  1505. DbgPrint(" Address: 0x%lx \n",
  1506. (&(T->Privileges[Index])) );
  1507. DbgPrint(" LUID: (0x%lx, 0x%lx) \n",
  1508. T->Privileges[Index].Luid.HighPart,
  1509. T->Privileges[Index].Luid.LowPart );
  1510. DbgPrint(" Attributes: 0x%lx \n",
  1511. T->Privileges[Index].Attributes );
  1512. Index += 1;
  1513. }
  1514. return;
  1515. }
  1516. #endif //TOKEN_DEBUG
  1517. NTSTATUS
  1518. NtCreateToken(
  1519. OUT PHANDLE TokenHandle,
  1520. IN ACCESS_MASK DesiredAccess,
  1521. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  1522. IN TOKEN_TYPE TokenType,
  1523. IN PLUID AuthenticationId,
  1524. IN PLARGE_INTEGER ExpirationTime,
  1525. IN PTOKEN_USER User,
  1526. IN PTOKEN_GROUPS Groups,
  1527. IN PTOKEN_PRIVILEGES Privileges,
  1528. IN PTOKEN_OWNER Owner OPTIONAL,
  1529. IN PTOKEN_PRIMARY_GROUP PrimaryGroup,
  1530. IN PTOKEN_DEFAULT_DACL DefaultDacl OPTIONAL,
  1531. IN PTOKEN_SOURCE TokenSource
  1532. )
  1533. /*++
  1534. Routine Description:
  1535. Create a token object and return a handle opened for access to
  1536. that token. This API requires SeCreateTokenPrivilege privilege.
  1537. Arguments:
  1538. TokenHandle - Receives the handle of the newly created token.
  1539. DesiredAccess - Is an access mask indicating which access types
  1540. the handle is to provide to the new object.
  1541. ObjectAttributes - Points to the standard object attributes data
  1542. structure. Refer to the NT Object Management
  1543. Specification for a description of this data structure.
  1544. If the token type is TokenImpersonation, then this parameter
  1545. must specify the impersonation level of the token.
  1546. TokenType - Type of token to be created. Privilege is required
  1547. to create any type of token.
  1548. AuthenticationId - Points to a LUID (or LUID) providing a unique
  1549. identifier associated with the authentication. This is used
  1550. within security only, for audit purposes.
  1551. ExpirationTime - Time at which the token becomes invalid. If this
  1552. value is specified as zero, then the token has no expiration
  1553. time.
  1554. User - Is the user SID to place in the token.
  1555. Groups - Are the group SIDs to place in the token. The API assumes that
  1556. the caller has not supplied duplicate group sids.
  1557. Privileges - Are the privileges to place in the token. The API assumes that
  1558. the caller has not supplied duplicate privileges.
  1559. Owner - (Optionally) identifies an identifier that is to be used
  1560. as the default owner for the token. If not provided, the
  1561. user ID is made the default owner.
  1562. PrimaryGroup - Identifies which of the group IDs is to be the
  1563. primary group of the token.
  1564. DefaultDacl - (optionally) establishes an ACL to be used as the
  1565. default discretionary access protection for the token.
  1566. TokenSource - Identifies the token source name string and
  1567. identifier to be assigned to the token.
  1568. Return Value:
  1569. STATUS_SUCCESS - Indicates the operation was successful.
  1570. STATUS_INVALID_OWNER - Indicates the ID provided to be assigned
  1571. as the default owner of the token does not have an attribute
  1572. indicating it may be assigned as an owner.
  1573. STATUS_INVALID_PRIMARY_GROUP - Indicates the group ID provided
  1574. via the PrimaryGroup parameter was not among those assigned
  1575. to the token in the Groups parameter.
  1576. STATUS_BAD_IMPERSONATION_LEVEL - Indicates no impersonation level
  1577. was provided when attempting to create a token of type
  1578. TokenImpersonation.
  1579. --*/
  1580. {
  1581. KPROCESSOR_MODE PreviousMode;
  1582. NTSTATUS Status;
  1583. ULONG Ignore;
  1584. HANDLE LocalHandle = NULL;
  1585. BOOLEAN SecurityQosPresent = FALSE;
  1586. SECURITY_ADVANCED_QUALITY_OF_SERVICE CapturedSecurityQos;
  1587. LUID CapturedAuthenticationId;
  1588. LARGE_INTEGER CapturedExpirationTime;
  1589. PSID_AND_ATTRIBUTES CapturedUser = NULL;
  1590. ULONG CapturedUserLength = 0;
  1591. ULONG CapturedGroupCount = 0;
  1592. PSID_AND_ATTRIBUTES CapturedGroups = NULL;
  1593. ULONG CapturedGroupsLength = 0;
  1594. ULONG CapturedPrivilegeCount = 0;
  1595. PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
  1596. ULONG CapturedPrivilegesLength = 0;
  1597. PSID CapturedOwner = NULL;
  1598. PSID CapturedPrimaryGroup = NULL;
  1599. PACL CapturedDefaultDacl = NULL;
  1600. TOKEN_SOURCE CapturedTokenSource;
  1601. PVOID CapturedAddress;
  1602. PAGED_CODE();
  1603. PreviousMode = KeGetPreviousMode();
  1604. if (PreviousMode != KernelMode) {
  1605. //
  1606. // Probe everything necessary for input to the capture subroutines.
  1607. //
  1608. try {
  1609. ProbeForWriteHandle(TokenHandle);
  1610. ProbeForReadSmallStructure( ExpirationTime, sizeof(LARGE_INTEGER), sizeof(ULONG) );
  1611. ProbeForReadSmallStructure( Groups, sizeof(TOKEN_GROUPS), sizeof(ULONG) );
  1612. ProbeForReadSmallStructure( Privileges, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG) );
  1613. ProbeForReadSmallStructure( TokenSource, sizeof(TOKEN_SOURCE), sizeof(ULONG) );
  1614. if ( ARGUMENT_PRESENT(Owner) ) {
  1615. ProbeForReadSmallStructure( Owner, sizeof(TOKEN_OWNER), sizeof(ULONG) );
  1616. }
  1617. ProbeForReadSmallStructure(
  1618. PrimaryGroup,
  1619. sizeof(TOKEN_PRIMARY_GROUP),
  1620. sizeof(ULONG)
  1621. );
  1622. if ( ARGUMENT_PRESENT(DefaultDacl) ) {
  1623. ProbeForReadSmallStructure(
  1624. DefaultDacl,
  1625. sizeof(TOKEN_DEFAULT_DACL),
  1626. sizeof(ULONG)
  1627. );
  1628. }
  1629. ProbeForReadSmallStructure(
  1630. AuthenticationId,
  1631. sizeof(LUID),
  1632. sizeof(ULONG)
  1633. );
  1634. } except(EXCEPTION_EXECUTE_HANDLER) {
  1635. return GetExceptionCode();
  1636. } // end_try
  1637. } //end_if
  1638. //
  1639. // Make sure the TokenType is valid
  1640. //
  1641. if ( (TokenType < TokenPrimary) || (TokenType > TokenImpersonation) ) {
  1642. return(STATUS_BAD_TOKEN_TYPE);
  1643. }
  1644. //
  1645. // Capture the security quality of service.
  1646. // This capture routine necessarily does some probing of its own.
  1647. //
  1648. Status = SeCaptureSecurityQos(
  1649. ObjectAttributes,
  1650. PreviousMode,
  1651. &SecurityQosPresent,
  1652. &CapturedSecurityQos
  1653. );
  1654. if (!NT_SUCCESS(Status)) {
  1655. return Status;
  1656. }
  1657. if (TokenType == TokenImpersonation) {
  1658. if (!SecurityQosPresent) {
  1659. return STATUS_BAD_IMPERSONATION_LEVEL;
  1660. } // endif
  1661. //
  1662. // Allow only valid impersonation levels.
  1663. //
  1664. switch (CapturedSecurityQos.ImpersonationLevel) {
  1665. case SecurityAnonymous:
  1666. case SecurityIdentification:
  1667. case SecurityImpersonation:
  1668. case SecurityDelegation:
  1669. break;
  1670. default:
  1671. SeFreeCapturedSecurityQos( &CapturedSecurityQos );
  1672. return STATUS_BAD_IMPERSONATION_LEVEL;
  1673. }
  1674. }
  1675. //
  1676. // Capture the rest of the arguments.
  1677. // These arguments have already been probed.
  1678. //
  1679. try {
  1680. Status = STATUS_SUCCESS;
  1681. //
  1682. // Capture and validate AuthenticationID
  1683. //
  1684. RtlCopyLuid( &CapturedAuthenticationId, AuthenticationId );
  1685. //
  1686. // Capture ExpirationTime
  1687. //
  1688. CapturedExpirationTime = (*ExpirationTime);
  1689. //
  1690. // Capture User
  1691. //
  1692. if (NT_SUCCESS(Status)) {
  1693. Status = SeCaptureSidAndAttributesArray(
  1694. &(User->User),
  1695. 1,
  1696. PreviousMode,
  1697. NULL, 0,
  1698. PagedPool,
  1699. TRUE,
  1700. &CapturedUser,
  1701. &CapturedUserLength
  1702. );
  1703. }
  1704. //
  1705. // Capture Groups
  1706. //
  1707. if (NT_SUCCESS(Status)) {
  1708. CapturedGroupCount = Groups->GroupCount;
  1709. Status = SeCaptureSidAndAttributesArray(
  1710. (Groups->Groups),
  1711. CapturedGroupCount,
  1712. PreviousMode,
  1713. NULL, 0,
  1714. PagedPool,
  1715. TRUE,
  1716. &CapturedGroups,
  1717. &CapturedGroupsLength
  1718. );
  1719. }
  1720. //
  1721. // Capture Privileges
  1722. //
  1723. if (NT_SUCCESS(Status)) {
  1724. CapturedPrivilegeCount = Privileges->PrivilegeCount;
  1725. Status = SeCaptureLuidAndAttributesArray(
  1726. (Privileges->Privileges),
  1727. CapturedPrivilegeCount,
  1728. PreviousMode,
  1729. NULL, 0,
  1730. PagedPool,
  1731. TRUE,
  1732. &CapturedPrivileges,
  1733. &CapturedPrivilegesLength
  1734. );
  1735. }
  1736. //
  1737. // Capture Owner
  1738. //
  1739. if ( ARGUMENT_PRESENT(Owner) && NT_SUCCESS(Status)) {
  1740. CapturedAddress = Owner->Owner;
  1741. Status = SeCaptureSid(
  1742. (PSID)CapturedAddress,
  1743. PreviousMode,
  1744. NULL, 0,
  1745. PagedPool,
  1746. TRUE,
  1747. &CapturedOwner
  1748. );
  1749. }
  1750. //
  1751. // Capture PrimaryGroup
  1752. //
  1753. if (NT_SUCCESS(Status)) {
  1754. CapturedAddress = PrimaryGroup->PrimaryGroup;
  1755. Status = SeCaptureSid(
  1756. (PSID)CapturedAddress,
  1757. PreviousMode,
  1758. NULL, 0,
  1759. PagedPool,
  1760. TRUE,
  1761. &CapturedPrimaryGroup
  1762. );
  1763. }
  1764. //
  1765. // Capture DefaultDacl
  1766. //
  1767. if ( ARGUMENT_PRESENT(DefaultDacl) && NT_SUCCESS(Status) ) {
  1768. CapturedAddress = DefaultDacl->DefaultDacl;
  1769. if (CapturedAddress != NULL) {
  1770. Status = SeCaptureAcl(
  1771. (PACL)CapturedAddress,
  1772. PreviousMode,
  1773. NULL, 0,
  1774. NonPagedPool,
  1775. TRUE,
  1776. &CapturedDefaultDacl,
  1777. &Ignore
  1778. );
  1779. }
  1780. }
  1781. //
  1782. // Capture TokenSource
  1783. //
  1784. CapturedTokenSource = (*TokenSource);
  1785. } except(EXCEPTION_EXECUTE_HANDLER) {
  1786. if (CapturedUser != NULL) {
  1787. SeReleaseSidAndAttributesArray(
  1788. CapturedUser,
  1789. PreviousMode,
  1790. TRUE
  1791. );
  1792. }
  1793. if (CapturedGroups != NULL) {
  1794. SeReleaseSidAndAttributesArray(
  1795. CapturedGroups,
  1796. PreviousMode,
  1797. TRUE
  1798. );
  1799. }
  1800. if (CapturedPrivileges != NULL) {
  1801. SeReleaseLuidAndAttributesArray(
  1802. CapturedPrivileges,
  1803. PreviousMode,
  1804. TRUE
  1805. );
  1806. }
  1807. if (CapturedOwner != NULL) {
  1808. SeReleaseSid( CapturedOwner, PreviousMode, TRUE);
  1809. }
  1810. if (CapturedPrimaryGroup != NULL) {
  1811. SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE);
  1812. }
  1813. if (CapturedDefaultDacl != NULL) {
  1814. SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE);
  1815. }
  1816. if (SecurityQosPresent == TRUE) {
  1817. SeFreeCapturedSecurityQos( &CapturedSecurityQos );
  1818. }
  1819. return GetExceptionCode();
  1820. } // end_try{}
  1821. //
  1822. // Create the token
  1823. //
  1824. if (NT_SUCCESS(Status)) {
  1825. Status = SepCreateToken(
  1826. &LocalHandle,
  1827. PreviousMode,
  1828. DesiredAccess,
  1829. ObjectAttributes,
  1830. TokenType,
  1831. CapturedSecurityQos.ImpersonationLevel,
  1832. &CapturedAuthenticationId,
  1833. &CapturedExpirationTime,
  1834. CapturedUser,
  1835. CapturedGroupCount,
  1836. CapturedGroups,
  1837. CapturedGroupsLength,
  1838. CapturedPrivilegeCount,
  1839. CapturedPrivileges,
  1840. CapturedOwner,
  1841. CapturedPrimaryGroup,
  1842. CapturedDefaultDacl,
  1843. &CapturedTokenSource,
  1844. FALSE, // Not a system token
  1845. SecurityQosPresent ? CapturedSecurityQos.ProxyData : NULL,
  1846. SecurityQosPresent ? CapturedSecurityQos.AuditData : NULL
  1847. );
  1848. }
  1849. //
  1850. // Clean up the temporary capture buffers
  1851. //
  1852. if (CapturedUser != NULL) {
  1853. SeReleaseSidAndAttributesArray( CapturedUser, PreviousMode, TRUE);
  1854. }
  1855. if (CapturedGroups != NULL) {
  1856. SeReleaseSidAndAttributesArray( CapturedGroups, PreviousMode, TRUE);
  1857. }
  1858. if (CapturedPrivileges != NULL) {
  1859. SeReleaseLuidAndAttributesArray( CapturedPrivileges, PreviousMode, TRUE);
  1860. }
  1861. if (CapturedOwner != NULL) {
  1862. SeReleaseSid( CapturedOwner, PreviousMode, TRUE);
  1863. }
  1864. if (CapturedPrimaryGroup != NULL) {
  1865. SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE);
  1866. }
  1867. if (CapturedDefaultDacl != NULL) {
  1868. SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE);
  1869. }
  1870. if (SecurityQosPresent == TRUE) {
  1871. SeFreeCapturedSecurityQos( &CapturedSecurityQos );
  1872. }
  1873. //
  1874. // Return the handle to this new token
  1875. //
  1876. if (NT_SUCCESS(Status)) {
  1877. try { *TokenHandle = LocalHandle; }
  1878. except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); }
  1879. }
  1880. return Status;
  1881. }
  1882. ////////////////////////////////////////////////////////////////////////
  1883. // //
  1884. // Token Private Routines //
  1885. // //
  1886. ////////////////////////////////////////////////////////////////////////
  1887. VOID
  1888. SepTokenDeleteMethod (
  1889. IN PVOID Token
  1890. )
  1891. /*++
  1892. Routine Description:
  1893. This function is the token object type-specific delete method.
  1894. It is needed to ensure that all memory allocated for the token
  1895. gets deallocated.
  1896. Arguments:
  1897. Token - Points to the token object being deleted.
  1898. Return Value:
  1899. None.
  1900. --*/
  1901. {
  1902. PAGED_CODE();
  1903. #if DBG || TOKEN_LEAK_MONITOR
  1904. SepRemoveTokenLogonSession( Token );
  1905. #endif
  1906. //
  1907. // De-reference the logon session referenced by this token object
  1908. //
  1909. if ((((TOKEN *)Token)->TokenFlags & TOKEN_SESSION_NOT_REFERENCED ) == 0 ) {
  1910. SepDeReferenceLogonSessionDirect( (((TOKEN *)Token)->LogonSession) );
  1911. }
  1912. //
  1913. // If this token had an active SEP_AUDIT_POLICY then decrement the Token audit counter
  1914. // because this token is going byebye.
  1915. //
  1916. if ( ((PTOKEN)Token)->AuditPolicy.Overlay ) {
  1917. SepModifyTokenPolicyCounter(&((PTOKEN)Token)->AuditPolicy, FALSE);
  1918. ASSERT(SepTokenPolicyCounter >= 0);
  1919. }
  1920. //
  1921. // If the token has an associated Dynamic part, deallocate it.
  1922. //
  1923. if (ARGUMENT_PRESENT( ((TOKEN *)Token)->DynamicPart)) {
  1924. ExFreePool( ((TOKEN *)Token)->DynamicPart );
  1925. }
  1926. //
  1927. // Free the Proxy and Global audit structures if present.
  1928. //
  1929. if (ARGUMENT_PRESENT(((TOKEN *) Token)->ProxyData)) {
  1930. SepFreeProxyData( ((TOKEN *)Token)->ProxyData );
  1931. }
  1932. if (ARGUMENT_PRESENT(((TOKEN *)Token)->AuditData )) {
  1933. ExFreePool( (((TOKEN *)Token)->AuditData) );
  1934. }
  1935. if (ARGUMENT_PRESENT(((TOKEN *)Token)->TokenLock )) {
  1936. ExDeleteResourceLite(((TOKEN *)Token)->TokenLock );
  1937. ExFreePool(((TOKEN *)Token)->TokenLock );
  1938. }
  1939. return;
  1940. }
  1941. NTSTATUS
  1942. SepCreateToken(
  1943. OUT PHANDLE TokenHandle,
  1944. IN KPROCESSOR_MODE RequestorMode,
  1945. IN ACCESS_MASK DesiredAccess,
  1946. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  1947. IN TOKEN_TYPE TokenType,
  1948. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel OPTIONAL,
  1949. IN PLUID AuthenticationId,
  1950. IN PLARGE_INTEGER ExpirationTime,
  1951. IN PSID_AND_ATTRIBUTES User,
  1952. IN ULONG GroupCount,
  1953. IN PSID_AND_ATTRIBUTES Groups,
  1954. IN ULONG GroupsLength,
  1955. IN ULONG PrivilegeCount,
  1956. IN PLUID_AND_ATTRIBUTES Privileges,
  1957. IN PSID Owner OPTIONAL,
  1958. IN PSID PrimaryGroup,
  1959. IN PACL DefaultDacl OPTIONAL,
  1960. IN PTOKEN_SOURCE TokenSource,
  1961. IN BOOLEAN SystemToken,
  1962. IN PSECURITY_TOKEN_PROXY_DATA ProxyData OPTIONAL,
  1963. IN PSECURITY_TOKEN_AUDIT_DATA AuditData OPTIONAL
  1964. )
  1965. /*++
  1966. Routine Description:
  1967. Create a token object and return a handle opened for access to
  1968. that token. This API implements the bulk of the work needed
  1969. for NtCreateToken.
  1970. All parameters except DesiredAccess and ObjectAttributes are assumed
  1971. to have been probed and captured.
  1972. The output parameter (TokenHandle) is expected to be returned to a
  1973. safe address, rather than to a user mode address that may cause an
  1974. exception.
  1975. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1976. NOTE: This routine is also used to create the initial system token.
  1977. In that case, the SystemToken parameter is TRUE and no handle
  1978. is established to the token. Instead, a pointer to the token
  1979. is returned via the TokenHandle parameter.
  1980. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  1981. Arguments:
  1982. TokenHandle - Receives the handle of the newly created token. If the
  1983. SystemToken parameter is specified is true, then this parameter
  1984. receives a pointer to the token instead of a handle to the token.
  1985. RequestorMode - The mode of the caller on whose behalf the token
  1986. is being created.
  1987. DesiredAccess - Is an access mask indicating which access types
  1988. the handle is to provide to the new object.
  1989. ObjectAttributes - Points to the standard object attributes data
  1990. structure. Refer to the NT Object Management
  1991. Specification for a description of this data structure.
  1992. TokenType - Type of token to be created. Privilege is required
  1993. to create any type of token.
  1994. ImpersonationLevel - If the token type is TokenImpersonation, then
  1995. this parameter is used to specify the impersonation level of
  1996. the token.
  1997. AuthenticationId - Points to a LUID (or LUID) providing a unique
  1998. identifier associated with the authentication. This is used
  1999. within security only, for audit purposes.
  2000. ExpirationTime - Time at which the token becomes invalid. If this
  2001. value is specified as zero, then the token has no expiration
  2002. time.
  2003. User - Is the user SID to place in the token.
  2004. GroupCount - Indicates the number of groups in the 'Groups' parameter.
  2005. This value may be zero, in which case the 'Groups' parameter is
  2006. ignored.
  2007. Groups - Are the group SIDs, and their corresponding attributes,
  2008. to place in the token.
  2009. GroupsLength - Indicates the length, in bytes, of the array of groups
  2010. to place in the token.
  2011. PrivilegeCount - Indicates the number of privileges in the 'Privileges'
  2012. parameter. This value may be zero, in which case the 'Privileges'
  2013. parameter is ignored.
  2014. Privileges - Are the privilege LUIDs, and their corresponding attributes,
  2015. to place in the token.
  2016. PrivilegesLength - Indicates the length, in bytes, of the array of
  2017. privileges to place in the token.
  2018. Owner - (Optionally) identifies an identifier that is to be used
  2019. as the default owner for the token. If not provided, the
  2020. user ID is made the default owner.
  2021. PrimaryGroup - Identifies which of the group IDs is to be the
  2022. primary group of the token.
  2023. DefaultDacl - (optionally) establishes an ACL to be used as the
  2024. default discretionary access protection for the token.
  2025. TokenSource - Identifies the token source name string and
  2026. identifier to be assigned to the token.
  2027. Return Value:
  2028. STATUS_SUCCESS - Indicates the operation was successful.
  2029. STATUS_INVALID_OWNER - Indicates the ID provided to be assigned
  2030. as the default owner of the token does not have an attribute
  2031. indicating it may be assigned as an owner.
  2032. STATUS_INVALID_PRIMARY_GROUP - Indicates the group ID provided
  2033. via the PrimaryGroup parameter was not among those assigned
  2034. to the token in the Groups parameter.
  2035. STATUS_INVALID_PARAMETER - Indicates that a required parameter,
  2036. such as User or PrimaryGroup, was not provided with a legitimate
  2037. value.
  2038. --*/
  2039. {
  2040. PTOKEN Token;
  2041. NTSTATUS Status;
  2042. ULONG PagedPoolSize;
  2043. ULONG PrimaryGroupLength;
  2044. ULONG TokenBodyLength;
  2045. ULONG VariableLength;
  2046. ULONG DefaultOwnerIndex = 0;
  2047. PUCHAR Where;
  2048. ULONG ComputedPrivLength;
  2049. PSID NextSidFree;
  2050. ULONG DynamicLength;
  2051. ULONG DynamicLengthUsed;
  2052. ULONG SubAuthorityCount;
  2053. ULONG GroupIndex;
  2054. ULONG PrivilegeIndex;
  2055. BOOLEAN OwnerFound;
  2056. UCHAR TokenFlags = 0;
  2057. ACCESS_STATE AccessState;
  2058. AUX_ACCESS_DATA AuxData;
  2059. LUID NewModifiedId;
  2060. PERESOURCE TokenLock;
  2061. #if DBG || TOKEN_LEAK_MONITOR
  2062. ULONG Frames;
  2063. #endif
  2064. PAGED_CODE();
  2065. ASSERT( sizeof(SECURITY_IMPERSONATION_LEVEL) <= sizeof(ULONG) );
  2066. //
  2067. // Make sure the Enabled and Enabled-by-default bits are set on every
  2068. // mandatory group.
  2069. //
  2070. // Also, check to see if the local administrators alias is present.
  2071. // if so, turn on the flag so that we can do restrictions later
  2072. //
  2073. for (GroupIndex=0; GroupIndex < GroupCount; GroupIndex++) {
  2074. if (Groups[GroupIndex].Attributes & SE_GROUP_MANDATORY) {
  2075. Groups[GroupIndex].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
  2076. }
  2077. }
  2078. for (GroupIndex=0; GroupIndex < GroupCount; GroupIndex++) {
  2079. if (RtlEqualSid( SeAliasAdminsSid, Groups[GroupIndex].Sid )) {
  2080. TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
  2081. break;
  2082. }
  2083. }
  2084. //
  2085. // Check to see if the token being created is going to be granted
  2086. // SeChangeNotifyPrivilege. If so, set a flag in the TokenFlags field
  2087. // so we can find this out quickly.
  2088. //
  2089. for (PrivilegeIndex = 0; PrivilegeIndex < PrivilegeCount; PrivilegeIndex++) {
  2090. if (((RtlEqualLuid(&Privileges[PrivilegeIndex].Luid,&SeChangeNotifyPrivilege))
  2091. &&
  2092. (Privileges[PrivilegeIndex].Attributes & SE_PRIVILEGE_ENABLED))) {
  2093. TokenFlags |= TOKEN_HAS_TRAVERSE_PRIVILEGE;
  2094. }
  2095. if (((RtlEqualLuid(&Privileges[PrivilegeIndex].Luid, &SeImpersonatePrivilege)) &&
  2096. ( Privileges[PrivilegeIndex].Attributes & SE_PRIVILEGE_ENABLED))) {
  2097. TokenFlags |= TOKEN_HAS_IMPERSONATE_PRIVILEGE ;
  2098. }
  2099. }
  2100. //
  2101. // Get a ModifiedId to use
  2102. //
  2103. ExAllocateLocallyUniqueId( &NewModifiedId );
  2104. //
  2105. // Validate the owner ID, if provided and establish the default
  2106. // owner index.
  2107. //
  2108. if (!ARGUMENT_PRESENT(Owner)) {
  2109. DefaultOwnerIndex = 0;
  2110. } else {
  2111. if ( RtlEqualSid( Owner, User->Sid ) ) {
  2112. DefaultOwnerIndex = 0;
  2113. } else {
  2114. GroupIndex = 0;
  2115. OwnerFound = FALSE;
  2116. while ((GroupIndex < GroupCount) && (!OwnerFound)) {
  2117. if ( RtlEqualSid( Owner, (Groups[GroupIndex].Sid) ) ) {
  2118. //
  2119. // Found a match - make sure it is assignable as owner.
  2120. //
  2121. if ( SepArrayGroupAttributes( Groups, GroupIndex ) &
  2122. SE_GROUP_OWNER ) {
  2123. DefaultOwnerIndex = GroupIndex + 1;
  2124. OwnerFound = TRUE;
  2125. } else {
  2126. return STATUS_INVALID_OWNER;
  2127. } // endif Owner attribute set
  2128. } // endif owner = group
  2129. GroupIndex += 1;
  2130. } // endwhile
  2131. if (!OwnerFound) {
  2132. return STATUS_INVALID_OWNER;
  2133. } // endif !OwnerFound
  2134. } // endif owner = user
  2135. } // endif owner specified
  2136. TokenLock = (PERESOURCE)ExAllocatePoolWithTag( NonPagedPool, sizeof( ERESOURCE ), 'dTeS' );
  2137. if (TokenLock == NULL) {
  2138. return( STATUS_INSUFFICIENT_RESOURCES );
  2139. }
  2140. //
  2141. // Calculate the length needed for the variable portion of the token
  2142. // This includes the User ID, Group IDs, and Privileges
  2143. //
  2144. //
  2145. // Align the privilege chunk by pointer alignment so that the SIDs will
  2146. // be correctly aligned. Align the Groups Length so that the SID_AND_ATTR
  2147. // array (which is
  2148. //
  2149. ComputedPrivLength = PrivilegeCount * sizeof( LUID_AND_ATTRIBUTES ) ;
  2150. ComputedPrivLength = ALIGN_UP( ComputedPrivLength, PVOID );
  2151. GroupsLength = ALIGN_UP( GroupsLength, PVOID );
  2152. VariableLength = GroupsLength + ComputedPrivLength +
  2153. ALIGN_UP( (GroupCount * sizeof( SID_AND_ATTRIBUTES )), PVOID ) ;
  2154. SubAuthorityCount = ((SID *)(User->Sid))->SubAuthorityCount;
  2155. VariableLength += sizeof(SID_AND_ATTRIBUTES) +
  2156. (ULONG)LongAlignSize(RtlLengthRequiredSid( SubAuthorityCount ));
  2157. //
  2158. // Calculate the length needed for the dynamic portion of the token
  2159. // This includes the default Dacl and the primary group.
  2160. //
  2161. SubAuthorityCount = ((SID *)PrimaryGroup)->SubAuthorityCount;
  2162. DynamicLengthUsed = (ULONG)LongAlignSize(RtlLengthRequiredSid( SubAuthorityCount ));
  2163. if (ARGUMENT_PRESENT(DefaultDacl)) {
  2164. DynamicLengthUsed += (ULONG)LongAlignSize(DefaultDacl->AclSize);
  2165. }
  2166. DynamicLength = DynamicLengthUsed;
  2167. //
  2168. // Now create the token body
  2169. //
  2170. TokenBodyLength = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
  2171. if (DynamicLength < TOKEN_DEFAULT_DYNAMIC_CHARGE) {
  2172. PagedPoolSize = TokenBodyLength + TOKEN_DEFAULT_DYNAMIC_CHARGE;
  2173. } else {
  2174. PagedPoolSize = TokenBodyLength + DynamicLength;
  2175. }
  2176. Status = ObCreateObject(
  2177. RequestorMode, // ProbeMode
  2178. SeTokenObjectType, // ObjectType
  2179. ObjectAttributes, // ObjectAttributes
  2180. UserMode, // OwnershipMode
  2181. NULL, // ParseContext
  2182. TokenBodyLength, // ObjectBodySize
  2183. PagedPoolSize, // PagedPoolCharge
  2184. 0, // NonPagedPoolCharge
  2185. (PVOID *)&Token // Return pointer to object
  2186. );
  2187. if (!NT_SUCCESS(Status)) {
  2188. ExFreePool( TokenLock );
  2189. return Status;
  2190. }
  2191. //
  2192. // Main Body initialization
  2193. //
  2194. Token->TokenLock = TokenLock;
  2195. ExInitializeResourceLite( Token->TokenLock );
  2196. ExAllocateLocallyUniqueId( &(Token->TokenId) );
  2197. Token->ParentTokenId = RtlConvertLongToLuid(0);
  2198. Token->OriginatingLogonSession = RtlConvertLongToLuid(0);
  2199. Token->AuthenticationId = (*AuthenticationId);
  2200. Token->TokenInUse = FALSE;
  2201. Token->ModifiedId = NewModifiedId;
  2202. Token->ExpirationTime = (*ExpirationTime);
  2203. Token->TokenType = TokenType;
  2204. Token->ImpersonationLevel = ImpersonationLevel;
  2205. Token->TokenSource = (*TokenSource);
  2206. Token->TokenFlags = TokenFlags;
  2207. Token->SessionId = 0;
  2208. Token->DynamicCharged = PagedPoolSize - TokenBodyLength;
  2209. Token->DynamicAvailable = 0;
  2210. Token->DefaultOwnerIndex = DefaultOwnerIndex;
  2211. Token->DefaultDacl = NULL;
  2212. Token->VariableLength = VariableLength;
  2213. Token->AuditPolicy.Overlay = 0;
  2214. // Ensure SepTokenDeleteMethod knows the buffers aren't allocated yet.
  2215. Token->ProxyData = NULL;
  2216. Token->AuditData = NULL;
  2217. Token->DynamicPart = NULL;
  2218. //
  2219. // Increment the reference count for this logon session
  2220. // (fail if there is no corresponding logon session.)
  2221. //
  2222. Status = SepReferenceLogonSession (AuthenticationId,
  2223. &Token->LogonSession);
  2224. if (!NT_SUCCESS (Status)) {
  2225. Token->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
  2226. Token->LogonSession = NULL;
  2227. ObDereferenceObject (Token);
  2228. return Status;
  2229. }
  2230. #if DBG || TOKEN_LEAK_MONITOR
  2231. Token->ProcessCid = PsGetCurrentThread()->Cid.UniqueProcess;
  2232. Token->ThreadCid = PsGetCurrentThread()->Cid.UniqueThread;
  2233. Token->CreateMethod = 0xC; // Create
  2234. Token->Count = 0;
  2235. Token->CaptureCount = 0;
  2236. RtlCopyMemory(
  2237. Token->ImageFileName,
  2238. PsGetCurrentProcess()->ImageFileName,
  2239. min(sizeof(Token->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName))
  2240. );
  2241. Frames = RtlWalkFrameChain(
  2242. (PVOID)Token->CreateTrace,
  2243. TRACE_SIZE,
  2244. 0
  2245. );
  2246. if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
  2247. RtlWalkFrameChain(
  2248. (PVOID)&Token->CreateTrace[Frames],
  2249. TRACE_SIZE - Frames,
  2250. 1
  2251. );
  2252. }
  2253. SepAddTokenLogonSession(Token);
  2254. #endif
  2255. if (ARGUMENT_PRESENT( ProxyData )) {
  2256. Status = SepCopyProxyData(
  2257. &Token->ProxyData,
  2258. ProxyData
  2259. );
  2260. if (!NT_SUCCESS(Status)) {
  2261. ObDereferenceObject( Token );
  2262. return( STATUS_NO_MEMORY );
  2263. }
  2264. } else {
  2265. Token->ProxyData = NULL;
  2266. }
  2267. if (ARGUMENT_PRESENT( AuditData )) {
  2268. Token->AuditData = ExAllocatePool( PagedPool, sizeof( SECURITY_TOKEN_AUDIT_DATA ));
  2269. if (Token->AuditData == NULL) {
  2270. ObDereferenceObject( Token );
  2271. return( STATUS_NO_MEMORY );
  2272. }
  2273. *(Token->AuditData) = *AuditData;
  2274. } else {
  2275. Token->AuditData = NULL;
  2276. }
  2277. //
  2278. // Variable part initialization
  2279. // Data is in the following order:
  2280. //
  2281. // Privileges array
  2282. // User (SID_AND_ATTRIBUTES)
  2283. // Groups (SID_AND_ATTRIBUTES)
  2284. // Restricted Sids (SID_AND_ATTRIBUTES)
  2285. // SIDs
  2286. //
  2287. Where = (PUCHAR) & Token->VariablePart ;
  2288. Token->Privileges = (PLUID_AND_ATTRIBUTES) Where ;
  2289. Token->PrivilegeCount = PrivilegeCount ;
  2290. RtlCopyMemory(
  2291. Where,
  2292. Privileges,
  2293. PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES) );
  2294. ASSERT( ComputedPrivLength >= PrivilegeCount * sizeof( LUID_AND_ATTRIBUTES ) );
  2295. Where += ComputedPrivLength ;
  2296. VariableLength -= ComputedPrivLength ;
  2297. ASSERT( (((ULONG_PTR) Where ) & (sizeof(PVOID) - 1)) == 0 );
  2298. //
  2299. // Now, copy the sid and attributes arrays.
  2300. //
  2301. NextSidFree = (PSID) (Where + (sizeof( SID_AND_ATTRIBUTES ) *
  2302. (GroupCount + 1) ) );
  2303. Token->UserAndGroups = (PSID_AND_ATTRIBUTES) Where ;
  2304. Token->UserAndGroupCount = GroupCount + 1 ;
  2305. ASSERT(VariableLength >= ((GroupCount + 1) * (ULONG)sizeof(SID_AND_ATTRIBUTES)));
  2306. VariableLength -= ((GroupCount + 1) * (ULONG)sizeof(SID_AND_ATTRIBUTES));
  2307. Status = RtlCopySidAndAttributesArray(
  2308. 1,
  2309. User,
  2310. VariableLength,
  2311. (PSID_AND_ATTRIBUTES)Where,
  2312. NextSidFree,
  2313. &NextSidFree,
  2314. &VariableLength
  2315. );
  2316. Where += sizeof( SID_AND_ATTRIBUTES );
  2317. ASSERT( (((ULONG_PTR) Where ) & (sizeof(PVOID) - 1)) == 0 );
  2318. Status = RtlCopySidAndAttributesArray(
  2319. GroupCount,
  2320. Groups,
  2321. VariableLength,
  2322. (PSID_AND_ATTRIBUTES)Where,
  2323. NextSidFree,
  2324. &NextSidFree,
  2325. &VariableLength
  2326. );
  2327. ASSERT(NT_SUCCESS(Status));
  2328. Token->RestrictedSids = NULL;
  2329. Token->RestrictedSidCount = 0;
  2330. //
  2331. // Dynamic part initialization
  2332. // Data is in the following order:
  2333. //
  2334. // PrimaryGroup (SID)
  2335. // Default Discreationary Acl (ACL)
  2336. //
  2337. Token->DynamicPart = (PULONG)ExAllocatePoolWithTag( PagedPool, DynamicLength, 'dTeS' );
  2338. //
  2339. // The attempt to allocate the DynamicPart of the token may have
  2340. // failed. Dereference the created object and exit with an error.
  2341. //
  2342. if (Token->DynamicPart == NULL) {
  2343. ObDereferenceObject( Token );
  2344. return( STATUS_NO_MEMORY );
  2345. }
  2346. Where = (PUCHAR) Token->DynamicPart;
  2347. Token->PrimaryGroup = (PSID) Where;
  2348. PrimaryGroupLength = RtlLengthRequiredSid( ((SID *)PrimaryGroup)->SubAuthorityCount );
  2349. RtlCopySid( PrimaryGroupLength, (PSID)Where, PrimaryGroup );
  2350. Where += (ULONG)LongAlignSize(PrimaryGroupLength);
  2351. if (ARGUMENT_PRESENT(DefaultDacl)) {
  2352. Token->DefaultDacl = (PACL)Where;
  2353. RtlCopyMemory( (PVOID)Where,
  2354. (PVOID)DefaultDacl,
  2355. DefaultDacl->AclSize
  2356. );
  2357. }
  2358. #ifdef TOKEN_DEBUG
  2359. ////////////////////////////////////////////////////////////////////////////
  2360. //
  2361. // Debug
  2362. SepDumpToken( Token );
  2363. // Debug
  2364. //
  2365. ////////////////////////////////////////////////////////////////////////////
  2366. #endif //TOKEN_DEBUG
  2367. //
  2368. // Insert the token unless it is a system token.
  2369. //
  2370. if (!SystemToken) {
  2371. Status = SeCreateAccessState(
  2372. &AccessState,
  2373. &AuxData,
  2374. DesiredAccess,
  2375. &SeTokenObjectType->TypeInfo.GenericMapping
  2376. );
  2377. if ( NT_SUCCESS(Status) ) {
  2378. BOOLEAN PrivilegeHeld;
  2379. PrivilegeHeld = SeSinglePrivilegeCheck(
  2380. SeCreateTokenPrivilege,
  2381. KeGetPreviousMode()
  2382. );
  2383. if (PrivilegeHeld) {
  2384. Status = ObInsertObject( Token,
  2385. &AccessState,
  2386. 0,
  2387. 0,
  2388. (PVOID *)NULL,
  2389. TokenHandle
  2390. );
  2391. } else {
  2392. Status = STATUS_PRIVILEGE_NOT_HELD;
  2393. ObDereferenceObject( Token );
  2394. }
  2395. SeDeleteAccessState( &AccessState );
  2396. } else {
  2397. ObDereferenceObject( Token );
  2398. }
  2399. } else {
  2400. ASSERT( NT_SUCCESS( Status ) );
  2401. //
  2402. // Insert the token unless this is phase0 initialization. The system token is inserted later.
  2403. //
  2404. if (!ExFastRefObjectNull (PsGetCurrentProcess()->Token)) {
  2405. Status = ObInsertObject( Token,
  2406. NULL,
  2407. 0,
  2408. 0,
  2409. NULL,
  2410. NULL
  2411. );
  2412. }
  2413. if (NT_SUCCESS (Status)) {
  2414. //
  2415. // Return pointer instead of handle.
  2416. //
  2417. (*TokenHandle) = (HANDLE)Token;
  2418. } else {
  2419. (*TokenHandle) = NULL;
  2420. }
  2421. }
  2422. #if DBG || TOKEN_LEAK_MONITOR
  2423. if (SepTokenLeakTracking && SepTokenLeakMethodWatch == 0xC && PsGetCurrentProcess()->UniqueProcessId == SepTokenLeakProcessCid) {
  2424. Token->Count = InterlockedIncrement(&SepTokenLeakMethodCount);
  2425. if (Token->Count >= SepTokenLeakBreakCount) {
  2426. DbgPrint("\nToken number 0x%x = 0x%x\n", Token->Count, Token);
  2427. DbgBreakPoint();
  2428. }
  2429. }
  2430. #endif
  2431. return Status;
  2432. }
  2433. BOOLEAN
  2434. SepIdAssignableAsOwner(
  2435. IN PTOKEN Token,
  2436. IN ULONG Index
  2437. )
  2438. /*++
  2439. Routine Description:
  2440. This routine returns a boolean value indicating whether the user
  2441. or group ID in the specified token with the specified index is
  2442. assignable as the owner of an object.
  2443. If the index is 0, which is always the USER ID, then the ID is
  2444. assignable as owner. Otherwise, the ID is that of a group, and
  2445. it must have the "Owner" attribute set to be assignable.
  2446. Arguments:
  2447. Token - Pointer to a locked Token to use.
  2448. Index - Index into the Token's UserAndGroupsArray. This value
  2449. is assumed to be valid.
  2450. Return Value:
  2451. TRUE - Indicates the index corresponds to an ID that may be assigned
  2452. as the owner of objects.
  2453. FALSE - Indicates the index does not correspond to an ID that may be
  2454. assigned as the owner of objects.
  2455. --*/
  2456. {
  2457. PAGED_CODE();
  2458. if (Index == 0) {
  2459. return TRUE;
  2460. } else {
  2461. return (BOOLEAN)
  2462. ( (SepTokenGroupAttributes(Token,Index) & SE_GROUP_OWNER)
  2463. != 0
  2464. );
  2465. }
  2466. }
  2467. NTSTATUS
  2468. SeIsChildToken(
  2469. IN HANDLE Token,
  2470. OUT PBOOLEAN IsChild
  2471. )
  2472. /*++
  2473. Routine Description:
  2474. This routine returns TRUE if the supplied token is a child of the caller's
  2475. process token. This is done by comparing the ParentTokenId field of the
  2476. supplied token to the TokenId field of the token from the current subject
  2477. context.
  2478. Arguments:
  2479. Token - Token to check for childhood
  2480. IsChild - Contains results of comparison.
  2481. TRUE - The supplied token is a child of the caller's token
  2482. FALSE- The supplied token is not a child of the caller's token
  2483. Returns:
  2484. Status codes from any NT services called.
  2485. --*/
  2486. {
  2487. PTOKEN CallerToken;
  2488. PTOKEN SuppliedToken;
  2489. LUID CallerTokenId;
  2490. LUID SuppliedParentTokenId;
  2491. NTSTATUS Status = STATUS_SUCCESS;
  2492. PEPROCESS Process;
  2493. *IsChild = FALSE;
  2494. //
  2495. // Capture the caller's token and get the token id
  2496. //
  2497. Process = PsGetCurrentProcess();
  2498. CallerToken = (PTOKEN) PsReferencePrimaryToken(Process);
  2499. CallerTokenId = CallerToken->TokenId;
  2500. PsDereferencePrimaryTokenEx(Process, CallerToken);
  2501. //
  2502. // Reference the supplied token and get the parent token id.
  2503. //
  2504. Status = ObReferenceObjectByHandle(
  2505. Token, // Handle
  2506. 0, // DesiredAccess
  2507. SeTokenObjectType, // ObjectType
  2508. KeGetPreviousMode(), // AccessMode
  2509. (PVOID *)&SuppliedToken, // Object
  2510. NULL // GrantedAccess
  2511. );
  2512. if (NT_SUCCESS(Status))
  2513. {
  2514. SuppliedParentTokenId = SuppliedToken->ParentTokenId;
  2515. ObDereferenceObject(SuppliedToken);
  2516. //
  2517. // Check to see if the supplied token's parent ID is the ID
  2518. // of the caller.
  2519. //
  2520. if (RtlEqualLuid(
  2521. &SuppliedParentTokenId,
  2522. &CallerTokenId
  2523. )) {
  2524. *IsChild = TRUE;
  2525. }
  2526. }
  2527. return(Status);
  2528. }
  2529. NTSTATUS
  2530. SeIsChildTokenByPointer(
  2531. IN PACCESS_TOKEN Token,
  2532. OUT PBOOLEAN IsChild
  2533. )
  2534. /*++
  2535. Routine Description:
  2536. This routine returns TRUE if the supplied token is a child of the caller's
  2537. token. This is done by comparing the ParentTokenId field of the supplied
  2538. token to the TokenId field of the token from the current subject context.
  2539. Arguments:
  2540. Token - Token to check for childhood
  2541. IsChild - Contains results of comparison.
  2542. TRUE - The supplied token is a child of the caller's token
  2543. FALSE- The supplied token is not a child of the caller's token
  2544. Returns:
  2545. Status codes from any NT services called.
  2546. --*/
  2547. {
  2548. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  2549. PTOKEN CallerToken;
  2550. PTOKEN SuppliedToken;
  2551. LUID CallerTokenId;
  2552. LUID SuppliedParentTokenId;
  2553. NTSTATUS Status = STATUS_SUCCESS;
  2554. PEPROCESS Process;
  2555. *IsChild = FALSE;
  2556. //
  2557. // Capture the caller's token and get the token id
  2558. //
  2559. Process = PsGetCurrentProcess();
  2560. CallerToken = (PTOKEN) PsReferencePrimaryToken(Process);
  2561. CallerTokenId = CallerToken->TokenId;
  2562. PsDereferencePrimaryTokenEx(Process, CallerToken);
  2563. SuppliedToken = (PTOKEN) Token;
  2564. SuppliedParentTokenId = SuppliedToken->ParentTokenId;
  2565. //
  2566. // Check to see if the supplied token's parent ID is the ID
  2567. // of the caller.
  2568. //
  2569. if (RtlEqualLuid(
  2570. &SuppliedParentTokenId,
  2571. &CallerTokenId
  2572. )) {
  2573. *IsChild = TRUE;
  2574. }
  2575. return(Status);
  2576. }
  2577. NTSTATUS
  2578. NtImpersonateAnonymousToken(
  2579. IN HANDLE ThreadHandle
  2580. )
  2581. /*++
  2582. Routine Description:
  2583. Impersonates the system's anonymous logon token on this thread.
  2584. Arguments:
  2585. ThreadHandle - Handle to the thread to do the impersonation.
  2586. Return Value:
  2587. STATUS_SUCCESS - Indicates the operation was successful.
  2588. STATUS_INVALID_HANDLE - the thread handle is invalid.
  2589. STATUS_ACCESS_DENIED - The thread handle is not open for impersonation
  2590. access.
  2591. --*/
  2592. {
  2593. PETHREAD CallerThread = NULL;
  2594. NTSTATUS Status = STATUS_SUCCESS;
  2595. PACCESS_TOKEN Token = NULL;
  2596. PEPROCESS Process;
  2597. HANDLE hAnonymousToken = NULL;
  2598. ULONG RegValue;
  2599. #define EVERYONE_INCLUDES_ANONYMOUS 1
  2600. //
  2601. // Reference the caller's thread to make sure we can impersonate
  2602. //
  2603. Status = ObReferenceObjectByHandle(
  2604. ThreadHandle,
  2605. THREAD_IMPERSONATE,
  2606. PsThreadType,
  2607. KeGetPreviousMode(),
  2608. (PVOID *)&CallerThread,
  2609. NULL
  2610. );
  2611. if (!NT_SUCCESS(Status)) {
  2612. return Status;
  2613. }
  2614. //
  2615. // Check the AnonymousIncludesEveryone reg key setting.
  2616. //
  2617. Status = SepRegQueryDwordValue(
  2618. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa",
  2619. L"EveryoneIncludesAnonymous",
  2620. &RegValue
  2621. );
  2622. if ( NT_SUCCESS( Status ) && ( RegValue == EVERYONE_INCLUDES_ANONYMOUS )) {
  2623. hAnonymousToken = SeAnonymousLogonToken;
  2624. } else {
  2625. hAnonymousToken = SeAnonymousLogonTokenNoEveryone;
  2626. };
  2627. //
  2628. // Reference the impersonation token to make sure we are allowed to
  2629. // impersonate it.
  2630. //
  2631. Status = ObReferenceObjectByPointer(
  2632. hAnonymousToken,
  2633. TOKEN_IMPERSONATE,
  2634. SeTokenObjectType,
  2635. KeGetPreviousMode()
  2636. );
  2637. if (!NT_SUCCESS(Status)) {
  2638. goto Cleanup;
  2639. }
  2640. ObDereferenceObject(hAnonymousToken);
  2641. Process = PsGetCurrentProcess();
  2642. Token = PsReferencePrimaryToken(Process);
  2643. //
  2644. // Do not allow anonymous impersonation if the primary token is restricted.
  2645. //
  2646. if (SeTokenIsRestricted(Token)) {
  2647. PsDereferencePrimaryToken(Token);
  2648. Status = STATUS_ACCESS_DENIED;
  2649. goto Cleanup;
  2650. }
  2651. PsDereferencePrimaryTokenEx(Process, Token);
  2652. //
  2653. // Do the impersonation. We want copy on open so the caller can't
  2654. // actually modify this system's copy of this token.
  2655. //
  2656. Status = PsImpersonateClient(
  2657. CallerThread,
  2658. hAnonymousToken,
  2659. TRUE, // copy on open
  2660. FALSE, // no effective only
  2661. SecurityImpersonation
  2662. );
  2663. Cleanup:
  2664. if (CallerThread != NULL) {
  2665. ObDereferenceObject(CallerThread);
  2666. }
  2667. return(Status);
  2668. }
  2669. #define SepEqualSidAndAttribute(a, b) \
  2670. ((RtlEqualSid((a).Sid, (b).Sid)) && \
  2671. ((((a).Attributes ^ (b).Attributes) & \
  2672. (SE_GROUP_ENABLED | SE_GROUP_USE_FOR_DENY_ONLY)) == 0) \
  2673. )
  2674. #define SepEqualLuidAndAttribute(a, b) \
  2675. ((RtlEqualLuid(&(a).Luid, &(b).Luid)) && \
  2676. ((((a).Attributes ^ (b).Attributes) & SE_PRIVILEGE_ENABLED) == 0) \
  2677. )
  2678. BOOLEAN
  2679. SepComparePrivilegeAndAttributeArrays(
  2680. IN PLUID_AND_ATTRIBUTES PrivilegeArray1,
  2681. IN ULONG Count1,
  2682. IN PLUID_AND_ATTRIBUTES PrivilegeArray2,
  2683. IN ULONG Count2
  2684. )
  2685. /*++
  2686. Routine Description:
  2687. This routine decides whether the given two privilege arrays are equivalent
  2688. from AccessCheck perspective.
  2689. Arguments:
  2690. PrivilegeArray1 - Privilege and attribute array from the first token.
  2691. Count1 - Number of elements from the first array.
  2692. PrivilegeArray2 - Privilege and attribute array from the second token.
  2693. Count2 - Number of elements from the second array.
  2694. Return Value:
  2695. TRUE - if the two arrays are equivalent
  2696. FALSE - otherwise
  2697. --*/
  2698. {
  2699. ULONG i = 0;
  2700. ULONG j = 0;
  2701. ULONG k = 0;
  2702. //
  2703. // If the number of privileges are not equal return FALSE.
  2704. //
  2705. if ( Count1 != Count2 ) {
  2706. return FALSE;
  2707. }
  2708. //
  2709. // In most cases when the privilege arrays are the same, the elements will
  2710. // be ordered in the same manner. Walk the two arrays till we get a mismatch
  2711. // or exhaust the number of entries in the array.
  2712. //
  2713. for ( k = 0; k < Count1; k++ ) {
  2714. if ( !SepEqualLuidAndAttribute(PrivilegeArray1[k], PrivilegeArray2[k]) ) {
  2715. break;
  2716. }
  2717. }
  2718. //
  2719. // If the arrays are identical return TRUE.
  2720. //
  2721. if ( k == Count1 ) {
  2722. return TRUE;
  2723. }
  2724. //
  2725. // Check if all the elements in the first array are present in the second.
  2726. //
  2727. for ( i = k; i < Count1; i++ ) {
  2728. for ( j = k; j < Count2; j++ ) {
  2729. if ( SepEqualLuidAndAttribute(PrivilegeArray1[i], PrivilegeArray2[j]) ) {
  2730. break;
  2731. }
  2732. }
  2733. //
  2734. // The second array does not contain ith element from the first.
  2735. //
  2736. if ( j == Count2 ) {
  2737. return FALSE;
  2738. }
  2739. }
  2740. //
  2741. // Check if all the elements in the second array are present in the first.
  2742. //
  2743. for ( i = k; i < Count2; i++ ) {
  2744. for ( j = k; j < Count1; j++ ) {
  2745. if ( SepEqualLuidAndAttribute(PrivilegeArray2[i], PrivilegeArray1[j]) ) {
  2746. break;
  2747. }
  2748. }
  2749. //
  2750. // The first array does not contain ith element from the second.
  2751. //
  2752. if ( j == Count1 ) {
  2753. return FALSE;
  2754. }
  2755. }
  2756. //
  2757. // If we are here, one array is a permutation of the other. Return TRUE.
  2758. //
  2759. return TRUE;
  2760. }
  2761. BOOLEAN
  2762. SepCompareSidAndAttributeArrays(
  2763. IN PSID_AND_ATTRIBUTES SidArray1,
  2764. IN ULONG Count1,
  2765. IN PSID_AND_ATTRIBUTES SidArray2,
  2766. IN ULONG Count2
  2767. )
  2768. /*++
  2769. Routine Description:
  2770. This routine decides whether the given two sid and attribute arrays are
  2771. equivalentfrom AccessCheck perspective.
  2772. Arguments:
  2773. SidArray1 - Sid and attribute array from the first token.
  2774. Count1 - Number of elements from the first array.
  2775. SidArray2 - Sid and attribute array from the second token.
  2776. Count2 - Number of elements from the second array.
  2777. Return Value:
  2778. TRUE - if the two arrays are equivalent
  2779. FALSE - otherwise
  2780. --*/
  2781. {
  2782. ULONG i = 0;
  2783. ULONG j = 0;
  2784. ULONG k = 0;
  2785. //
  2786. // If the number of groups sids are not equal return FALSE.
  2787. //
  2788. if ( Count1 != Count2 ) {
  2789. return FALSE;
  2790. }
  2791. //
  2792. // In most cases when the sid arrays are the same, the elements will
  2793. // be ordered in the same manner. Walk the two arrays till we get a mismatch
  2794. // or exhaust the number of entries in the array.
  2795. //
  2796. for ( k = 0; k < Count1; k++ ) {
  2797. if ( !SepEqualSidAndAttribute(SidArray1[k], SidArray2[k]) ) {
  2798. break;
  2799. }
  2800. }
  2801. //
  2802. // If the arrays are identical return TRUE.
  2803. //
  2804. if ( k == Count1 ) {
  2805. return TRUE;
  2806. }
  2807. //
  2808. // Check if all the elements in the first array are present in the second.
  2809. //
  2810. for ( i = k; i < Count1; i++ ) {
  2811. for ( j = k; j < Count2; j++ ) {
  2812. if ( SepEqualSidAndAttribute(SidArray1[i], SidArray2[j]) ) {
  2813. break;
  2814. }
  2815. }
  2816. //
  2817. // The second array does not contain ith element from the first.
  2818. //
  2819. if ( j == Count2 ) {
  2820. return FALSE;
  2821. }
  2822. }
  2823. //
  2824. // Check if all the elements in the second array are present in the first.
  2825. //
  2826. for ( i = k; i < Count2; i++ ) {
  2827. for ( j = k; j < Count1; j++ ) {
  2828. if ( SepEqualSidAndAttribute(SidArray2[i], SidArray1[j]) ) {
  2829. break;
  2830. }
  2831. }
  2832. //
  2833. // The first array does not contain ith element from the second.
  2834. //
  2835. if ( j == Count1 ) {
  2836. return FALSE;
  2837. }
  2838. }
  2839. //
  2840. // If we are here, one array is a permutation of the other. Return TRUE.
  2841. //
  2842. return TRUE;
  2843. }
  2844. NTSTATUS
  2845. NtCompareTokens(
  2846. IN HANDLE FirstTokenHandle,
  2847. IN HANDLE SecondTokenHandle,
  2848. OUT PBOOLEAN Equal
  2849. )
  2850. /*++
  2851. Routine Description:
  2852. This routine decides whether the given two tokens are equivalent from
  2853. AccessCheck perspective.
  2854. Two tokens are considered equal if all of the below are true.
  2855. 1. Every sid present in one token is the present in the other and vice-versa.
  2856. The access check attributes (SE_GROUP_ENABLED and SE_GROUP_USE_FOR_DENY_ONLY)
  2857. for these sids should match too.
  2858. 2. Either none or both the tokens are restricted.
  2859. 3. If both tokens are restricted then 1 should hold true for RestrictedSids.
  2860. 4. Every privilege present in the one token should be present in the other
  2861. and vice-versa.
  2862. Arguments:
  2863. FirstTokenHandle - Handle to the first token. The caller must have TOKEN_QUERY
  2864. access to the token.
  2865. SecondTokenHandle - Handle to the second token. The caller must have TOKEN_QUERY
  2866. access to the token.
  2867. Equal - To return whether the two tokens are equivalent from AccessCheck
  2868. viewpoint.
  2869. Return Value:
  2870. STATUS_SUCCESS - Indicates the operation was successful.
  2871. --*/
  2872. {
  2873. PTOKEN TokenOne = NULL;
  2874. PTOKEN TokenTwo = NULL;
  2875. BOOLEAN RetVal = FALSE;
  2876. NTSTATUS Status = STATUS_SUCCESS;
  2877. KPROCESSOR_MODE PreviousMode;
  2878. PAGED_CODE();
  2879. PreviousMode = KeGetPreviousMode();
  2880. if (PreviousMode != KernelMode) {
  2881. try {
  2882. ProbeForWriteBoolean(Equal);
  2883. } except(EXCEPTION_EXECUTE_HANDLER) {
  2884. return GetExceptionCode();
  2885. } // end_try
  2886. } //end_if
  2887. //
  2888. // If its the same handle, return TRUE.
  2889. //
  2890. if ( FirstTokenHandle == SecondTokenHandle ) {
  2891. RetVal = TRUE;
  2892. goto Cleanup;
  2893. }
  2894. //
  2895. // Reference the first token handle with TOKEN_QUERY access so that it does
  2896. // not go away.
  2897. //
  2898. Status = ObReferenceObjectByHandle(
  2899. FirstTokenHandle, // Handle
  2900. TOKEN_QUERY, // DesiredAccess
  2901. SeTokenObjectType, // ObjectType
  2902. PreviousMode, // AccessMode
  2903. (PVOID *)&TokenOne, // Object
  2904. NULL // GrantedAccess
  2905. );
  2906. if (!NT_SUCCESS(Status)) {
  2907. TokenOne = NULL;
  2908. goto Cleanup;
  2909. }
  2910. //
  2911. // Reference the second token handle with TOKEN_QUERY access so that it does
  2912. // not go away.
  2913. //
  2914. Status = ObReferenceObjectByHandle(
  2915. SecondTokenHandle, // Handle
  2916. TOKEN_QUERY, // DesiredAccess
  2917. SeTokenObjectType, // ObjectType
  2918. PreviousMode, // AccessMode
  2919. (PVOID *)&TokenTwo, // Object
  2920. NULL // GrantedAccess
  2921. );
  2922. if (!NT_SUCCESS(Status)) {
  2923. TokenTwo = NULL;
  2924. goto Cleanup;
  2925. }
  2926. //
  2927. // Acquire read lock on the first token.
  2928. //
  2929. SepAcquireTokenReadLock( TokenOne );
  2930. //
  2931. // Acquire read lock on the second token.
  2932. //
  2933. SepAcquireTokenReadLock( TokenTwo );
  2934. //
  2935. // Compare the user sid as well as its relevant attributes.
  2936. //
  2937. if ( !SepEqualSidAndAttribute(TokenOne->UserAndGroups[0], TokenTwo->UserAndGroups[0]) ) {
  2938. goto Cleanup1;
  2939. }
  2940. //
  2941. // Continue if both tokens are unrestricted OR
  2942. // if both tokens are restricted and Restricted arrays are equal.
  2943. // Else return UNEQUAL.
  2944. //
  2945. if ( SeTokenIsRestricted( (PACCESS_TOKEN) TokenOne )) {
  2946. if ( !SeTokenIsRestricted( (PACCESS_TOKEN) TokenTwo )) {
  2947. goto Cleanup1;
  2948. }
  2949. RetVal = SepCompareSidAndAttributeArrays(
  2950. TokenOne->RestrictedSids,
  2951. TokenOne->RestrictedSidCount,
  2952. TokenTwo->RestrictedSids,
  2953. TokenTwo->RestrictedSidCount
  2954. );
  2955. if (!RetVal) {
  2956. goto Cleanup1;
  2957. }
  2958. } else {
  2959. if ( SeTokenIsRestricted( (PACCESS_TOKEN) TokenTwo )) {
  2960. goto Cleanup1;
  2961. }
  2962. }
  2963. //
  2964. // Compare the sid arrays.
  2965. //
  2966. RetVal = SepCompareSidAndAttributeArrays(
  2967. TokenOne->UserAndGroups+1,
  2968. TokenOne->UserAndGroupCount-1,
  2969. TokenTwo->UserAndGroups+1,
  2970. TokenTwo->UserAndGroupCount-1
  2971. );
  2972. if (!RetVal) {
  2973. goto Cleanup1;
  2974. }
  2975. //
  2976. // Compare the privilege arrays.
  2977. //
  2978. RetVal = SepComparePrivilegeAndAttributeArrays(
  2979. TokenOne->Privileges,
  2980. TokenOne->PrivilegeCount,
  2981. TokenTwo->Privileges,
  2982. TokenTwo->PrivilegeCount
  2983. );
  2984. Cleanup1:
  2985. SepReleaseTokenReadLock( TokenOne );
  2986. SepReleaseTokenReadLock( TokenTwo );
  2987. Cleanup:
  2988. if ( TokenOne != NULL) {
  2989. ObDereferenceObject( TokenOne );
  2990. }
  2991. if ( TokenTwo != NULL) {
  2992. ObDereferenceObject( TokenTwo );
  2993. }
  2994. try {
  2995. *Equal = RetVal;
  2996. } except(EXCEPTION_EXECUTE_HANDLER) {
  2997. Status = GetExceptionCode();
  2998. }
  2999. return Status;
  3000. }
  3001. #ifdef ALLOC_DATA_PRAGMA
  3002. #pragma data_seg()
  3003. #pragma const_seg()
  3004. #endif