Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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