Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2647 lines
73 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. tokendup.c
  5. Abstract:
  6. This module implements the token duplication service.
  7. Author:
  8. Jim Kelly (JimK) 5-April-1990
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. //#ifndef TOKEN_DEBUG
  14. //#define TOKEN_DEBUG
  15. //#endif
  16. #include "pch.h"
  17. #pragma hdrstop
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE,NtDuplicateToken)
  20. #pragma alloc_text(PAGE,SepDuplicateToken)
  21. #pragma alloc_text(PAGE,SepMakeTokenEffectiveOnly)
  22. #pragma alloc_text(PAGE,SepSidInSidAndAttributes)
  23. #pragma alloc_text(PAGE,SepRemoveDisabledGroupsAndPrivileges)
  24. #pragma alloc_text(PAGE,SeCopyClientToken)
  25. #pragma alloc_text(PAGE,NtFilterToken)
  26. #pragma alloc_text(PAGE,SeFilterToken)
  27. #pragma alloc_text(PAGE,SeFastFilterToken)
  28. #pragma alloc_text(PAGE,SepFilterToken)
  29. #endif
  30. NTSTATUS
  31. NtDuplicateToken(
  32. IN HANDLE ExistingTokenHandle,
  33. IN ACCESS_MASK DesiredAccess,
  34. IN POBJECT_ATTRIBUTES ObjectAttributes,
  35. IN BOOLEAN EffectiveOnly,
  36. IN TOKEN_TYPE TokenType,
  37. OUT PHANDLE NewTokenHandle
  38. )
  39. /*++
  40. Routine Description:
  41. Create a new token that is a duplicate of an existing token.
  42. Arguments:
  43. ExistingTokenHandle - Is a handle to a token already open for
  44. TOKEN_DUPLICATE access.
  45. DesiredAccess - Is an access mask indicating which access types
  46. are desired to the newly created token. If specified as zero,
  47. the granted access mask of the existing token handle
  48. is used as the desired access mask for the new token.
  49. ObjectAttributes - Points to the standard object attributes data
  50. structure. Refer to the NT Object Management
  51. Specification for a description of this data structure.
  52. If the new token type is TokenImpersonation, then this
  53. parameter may be used to specify the impersonation level
  54. of the new token. If no value is provided, and the source
  55. token is an impersonation token, then the impersonation level
  56. of the source will become that of the target as well. If the
  57. source token is a primary token, then an impersonation level
  58. must be explicitly provided.
  59. If the token being duplicated is an impersonation token, and
  60. an impersonation level is explicitly provided for the target,
  61. then the value provided must not be greater than that of the
  62. source token. For example, an Identification level token can
  63. not be duplicated to produce a Delegation level token.
  64. EffectiveOnly - Is a boolean flag indicating whether the entire
  65. source token should be duplicated into the target token or
  66. just the effective (currently enabled) part of the token.
  67. This provides a means for a caller of a protected subsystem
  68. to limit which privileges and optional groups are made
  69. available to the protected subsystem. A value of TRUE
  70. indicates only the currently enabled parts of the source
  71. token are to be duplicated. Otherwise, the entire source
  72. token is duplicated.
  73. TokenType - Indicates which type of object the new object is to
  74. be created as (primary or impersonation). If you are duplicating
  75. an Impersonation token to produce a Primary token, then
  76. the Impersonation token must have an impersonation level of
  77. either DELEGATE or IMPERSONATE.
  78. NewTokenHandle - Receives the handle of the newly created token.
  79. Return Value:
  80. STATUS_SUCCESS - Indicates the operation was successful.
  81. STATUS_INVALID_PARAMETER - Indicates one or more of the parameter values
  82. was invalid. This value is returned if the target token is not
  83. an impersonation token.
  84. STATUS_BAD_IMPERSONATION_LEVEL - Indicates the impersonation level
  85. requested for the duplicate token is not compatible with the
  86. level of the source token. The duplicate token may not be assigned
  87. a level greater than that of the source token.
  88. --*/
  89. {
  90. PTOKEN Token;
  91. PTOKEN NewToken;
  92. KPROCESSOR_MODE PreviousMode;
  93. NTSTATUS Status;
  94. SECURITY_ADVANCED_QUALITY_OF_SERVICE SecurityQos;
  95. BOOLEAN SecurityQosPresent = FALSE;
  96. HANDLE LocalHandle = NULL;
  97. OBJECT_HANDLE_INFORMATION HandleInformation;
  98. ACCESS_MASK EffectiveDesiredAccess;
  99. PAGED_CODE();
  100. PreviousMode = KeGetPreviousMode();
  101. //
  102. // Probe parameters
  103. //
  104. if (PreviousMode != KernelMode) {
  105. try {
  106. //
  107. // Make sure the TokenType is valid
  108. //
  109. if ( (TokenType < TokenPrimary) || (TokenType > TokenImpersonation) ) {
  110. return(STATUS_INVALID_PARAMETER);
  111. }
  112. //
  113. // Make sure we can write the handle
  114. //
  115. ProbeForWriteHandle(NewTokenHandle);
  116. } except(EXCEPTION_EXECUTE_HANDLER) {
  117. return GetExceptionCode();
  118. } // end_try
  119. } //end_if
  120. Status = SeCaptureSecurityQos(
  121. ObjectAttributes,
  122. PreviousMode,
  123. &SecurityQosPresent,
  124. &SecurityQos
  125. );
  126. if (!NT_SUCCESS(Status)) {
  127. return Status;
  128. }
  129. //
  130. // Check the handle's access to the existing token and get
  131. // a pointer to that token. Pick up the default desired
  132. // access mask from the handle while we're at it.
  133. //
  134. Status = ObReferenceObjectByHandle(
  135. ExistingTokenHandle, // Handle
  136. TOKEN_DUPLICATE, // DesiredAccess
  137. SeTokenObjectType, // ObjectType
  138. PreviousMode, // AccessMode
  139. (PVOID *)&Token, // Object
  140. &HandleInformation // GrantedAccess
  141. );
  142. if ( !NT_SUCCESS(Status) ) {
  143. if (SecurityQosPresent) {
  144. SeFreeCapturedSecurityQos( &SecurityQos );
  145. }
  146. return Status;
  147. }
  148. #ifdef TOKEN_DEBUG
  149. ////////////////////////////////////////////////////////////////////////////
  150. //
  151. // Debug
  152. SepAcquireTokenReadLock( Token );
  153. DbgPrint("\n");
  154. DbgPrint("\n");
  155. DbgPrint("Token being duplicated: \n");
  156. SepDumpToken( Token );
  157. SepReleaseTokenReadLock( Token );
  158. // Debug
  159. //
  160. ////////////////////////////////////////////////////////////////////////////
  161. #endif //TOKEN_DEBUG
  162. //
  163. // Check to see if an alternate desired access mask was provided.
  164. //
  165. if (ARGUMENT_PRESENT(DesiredAccess)) {
  166. EffectiveDesiredAccess = DesiredAccess;
  167. } else {
  168. EffectiveDesiredAccess = HandleInformation.GrantedAccess;
  169. }
  170. //
  171. // If no impersonation level was specified, pick one up from
  172. // the source token.
  173. //
  174. if ( !SecurityQosPresent ) {
  175. SecurityQos.ImpersonationLevel = Token->ImpersonationLevel;
  176. }
  177. //
  178. // If an impersonation token is duplicated into an impersonation token, we
  179. // need to do checks on the impersonation level.
  180. // The impersonation level requested for the new token is ignored if the
  181. // new token type is TokenPrimary.
  182. //
  183. if ( (Token->TokenType == TokenImpersonation) &&
  184. (TokenType == TokenImpersonation)
  185. ) {
  186. //
  187. // Make sure a legitimate transformation is being requested:
  188. //
  189. // (1) The impersonation level of a target duplicate must not
  190. // exceed that of the source token.
  191. //
  192. //
  193. ASSERT( SecurityDelegation > SecurityImpersonation );
  194. ASSERT( SecurityImpersonation > SecurityIdentification );
  195. ASSERT( SecurityIdentification > SecurityAnonymous );
  196. if ( (SecurityQos.ImpersonationLevel > Token->ImpersonationLevel) ) {
  197. ObDereferenceObject( (PVOID)Token );
  198. if (SecurityQosPresent) {
  199. SeFreeCapturedSecurityQos( &SecurityQos );
  200. }
  201. return STATUS_BAD_IMPERSONATION_LEVEL;
  202. }
  203. }
  204. //
  205. // If we are producing a Primary token from an impersonation
  206. // token, then specify an impersonation level of at least
  207. // Impersonate.
  208. //
  209. if ( (Token->TokenType == TokenImpersonation) &&
  210. (TokenType == TokenPrimary) &&
  211. (Token->ImpersonationLevel < SecurityImpersonation)
  212. ) {
  213. ObDereferenceObject( (PVOID)Token );
  214. if (SecurityQosPresent) {
  215. SeFreeCapturedSecurityQos( &SecurityQos );
  216. }
  217. return STATUS_BAD_IMPERSONATION_LEVEL;
  218. }
  219. //
  220. // Duplicate the existing token
  221. //
  222. NewToken = NULL;
  223. Status = SepDuplicateToken(
  224. Token,
  225. ObjectAttributes,
  226. EffectiveOnly,
  227. TokenType,
  228. SecurityQos.ImpersonationLevel,
  229. PreviousMode,
  230. &NewToken
  231. );
  232. if (NT_SUCCESS(Status)) {
  233. //
  234. // Insert the new token
  235. //
  236. Status = ObInsertObject( NewToken,
  237. NULL,
  238. EffectiveDesiredAccess,
  239. 0,
  240. (PVOID *)NULL,
  241. &LocalHandle
  242. );
  243. if (!NT_SUCCESS( Status )) {
  244. #ifdef TOKEN_DEBUG
  245. DbgPrint( "SE: ObInsertObject failed (%x) for token at %x\n", Status, NewToken );
  246. #endif
  247. }
  248. } else
  249. if (NewToken != NULL) {
  250. #ifdef TOKEN_DEBUG
  251. DbgPrint( "SE: SepDuplicateToken failed (%x) but allocated token at %x\n", Status, NewToken );
  252. #endif
  253. }
  254. //
  255. // We no longer need our reference to the source token
  256. //
  257. ObDereferenceObject( (PVOID)Token );
  258. if (SecurityQosPresent) {
  259. SeFreeCapturedSecurityQos( &SecurityQos );
  260. }
  261. //
  262. // Return the new handle
  263. //
  264. if (NT_SUCCESS(Status)) {
  265. try {
  266. *NewTokenHandle = LocalHandle;
  267. } except(EXCEPTION_EXECUTE_HANDLER) {
  268. return GetExceptionCode();
  269. }
  270. }
  271. return Status;
  272. }
  273. NTSTATUS
  274. SepDuplicateToken(
  275. IN PTOKEN ExistingToken,
  276. IN POBJECT_ATTRIBUTES ObjectAttributes,
  277. IN BOOLEAN EffectiveOnly,
  278. IN TOKEN_TYPE TokenType,
  279. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel OPTIONAL,
  280. IN KPROCESSOR_MODE RequestorMode,
  281. OUT PTOKEN *DuplicateToken
  282. )
  283. /*++
  284. Routine Description:
  285. This routine does the bulk of the work to actually duplicate
  286. a token. This routine assumes all access validation and argument
  287. probing (except the ObjectAttributes) has been performed.
  288. THE CALLER IS RESPONSIBLE FOR CHECKING SUBJECT RIGHTS TO CREATE THE
  289. TYPE OF TOKEN BEING CREATED.
  290. This routine acquires a read lock on the token being duplicated.
  291. Arguments:
  292. ExistingToken - Points to the token to be duplicated.
  293. ObjectAttributes - Points to the standard object attributes data
  294. structure. Refer to the NT Object Management
  295. Specification for a description of this data structure.
  296. The security Quality Of Service of the object attributes are ignored.
  297. This information must be specified using parameters to this
  298. routine.
  299. EffectiveOnly - Is a boolean flag indicating whether the entire
  300. source token should be duplicated into the target token or
  301. just the effective (currently enabled) part of the token.
  302. This provides a means for a caller of a protected subsystem
  303. to limit which privileges and optional groups are made
  304. available to the protected subsystem. A value of TRUE
  305. indicates only the currently enabled parts of the source
  306. token are to be duplicated. Otherwise, the entire source
  307. token is duplicated.
  308. TokenType - Indicates the type of token to make the duplicate token.
  309. ImpersonationLevel - This value specifies the impersonation level
  310. to assign to the duplicate token. If the TokenType of the
  311. duplicate is not TokenImpersonation then this parameter is
  312. ignored. Otherwise, it is must be provided.
  313. RequestorMode - Mode of client requesting the token be duplicated.
  314. DuplicateToken - Receives a pointer to the duplicate token.
  315. The token has not yet been inserted into any object table.
  316. No exceptions are expected when tring to set this OUT value.
  317. Return Value:
  318. STATUS_SUCCESS - The service successfully completed the requested
  319. operation.
  320. --*/
  321. {
  322. NTSTATUS Status;
  323. PTOKEN NewToken;
  324. PULONG DynamicPart;
  325. ULONG PagedPoolSize;
  326. ULONG NonPagedPoolSize;
  327. ULONG TokenBodyLength;
  328. ULONG_PTR FieldOffset;
  329. ULONG DynamicSize;
  330. ULONG Index;
  331. PSECURITY_TOKEN_PROXY_DATA NewProxyData = NULL;
  332. PSECURITY_TOKEN_AUDIT_DATA NewAuditData = NULL;
  333. PSID_AND_ATTRIBUTES UserAndGroups;
  334. PSID_AND_ATTRIBUTES RestrictedSids;
  335. PERESOURCE TokenLock;
  336. #if DBG || TOKEN_LEAK_MONITOR
  337. ULONG Frames;
  338. #endif
  339. PAGED_CODE();
  340. ASSERT( sizeof(SECURITY_IMPERSONATION_LEVEL) <= sizeof(ULONG) );
  341. if ( TokenType == TokenImpersonation ) {
  342. ASSERT( SecurityDelegation > SecurityImpersonation );
  343. ASSERT( SecurityImpersonation > SecurityIdentification );
  344. ASSERT( SecurityIdentification > SecurityAnonymous );
  345. if ( (ImpersonationLevel > SecurityDelegation) ||
  346. (ImpersonationLevel < SecurityAnonymous) ) {
  347. return STATUS_BAD_IMPERSONATION_LEVEL;
  348. }
  349. }
  350. if (ARGUMENT_PRESENT(ExistingToken->ProxyData)) {
  351. Status = SepCopyProxyData(
  352. &NewProxyData,
  353. ExistingToken->ProxyData
  354. );
  355. if (!NT_SUCCESS(Status)) {
  356. return( Status );
  357. }
  358. } else {
  359. NewProxyData = NULL;
  360. }
  361. if (ARGUMENT_PRESENT( ExistingToken->AuditData )) {
  362. NewAuditData = ExAllocatePool( PagedPool, sizeof( SECURITY_TOKEN_AUDIT_DATA ));
  363. if (NewAuditData == NULL) {
  364. SepFreeProxyData( NewProxyData );
  365. return( STATUS_INSUFFICIENT_RESOURCES );
  366. } else {
  367. *NewAuditData = *(ExistingToken->AuditData);
  368. }
  369. } else {
  370. NewAuditData = NULL;
  371. }
  372. TokenLock = (PERESOURCE)ExAllocatePoolWithTag( NonPagedPool, sizeof( ERESOURCE ), 'dTeS' );
  373. if (TokenLock == NULL) {
  374. if (NewAuditData != NULL) {
  375. ExFreePool( NewAuditData );
  376. }
  377. SepFreeProxyData( NewProxyData );
  378. return( STATUS_INSUFFICIENT_RESOURCES );
  379. }
  380. //
  381. // Create a new object
  382. //
  383. TokenBodyLength = FIELD_OFFSET(TOKEN, VariablePart) +
  384. ExistingToken->VariableLength;
  385. NonPagedPoolSize = TokenBodyLength;
  386. PagedPoolSize = ExistingToken->DynamicCharged;
  387. Status = ObCreateObject(
  388. RequestorMode, // ProbeMode
  389. SeTokenObjectType, // ObjectType
  390. ObjectAttributes, // ObjectAttributes
  391. RequestorMode, // OwnershipMode
  392. NULL, // ParseContext
  393. TokenBodyLength, // ObjectBodySize
  394. PagedPoolSize, // PagedPoolCharge
  395. NonPagedPoolSize, // NonPagedPoolCharge
  396. (PVOID *)&NewToken // Return pointer to object
  397. );
  398. if (!NT_SUCCESS(Status)) {
  399. SepFreeProxyData( NewProxyData );
  400. ExFreePool( TokenLock );
  401. if (NewAuditData != NULL) {
  402. ExFreePool( NewAuditData );
  403. }
  404. return Status;
  405. }
  406. //
  407. // The following fields differ in the new token and can be filled out without the lock.
  408. //
  409. ExAllocateLocallyUniqueId( &(NewToken->TokenId) );
  410. NewToken->TokenInUse = FALSE;
  411. NewToken->TokenType = TokenType;
  412. NewToken->ImpersonationLevel = ImpersonationLevel;
  413. NewToken->TokenLock = TokenLock;
  414. ExInitializeResourceLite( NewToken->TokenLock );
  415. NewToken->AuthenticationId = ExistingToken->AuthenticationId;
  416. NewToken->TokenSource = ExistingToken->TokenSource;
  417. NewToken->DynamicAvailable = 0;
  418. NewToken->ProxyData = NewProxyData;
  419. NewToken->AuditData = NewAuditData;
  420. NewToken->ParentTokenId = ExistingToken->ParentTokenId;
  421. NewToken->ExpirationTime = ExistingToken->ExpirationTime;
  422. NewToken->OriginatingLogonSession = ExistingToken->OriginatingLogonSession ;
  423. //
  424. // acquire exclusive access to the source token
  425. //
  426. SepAcquireTokenReadLock( ExistingToken );
  427. //
  428. // Main Body initialization
  429. //
  430. //
  431. // The following fields are unchanged from the source token.
  432. // Although some may change if EffectiveOnly has been specified.
  433. //
  434. NewToken->ModifiedId = ExistingToken->ModifiedId;
  435. NewToken->DynamicCharged = ExistingToken->DynamicCharged;
  436. NewToken->DefaultOwnerIndex = ExistingToken->DefaultOwnerIndex;
  437. NewToken->UserAndGroupCount = ExistingToken->UserAndGroupCount;
  438. NewToken->RestrictedSidCount = ExistingToken->RestrictedSidCount;
  439. NewToken->PrivilegeCount = ExistingToken->PrivilegeCount;
  440. NewToken->VariableLength = ExistingToken->VariableLength;
  441. NewToken->TokenFlags = ExistingToken->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
  442. NewToken->SessionId = ExistingToken->SessionId;
  443. NewToken->AuditPolicy = ExistingToken->AuditPolicy;
  444. //
  445. // Increment the reference count for this logon session
  446. // This can not fail, since there is already a token in this logon
  447. // session.
  448. //
  449. Status = SepDuplicateLogonSessionReference (NewToken, ExistingToken);
  450. ASSERT( NT_SUCCESS(Status) );
  451. if (!NT_SUCCESS (Status)) {
  452. SepReleaseTokenReadLock( ExistingToken );
  453. NewToken->DynamicPart = NULL;
  454. ObDereferenceObject (NewToken);
  455. return Status;
  456. }
  457. #if DBG || TOKEN_LEAK_MONITOR
  458. NewToken->ProcessCid = PsGetCurrentThread()->Cid.UniqueProcess;
  459. NewToken->ThreadCid = PsGetCurrentThread()->Cid.UniqueThread;
  460. NewToken->CreateMethod = 0xD; // Duplicate
  461. NewToken->Count = 0;
  462. NewToken->CaptureCount = 0;
  463. RtlCopyMemory(
  464. NewToken->ImageFileName,
  465. PsGetCurrentProcess()->ImageFileName,
  466. min(sizeof(NewToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName))
  467. );
  468. Frames = RtlWalkFrameChain(
  469. (PVOID)NewToken->CreateTrace,
  470. TRACE_SIZE,
  471. 0
  472. );
  473. if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
  474. RtlWalkFrameChain(
  475. (PVOID)&NewToken->CreateTrace[Frames],
  476. TRACE_SIZE - Frames,
  477. 1
  478. );
  479. }
  480. SepAddTokenLogonSession(NewToken);
  481. #endif
  482. //
  483. // Copy and initialize the variable part.
  484. // The variable part is assumed to be position independent.
  485. //
  486. RtlCopyMemory( (PVOID)&(NewToken->VariablePart),
  487. (PVOID)&(ExistingToken->VariablePart),
  488. ExistingToken->VariableLength
  489. );
  490. //
  491. // Set the address of the UserAndGroups array.
  492. //
  493. ASSERT( ARGUMENT_PRESENT(ExistingToken->UserAndGroups ) );
  494. ASSERT( (ULONG_PTR)(ExistingToken->UserAndGroups) >=
  495. (ULONG_PTR)(&(ExistingToken->VariablePart)) );
  496. //
  497. // Calculate the relative offset between the old and new block. We
  498. // will use this value to fixup embeded pointers in this block.
  499. //
  500. FieldOffset = (ULONG_PTR)&NewToken->VariablePart - (ULONG_PTR)&ExistingToken->VariablePart;
  501. UserAndGroups = (PSID_AND_ATTRIBUTES) ((ULONG_PTR) ExistingToken->UserAndGroups + FieldOffset);
  502. NewToken->UserAndGroups = UserAndGroups;
  503. //
  504. // Now go through and change the address of each SID pointer
  505. // for the user and groups
  506. //
  507. Index = NewToken->UserAndGroupCount;
  508. while (Index > 0) {
  509. (ULONG_PTR) UserAndGroups->Sid += FieldOffset;
  510. Index -= 1;
  511. UserAndGroups++;
  512. }
  513. //
  514. // Set the address of the RestrictedSids array.
  515. //
  516. RestrictedSids = ExistingToken->RestrictedSids;
  517. NewToken->RestrictedSids = RestrictedSids;
  518. if (ARGUMENT_PRESENT(RestrictedSids) ) {
  519. ASSERT( (ULONG_PTR)(ExistingToken->RestrictedSids) >=
  520. (ULONG_PTR)(&(ExistingToken->VariablePart)) );
  521. (ULONG_PTR) RestrictedSids += FieldOffset;
  522. NewToken->RestrictedSids = RestrictedSids;
  523. //
  524. // Now go through and change the address of each SID pointer
  525. // for the user and groups
  526. //
  527. Index = NewToken->RestrictedSidCount;
  528. while (Index > 0) {
  529. (ULONG_PTR) RestrictedSids->Sid += FieldOffset;
  530. RestrictedSids++;
  531. Index -= 1;
  532. }
  533. }
  534. //
  535. // If present, set the address of the privileges
  536. //
  537. if (ExistingToken->PrivilegeCount > 0) {
  538. ASSERT( ARGUMENT_PRESENT(ExistingToken->Privileges ) );
  539. ASSERT( (ULONG_PTR)(ExistingToken->Privileges) >=
  540. (ULONG_PTR)(&(ExistingToken->VariablePart)) );
  541. (ULONG_PTR) NewToken->Privileges = (ULONG_PTR) ExistingToken->Privileges + FieldOffset;
  542. } else {
  543. NewToken->Privileges = NULL;
  544. }
  545. //
  546. // Allocate the dynamic portion
  547. //
  548. DynamicSize = SeLengthSid( ExistingToken->PrimaryGroup );
  549. if (ExistingToken->DefaultDacl) {
  550. DynamicSize += ExistingToken->DefaultDacl->AclSize;
  551. }
  552. DynamicPart = (PULONG)ExAllocatePoolWithTag(
  553. PagedPool,
  554. DynamicSize,
  555. 'dTeS'
  556. );
  557. NewToken->DynamicPart = DynamicPart;
  558. if (DynamicPart == NULL) {
  559. SepReleaseTokenReadLock( ExistingToken );
  560. ObDereferenceObject (NewToken);
  561. return( STATUS_INSUFFICIENT_RESOURCES );
  562. }
  563. //
  564. // Copy and initialize the dynamic part.
  565. // The dynamic part is assumed to be position independent.
  566. //
  567. RtlCopyMemory( (PVOID)DynamicPart,
  568. (PVOID)(ExistingToken->DynamicPart),
  569. DynamicSize
  570. );
  571. FieldOffset = (ULONG_PTR) DynamicPart - (ULONG_PTR) ExistingToken->DynamicPart;
  572. //
  573. // If present, set the address of the default Dacl
  574. //
  575. NewToken->DefaultDacl = ExistingToken->DefaultDacl;
  576. if (ARGUMENT_PRESENT(NewToken->DefaultDacl)) {
  577. ASSERT( (ULONG_PTR)(ExistingToken->DefaultDacl) >=
  578. (ULONG_PTR)(ExistingToken->DynamicPart) );
  579. (ULONG_PTR) NewToken->DefaultDacl += FieldOffset;
  580. }
  581. //
  582. // Set the address of the primary group
  583. //
  584. ASSERT(ARGUMENT_PRESENT(ExistingToken->PrimaryGroup));
  585. ASSERT( (ULONG_PTR)(ExistingToken->PrimaryGroup) >=
  586. (ULONG_PTR)(ExistingToken->DynamicPart) );
  587. (ULONG_PTR) NewToken->PrimaryGroup = (ULONG_PTR) ExistingToken->PrimaryGroup + FieldOffset;
  588. //
  589. // Release the source token.
  590. //
  591. SepReleaseTokenReadLock( ExistingToken );
  592. //
  593. // For the time being, take the easy way to generating an "EffectiveOnly"
  594. // duplicate. That is, use the same space required of the original, just
  595. // eliminate any IDs or privileges not active.
  596. //
  597. // Ultimately, if duplication becomes a common operation, then it will be
  598. // worthwhile to recalculate the actual space needed and copy only the
  599. // effective IDs/privileges into the new token.
  600. //
  601. if (EffectiveOnly) {
  602. SepMakeTokenEffectiveOnly( NewToken );
  603. }
  604. #ifdef TOKEN_DEBUG
  605. ////////////////////////////////////////////////////////////////////////////
  606. //
  607. // Debug
  608. DbgPrint("\n");
  609. DbgPrint("\n");
  610. DbgPrint("\n");
  611. DbgPrint("Duplicate token:\n");
  612. SepDumpToken( NewToken );
  613. // Debug
  614. //
  615. ////////////////////////////////////////////////////////////////////////////
  616. #endif //TOKEN_DEBUG
  617. //
  618. // If the NewToken inherited an active SEP_AUDIT_POLICY from ExistingToken,
  619. // then increment the counter of tokens with policies.
  620. //
  621. if ( NewToken->AuditPolicy.Overlay ) {
  622. SepModifyTokenPolicyCounter(&NewToken->AuditPolicy, TRUE);
  623. }
  624. #if DBG || TOKEN_LEAK_MONITOR
  625. if (SepTokenLeakTracking && SepTokenLeakMethodWatch == 0xD && PsGetCurrentProcess()->UniqueProcessId == SepTokenLeakProcessCid) {
  626. NewToken->Count = InterlockedIncrement(&SepTokenLeakMethodCount);
  627. if (NewToken->Count >= SepTokenLeakBreakCount) {
  628. DbgPrint("\nToken number 0x%x = 0x%x\n", NewToken->Count, NewToken);
  629. DbgBreakPoint();
  630. }
  631. }
  632. #endif
  633. (*DuplicateToken) = NewToken;
  634. return Status;
  635. }
  636. VOID
  637. SepMakeTokenEffectiveOnly(
  638. IN PTOKEN Token
  639. )
  640. /*++
  641. Routine Description:
  642. This routine eliminates all but the effective groups and privileges from
  643. a token. It does this by moving elements of the SID and privileges arrays
  644. to overwrite lapsed IDs/privileges, and then reducing the array element
  645. counts. This results in wasted memory within the token object.
  646. One side effect of this routine is that a token that initially had a
  647. default owner ID corresponding to a lapsed group will be changed so
  648. that the default owner ID is the user ID.
  649. THIS ROUTINE MUST BE CALLED ONLY AS PART OF TOKEN CREATION (FOR TOKENS
  650. WHICH HAVE NOT YET BEEN INSERTED INTO AN OBJECT TABLE.) THIS ROUTINE
  651. MODIFIES READ ONLY TOKEN FIELDS.
  652. Note that since we are operating on a token that is not yet visible
  653. to the user, we do not bother acquiring a read lock on the token
  654. being modified.
  655. Arguments:
  656. Token - Points to the token to be made effective only.
  657. Return Value:
  658. None.
  659. --*/
  660. {
  661. ULONG Index;
  662. ULONG ElementCount;
  663. PAGED_CODE();
  664. //
  665. // Walk the privilege array, discarding any lapsed privileges
  666. //
  667. ElementCount = Token->PrivilegeCount;
  668. Index = 0;
  669. while (Index < ElementCount) {
  670. //
  671. // If this privilege is not enabled, replace it with the one at
  672. // the end of the array and reduce the size of the array by one.
  673. // Otherwise, move on to the next entry in the array.
  674. //
  675. if ( !(SepTokenPrivilegeAttributes(Token,Index) & SE_PRIVILEGE_ENABLED)
  676. ) {
  677. (Token->Privileges)[Index] =
  678. (Token->Privileges)[ElementCount - 1];
  679. ElementCount -= 1;
  680. } else {
  681. Index += 1;
  682. }
  683. } // endwhile
  684. Token->PrivilegeCount = ElementCount;
  685. //
  686. // Walk the UserAndGroups array (except for the first entry, which is
  687. // the user - and can't be disabled) discarding any lapsed groups.
  688. //
  689. ElementCount = Token->UserAndGroupCount;
  690. ASSERT( ElementCount >= 1 ); // Must be at least a user ID
  691. Index = 1; // Start at the first group, not the user ID.
  692. while (Index < ElementCount) {
  693. //
  694. // If this group is not enabled, replace it with the one at
  695. // the end of the array and reduce the size of the array by one.
  696. //
  697. if ( !(SepTokenGroupAttributes(Token, Index) & SE_GROUP_ENABLED) &&
  698. !(SepTokenGroupAttributes(Token, Index) & SE_GROUP_USE_FOR_DENY_ONLY) ) {
  699. //
  700. // Reset the TOKEN_HAS_ADMIN_GROUP flag
  701. //
  702. if (RtlEqualSid(
  703. Token->UserAndGroups[Index].Sid,
  704. SeAliasAdminsSid
  705. )) {
  706. Token->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
  707. }
  708. (Token->UserAndGroups)[Index] =
  709. (Token->UserAndGroups)[ElementCount - 1];
  710. ElementCount -= 1;
  711. } else {
  712. Index += 1;
  713. }
  714. } // endwhile
  715. Token->UserAndGroupCount = ElementCount;
  716. return;
  717. }
  718. BOOLEAN
  719. SepSidInSidAndAttributes (
  720. IN PSID_AND_ATTRIBUTES SidAndAttributes,
  721. IN ULONG SidCount,
  722. IN PSID PrincipalSelfSid,
  723. IN PSID Sid
  724. )
  725. /*++
  726. Routine Description:
  727. Checks to see if a given SID is in the given token.
  728. N.B. The code to compute the length of a SID and test for equality
  729. is duplicated from the security runtime since this is such a
  730. frequently used routine.
  731. Arguments:
  732. SidAndAttributes - Pointer to the sid and attributes to be examined
  733. PrincipalSelfSid - If the object being access checked is an object which
  734. represents a principal (e.g., a user object), this parameter should
  735. be the SID of the object. Any ACE containing the constant
  736. PRINCIPAL_SELF_SID is replaced by this SID.
  737. The parameter should be NULL if the object does not represent a principal.
  738. Sid - Pointer to the SID of interest
  739. Return Value:
  740. A value of TRUE indicates that the SID is in the token, FALSE
  741. otherwise.
  742. --*/
  743. {
  744. ULONG i;
  745. PISID MatchSid;
  746. ULONG SidLength;
  747. PTOKEN Token;
  748. PSID_AND_ATTRIBUTES TokenSid;
  749. ULONG UserAndGroupCount;
  750. PAGED_CODE();
  751. if (!ARGUMENT_PRESENT( SidAndAttributes ) ) {
  752. return(FALSE);
  753. }
  754. //
  755. // If Sid is the constant PrincipalSelfSid,
  756. // replace it with the passed in PrincipalSelfSid.
  757. //
  758. if ( PrincipalSelfSid != NULL &&
  759. RtlEqualSid( SePrincipalSelfSid, Sid ) ) {
  760. Sid = PrincipalSelfSid;
  761. }
  762. //
  763. // Get the length of the source SID since this only needs to be computed
  764. // once.
  765. //
  766. SidLength = 8 + (4 * ((PISID)Sid)->SubAuthorityCount);
  767. //
  768. // Get address of user/group array and number of user/groups.
  769. //
  770. TokenSid = SidAndAttributes;
  771. UserAndGroupCount = SidCount;
  772. //
  773. // Scan through the user/groups and attempt to find a match with the
  774. // specified SID.
  775. //
  776. for (i = 0 ; i < UserAndGroupCount ; i += 1) {
  777. MatchSid = (PISID)TokenSid->Sid;
  778. //
  779. // If the SID revision and length matches, then compare the SIDs
  780. // for equality.
  781. //
  782. if ((((PISID)Sid)->Revision == MatchSid->Revision) &&
  783. (SidLength == (8 + (4 * (ULONG)MatchSid->SubAuthorityCount)))) {
  784. if (RtlEqualMemory(Sid, MatchSid, SidLength)) {
  785. return TRUE;
  786. }
  787. }
  788. TokenSid += 1;
  789. }
  790. return FALSE;
  791. }
  792. VOID
  793. SepRemoveDisabledGroupsAndPrivileges(
  794. IN PTOKEN Token,
  795. IN ULONG Flags,
  796. IN ULONG GroupCount,
  797. IN PSID_AND_ATTRIBUTES GroupsToDisable,
  798. IN ULONG PrivilegeCount,
  799. IN PLUID_AND_ATTRIBUTES PrivilegesToDelete
  800. )
  801. /*++
  802. Routine Description:
  803. This routine eliminates all groups and privileges that are marked
  804. to be deleted/disabled. It does this by looping through the groups in
  805. the token and checking each one agains the groups to disable. Similary
  806. the privilegs are compared. It does this by moving elements of the SID and privileges arrays
  807. to overwrite lapsed IDs/privileges, and then reducing the array element
  808. counts. This results in wasted memory within the token object.
  809. THIS ROUTINE MUST BE CALLED ONLY AS PART OF TOKEN CREATION (FOR TOKENS
  810. WHICH HAVE NOT YET BEEN INSERTED INTO AN OBJECT TABLE.) THIS ROUTINE
  811. MODIFIES READ ONLY TOKEN FIELDS.
  812. Note that since we are operating on a token that is not yet visible
  813. to the user, we do not bother acquiring a read lock on the token
  814. being modified.
  815. Arguments:
  816. Token - Points to the token to be made effective only.
  817. Flags - Flags indicating additional filtering. The flags may be:
  818. DISABLE_MAX_PRIVILEGE - Disable all privileges
  819. GroupCount - Count of groups to be removed
  820. GroupsToDisable - Groups to disable and mark with SE_GROUP_USE_FOR_DENY_ONLY
  821. PrivilegeCount - Count of privileges to remove
  822. PrivilegesToDelete - List of privileges to remove
  823. Return Value:
  824. None.
  825. --*/
  826. {
  827. ULONG Index;
  828. ULONG Index2;
  829. ULONG ElementCount;
  830. BOOLEAN Found;
  831. PAGED_CODE();
  832. //
  833. // Walk the privilege array, discarding any lapsed privileges
  834. //
  835. ElementCount = Token->PrivilegeCount;
  836. Index = 0;
  837. while (Index < ElementCount) {
  838. //
  839. // If the caller asked us to disable all privileges except change
  840. // notify, do so now.
  841. //
  842. if (((Flags & DISABLE_MAX_PRIVILEGE) != 0) &&
  843. !RtlEqualLuid(
  844. &Token->Privileges[Index].Luid,
  845. &SeChangeNotifyPrivilege
  846. )) {
  847. (Token->Privileges)[Index] =
  848. (Token->Privileges)[ElementCount - 1];
  849. ElementCount -= 1;
  850. } else {
  851. //
  852. // If this privilege is in the list of those to be removed, replace it
  853. // with the one at the end of the array and reduce the size of the
  854. // array by one. Otherwise, move on to the next entry in the array.
  855. //
  856. Found = FALSE;
  857. for (Index2 = 0; Index2 < PrivilegeCount ; Index2++ ) {
  858. if (RtlEqualLuid(
  859. &Token->Privileges[Index].Luid,
  860. &PrivilegesToDelete[Index2].Luid
  861. )) {
  862. (Token->Privileges)[Index] =
  863. (Token->Privileges)[ElementCount - 1];
  864. ElementCount -= 1;
  865. //
  866. // If this was SeChangeNotifyPrivilege, we need to turn off
  867. // the TOKEN_HAS_TRAVERSE_PRIVILEGE in the token
  868. //
  869. if (RtlEqualLuid(
  870. &PrivilegesToDelete[Index2].Luid,
  871. &SeChangeNotifyPrivilege
  872. )) {
  873. Token->TokenFlags &= ~TOKEN_HAS_TRAVERSE_PRIVILEGE;
  874. }
  875. Found = TRUE;
  876. break;
  877. }
  878. }
  879. if (!Found) {
  880. Index += 1;
  881. }
  882. }
  883. } // endwhile
  884. Token->PrivilegeCount = ElementCount;
  885. //
  886. // Walk the UserAndGroups array marking any disabled groups.
  887. //
  888. ElementCount = Token->UserAndGroupCount;
  889. ASSERT( ElementCount >= 1 ); // Must be at least a user ID
  890. Index = 0; // Start at the first group, not the user ID.
  891. while (Index < ElementCount) {
  892. //
  893. // If this group is not enabled, replace it with the one at
  894. // the end of the array and reduce the size of the array by one.
  895. //
  896. if ( SepSidInSidAndAttributes(
  897. GroupsToDisable,
  898. GroupCount,
  899. NULL, // no principal self sid
  900. Token->UserAndGroups[Index].Sid
  901. )){
  902. (Token->UserAndGroups)[Index].Attributes &= ~(SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
  903. (Token->UserAndGroups)[Index].Attributes |= SE_GROUP_USE_FOR_DENY_ONLY;
  904. //
  905. // If this was the owner, reset the owner to be the user
  906. //
  907. if (Index == Token->DefaultOwnerIndex) {
  908. Token->DefaultOwnerIndex = 0;
  909. }
  910. //
  911. // If this is the admins sid, turn off the admin group flag
  912. //
  913. if (RtlEqualSid(
  914. Token->UserAndGroups[Index].Sid,
  915. SeAliasAdminsSid
  916. )) {
  917. Token->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
  918. }
  919. }
  920. Index += 1;
  921. } // endwhile
  922. return;
  923. }
  924. NTSTATUS
  925. SeCopyClientToken(
  926. IN PACCESS_TOKEN ClientToken,
  927. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  928. IN KPROCESSOR_MODE RequestorMode,
  929. OUT PACCESS_TOKEN *DuplicateToken
  930. )
  931. /*++
  932. Routine Description:
  933. This routine copies a client's token as part of establishing a client
  934. context for impersonation.
  935. The result will be an impersonation token.
  936. No handles to the new token are established.
  937. The token will be an exact duplicate of the source token. It is the
  938. caller's responsibility to ensure an effective only copy of the token
  939. is produced when the token is opened, if necessary.
  940. Arguments:
  941. ClientToken - Points to the token to be duplicated. This may be either
  942. a primary or impersonation token.
  943. ImpersonationLevel - The impersonation level to be assigned to the new
  944. token.
  945. RequestorMode - Mode to be assigned as the owner mode of the new token.
  946. DuplicateToken - Receives a pointer to the duplicate token.
  947. The token has not yet been inserted into any object table.
  948. No exceptions are expected when tring to set this OUT value.
  949. Return Value:
  950. STATUS_SUCCESS - The service successfully completed the requested
  951. operation.
  952. --*/
  953. {
  954. NTSTATUS Status;
  955. OBJECT_ATTRIBUTES ObjectAttributes;
  956. PTOKEN NewToken;
  957. PAGED_CODE();
  958. InitializeObjectAttributes(
  959. &ObjectAttributes,
  960. NULL,
  961. 0,
  962. NULL,
  963. NULL
  964. );
  965. Status = SepDuplicateToken(
  966. (PTOKEN)ClientToken, // ExistingToken
  967. &ObjectAttributes, // ObjectAttributes
  968. FALSE, // EffectiveOnly
  969. TokenImpersonation, // TokenType (target)
  970. ImpersonationLevel, // ImpersonationLevel
  971. RequestorMode, // RequestorMode
  972. &NewToken // DuplicateToken
  973. );
  974. if (NT_SUCCESS (Status)) {
  975. //
  976. // Insert the new token
  977. //
  978. Status = ObInsertObject( NewToken,
  979. NULL,
  980. 0,
  981. 0,
  982. NULL,
  983. NULL
  984. );
  985. }
  986. if (NT_SUCCESS (Status)) {
  987. *DuplicateToken = (PACCESS_TOKEN)NewToken;
  988. } else {
  989. *DuplicateToken = NULL;
  990. }
  991. return Status;
  992. }
  993. NTSTATUS
  994. NtFilterToken (
  995. IN HANDLE ExistingTokenHandle,
  996. IN ULONG Flags,
  997. IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
  998. IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
  999. IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
  1000. OUT PHANDLE NewTokenHandle
  1001. )
  1002. /*++
  1003. Routine Description:
  1004. Create a new token that is a subset of an existing token.
  1005. Arguments:
  1006. ExistingTokenHandle - Is a handle to a token already open for
  1007. TOKEN_DUPLICATE access.
  1008. Flags - Flags indicating additional filtering. The flags may be:
  1009. DISABLE_MAX_PRIVILEGE - Disable all privileges
  1010. SANDBOX_INERT - Record this SAIFER flag in the token.
  1011. SidsToDisable - Contains a list of sids and attributes. All sids with
  1012. the USE_FOR_DENY_ONLY attribute that also exist in the token will
  1013. cause the new token to have that sid set with the USE_FOR_DENY_ONLY
  1014. attribte.
  1015. PrivilegesToDelete - Privileges in this list that are present in the
  1016. existing token will not exist in the final token. This is similar
  1017. to duplicating a token effective only with these privileges set to
  1018. disabled.
  1019. RestrictedSids - Contains a list of SIDs and attributes that will be
  1020. stored in the RestrictedSids field of the new token. These SIDs
  1021. are used after a normal access check to futher restrict access.
  1022. The attributes of these groups are always SE_GROUP_MANDATORY |
  1023. SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT. If there already
  1024. exist RestrictedSids in the original token, these sids will be
  1025. appended.
  1026. NewTokenHandle - Receives the handle of the newly created token.
  1027. Return Value:
  1028. STATUS_SUCCESS - Indicates the operation was successful.
  1029. STATUS_INVALID_PARAMETER - Indicates one or more of the parameter values
  1030. was invalid. This value is returned if the target token is not
  1031. an impersonation token.
  1032. --*/
  1033. {
  1034. PTOKEN Token;
  1035. PTOKEN NewToken;
  1036. KPROCESSOR_MODE PreviousMode;
  1037. NTSTATUS Status = STATUS_SUCCESS;
  1038. ULONG CapturedSidCount = 0;
  1039. PSID_AND_ATTRIBUTES CapturedSids = NULL;
  1040. ULONG CapturedSidsLength = 0;
  1041. ULONG CapturedGroupCount = 0;
  1042. PSID_AND_ATTRIBUTES CapturedGroups = NULL;
  1043. ULONG CapturedGroupsLength = 0;
  1044. ULONG CapturedPrivilegeCount = 0;
  1045. PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
  1046. ULONG CapturedPrivilegesLength = 0;
  1047. ULONG Index;
  1048. HANDLE LocalHandle = NULL;
  1049. OBJECT_HANDLE_INFORMATION HandleInformation;
  1050. ACCESS_MASK EffectiveDesiredAccess;
  1051. PAGED_CODE();
  1052. PreviousMode = KeGetPreviousMode();
  1053. //
  1054. // Probe parameters
  1055. //
  1056. try {
  1057. //
  1058. // Make sure we can write the handle
  1059. //
  1060. ProbeForWriteHandle(NewTokenHandle);
  1061. //
  1062. // Capture Sids to remove
  1063. //
  1064. if (ARGUMENT_PRESENT(SidsToDisable)) {
  1065. ProbeForReadSmallStructure( SidsToDisable, sizeof(TOKEN_GROUPS), sizeof(ULONG) );
  1066. CapturedGroupCount = SidsToDisable->GroupCount;
  1067. Status = SeCaptureSidAndAttributesArray(
  1068. SidsToDisable->Groups,
  1069. CapturedGroupCount,
  1070. PreviousMode,
  1071. NULL, 0,
  1072. PagedPool,
  1073. TRUE,
  1074. &CapturedGroups,
  1075. &CapturedGroupsLength
  1076. );
  1077. }
  1078. //
  1079. // Capture PrivilegesToDelete
  1080. //
  1081. if (NT_SUCCESS(Status) && ARGUMENT_PRESENT(PrivilegesToDelete)) {
  1082. ProbeForReadSmallStructure( PrivilegesToDelete, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG) );
  1083. CapturedPrivilegeCount = PrivilegesToDelete->PrivilegeCount;
  1084. Status = SeCaptureLuidAndAttributesArray(
  1085. PrivilegesToDelete->Privileges,
  1086. CapturedPrivilegeCount,
  1087. PreviousMode,
  1088. NULL, 0,
  1089. PagedPool,
  1090. TRUE,
  1091. &CapturedPrivileges,
  1092. &CapturedPrivilegesLength
  1093. );
  1094. }
  1095. //
  1096. // Capture Restricted Sids
  1097. //
  1098. if (NT_SUCCESS(Status) && ARGUMENT_PRESENT(RestrictedSids)) {
  1099. ProbeForReadSmallStructure( RestrictedSids, sizeof(TOKEN_GROUPS), sizeof(ULONG) );
  1100. CapturedSidCount = RestrictedSids->GroupCount;
  1101. Status = SeCaptureSidAndAttributesArray(
  1102. RestrictedSids->Groups,
  1103. CapturedSidCount,
  1104. PreviousMode,
  1105. NULL, 0,
  1106. PagedPool,
  1107. TRUE,
  1108. &CapturedSids,
  1109. &CapturedSidsLength
  1110. );
  1111. }
  1112. } except(EXCEPTION_EXECUTE_HANDLER) {
  1113. Status = GetExceptionCode();
  1114. } // end_try
  1115. if (!NT_SUCCESS(Status)) {
  1116. goto Cleanup;
  1117. }
  1118. //
  1119. // Check that the attribtes are all zero for the restricted sids
  1120. //
  1121. for (Index = 0; Index < CapturedSidCount ; Index++ )
  1122. {
  1123. if (CapturedSids[Index].Attributes != 0) {
  1124. Status = STATUS_INVALID_PARAMETER;
  1125. goto Cleanup;
  1126. }
  1127. }
  1128. //
  1129. // Check the handle's access to the existing token and get
  1130. // a pointer to that token. Pick up the default desired
  1131. // access mask from the handle while we're at it.
  1132. //
  1133. Status = ObReferenceObjectByHandle(
  1134. ExistingTokenHandle, // Handle
  1135. TOKEN_DUPLICATE, // DesiredAccess
  1136. SeTokenObjectType, // ObjectType
  1137. PreviousMode, // AccessMode
  1138. (PVOID *)&Token, // Object
  1139. &HandleInformation // GrantedAccess
  1140. );
  1141. if ( !NT_SUCCESS(Status) ) {
  1142. goto Cleanup;
  1143. }
  1144. #ifdef TOKEN_DEBUG
  1145. ////////////////////////////////////////////////////////////////////////////
  1146. //
  1147. // Debug
  1148. SepAcquireTokenReadLock( Token );
  1149. DbgPrint("\n");
  1150. DbgPrint("\n");
  1151. DbgPrint("Token being filtered: \n");
  1152. SepDumpToken( Token );
  1153. SepReleaseTokenReadLock( Token );
  1154. // Debug
  1155. //
  1156. ////////////////////////////////////////////////////////////////////////////
  1157. #endif //TOKEN_DEBUG
  1158. //
  1159. // Check to see if an alternate desired access mask was provided.
  1160. //
  1161. EffectiveDesiredAccess = HandleInformation.GrantedAccess;
  1162. //
  1163. // Filter the existing token
  1164. //
  1165. NewToken = NULL;
  1166. Status = SepFilterToken(
  1167. Token,
  1168. PreviousMode,
  1169. Flags,
  1170. CapturedGroupCount,
  1171. CapturedGroups,
  1172. CapturedPrivilegeCount,
  1173. CapturedPrivileges,
  1174. CapturedSidCount,
  1175. CapturedSids,
  1176. CapturedSidsLength,
  1177. &NewToken
  1178. );
  1179. if (NT_SUCCESS(Status)) {
  1180. //
  1181. // Insert the new token
  1182. //
  1183. Status = ObInsertObject( NewToken,
  1184. NULL,
  1185. EffectiveDesiredAccess,
  1186. 0,
  1187. (PVOID *)NULL,
  1188. &LocalHandle
  1189. );
  1190. if (!NT_SUCCESS( Status )) {
  1191. #ifdef TOKEN_DEBUG
  1192. DbgPrint( "SE: ObInsertObject failed (%x) for token at %x\n", Status, NewToken );
  1193. #endif
  1194. }
  1195. } else
  1196. if (NewToken != NULL) {
  1197. #ifdef TOKEN_DEBUG
  1198. DbgPrint( "SE: SepFilterToken failed (%x) but allocated token at %x\n", Status, NewToken );
  1199. #endif
  1200. }
  1201. //
  1202. // We no longer need our reference to the source token
  1203. //
  1204. ObDereferenceObject( (PVOID)Token );
  1205. //
  1206. // Return the new handle
  1207. //
  1208. if (NT_SUCCESS(Status)) {
  1209. try { *NewTokenHandle = LocalHandle; }
  1210. except(EXCEPTION_EXECUTE_HANDLER) {
  1211. Status = GetExceptionCode();
  1212. }
  1213. }
  1214. Cleanup:
  1215. if (CapturedGroups != NULL) {
  1216. SeReleaseSidAndAttributesArray(
  1217. CapturedGroups,
  1218. PreviousMode,
  1219. TRUE
  1220. );
  1221. }
  1222. if (CapturedPrivileges != NULL) {
  1223. SeReleaseLuidAndAttributesArray(
  1224. CapturedPrivileges,
  1225. PreviousMode,
  1226. TRUE
  1227. );
  1228. }
  1229. if (CapturedSids != NULL) {
  1230. SeReleaseSidAndAttributesArray(
  1231. CapturedSids,
  1232. PreviousMode,
  1233. TRUE
  1234. );
  1235. }
  1236. return Status;
  1237. }
  1238. NTSTATUS
  1239. SeFilterToken (
  1240. IN PACCESS_TOKEN ExistingToken,
  1241. IN ULONG Flags,
  1242. IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
  1243. IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
  1244. IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
  1245. OUT PACCESS_TOKEN * NewToken
  1246. )
  1247. /*++
  1248. Routine Description:
  1249. Create a new token that is a subset of an existing token.
  1250. Arguments:
  1251. ExistingToken - Is a token already open for
  1252. TOKEN_DUPLICATE access.
  1253. Flags - Flags indicating additional filtering. The flags may be:
  1254. DISABLE_MAX_PRIVILEGE - Disable all privileges
  1255. SANDBOX_INERT - Record this SAIFER flag in the token.
  1256. SidsToDisable - Contains a list of sids and attributes. All sids with
  1257. the USE_FOR_DENY_ONLY attribute that also exist in the token will
  1258. cause the new token to have that sid set with the USE_FOR_DENY_ONLY
  1259. attribte.
  1260. PrivilegesToDelete - Privileges in this list that are present in the
  1261. existing token will not exist in the final token. This is similar
  1262. to duplicating a token effective only with these privileges set to
  1263. disabled.
  1264. RestrictedSids - Contains a list of SIDs and attributes that will be
  1265. stored in the RestrictedSids field of the new token. These SIDs
  1266. are used after a normal access check to futher restrict access.
  1267. The attributes of these groups are always SE_GROUP_MANDATORY |
  1268. SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT. If there already
  1269. exist RestrictedSids in the original token, these sids will be
  1270. appended.
  1271. NewToken - Receives a pointer to the newly created token.
  1272. Return Value:
  1273. STATUS_SUCCESS - Indicates the operation was successful.
  1274. STATUS_INVALID_PARAMETER - Indicates one or more of the parameter values
  1275. was invalid. This value is returned if the target token is not
  1276. an impersonation token.
  1277. --*/
  1278. {
  1279. PTOKEN Token;
  1280. PTOKEN FilteredToken = NULL;
  1281. KPROCESSOR_MODE PreviousMode;
  1282. NTSTATUS Status = STATUS_SUCCESS;
  1283. ULONG Index;
  1284. ULONG CapturedSidCount = 0;
  1285. PSID_AND_ATTRIBUTES CapturedSids = NULL;
  1286. ULONG CapturedSidsLength = 0;
  1287. ULONG CapturedGroupCount = 0;
  1288. PSID_AND_ATTRIBUTES CapturedGroups = NULL;
  1289. ULONG CapturedGroupsLength = 0;
  1290. ULONG CapturedPrivilegeCount = 0;
  1291. PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
  1292. ULONG CapturedPrivilegesLength = 0;
  1293. HANDLE LocalHandle;
  1294. OBJECT_HANDLE_INFORMATION HandleInformation;
  1295. ACCESS_MASK EffectiveDesiredAccess;
  1296. PAGED_CODE();
  1297. PreviousMode = KeGetPreviousMode();
  1298. //
  1299. // Probe parameters
  1300. //
  1301. *NewToken = NULL;
  1302. //
  1303. // Capture Sids to remove
  1304. //
  1305. if (ARGUMENT_PRESENT(SidsToDisable)) {
  1306. CapturedGroupCount = SidsToDisable->GroupCount;
  1307. CapturedGroups = SidsToDisable->Groups;
  1308. }
  1309. //
  1310. // Capture PrivilegesToDelete
  1311. //
  1312. if (ARGUMENT_PRESENT(PrivilegesToDelete)) {
  1313. CapturedPrivilegeCount = PrivilegesToDelete->PrivilegeCount;
  1314. CapturedPrivileges = PrivilegesToDelete->Privileges;
  1315. }
  1316. //
  1317. // Capture Restricted Sids
  1318. //
  1319. if (ARGUMENT_PRESENT(RestrictedSids)) {
  1320. CapturedSidCount = RestrictedSids->GroupCount;
  1321. CapturedSids = RestrictedSids->Groups;
  1322. //
  1323. // Check that the attribtes are all zero for the restricted sids
  1324. //
  1325. for (Index = 0; Index < CapturedSidCount ; Index++ ) {
  1326. if (CapturedSids[Index].Attributes != 0) {
  1327. return(STATUS_INVALID_PARAMETER);
  1328. }
  1329. }
  1330. }
  1331. //
  1332. // Check the handle's access to the existing token and get
  1333. // a pointer to that token. Pick up the default desired
  1334. // access mask from the handle while we're at it.
  1335. //
  1336. Token = (PTOKEN) ExistingToken;
  1337. #ifdef TOKEN_DEBUG
  1338. ////////////////////////////////////////////////////////////////////////////
  1339. //
  1340. // Debug
  1341. SepAcquireTokenReadLock( Token );
  1342. DbgPrint("\n");
  1343. DbgPrint("\n");
  1344. DbgPrint("Token being filtered: \n");
  1345. SepDumpToken( Token );
  1346. SepReleaseTokenReadLock( Token );
  1347. // Debug
  1348. //
  1349. ////////////////////////////////////////////////////////////////////////////
  1350. #endif //TOKEN_DEBUG
  1351. //
  1352. // Filter the existing token
  1353. //
  1354. Status = SepFilterToken(
  1355. Token,
  1356. KernelMode,
  1357. Flags,
  1358. CapturedGroupCount,
  1359. CapturedGroups,
  1360. CapturedPrivilegeCount,
  1361. CapturedPrivileges,
  1362. CapturedSidCount,
  1363. CapturedSids,
  1364. CapturedSidsLength,
  1365. &FilteredToken
  1366. );
  1367. if (NT_SUCCESS(Status)) {
  1368. //
  1369. // Insert the new token
  1370. //
  1371. Status = ObInsertObject( FilteredToken,
  1372. NULL,
  1373. 0,
  1374. 0,
  1375. NULL,
  1376. NULL
  1377. );
  1378. if (NT_SUCCESS( Status )) {
  1379. *NewToken = FilteredToken;
  1380. } else {
  1381. //
  1382. // ObInsertObject dereferences the passed object on failure
  1383. // so we don't have to clean up here.
  1384. //
  1385. #ifdef TOKEN_DEBUG
  1386. DbgPrint( "SE: ObInsertObject failed (%x) for token at %x\n", Status, NewToken );
  1387. #endif
  1388. }
  1389. }
  1390. return Status;
  1391. }
  1392. NTSTATUS
  1393. SeFastFilterToken(
  1394. IN PACCESS_TOKEN ExistingToken,
  1395. IN KPROCESSOR_MODE RequestorMode,
  1396. IN ULONG Flags,
  1397. IN ULONG GroupCount,
  1398. IN PSID_AND_ATTRIBUTES GroupsToDisable OPTIONAL,
  1399. IN ULONG PrivilegeCount,
  1400. IN PLUID_AND_ATTRIBUTES PrivilegesToDelete OPTIONAL,
  1401. IN ULONG SidCount,
  1402. IN PSID_AND_ATTRIBUTES RestrictedSids OPTIONAL,
  1403. IN ULONG SidLength,
  1404. OUT PACCESS_TOKEN * FilteredToken
  1405. )
  1406. /*++
  1407. Routine Description:
  1408. This is a fast wrapper for the Ps code to filter a token
  1409. inline of an impersonate.
  1410. This routine acquires a read lock on the token being filtered.
  1411. Arguments:
  1412. ExistingToken - Points to the token to be duplicated.
  1413. RequestorMode - Mode of client requesting the token be duplicated.
  1414. Flags - Flags indicating additional filtering. The flags may be:
  1415. DISABLE_MAX_PRIVILEGE - Disable all privileges
  1416. SANDBOX_INERT - Record this SAIFER flag in the token.
  1417. GroupCount - Count of groups to disable
  1418. GroupsToDisable - Contains a list of sids and attributes. All sids with
  1419. the USE_FOR_DENY_ONLY attribute that also exist in the token will
  1420. cause the new token to have that sid set with the USE_FOR_DENY_ONLY
  1421. attribute.
  1422. PrivilegeCount - Count of privileges to delete
  1423. PrivilegesToDelete - Privileges in this list that are present in the
  1424. existing token will not exist in the final token. This is similar
  1425. to duplicating a token effective only with these privileges set to
  1426. disabled.
  1427. SidCount - Count of restricted sids to add.
  1428. RestrictedSids - Contains a list of SIDs and attributes that will be
  1429. stored in the RestrictedSids field of the new token. These SIDs
  1430. are used after a normal access check to futher restrict access.
  1431. The attributes of these groups are always SE_GROUP_MANDATORY |
  1432. SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT. If there already
  1433. exist RestrictedSids in the original token, these sids will be
  1434. appended.
  1435. SidLength - Length of added restricted sids.
  1436. FilteredToken - Receives a pointer to the duplicate token.
  1437. The token has not yet been inserted into any object table.
  1438. No exceptions are expected when tring to set this OUT value.
  1439. Return Value:
  1440. STATUS_SUCCESS - The service successfully completed the requested
  1441. operation.
  1442. --*/
  1443. {
  1444. NTSTATUS Status;
  1445. PTOKEN NewToken;
  1446. Status = SepFilterToken( (PTOKEN) ExistingToken,
  1447. RequestorMode,
  1448. Flags,
  1449. GroupCount,
  1450. GroupsToDisable,
  1451. PrivilegeCount,
  1452. PrivilegesToDelete,
  1453. SidCount,
  1454. RestrictedSids,
  1455. SidLength,
  1456. &NewToken );
  1457. if (NT_SUCCESS (Status)) {
  1458. //
  1459. // Insert the new token
  1460. //
  1461. Status = ObInsertObject( NewToken,
  1462. NULL,
  1463. 0,
  1464. 0,
  1465. NULL,
  1466. NULL
  1467. );
  1468. }
  1469. if (NT_SUCCESS( Status )) {
  1470. *FilteredToken = (PACCESS_TOKEN) NewToken;
  1471. } else {
  1472. *FilteredToken = NULL;
  1473. }
  1474. return Status;
  1475. }
  1476. NTSTATUS
  1477. SepFilterToken(
  1478. IN PTOKEN ExistingToken,
  1479. IN KPROCESSOR_MODE RequestorMode,
  1480. IN ULONG Flags,
  1481. IN ULONG GroupCount,
  1482. IN PSID_AND_ATTRIBUTES GroupsToDisable OPTIONAL,
  1483. IN ULONG PrivilegeCount,
  1484. IN PLUID_AND_ATTRIBUTES PrivilegesToDelete OPTIONAL,
  1485. IN ULONG SidCount,
  1486. IN PSID_AND_ATTRIBUTES RestrictedSids OPTIONAL,
  1487. IN ULONG SidLength,
  1488. OUT PTOKEN * FilteredToken
  1489. )
  1490. /*++
  1491. Routine Description:
  1492. This routine does the bulk of the work to actually filter
  1493. a token. This routine assumes all access validation and argument
  1494. probing has been performed.
  1495. THE CALLER IS RESPONSIBLE FOR CHECKING SUBJECT RIGHTS TO CREATE THE
  1496. TYPE OF TOKEN BEING CREATED.
  1497. This routine acquires a read lock on the token being filtered.
  1498. Arguments:
  1499. ExistingToken - Points to the token to be duplicated.
  1500. RequestorMode - Mode of client requesting the token be duplicated.
  1501. Flags - Flags indicating additional filtering. The flags may be:
  1502. DISABLE_MAX_PRIVILEGE - Disable all privileges
  1503. SANDBOX_INERT - Record this SAIFER flag in the token.
  1504. GroupCount - Count of groups to disable
  1505. GroupsToDisable - Contains a list of sids and attributes. All sids with
  1506. the USE_FOR_DENY_ONLY attribute that also exist in the token will
  1507. cause the new token to have that sid set with the USE_FOR_DENY_ONLY
  1508. attribute.
  1509. PrivilegeCount - Count of privileges to delete
  1510. PrivilegesToDelete - Privileges in this list that are present in the
  1511. existing token will not exist in the final token. This is similar
  1512. to duplicating a token effective only with these privileges set to
  1513. disabled.
  1514. SidCount - Count of restricted sids to add.
  1515. RestrictedSids - Contains a list of SIDs and attributes that will be
  1516. stored in the RestrictedSids field of the new token. These SIDs
  1517. are used after a normal access check to futher restrict access.
  1518. The attributes of these groups are always SE_GROUP_MANDATORY |
  1519. SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT. If there already
  1520. exist RestrictedSids in the original token, the intersection of the
  1521. two sets will be in the final tokense sids will be.
  1522. SidLength - Length of added restricted sids.
  1523. FilteredToken - Receives a pointer to the duplicate token.
  1524. The token has not yet been inserted into any object table.
  1525. No exceptions are expected when tring to set this OUT value.
  1526. Return Value:
  1527. STATUS_SUCCESS - The service successfully completed the requested
  1528. operation.
  1529. --*/
  1530. {
  1531. NTSTATUS Status;
  1532. PTOKEN NewToken;
  1533. PULONG DynamicPart;
  1534. ULONG PagedPoolSize;
  1535. ULONG NonPagedPoolSize;
  1536. ULONG TokenBodyLength;
  1537. ULONG FieldOffset;
  1538. ULONG_PTR NextFree;
  1539. PSID NextSidFree;
  1540. ULONG VariableLength;
  1541. ULONG Pad;
  1542. ULONG DynamicSize;
  1543. ULONG Index;
  1544. PSECURITY_TOKEN_PROXY_DATA NewProxyData;
  1545. PSECURITY_TOKEN_AUDIT_DATA NewAuditData;
  1546. OBJECT_ATTRIBUTES ObjA ;
  1547. PERESOURCE TokenLock;
  1548. #if DBG || TOKEN_LEAK_MONITOR
  1549. ULONG Frames;
  1550. #endif
  1551. PAGED_CODE();
  1552. ASSERT( sizeof(SECURITY_IMPERSONATION_LEVEL) <= sizeof(ULONG) );
  1553. if (ARGUMENT_PRESENT(ExistingToken->ProxyData)) {
  1554. Status = SepCopyProxyData(
  1555. &NewProxyData,
  1556. ExistingToken->ProxyData
  1557. );
  1558. if (!NT_SUCCESS(Status)) {
  1559. return( Status );
  1560. }
  1561. } else {
  1562. NewProxyData = NULL;
  1563. }
  1564. if (ARGUMENT_PRESENT( ExistingToken->AuditData )) {
  1565. NewAuditData = ExAllocatePool( PagedPool, sizeof( SECURITY_TOKEN_AUDIT_DATA ));
  1566. if (NewAuditData == NULL) {
  1567. SepFreeProxyData( NewProxyData );
  1568. return( STATUS_INSUFFICIENT_RESOURCES );
  1569. } else {
  1570. *NewAuditData = *(ExistingToken->AuditData);
  1571. }
  1572. } else {
  1573. NewAuditData = NULL;
  1574. }
  1575. TokenLock = (PERESOURCE)ExAllocatePoolWithTag( NonPagedPool, sizeof( ERESOURCE ), 'dTeS' );
  1576. if (TokenLock == NULL) {
  1577. if (NewAuditData != NULL) {
  1578. ExFreePool( NewAuditData );
  1579. }
  1580. SepFreeProxyData( NewProxyData );
  1581. return( STATUS_INSUFFICIENT_RESOURCES );
  1582. }
  1583. //
  1584. // Create a new object
  1585. //
  1586. VariableLength = ExistingToken->VariableLength + SidLength;
  1587. #if defined(_WIN64)
  1588. //
  1589. // Account for some additional alignment requirements later on.
  1590. //
  1591. VariableLength += sizeof(ULONG);
  1592. #endif
  1593. TokenBodyLength = FIELD_OFFSET(TOKEN, VariablePart) +
  1594. VariableLength;
  1595. NonPagedPoolSize = TokenBodyLength;
  1596. PagedPoolSize = ExistingToken->DynamicCharged;
  1597. InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
  1598. Status = ObCreateObject(
  1599. RequestorMode, // ProbeMode
  1600. SeTokenObjectType, // ObjectType
  1601. NULL, // ObjectAttributes
  1602. RequestorMode, // OwnershipMode
  1603. NULL, // ParseContext
  1604. TokenBodyLength, // ObjectBodySize
  1605. PagedPoolSize, // PagedPoolCharge
  1606. NonPagedPoolSize, // NonPagedPoolCharge
  1607. (PVOID *)&NewToken // Return pointer to object
  1608. );
  1609. if (!NT_SUCCESS(Status)) {
  1610. SepFreeProxyData( NewProxyData );
  1611. ExFreePool( TokenLock );
  1612. if (NewAuditData != NULL) {
  1613. ExFreePool( NewAuditData );
  1614. }
  1615. return Status;
  1616. }
  1617. //
  1618. // The following fields differ in the new token.
  1619. //
  1620. NewToken->TokenLock = TokenLock;
  1621. ExInitializeResourceLite( NewToken->TokenLock );
  1622. //
  1623. // Allocate a new modified Id to distinguish this token from the orignial
  1624. // token.
  1625. //
  1626. ExAllocateLocallyUniqueId( &(NewToken->ModifiedId) );
  1627. ExAllocateLocallyUniqueId( &(NewToken->TokenId) );
  1628. NewToken->TokenInUse = FALSE;
  1629. NewToken->AuthenticationId = ExistingToken->AuthenticationId;
  1630. NewToken->TokenSource = ExistingToken->TokenSource;
  1631. NewToken->DynamicAvailable = 0;
  1632. NewToken->RestrictedSidCount = 0;
  1633. NewToken->VariableLength = VariableLength;
  1634. NewToken->ProxyData = NewProxyData;
  1635. NewToken->AuditData = NewAuditData;
  1636. NewToken->ParentTokenId = ExistingToken->TokenId;
  1637. NewToken->TokenType = ExistingToken->TokenType;
  1638. NewToken->ImpersonationLevel = ExistingToken->ImpersonationLevel;
  1639. NewToken->ExpirationTime = ExistingToken->ExpirationTime;
  1640. //
  1641. // acquire exclusive access to the source token
  1642. //
  1643. SepAcquireTokenReadLock( ExistingToken );
  1644. //
  1645. // Main Body initialization
  1646. //
  1647. //
  1648. // The following fields are unchanged from the source token.
  1649. // Although some may change if EffectiveOnly has been specified.
  1650. //
  1651. NewToken->DynamicCharged = ExistingToken->DynamicCharged;
  1652. NewToken->DefaultOwnerIndex = ExistingToken->DefaultOwnerIndex;
  1653. NewToken->UserAndGroupCount = ExistingToken->UserAndGroupCount;
  1654. NewToken->SessionId = ExistingToken->SessionId;
  1655. NewToken->PrivilegeCount = ExistingToken->PrivilegeCount;
  1656. NewToken->TokenFlags = ExistingToken->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
  1657. NewToken->AuditPolicy = ExistingToken->AuditPolicy;
  1658. //
  1659. // Increment the reference count for this logon session
  1660. // This can not fail, since there is already a token in this logon
  1661. // session.
  1662. //
  1663. Status = SepDuplicateLogonSessionReference (NewToken, ExistingToken);
  1664. ASSERT( NT_SUCCESS(Status) );
  1665. if (!NT_SUCCESS (Status)) {
  1666. SepReleaseTokenReadLock( ExistingToken );
  1667. NewToken->DynamicPart = NULL;
  1668. ObDereferenceObject (NewToken);
  1669. return Status;
  1670. }
  1671. #if DBG || TOKEN_LEAK_MONITOR
  1672. NewToken->ProcessCid = PsGetCurrentThread()->Cid.UniqueProcess;
  1673. NewToken->ThreadCid = PsGetCurrentThread()->Cid.UniqueThread;
  1674. NewToken->CreateMethod = 0xF; // Filter
  1675. NewToken->Count = 0;
  1676. NewToken->CaptureCount = 0;
  1677. RtlCopyMemory(
  1678. NewToken->ImageFileName,
  1679. PsGetCurrentProcess()->ImageFileName,
  1680. min(sizeof(NewToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName))
  1681. );
  1682. Frames = RtlWalkFrameChain(
  1683. (PVOID)NewToken->CreateTrace,
  1684. TRACE_SIZE,
  1685. 0
  1686. );
  1687. if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
  1688. RtlWalkFrameChain(
  1689. (PVOID)&NewToken->CreateTrace[Frames],
  1690. TRACE_SIZE - Frames,
  1691. 1
  1692. );
  1693. }
  1694. SepAddTokenLogonSession(NewToken);
  1695. #endif
  1696. //
  1697. // If the caller passed in the sandbox inert flag then record it.
  1698. //
  1699. if ((Flags & SANDBOX_INERT) != 0) {
  1700. NewToken->TokenFlags |= TOKEN_SANDBOX_INERT;
  1701. }
  1702. //
  1703. // Compute the beginning portion of the variable part, which contains the
  1704. // sid & attributes arrays and the privilege set.
  1705. //
  1706. //
  1707. // First copy the privileges. We will later remove the ones that are
  1708. // to be deleted.
  1709. //
  1710. NextFree = (ULONG_PTR)(&NewToken->VariablePart);
  1711. NewToken->Privileges = (PLUID_AND_ATTRIBUTES)NextFree;
  1712. RtlCopyLuidAndAttributesArray( ExistingToken->PrivilegeCount,
  1713. ExistingToken->Privileges,
  1714. (PLUID_AND_ATTRIBUTES)NextFree
  1715. );
  1716. NextFree += (ExistingToken->PrivilegeCount * (ULONG)sizeof(LUID_AND_ATTRIBUTES));
  1717. VariableLength -= ( (ExistingToken->PrivilegeCount * (ULONG)sizeof(LUID_AND_ATTRIBUTES)) );
  1718. #if defined(_WIN64)
  1719. //
  1720. // At this point NextFree is 4-byte aligned, so no alignment work
  1721. // is necessary for the 32-bit product. For Win64, ensure that NextFree
  1722. // is 8-byte aligned.
  1723. //
  1724. Pad = (ULONG)(NextFree & (sizeof(PVOID)-1));
  1725. if (Pad != 0) {
  1726. Pad = sizeof(PVOID) - Pad;
  1727. NextFree += Pad;
  1728. VariableLength -= Pad;
  1729. }
  1730. #endif
  1731. //
  1732. // Figure out the count of SIDs. This is the count of users&groups +
  1733. // the number of existing restricuted SIDs plus the number of new
  1734. // restricted Sids
  1735. //
  1736. #define MAX(_x_,_y_) ((_x_) > (_y_) ? (_x_) : (_y_))
  1737. NextSidFree = (PSID) (NextFree + (ExistingToken->UserAndGroupCount +
  1738. MAX(ExistingToken->RestrictedSidCount,SidCount)) * sizeof(SID_AND_ATTRIBUTES));
  1739. NewToken->UserAndGroups = (PSID_AND_ATTRIBUTES) NextFree;
  1740. //
  1741. // Copy in the existing users & groups. We will later flag the ones
  1742. // to be disabled.
  1743. //
  1744. Status = RtlCopySidAndAttributesArray(
  1745. ExistingToken->UserAndGroupCount,
  1746. ExistingToken->UserAndGroups,
  1747. VariableLength,
  1748. (PSID_AND_ATTRIBUTES)NextFree,
  1749. NextSidFree,
  1750. &NextSidFree,
  1751. &VariableLength
  1752. );
  1753. ASSERT(NT_SUCCESS(Status));
  1754. NextFree += (ExistingToken->UserAndGroupCount * (ULONG)sizeof(SID_AND_ATTRIBUTES));
  1755. //
  1756. // Now add all the existing restricted sids. We need to take the
  1757. // intersection of the two sets.
  1758. //
  1759. NewToken->RestrictedSids = (PSID_AND_ATTRIBUTES) NextFree;
  1760. for (Index = 0; Index < SidCount ; Index++ ) {
  1761. if ( ( ExistingToken->RestrictedSidCount == 0 ) ||
  1762. SepSidInSidAndAttributes(
  1763. ExistingToken->RestrictedSids,
  1764. ExistingToken->RestrictedSidCount,
  1765. NULL, // no self sid
  1766. RestrictedSids[Index].Sid
  1767. )) {
  1768. Status = RtlCopySidAndAttributesArray(
  1769. 1,
  1770. &RestrictedSids[Index],
  1771. VariableLength,
  1772. (PSID_AND_ATTRIBUTES)NextFree,
  1773. NextSidFree,
  1774. &NextSidFree,
  1775. &VariableLength
  1776. );
  1777. ASSERT(NT_SUCCESS(Status));
  1778. NextFree += sizeof(SID_AND_ATTRIBUTES);
  1779. NewToken->RestrictedSids[NewToken->RestrictedSidCount].Attributes =
  1780. SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
  1781. NewToken->RestrictedSidCount++;
  1782. }
  1783. }
  1784. //
  1785. // Allocate the dynamic portion
  1786. //
  1787. DynamicSize = SeLengthSid( ExistingToken->PrimaryGroup );
  1788. if (ExistingToken->DefaultDacl) {
  1789. DynamicSize += ExistingToken->DefaultDacl->AclSize;
  1790. }
  1791. DynamicPart = (PULONG)ExAllocatePoolWithTag(
  1792. PagedPool,
  1793. DynamicSize,
  1794. 'dTeS'
  1795. );
  1796. NewToken->DynamicPart = DynamicPart;
  1797. if (DynamicPart == NULL) {
  1798. SepReleaseTokenReadLock( ExistingToken );
  1799. ObDereferenceObject( NewToken );
  1800. return( STATUS_INSUFFICIENT_RESOURCES );
  1801. }
  1802. //
  1803. // Make sure the new token has some restrictions.
  1804. // If it doesn't, then we've ended up with a token
  1805. // that gives us more access than the original,
  1806. // which we don't want.
  1807. //
  1808. if ((ExistingToken->RestrictedSidCount != 0) &&
  1809. (NewToken->RestrictedSidCount == 0)) {
  1810. SepReleaseTokenReadLock( ExistingToken );
  1811. Status = STATUS_INVALID_PARAMETER;
  1812. //
  1813. // Cleanup. ObDereferenceObject will cause the logon
  1814. // session to be dereferenced, and will free the proxy data
  1815. // as well as the audit data.
  1816. //
  1817. // See SepTokenDeleteMethod(), which is called by
  1818. // the object manager when the token object is
  1819. // being freed.
  1820. //
  1821. ObDereferenceObject( NewToken );
  1822. return(Status);
  1823. }
  1824. //
  1825. // If there are any restricted sids in the token, turn on the restricted
  1826. // flag
  1827. //
  1828. if (NewToken->RestrictedSidCount > 0) {
  1829. NewToken->TokenFlags |= TOKEN_IS_RESTRICTED;
  1830. }
  1831. //
  1832. // Copy and initialize the dynamic part.
  1833. // The dynamic part is assumed to be position independent.
  1834. //
  1835. RtlCopyMemory( (PVOID)DynamicPart,
  1836. (PVOID)(ExistingToken->DynamicPart),
  1837. DynamicSize
  1838. );
  1839. //
  1840. // If present, set the address of the default Dacl
  1841. //
  1842. if (ARGUMENT_PRESENT(ExistingToken->DefaultDacl)) {
  1843. ASSERT( (ULONG_PTR)(ExistingToken->DefaultDacl) >=
  1844. (ULONG_PTR)(ExistingToken->DynamicPart) );
  1845. FieldOffset = (ULONG)((ULONG_PTR)(ExistingToken->DefaultDacl) -
  1846. (ULONG_PTR)(ExistingToken->DynamicPart));
  1847. NewToken->DefaultDacl = (PACL)(FieldOffset + (ULONG_PTR)DynamicPart);
  1848. } else {
  1849. NewToken->DefaultDacl = NULL;
  1850. }
  1851. //
  1852. // Set the address of the primary group
  1853. //
  1854. ASSERT(ARGUMENT_PRESENT(ExistingToken->PrimaryGroup));
  1855. ASSERT( (ULONG_PTR)(ExistingToken->PrimaryGroup) >=
  1856. (ULONG_PTR)(ExistingToken->DynamicPart) );
  1857. FieldOffset = (ULONG)((ULONG_PTR)(ExistingToken->PrimaryGroup) -
  1858. (ULONG_PTR)(ExistingToken->DynamicPart));
  1859. //
  1860. // Release the source token.
  1861. //
  1862. SepReleaseTokenReadLock( ExistingToken );
  1863. NewToken->PrimaryGroup = (PACL)(FieldOffset + (ULONG_PTR)(DynamicPart));
  1864. //
  1865. // For the time being, take the easy way to generating an "EffectiveOnly"
  1866. // duplicate. That is, use the same space required of the original, just
  1867. // eliminate any IDs or privileges not active.
  1868. //
  1869. // Ultimately, if duplication becomes a common operation, then it will be
  1870. // worthwhile to recalculate the actual space needed and copy only the
  1871. // effective IDs/privileges into the new token.
  1872. //
  1873. SepRemoveDisabledGroupsAndPrivileges(
  1874. NewToken,
  1875. Flags,
  1876. GroupCount,
  1877. GroupsToDisable,
  1878. PrivilegeCount,
  1879. PrivilegesToDelete
  1880. );
  1881. #ifdef TOKEN_DEBUG
  1882. ////////////////////////////////////////////////////////////////////////////
  1883. //
  1884. // Debug
  1885. DbgPrint("\n");
  1886. DbgPrint("\n");
  1887. DbgPrint("\n");
  1888. DbgPrint("Filter token:\n");
  1889. SepDumpToken( NewToken );
  1890. // Debug
  1891. //
  1892. ////////////////////////////////////////////////////////////////////////////
  1893. #endif //TOKEN_DEBUG
  1894. //
  1895. // If the NewToken inherited an active SEP_AUDIT_POLICY from ExistingToken,
  1896. // then increment the counter of tokens with policies.
  1897. //
  1898. if ( NewToken->AuditPolicy.Overlay ) {
  1899. SepModifyTokenPolicyCounter(&NewToken->AuditPolicy, TRUE);
  1900. }
  1901. #if DBG || TOKEN_LEAK_MONITOR
  1902. if (SepTokenLeakTracking && SepTokenLeakMethodWatch == 0xF && PsGetCurrentProcess()->UniqueProcessId == SepTokenLeakProcessCid) {
  1903. NewToken->Count = InterlockedIncrement(&SepTokenLeakMethodCount);
  1904. if (NewToken->Count >= SepTokenLeakBreakCount) {
  1905. DbgPrint("\nToken number 0x%x = 0x%x\n", NewToken->Count, NewToken);
  1906. DbgBreakPoint();
  1907. }
  1908. }
  1909. #endif
  1910. (*FilteredToken) = NewToken;
  1911. return Status;
  1912. }