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

584 lines
14 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Privileg.c
  5. Abstract:
  6. This Module implements the privilege check procedures.
  7. Author:
  8. Robert Reichel (robertre) 26-Nov-90
  9. Environment:
  10. Kernel Mode
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #pragma hdrstop
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE,NtPrivilegeCheck)
  17. #pragma alloc_text(PAGE,SeCheckPrivilegedObject)
  18. #pragma alloc_text(PAGE,SepPrivilegeCheck)
  19. #pragma alloc_text(PAGE,SePrivilegeCheck)
  20. #pragma alloc_text(PAGE,SeSinglePrivilegeCheck)
  21. #endif
  22. BOOLEAN
  23. SepPrivilegeCheck(
  24. IN PTOKEN Token,
  25. IN OUT PLUID_AND_ATTRIBUTES RequiredPrivileges,
  26. IN ULONG RequiredPrivilegeCount,
  27. IN ULONG PrivilegeSetControl,
  28. IN KPROCESSOR_MODE PreviousMode
  29. )
  30. /*++
  31. Routine Description:
  32. Worker routine for SePrivilegeCheck
  33. Arguments:
  34. Token - The user's effective token.
  35. RequiredPrivileges - A privilege set describing the required
  36. privileges. The UsedForAccess bits will be set in any privilege
  37. that is actually used (usually all of them).
  38. RequiredPrivilegeCount - How many privileges are in the
  39. RequiredPrivileges set.
  40. PrivilegeSetControl - Describes how many privileges are required.
  41. PreviousMode - The previous processor mode.
  42. Return Value:
  43. Returns TRUE if requested privileges are granted, FALSE otherwise.
  44. --*/
  45. {
  46. PLUID_AND_ATTRIBUTES CurrentRequiredPrivilege;
  47. PLUID_AND_ATTRIBUTES CurrentTokenPrivilege;
  48. BOOLEAN RequiredAll;
  49. ULONG TokenPrivilegeCount;
  50. ULONG MatchCount = 0;
  51. ULONG i;
  52. ULONG j;
  53. PAGED_CODE();
  54. //
  55. // Take care of kernel callers first
  56. //
  57. if (PreviousMode == KernelMode) {
  58. return(TRUE);
  59. }
  60. TokenPrivilegeCount = Token->PrivilegeCount;
  61. //
  62. // Save whether we require ALL of them or ANY
  63. //
  64. RequiredAll = (BOOLEAN)(PrivilegeSetControl & PRIVILEGE_SET_ALL_NECESSARY);
  65. SepAcquireTokenReadLock( Token );
  66. for ( i = 0 , CurrentRequiredPrivilege = RequiredPrivileges ;
  67. i < RequiredPrivilegeCount ;
  68. i++, CurrentRequiredPrivilege++ ) {
  69. for ( j = 0, CurrentTokenPrivilege = Token->Privileges;
  70. j < TokenPrivilegeCount ;
  71. j++, CurrentTokenPrivilege++ ) {
  72. if ((CurrentTokenPrivilege->Attributes & SE_PRIVILEGE_ENABLED) &&
  73. (RtlEqualLuid(&CurrentTokenPrivilege->Luid,
  74. &CurrentRequiredPrivilege->Luid))
  75. ) {
  76. CurrentRequiredPrivilege->Attributes |=
  77. SE_PRIVILEGE_USED_FOR_ACCESS;
  78. MatchCount++;
  79. break; // start looking for next one
  80. }
  81. }
  82. }
  83. SepReleaseTokenReadLock( Token );
  84. //
  85. // If we wanted ANY and didn't get any, return failure.
  86. //
  87. if (!RequiredAll && (MatchCount == 0)) {
  88. return (FALSE);
  89. }
  90. //
  91. // If we wanted ALL and didn't get all, return failure.
  92. //
  93. if (RequiredAll && (MatchCount != RequiredPrivilegeCount)) {
  94. return(FALSE);
  95. }
  96. return(TRUE);
  97. }
  98. BOOLEAN
  99. SePrivilegeCheck(
  100. IN OUT PPRIVILEGE_SET RequiredPrivileges,
  101. IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
  102. IN KPROCESSOR_MODE AccessMode
  103. )
  104. /*++
  105. Routine Description:
  106. This routine checks to see if the token contains the specified
  107. privileges.
  108. Arguments:
  109. RequiredPrivileges - Points to a set of privileges. The subject's
  110. security context is to be checked to see which of the specified
  111. privileges are present. The results will be indicated in the
  112. attributes associated with each privilege. Note that
  113. flags in this parameter indicate whether all the privileges listed
  114. are needed, or any of the privileges.
  115. SubjectSecurityContext - A pointer to the subject's captured security
  116. context.
  117. AccessMode - Indicates the access mode to use for access check. One of
  118. UserMode or KernelMode. If the mode is kernel, then all privileges
  119. will be marked as being possessed by the subject, and successful
  120. completion status is returned.
  121. Return Value:
  122. BOOLEAN - TRUE if all specified privileges are held by the subject,
  123. otherwise FALSE.
  124. --*/
  125. {
  126. BOOLEAN Status;
  127. PAGED_CODE();
  128. //
  129. // If we're impersonating a client, we have to be at impersonation level
  130. // of SecurityImpersonation or above.
  131. //
  132. if ( (SubjectSecurityContext->ClientToken != NULL) &&
  133. (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation)
  134. ) {
  135. return(FALSE);
  136. }
  137. //
  138. // SepPrivilegeCheck locks the passed token for read access
  139. //
  140. Status = SepPrivilegeCheck(
  141. EffectiveToken( SubjectSecurityContext ),
  142. RequiredPrivileges->Privilege,
  143. RequiredPrivileges->PrivilegeCount,
  144. RequiredPrivileges->Control,
  145. AccessMode
  146. );
  147. return(Status);
  148. }
  149. NTSTATUS
  150. NtPrivilegeCheck(
  151. IN HANDLE ClientToken,
  152. IN OUT PPRIVILEGE_SET RequiredPrivileges,
  153. OUT PBOOLEAN Result
  154. )
  155. /*++
  156. Routine Description:
  157. This routine tests the caller's client's security context to see if it
  158. contains the specified privileges.
  159. This API requires the caller have SeTcbPrivilege privilege. The test
  160. for this privilege is always against the primary token of the calling
  161. process, not the impersonation token of the thread.
  162. Arguments:
  163. ClientToken - A handle to a token object representing a client
  164. attempting access. This handle must be obtained from a
  165. communication session layer, such as from an LPC Port or Local
  166. Named Pipe, to prevent possible security policy violations.
  167. RequiredPrivileges - Points to a set of privileges. The client's
  168. security context is to be checked to see which of the specified
  169. privileges are present. The results will be indicated in the
  170. attributes associated with each privilege. Note that
  171. flags in this parameter indicate whether all the privileges listed
  172. are needed, or any of the privileges.
  173. Result - Receives a boolean flag indicating whether the client has all
  174. the specified privileges or not. A value of TRUE indicates the
  175. client has all the specified privileges. Otherwise a value of
  176. FALSE is returned.
  177. Return Value:
  178. STATUS_SUCCESS - Indicates the call completed successfully.
  179. STATUS_PRIVILEGE_NOT_HELD - Indicates the caller does not have
  180. sufficient privilege to use this privileged system service.
  181. --*/
  182. {
  183. BOOLEAN BStatus;
  184. KPROCESSOR_MODE PreviousMode;
  185. NTSTATUS Status;
  186. PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
  187. PTOKEN Token = NULL;
  188. ULONG CapturedPrivilegeCount = 0;
  189. ULONG CapturedPrivilegesLength = 0;
  190. ULONG ParameterLength = 0;
  191. ULONG PrivilegeSetControl = 0;
  192. PAGED_CODE();
  193. PreviousMode = KeGetPreviousMode();
  194. Status = ObReferenceObjectByHandle(
  195. ClientToken, // Handle
  196. TOKEN_QUERY, // DesiredAccess
  197. SeTokenObjectType, // ObjectType
  198. PreviousMode, // AccessMode
  199. (PVOID *)&Token, // Object
  200. NULL // GrantedAccess
  201. );
  202. if ( !NT_SUCCESS(Status) ) {
  203. return Status;
  204. }
  205. //
  206. // If the passed token is an impersonation token, make sure
  207. // it is at SecurityIdentification or above.
  208. //
  209. if (Token->TokenType == TokenImpersonation) {
  210. if (Token->ImpersonationLevel < SecurityIdentification) {
  211. ObDereferenceObject( (PVOID)Token );
  212. return( STATUS_BAD_IMPERSONATION_LEVEL );
  213. }
  214. }
  215. try {
  216. //
  217. // Capture passed Privilege Set
  218. //
  219. ProbeForWriteSmallStructure(
  220. RequiredPrivileges,
  221. sizeof(PRIVILEGE_SET),
  222. sizeof(ULONG)
  223. );
  224. CapturedPrivilegeCount = RequiredPrivileges->PrivilegeCount;
  225. if (!IsValidElementCount(CapturedPrivilegeCount, LUID_AND_ATTRIBUTES)) {
  226. Status = STATUS_INVALID_PARAMETER;
  227. leave;
  228. }
  229. ParameterLength = (ULONG)sizeof(PRIVILEGE_SET) +
  230. ((CapturedPrivilegeCount - ANYSIZE_ARRAY) *
  231. (ULONG)sizeof(LUID_AND_ATTRIBUTES) );
  232. ProbeForWrite(
  233. RequiredPrivileges,
  234. ParameterLength,
  235. sizeof(ULONG)
  236. );
  237. ProbeForWriteBoolean(Result);
  238. PrivilegeSetControl = RequiredPrivileges->Control;
  239. } except(EXCEPTION_EXECUTE_HANDLER) {
  240. Status = GetExceptionCode();
  241. }
  242. if (!NT_SUCCESS(Status)) {
  243. ObDereferenceObject( (PVOID)Token );
  244. return Status;
  245. }
  246. Status = SeCaptureLuidAndAttributesArray(
  247. (RequiredPrivileges->Privilege),
  248. CapturedPrivilegeCount,
  249. UserMode,
  250. NULL, 0,
  251. PagedPool,
  252. TRUE,
  253. &CapturedPrivileges,
  254. &CapturedPrivilegesLength
  255. );
  256. if (!NT_SUCCESS(Status)) {
  257. ObDereferenceObject( (PVOID)Token );
  258. return Status;
  259. }
  260. BStatus = SepPrivilegeCheck(
  261. Token, // Token,
  262. CapturedPrivileges, // RequiredPrivileges,
  263. CapturedPrivilegeCount, // RequiredPrivilegeCount,
  264. PrivilegeSetControl, // PrivilegeSetControl
  265. PreviousMode // PreviousMode
  266. );
  267. ObDereferenceObject( Token );
  268. try {
  269. //
  270. // copy the modified privileges buffer back to user
  271. //
  272. RtlCopyMemory(
  273. RequiredPrivileges->Privilege,
  274. CapturedPrivileges,
  275. CapturedPrivilegesLength
  276. );
  277. *Result = BStatus;
  278. } except (EXCEPTION_EXECUTE_HANDLER) {
  279. SeReleaseLuidAndAttributesArray(
  280. CapturedPrivileges,
  281. PreviousMode,
  282. TRUE
  283. );
  284. return(GetExceptionCode());
  285. }
  286. SeReleaseLuidAndAttributesArray(
  287. CapturedPrivileges,
  288. PreviousMode,
  289. TRUE
  290. );
  291. return( STATUS_SUCCESS );
  292. }
  293. BOOLEAN
  294. SeSinglePrivilegeCheck(
  295. LUID PrivilegeValue,
  296. KPROCESSOR_MODE PreviousMode
  297. )
  298. /*++
  299. Routine Description:
  300. This function will check for the passed privilege value in the
  301. current context.
  302. Arguments:
  303. PrivilegeValue - The value of the privilege being checked.
  304. Return Value:
  305. TRUE - The current subject has the desired privilege.
  306. FALSE - The current subject does not have the desired privilege.
  307. --*/
  308. {
  309. BOOLEAN AccessGranted;
  310. PRIVILEGE_SET RequiredPrivileges;
  311. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  312. PAGED_CODE();
  313. //
  314. // Make sure the caller has the privilege to make this
  315. // call.
  316. //
  317. RequiredPrivileges.PrivilegeCount = 1;
  318. RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
  319. RequiredPrivileges.Privilege[0].Luid = PrivilegeValue;
  320. RequiredPrivileges.Privilege[0].Attributes = 0;
  321. SeCaptureSubjectContext( &SubjectSecurityContext );
  322. AccessGranted = SePrivilegeCheck(
  323. &RequiredPrivileges,
  324. &SubjectSecurityContext,
  325. PreviousMode
  326. );
  327. if ( PreviousMode != KernelMode ) {
  328. SePrivilegedServiceAuditAlarm (
  329. NULL,
  330. &SubjectSecurityContext,
  331. &RequiredPrivileges,
  332. AccessGranted
  333. );
  334. }
  335. SeReleaseSubjectContext( &SubjectSecurityContext );
  336. return( AccessGranted );
  337. }
  338. BOOLEAN
  339. SeCheckPrivilegedObject(
  340. LUID PrivilegeValue,
  341. HANDLE ObjectHandle,
  342. ACCESS_MASK DesiredAccess,
  343. KPROCESSOR_MODE PreviousMode
  344. )
  345. /*++
  346. Routine Description:
  347. This function will check for the passed privilege value in the
  348. current context, and generate audits as appropriate.
  349. Arguments:
  350. PrivilegeValue - The value of the privilege being checked.
  351. Object - Specifies a pointer to the object being accessed.
  352. ObjectHandle - Specifies the object handle being used.
  353. DesiredAccess - The desired access mask, if any
  354. PreviousMode - The previous processor mode
  355. Return Value:
  356. TRUE - The current subject has the desired privilege.
  357. FALSE - The current subject does not have the desired privilege.
  358. --*/
  359. {
  360. BOOLEAN AccessGranted;
  361. PRIVILEGE_SET RequiredPrivileges;
  362. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  363. PAGED_CODE();
  364. //
  365. // Make sure the caller has the privilege to make this
  366. // call.
  367. //
  368. RequiredPrivileges.PrivilegeCount = 1;
  369. RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
  370. RequiredPrivileges.Privilege[0].Luid = PrivilegeValue;
  371. RequiredPrivileges.Privilege[0].Attributes = 0;
  372. SeCaptureSubjectContext( &SubjectSecurityContext );
  373. AccessGranted = SePrivilegeCheck(
  374. &RequiredPrivileges,
  375. &SubjectSecurityContext,
  376. PreviousMode
  377. );
  378. if ( PreviousMode != KernelMode ) {
  379. SePrivilegeObjectAuditAlarm(
  380. ObjectHandle,
  381. &SubjectSecurityContext,
  382. DesiredAccess,
  383. &RequiredPrivileges,
  384. AccessGranted,
  385. PreviousMode
  386. );
  387. }
  388. SeReleaseSubjectContext( &SubjectSecurityContext );
  389. return( AccessGranted );
  390. }