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.

1336 lines
36 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Tokenset.c
  5. Abstract:
  6. This module implements the SET function for the executive
  7. token object.
  8. Author:
  9. Jim Kelly (JimK) 15-June-1990
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #pragma hdrstop
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE,NtSetInformationToken)
  16. #pragma alloc_text(PAGE,SepExpandDynamic)
  17. #pragma alloc_text(PAGE,SepFreePrimaryGroup)
  18. #pragma alloc_text(PAGE,SepFreeDefaultDacl)
  19. #pragma alloc_text(PAGE,SepAppendPrimaryGroup)
  20. #pragma alloc_text(PAGE,SepAppendDefaultDacl)
  21. #pragma alloc_text(PAGE,SeSetSessionIdToken)
  22. #pragma alloc_text(PAGE,SepModifyTokenPolicyCounter)
  23. #endif
  24. NTSTATUS
  25. NtSetInformationToken (
  26. IN HANDLE TokenHandle,
  27. IN TOKEN_INFORMATION_CLASS TokenInformationClass,
  28. IN PVOID TokenInformation,
  29. IN ULONG TokenInformationLength
  30. )
  31. /*++
  32. Routine Description:
  33. Modify information in a specified token.
  34. Arguments:
  35. TokenHandle - Provides a handle to the token to operate on.
  36. TokenInformationClass - The token information class being set.
  37. TokenInformation - The buffer containing the new values for the
  38. specified class of information. The buffer must be aligned
  39. on at least a longword boundary. The actual structures
  40. provided are dependent upon the information class specified,
  41. as defined in the TokenInformationClass parameter
  42. description.
  43. TokenInformation Format By Information Class:
  44. TokenUser => This value is not a valid value for this API.
  45. The User ID may not be replaced.
  46. TokenGroups => This value is not a valid value for this
  47. API. The Group IDs may not be replaced. However, groups
  48. may be enabled and disabled using NtAdjustGroupsToken().
  49. TokenPrivileges => This value is not a valid value for
  50. this API. Privilege information may not be replaced.
  51. However, privileges may be explicitly enabled and disabled
  52. using the NtAdjustPrivilegesToken API.
  53. TokenOwner => TOKEN_OWNER data structure.
  54. TOKEN_ADJUST_DEFAULT access is needed to replace this
  55. information in a token. The owner values that may be
  56. specified are restricted to the user and group IDs with an
  57. attribute indicating they may be assigned as the owner of
  58. objects.
  59. TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure.
  60. TOKEN_ADJUST_DEFAULT access is needed to replace this
  61. information in a token. The primary group values that may
  62. be specified are restricted to be one of the group IDs
  63. already in the token.
  64. TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure.
  65. TOKEN_ADJUST_DEFAULT access is needed to replace this
  66. information in a token. The ACL provided as a new default
  67. discretionary ACL is not validated for structural
  68. correctness or consistency.
  69. TokenSource => This value is not a valid value for this
  70. API. The source name and context handle may not be
  71. replaced.
  72. TokenStatistics => This value is not a valid value for this
  73. API. The statistics of a token are read-only.
  74. TokenSessionId => ULONG to set the token session. Must have
  75. TOKEN_ADJUST_SESSIONID and TCB privilege.
  76. TokenSessionReference => ULONG. Must be zero. Must have
  77. TCB privilege to dereference the logon session. This info class
  78. will remove a reference for the logon session, and mark the token
  79. as not referencing the session.
  80. TokenAuditPolicy => TOKEN_AUDIT_POLICY structure. This sets the per
  81. user policy for the token, and all tokens derived from it. Requires
  82. TCB privilege.
  83. TokenParent => TOKEN_PARENT structure. The parent id can be set
  84. by a caller with TCB privilege. The token id cannot.
  85. TokenInformationLength - Indicates the length, in bytes, of the
  86. TokenInformation buffer. This is only the length of the primary
  87. buffer. All extensions of the primary buffer are self describing.
  88. Return Value:
  89. STATUS_SUCCESS - The operation was successful.
  90. STATUS_INVALID_OWNER - The ID specified to be an owner (or
  91. default owner) is not one the caller may assign as the owner
  92. of an object.
  93. STATUS_INVALID_INFO_CLASS - The specified information class is
  94. not one that may be specified in this API.
  95. STATUS_ALLOTTED_SPACE_EXCEEDED - The space allotted for storage
  96. of the default discretionary access control and the primary
  97. group ID is not large enough to accept the new value of one
  98. of these fields.
  99. --*/
  100. {
  101. KPROCESSOR_MODE PreviousMode;
  102. NTSTATUS Status;
  103. PTOKEN Token;
  104. ULONG Index;
  105. BOOLEAN Found;
  106. BOOLEAN TokenModified = FALSE;
  107. ULONG NewLength;
  108. ULONG CurrentLength;
  109. PSID CapturedOwner;
  110. PSID CapturedPrimaryGroup;
  111. PACL CapturedDefaultDacl;
  112. ACCESS_MASK DesiredAccess;
  113. PAGED_CODE();
  114. //
  115. // Get previous processor mode and probe input buffer if necessary.
  116. //
  117. PreviousMode = KeGetPreviousMode();
  118. if (PreviousMode != KernelMode) {
  119. try {
  120. //
  121. // This just probes the main part of the information buffer.
  122. // Any information class-specific data hung off the primary
  123. // buffer are self describing and must be probed separately
  124. // below.
  125. //
  126. ProbeForRead(
  127. TokenInformation,
  128. TokenInformationLength,
  129. sizeof(ULONG)
  130. );
  131. } except(EXCEPTION_EXECUTE_HANDLER) {
  132. return GetExceptionCode();
  133. }
  134. }
  135. //
  136. // Return error if not legal class
  137. //
  138. if ( (TokenInformationClass != TokenOwner) &&
  139. (TokenInformationClass != TokenPrimaryGroup) &&
  140. (TokenInformationClass != TokenSessionId) &&
  141. (TokenInformationClass != TokenDefaultDacl) &&
  142. (TokenInformationClass != TokenSessionReference) &&
  143. (TokenInformationClass != TokenAuditPolicy) &&
  144. (TokenInformationClass != TokenOrigin) ) {
  145. return STATUS_INVALID_INFO_CLASS;
  146. }
  147. //
  148. // Check access rights and reference token
  149. //
  150. DesiredAccess = TOKEN_ADJUST_DEFAULT;
  151. if (TokenInformationClass == TokenSessionId) {
  152. DesiredAccess |= TOKEN_ADJUST_SESSIONID;
  153. }
  154. Status = ObReferenceObjectByHandle(
  155. TokenHandle, // Handle
  156. DesiredAccess, // DesiredAccess
  157. SeTokenObjectType, // ObjectType
  158. PreviousMode, // AccessMode
  159. (PVOID *)&Token, // Object
  160. NULL // GrantedAccess
  161. );
  162. if ( !NT_SUCCESS(Status) ) {
  163. return Status;
  164. }
  165. //
  166. // Case on information class.
  167. //
  168. switch ( TokenInformationClass ) {
  169. case TokenOwner:
  170. //
  171. // Make sure the buffer is large enough to hold the
  172. // necessary information class data structure.
  173. //
  174. if (TokenInformationLength < (ULONG)sizeof(TOKEN_OWNER)) {
  175. ObDereferenceObject( Token );
  176. return STATUS_INFO_LENGTH_MISMATCH;
  177. }
  178. //
  179. // Capture and copy
  180. try {
  181. //
  182. // Capture Owner SID
  183. //
  184. CapturedOwner = ((PTOKEN_OWNER)TokenInformation)->Owner;
  185. Status = SeCaptureSid(
  186. CapturedOwner,
  187. PreviousMode,
  188. NULL, 0,
  189. PagedPool,
  190. TRUE,
  191. &CapturedOwner
  192. );
  193. } except(EXCEPTION_EXECUTE_HANDLER) {
  194. ObDereferenceObject( Token );
  195. return GetExceptionCode();
  196. }
  197. if (!NT_SUCCESS(Status)) {
  198. ObDereferenceObject( Token );
  199. return Status;
  200. }
  201. Index = 0;
  202. //
  203. // Gain write access to the token.
  204. //
  205. SepAcquireTokenWriteLock( Token );
  206. //
  207. // Walk through the list of user and group IDs looking
  208. // for a match to the specified SID. If one is found,
  209. // make sure it may be assigned as an owner. If it can,
  210. // then set the index in the token's OwnerIndex field.
  211. // Otherwise, return invalid owner error.
  212. //
  213. while (Index < Token->UserAndGroupCount) {
  214. try {
  215. Found = RtlEqualSid(
  216. CapturedOwner,
  217. Token->UserAndGroups[Index].Sid
  218. );
  219. if ( Found ) {
  220. if ( SepIdAssignableAsOwner(Token,Index) ){
  221. Token->DefaultOwnerIndex = Index;
  222. TokenModified = TRUE;
  223. Status = STATUS_SUCCESS;
  224. } else {
  225. Status = STATUS_INVALID_OWNER;
  226. } //endif assignable
  227. SepReleaseTokenWriteLock( Token, TokenModified );
  228. ObDereferenceObject( Token );
  229. SeReleaseSid( CapturedOwner, PreviousMode, TRUE);
  230. return Status;
  231. } //endif Found
  232. } except(EXCEPTION_EXECUTE_HANDLER) {
  233. SepReleaseTokenWriteLock( Token, TokenModified );
  234. ObDereferenceObject( Token );
  235. SeReleaseSid( CapturedOwner, PreviousMode, TRUE);
  236. return GetExceptionCode();
  237. } //endtry
  238. Index += 1;
  239. } //endwhile
  240. SepReleaseTokenWriteLock( Token, TokenModified );
  241. ObDereferenceObject( Token );
  242. SeReleaseSid( CapturedOwner, PreviousMode, TRUE);
  243. return STATUS_INVALID_OWNER;
  244. case TokenPrimaryGroup:
  245. //
  246. // Assuming everything works out, the strategy is to move everything
  247. // in the Dynamic part of the token (exept the primary group) to
  248. // the beginning of the dynamic part, freeing up the entire end of
  249. // the dynamic part for the new primary group.
  250. //
  251. //
  252. // Make sure the buffer is large enough to hold the
  253. // necessary information class data structure.
  254. //
  255. if (TokenInformationLength < (ULONG)sizeof(TOKEN_PRIMARY_GROUP)) {
  256. ObDereferenceObject( Token );
  257. return STATUS_INFO_LENGTH_MISMATCH;
  258. }
  259. //
  260. // Capture And Validate TOKEN_PRIMARY_GROUP and corresponding SID.
  261. //
  262. try {
  263. CapturedPrimaryGroup =
  264. ((PTOKEN_PRIMARY_GROUP)TokenInformation)->PrimaryGroup;
  265. Status = SeCaptureSid(
  266. CapturedPrimaryGroup,
  267. PreviousMode,
  268. NULL, 0,
  269. PagedPool,
  270. TRUE,
  271. &CapturedPrimaryGroup
  272. );
  273. } except(EXCEPTION_EXECUTE_HANDLER) {
  274. ObDereferenceObject( Token );
  275. return GetExceptionCode();
  276. }
  277. if (!NT_SUCCESS(Status)) {
  278. ObDereferenceObject( Token );
  279. return Status;
  280. }
  281. if (!SepIdAssignableAsGroup( Token, CapturedPrimaryGroup )) {
  282. ObDereferenceObject( Token );
  283. SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE);
  284. return STATUS_INVALID_PRIMARY_GROUP;
  285. }
  286. NewLength = SeLengthSid( CapturedPrimaryGroup );
  287. //
  288. // Gain write access to the token.
  289. //
  290. SepAcquireTokenWriteLock( Token );
  291. //
  292. // See if there is enough room in the dynamic part of the token
  293. // to replace the current Primary Group with the one specified.
  294. //
  295. if (Token->DefaultDacl) {
  296. NewLength += Token->DefaultDacl->AclSize;
  297. }
  298. if (NewLength > Token->DynamicCharged) {
  299. SepReleaseTokenWriteLock( Token, TokenModified );
  300. ObDereferenceObject( Token );
  301. SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE);
  302. return STATUS_ALLOTTED_SPACE_EXCEEDED;
  303. }
  304. //
  305. // Expand the tokens dynamic buffer if we have to
  306. //
  307. Status = SepExpandDynamic( Token, NewLength );
  308. if (!NT_SUCCESS (Status)) {
  309. SepReleaseTokenWriteLock( Token, TokenModified );
  310. ObDereferenceObject( Token );
  311. SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE);
  312. return Status;
  313. }
  314. //
  315. // Free up the existing primary group
  316. //
  317. SepFreePrimaryGroup( Token );
  318. //
  319. // And put the new SID in its place
  320. //
  321. SepAppendPrimaryGroup( Token, CapturedPrimaryGroup );
  322. TokenModified = TRUE;
  323. //
  324. // All done.
  325. //
  326. SepReleaseTokenWriteLock( Token, TokenModified );
  327. ObDereferenceObject( Token );
  328. SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE);
  329. return STATUS_SUCCESS;
  330. case TokenDefaultDacl:
  331. //
  332. // Assuming everything works out, the strategy is to move everything
  333. // in the Dynamic part of the token (exept the default Dacl) to
  334. // the beginning of the dynamic part, freeing up the entire end of
  335. // the dynamic part for the new default Dacl.
  336. //
  337. //
  338. // Make sure the buffer is large enough to hold the
  339. // necessary information class data structure.
  340. //
  341. if (TokenInformationLength < (ULONG)sizeof(TOKEN_DEFAULT_DACL)) {
  342. ObDereferenceObject( Token );
  343. return STATUS_INFO_LENGTH_MISMATCH;
  344. }
  345. //
  346. // Capture And Validate TOKEN_DEFAULT_DACL and corresponding ACL.
  347. //
  348. try {
  349. CapturedDefaultDacl =
  350. ((PTOKEN_DEFAULT_DACL)TokenInformation)->DefaultDacl;
  351. if (ARGUMENT_PRESENT(CapturedDefaultDacl)) {
  352. Status = SeCaptureAcl(
  353. CapturedDefaultDacl,
  354. PreviousMode,
  355. NULL, 0,
  356. PagedPool,
  357. TRUE,
  358. &CapturedDefaultDacl,
  359. &NewLength
  360. );
  361. } else {
  362. NewLength = 0;
  363. Status = STATUS_SUCCESS;
  364. }
  365. } except(EXCEPTION_EXECUTE_HANDLER) {
  366. ObDereferenceObject( Token );
  367. return GetExceptionCode();
  368. }
  369. if (!NT_SUCCESS(Status)) {
  370. ObDereferenceObject( Token );
  371. return Status;
  372. }
  373. //
  374. // Gain write access to the token.
  375. //
  376. SepAcquireTokenWriteLock( Token );
  377. //
  378. // See if there is enough room in the dynamic part of the token
  379. // to replace the current Default Dacl with the one specified.
  380. //
  381. NewLength += SeLengthSid( Token->PrimaryGroup );
  382. if (NewLength > Token->DynamicCharged) {
  383. SepReleaseTokenWriteLock( Token, TokenModified );
  384. ObDereferenceObject( Token );
  385. if (ARGUMENT_PRESENT(CapturedDefaultDacl)) {
  386. SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE);
  387. }
  388. return STATUS_ALLOTTED_SPACE_EXCEEDED;
  389. }
  390. //
  391. // Expand the tokens dynamic buffer if we have to
  392. //
  393. Status = SepExpandDynamic( Token, NewLength );
  394. if (!NT_SUCCESS (Status)) {
  395. SepReleaseTokenWriteLock( Token, TokenModified );
  396. ObDereferenceObject( Token );
  397. if (ARGUMENT_PRESENT(CapturedDefaultDacl)) {
  398. SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE);
  399. }
  400. return Status;
  401. }
  402. //
  403. // Free up the existing Default Dacl
  404. //
  405. SepFreeDefaultDacl( Token );
  406. //
  407. // And put the new ACL in its place
  408. //
  409. if (ARGUMENT_PRESENT(CapturedDefaultDacl)) {
  410. SepAppendDefaultDacl( Token, CapturedDefaultDacl );
  411. }
  412. TokenModified = TRUE;
  413. //
  414. // All done.
  415. //
  416. SepReleaseTokenWriteLock( Token, TokenModified );
  417. ObDereferenceObject( Token );
  418. if (ARGUMENT_PRESENT(CapturedDefaultDacl)) {
  419. SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE);
  420. }
  421. return STATUS_SUCCESS;
  422. case TokenSessionId:
  423. {
  424. ULONG SessionId;
  425. if ( TokenInformationLength != sizeof(ULONG) ) {
  426. ObDereferenceObject( Token );
  427. return( STATUS_INFO_LENGTH_MISMATCH );
  428. }
  429. try {
  430. SessionId = *(PULONG)TokenInformation;
  431. } except(EXCEPTION_EXECUTE_HANDLER) {
  432. ObDereferenceObject( Token );
  433. return GetExceptionCode();
  434. }
  435. //
  436. // We only allow TCB to set SessionId's
  437. //
  438. if ( !SeSinglePrivilegeCheck(SeTcbPrivilege,PreviousMode) ) {
  439. ObDereferenceObject( Token );
  440. return( STATUS_PRIVILEGE_NOT_HELD );
  441. }
  442. //
  443. // Set SessionId for the token
  444. //
  445. SeSetSessionIdToken( (PACCESS_TOKEN)Token,
  446. SessionId );
  447. ObDereferenceObject( Token );
  448. return( STATUS_SUCCESS );
  449. }
  450. case TokenSessionReference:
  451. {
  452. ULONG SessionReferenced;
  453. BOOLEAN DereferenceSession = FALSE;
  454. if ( TokenInformationLength != sizeof(ULONG) ) {
  455. ObDereferenceObject( Token );
  456. return( STATUS_INFO_LENGTH_MISMATCH );
  457. }
  458. try {
  459. SessionReferenced = *(PULONG)TokenInformation;
  460. } except(EXCEPTION_EXECUTE_HANDLER) {
  461. ObDereferenceObject( Token );
  462. return GetExceptionCode();
  463. }
  464. //
  465. // We only allow TCB to set Session referenced.
  466. //
  467. if ( !SeSinglePrivilegeCheck(SeTcbPrivilege,PreviousMode) ) {
  468. ObDereferenceObject( Token );
  469. return( STATUS_PRIVILEGE_NOT_HELD );
  470. }
  471. //
  472. // We don't yet have use for this so don't implement it.
  473. //
  474. if ( SessionReferenced ) {
  475. ObDereferenceObject( Token );
  476. return STATUS_INVALID_PARAMETER;
  477. }
  478. //
  479. // Determine if we're changing the state and change it with the write lock held
  480. //
  481. SepAcquireTokenWriteLock( Token );
  482. if ( (Token->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) == 0 ) {
  483. #if DBG || TOKEN_LEAK_MONITOR
  484. SepRemoveTokenLogonSession( Token );
  485. #endif
  486. Token->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
  487. DereferenceSession = TRUE;
  488. }
  489. SepReleaseTokenWriteLock( Token, FALSE );
  490. //
  491. // Do the actual dereference without any locks held
  492. //
  493. if ( DereferenceSession ) {
  494. SepDeReferenceLogonSessionDirect (Token->LogonSession);
  495. }
  496. ObDereferenceObject( Token );
  497. return( STATUS_SUCCESS );
  498. }
  499. case TokenAuditPolicy:
  500. {
  501. PTOKEN_AUDIT_POLICY pAuditPolicy = (PTOKEN_AUDIT_POLICY)TokenInformation;
  502. PTOKEN_AUDIT_POLICY pCapturedAuditPolicy = NULL;
  503. PTOKEN_AUDIT_POLICY_ELEMENT pPolicyElement;
  504. SEP_AUDIT_POLICY TokenPolicy;
  505. SEP_AUDIT_POLICY OldTokenPolicy;
  506. ULONG i;
  507. if (pAuditPolicy == NULL) {
  508. ObDereferenceObject( Token );
  509. return STATUS_INVALID_PARAMETER;
  510. }
  511. //
  512. // We require TCB privilege to set AuditPolicy
  513. //
  514. if ( !SeSinglePrivilegeCheck(SeTcbPrivilege,PreviousMode) ) {
  515. ObDereferenceObject( Token );
  516. return( STATUS_PRIVILEGE_NOT_HELD );
  517. }
  518. //
  519. // If the policy was already set on this token then fail. We only
  520. // allow setting a token's policy once.
  521. //
  522. SepAcquireTokenReadLock( Token );
  523. OldTokenPolicy = Token->AuditPolicy;
  524. SepReleaseTokenReadLock( Token );
  525. if (OldTokenPolicy.PolicyOverlay.SetBit) {
  526. ObDereferenceObject( Token );
  527. return( STATUS_INVALID_PARAMETER );
  528. }
  529. //
  530. // Capture And Validate TOKEN_AUDIT_POLICY.
  531. //
  532. try {
  533. Status = SeCaptureAuditPolicy(
  534. pAuditPolicy,
  535. PreviousMode,
  536. NULL,
  537. 0,
  538. PagedPool,
  539. TRUE,
  540. &pCapturedAuditPolicy
  541. );
  542. } except(EXCEPTION_EXECUTE_HANDLER) {
  543. ObDereferenceObject( Token );
  544. SeReleaseAuditPolicy(
  545. pCapturedAuditPolicy,
  546. PreviousMode,
  547. TRUE
  548. );
  549. return GetExceptionCode();
  550. }
  551. if (!NT_SUCCESS(Status)) {
  552. ObDereferenceObject( Token );
  553. return Status;
  554. }
  555. TokenPolicy.Overlay = 0;
  556. TokenPolicy.PolicyOverlay.SetBit = 1;
  557. if (pCapturedAuditPolicy->PolicyCount) {
  558. for (i = 0; i < pCapturedAuditPolicy->PolicyCount; i++) {
  559. pPolicyElement = &pCapturedAuditPolicy->Policy[i];
  560. switch (pPolicyElement->Category) {
  561. case AuditCategorySystem:
  562. TokenPolicy.PolicyElements.System = pPolicyElement->PolicyMask;
  563. break;
  564. case AuditCategoryLogon:
  565. TokenPolicy.PolicyElements.Logon = pPolicyElement->PolicyMask;
  566. break;
  567. case AuditCategoryObjectAccess:
  568. TokenPolicy.PolicyElements.ObjectAccess = pPolicyElement->PolicyMask;
  569. break;
  570. case AuditCategoryPrivilegeUse:
  571. TokenPolicy.PolicyElements.PrivilegeUse = pPolicyElement->PolicyMask;
  572. break;
  573. case AuditCategoryDetailedTracking:
  574. TokenPolicy.PolicyElements.DetailedTracking = pPolicyElement->PolicyMask;
  575. break;
  576. case AuditCategoryPolicyChange:
  577. TokenPolicy.PolicyElements.PolicyChange = pPolicyElement->PolicyMask;
  578. break;
  579. case AuditCategoryAccountManagement:
  580. TokenPolicy.PolicyElements.AccountManagement = pPolicyElement->PolicyMask;
  581. break;
  582. case AuditCategoryDirectoryServiceAccess:
  583. TokenPolicy.PolicyElements.DirectoryServiceAccess = pPolicyElement->PolicyMask;
  584. break;
  585. case AuditCategoryAccountLogon:
  586. TokenPolicy.PolicyElements.AccountLogon = pPolicyElement->PolicyMask;
  587. break;
  588. default:
  589. ASSERT(FALSE && "Illegal audit category");
  590. break;
  591. }
  592. }
  593. }
  594. SepAcquireTokenWriteLock( Token );
  595. OldTokenPolicy = Token->AuditPolicy;
  596. Token->AuditPolicy = TokenPolicy;
  597. SepReleaseTokenWriteLock( Token, TRUE );
  598. ObDereferenceObject( Token );
  599. if (TokenPolicy.Overlay) {
  600. SepModifyTokenPolicyCounter(&TokenPolicy, TRUE);
  601. }
  602. SeReleaseAuditPolicy(
  603. pCapturedAuditPolicy,
  604. PreviousMode,
  605. TRUE
  606. );
  607. return STATUS_SUCCESS;
  608. }
  609. case TokenOrigin:
  610. {
  611. TOKEN_ORIGIN Origin ;
  612. if ( TokenInformationLength != sizeof( TOKEN_ORIGIN ) ) {
  613. ObDereferenceObject( Token );
  614. return( STATUS_INFO_LENGTH_MISMATCH );
  615. }
  616. try {
  617. RtlCopyMemory(
  618. &Origin,
  619. TokenInformation,
  620. sizeof( TOKEN_ORIGIN ) );
  621. } except(EXCEPTION_EXECUTE_HANDLER) {
  622. ObDereferenceObject( Token );
  623. return GetExceptionCode();
  624. }
  625. //
  626. // We only allow TCB to set Origin information.
  627. //
  628. if ( !SeSinglePrivilegeCheck(SeTcbPrivilege,PreviousMode) ) {
  629. ObDereferenceObject( Token );
  630. return( STATUS_PRIVILEGE_NOT_HELD );
  631. }
  632. SepAcquireTokenWriteLock( Token );
  633. if ( RtlIsZeroLuid( &Token->OriginatingLogonSession ) )
  634. {
  635. Token->OriginatingLogonSession = Origin.OriginatingLogonSession ;
  636. }
  637. SepReleaseTokenWriteLock( Token, TRUE );
  638. ObDereferenceObject( Token );
  639. return( STATUS_SUCCESS );
  640. }
  641. } //endswitch
  642. ASSERT( TRUE == FALSE ); // Should never reach here.
  643. return( STATUS_INVALID_PARAMETER );
  644. }
  645. VOID
  646. SepModifyTokenPolicyCounter(
  647. PSEP_AUDIT_POLICY TokenPolicy,
  648. BOOLEAN bIncrement
  649. )
  650. /**
  651. Routine Description:
  652. This modifies the global SepTokenPolicyCounter hint which records the number of
  653. tokens in the system with per user auditing settings.
  654. Arguments:
  655. TokenPolicy - the policy which should be reflected in the hint.
  656. bIncrement - boolean indicating if this policy is being added (TRUE) or
  657. deleted (FALSE) from the counters.
  658. Return Value:
  659. None.
  660. **/
  661. {
  662. LONG increment;
  663. if (bIncrement) {
  664. increment = 1;
  665. } else {
  666. increment = -1;
  667. }
  668. if (TokenPolicy->PolicyElements.System) {
  669. InterlockedExchangeAdd(&SepTokenPolicyCounter[AuditCategorySystem], increment);
  670. ASSERT(SepTokenPolicyCounter[AuditCategorySystem] >= 0);
  671. }
  672. if (TokenPolicy->PolicyElements.Logon) {
  673. InterlockedExchangeAdd(&SepTokenPolicyCounter[AuditCategoryLogon], increment);
  674. ASSERT(SepTokenPolicyCounter[AuditCategoryLogon] >= 0);
  675. }
  676. if (TokenPolicy->PolicyElements.ObjectAccess) {
  677. InterlockedExchangeAdd(&SepTokenPolicyCounter[AuditCategoryObjectAccess], increment);
  678. ASSERT(SepTokenPolicyCounter[AuditCategoryObjectAccess] >= 0);
  679. }
  680. if (TokenPolicy->PolicyElements.PrivilegeUse) {
  681. InterlockedExchangeAdd(&SepTokenPolicyCounter[AuditCategoryPrivilegeUse], increment);
  682. ASSERT(SepTokenPolicyCounter[AuditCategoryPrivilegeUse] >= 0);
  683. }
  684. if (TokenPolicy->PolicyElements.DetailedTracking) {
  685. InterlockedExchangeAdd(&SepTokenPolicyCounter[AuditCategoryDetailedTracking], increment);
  686. ASSERT(SepTokenPolicyCounter[AuditCategoryDetailedTracking] >= 0);
  687. }
  688. if (TokenPolicy->PolicyElements.PolicyChange) {
  689. InterlockedExchangeAdd(&SepTokenPolicyCounter[AuditCategoryPolicyChange], increment);
  690. ASSERT(SepTokenPolicyCounter[AuditCategoryPolicyChange] >= 0);
  691. }
  692. if (TokenPolicy->PolicyElements.AccountManagement) {
  693. InterlockedExchangeAdd(&SepTokenPolicyCounter[AuditCategoryAccountManagement], increment);
  694. ASSERT(SepTokenPolicyCounter[AuditCategoryAccountManagement] >= 0);
  695. }
  696. if (TokenPolicy->PolicyElements.DirectoryServiceAccess) {
  697. InterlockedExchangeAdd(&SepTokenPolicyCounter[AuditCategoryDirectoryServiceAccess], increment);
  698. ASSERT(SepTokenPolicyCounter[AuditCategoryDirectoryServiceAccess] >= 0);
  699. }
  700. if (TokenPolicy->PolicyElements.AccountLogon) {
  701. InterlockedExchangeAdd(&SepTokenPolicyCounter[AuditCategoryAccountLogon], increment);
  702. ASSERT(SepTokenPolicyCounter[AuditCategoryAccountLogon] >= 0);
  703. }
  704. }
  705. NTSTATUS
  706. SepExpandDynamic(
  707. IN PTOKEN Token,
  708. IN ULONG NewLength
  709. )
  710. /*++
  711. Routine Description:
  712. This routines checks if the existing token dynamic buffer is big enough for the new group/dacl.
  713. If it isn't then its reallocated.
  714. Arguments:
  715. Token - Pointer to the token to expand. Locked for write access.
  716. Return Value:
  717. NTSTATUS - Status of operation
  718. --*/
  719. {
  720. ULONG CurrentSize;
  721. PVOID NewDynamic, OldDynamic;
  722. //
  723. // Work out how big it is now
  724. //
  725. CurrentSize = SeLengthSid( Token->PrimaryGroup ) + Token->DynamicAvailable;
  726. if (Token->DefaultDacl) {
  727. CurrentSize += Token->DefaultDacl->AclSize;
  728. }
  729. if (NewLength <= CurrentSize) {
  730. return STATUS_SUCCESS;
  731. }
  732. NewDynamic = ExAllocatePoolWithTag (PagedPool,
  733. NewLength,
  734. 'dTeS');
  735. if (NewDynamic == NULL) {
  736. return STATUS_INSUFFICIENT_RESOURCES;
  737. }
  738. OldDynamic = Token->DynamicPart;
  739. RtlCopyMemory (NewDynamic, OldDynamic, CurrentSize);
  740. Token->DynamicPart = NewDynamic;
  741. Token->DynamicAvailable += NewLength - CurrentSize;
  742. //
  743. //Relocate the pointers within the new buffer
  744. //
  745. if (Token->DefaultDacl) {
  746. Token->DefaultDacl = (PACL) ((PUCHAR) NewDynamic + ((PUCHAR) Token->DefaultDacl - (PUCHAR) OldDynamic));
  747. }
  748. Token->PrimaryGroup = (PSID) ((PUCHAR) NewDynamic + ((PUCHAR) Token->PrimaryGroup - (PUCHAR) OldDynamic));
  749. ExFreePool (OldDynamic);
  750. return STATUS_SUCCESS;
  751. }
  752. VOID
  753. SepFreePrimaryGroup(
  754. IN PTOKEN Token
  755. )
  756. /*++
  757. Routine Description:
  758. Free up the space in the dynamic part of the token take up by the primary
  759. group.
  760. The token is assumed to be locked for write access before calling
  761. this routine.
  762. Arguments:
  763. Token - Pointer to the token.
  764. Return Value:
  765. None.
  766. --*/
  767. {
  768. PAGED_CODE();
  769. //
  770. // Add the size of the primary group to the DynamicAvailable field.
  771. //
  772. Token->DynamicAvailable += SeLengthSid( Token->PrimaryGroup );
  773. //
  774. // If there is a default discretionary ACL, and it is not already at the
  775. // beginning of the dynamic part, move it there (remember to update the
  776. // pointer to it).
  777. //
  778. if (ARGUMENT_PRESENT(Token->DefaultDacl)) {
  779. if (Token->DynamicPart != (PULONG)(Token->DefaultDacl)) {
  780. RtlMoveMemory(
  781. (PVOID)(Token->DynamicPart),
  782. (PVOID)(Token->DefaultDacl),
  783. Token->DefaultDacl->AclSize
  784. );
  785. Token->DefaultDacl = (PACL)(Token->DynamicPart);
  786. }
  787. }
  788. return;
  789. }
  790. VOID
  791. SepFreeDefaultDacl(
  792. IN PTOKEN Token
  793. )
  794. /*++
  795. Routine Description:
  796. Free up the space in the dynamic part of the token take up by the default
  797. discretionary access control list.
  798. The token is assumed to be locked for write access before calling
  799. this routine.
  800. Arguments:
  801. Token - Pointer to the token.
  802. Return Value:
  803. None.
  804. --*/
  805. {
  806. ULONG PrimaryGroupSize;
  807. PAGED_CODE();
  808. //
  809. // Add the size of the Default Dacl (if there is one) to the
  810. // DynamicAvailable field.
  811. //
  812. if (ARGUMENT_PRESENT(Token->DefaultDacl)) {
  813. Token->DynamicAvailable += Token->DefaultDacl->AclSize;
  814. Token->DefaultDacl = NULL;
  815. }
  816. //
  817. // If it is not already at the beginning of the dynamic part, move
  818. // the primary group there (remember to update the pointer to it).
  819. //
  820. if (Token->DynamicPart != (PULONG)(Token->PrimaryGroup)) {
  821. PrimaryGroupSize = SeLengthSid( Token->PrimaryGroup );
  822. RtlMoveMemory(
  823. (PVOID)(Token->DynamicPart),
  824. (PVOID)(Token->PrimaryGroup),
  825. PrimaryGroupSize
  826. );
  827. Token->PrimaryGroup = (PSID)(Token->DynamicPart);
  828. }
  829. return;
  830. }
  831. VOID
  832. SepAppendPrimaryGroup(
  833. IN PTOKEN Token,
  834. IN PSID PSid
  835. )
  836. /*++
  837. Routine Description:
  838. Add a primary group SID to the available space at the end of the dynamic
  839. part of the token. It is the caller's responsibility to ensure that the
  840. primary group SID fits within the available space of the dynamic part of
  841. the token.
  842. The token is assumed to be locked for write access before calling
  843. this routine.
  844. Arguments:
  845. Token - Pointer to the token.
  846. PSid - Pointer to the SID to add.
  847. Return Value:
  848. None.
  849. --*/
  850. {
  851. ULONG_PTR NextFree;
  852. ULONG SidSize;
  853. PAGED_CODE();
  854. //
  855. // Add the size of the Default Dacl (if there is one) to the
  856. // address of the Dynamic Part of the token to establish
  857. // where the primary group should be placed.
  858. //
  859. if (ARGUMENT_PRESENT(Token->DefaultDacl)) {
  860. // ASSERT( (ULONG)(Token->DefaultDacl->AclSize) ==
  861. // (ULONG)LongAlignSize(Token->DefaultDacl->AclSize) );
  862. NextFree = (ULONG_PTR)(Token->DynamicPart) + Token->DefaultDacl->AclSize;
  863. } else {
  864. NextFree = (ULONG_PTR)(Token->DynamicPart);
  865. }
  866. //
  867. // Now copy the primary group SID.
  868. //
  869. SidSize = SeLengthSid( PSid );
  870. RtlCopyMemory(
  871. (PVOID)NextFree,
  872. (PVOID)PSid,
  873. SidSize
  874. );
  875. Token->PrimaryGroup = (PSID)NextFree;
  876. //
  877. // And decrement the amount of the dynamic part that is available.
  878. //
  879. ASSERT( SidSize <= (Token->DynamicAvailable) );
  880. Token->DynamicAvailable -= SidSize;
  881. return;
  882. }
  883. VOID
  884. SepAppendDefaultDacl(
  885. IN PTOKEN Token,
  886. IN PACL PAcl
  887. )
  888. /*++
  889. Routine Description:
  890. Add a default discretionary ACL to the available space at the end of the
  891. dynamic part of the token. It is the caller's responsibility to ensure
  892. that the default Dacl fits within the available space of the dynamic
  893. part of the token.
  894. The token is assumed to be locked for write access before calling
  895. this routine.
  896. Arguments:
  897. Token - Pointer to the token.
  898. PAcl - Pointer to the ACL to add.
  899. Return Value:
  900. None.
  901. --*/
  902. {
  903. ULONG_PTR NextFree;
  904. ULONG AclSize;
  905. PAGED_CODE();
  906. //
  907. // Add the size of the primary group to the
  908. // address of the Dynamic Part of the token to establish
  909. // where the primary group should be placed.
  910. //
  911. ASSERT(ARGUMENT_PRESENT(Token->PrimaryGroup));
  912. NextFree = (ULONG_PTR)(Token->DynamicPart) + SeLengthSid(Token->PrimaryGroup);
  913. //
  914. // Now copy the default Dacl
  915. //
  916. AclSize = (ULONG)(PAcl->AclSize);
  917. // ASSERT(AclSize == (ULONG)LongAlignSize(AclSize));
  918. RtlCopyMemory(
  919. (PVOID)NextFree,
  920. (PVOID)PAcl,
  921. AclSize
  922. );
  923. Token->DefaultDacl = (PACL)NextFree;
  924. //
  925. // And decrement the amount of the dynamic part that is available.
  926. //
  927. ASSERT( AclSize <= (Token->DynamicAvailable) );
  928. Token->DynamicAvailable -= AclSize;
  929. return;
  930. }
  931. NTSTATUS
  932. SeSetSessionIdToken(
  933. PACCESS_TOKEN Token,
  934. ULONG SessionId
  935. )
  936. /*++
  937. Routine Description:
  938. Sets the SessionId for the specified token object.
  939. Arguments:
  940. pOpaqueToken (input)
  941. Opaque kernel Token access pointer
  942. SessionId (input)
  943. SessionId to store in token
  944. Return Value:
  945. STATUS_SUCCESS - no error
  946. --*/
  947. {
  948. PAGED_CODE();
  949. //
  950. // Gain write access to the token.
  951. //
  952. SepAcquireTokenWriteLock( ((PTOKEN)Token) );
  953. ((PTOKEN)Token)->SessionId = SessionId;
  954. SepReleaseTokenWriteLock( ((PTOKEN)Token), FALSE );
  955. return( STATUS_SUCCESS );
  956. }