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.

841 lines
21 KiB

  1. /*++
  2. Copyright (c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. seutil.c
  5. Abstract:
  6. This module implements general security utilities, and
  7. dispatch routines for security IRPs.
  8. Author:
  9. Keith Moore (keithmo) 25-Mar-1999
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text( PAGE, UlAssignSecurity )
  15. #pragma alloc_text( PAGE, UlDeassignSecurity )
  16. #pragma alloc_text( PAGE, UlSetSecurity )
  17. #pragma alloc_text( PAGE, UlQuerySecurity )
  18. #pragma alloc_text( PAGE, UlAccessCheck )
  19. #pragma alloc_text( PAGE, UlSetSecurityDispatch )
  20. #pragma alloc_text( PAGE, UlQuerySecurityDispatch )
  21. #pragma alloc_text( PAGE, UlThreadAdminCheck )
  22. #pragma alloc_text( PAGE, UlCreateSecurityDescriptor )
  23. #pragma alloc_text( PAGE, UlCleanupSecurityDescriptor )
  24. #pragma alloc_test( PAGE, UlMapGenericMask )
  25. #endif // ALLOC_PRAGMA
  26. #if 0
  27. #endif
  28. //
  29. // Public functions.
  30. //
  31. /***************************************************************************++
  32. Routine Description:
  33. Assigns a new security descriptor.
  34. Arguments:
  35. pSecurityDescriptor - Supplies a pointer to the current security
  36. descriptor pointer. The current security descriptor pointer
  37. will be updated with the new security descriptor.
  38. pAccessState - Supplies the ACCESS_STATE structure containing
  39. the state of an access in progress.
  40. Return Value:
  41. NTSTATUS - Completion status.
  42. --***************************************************************************/
  43. NTSTATUS
  44. UlAssignSecurity(
  45. IN OUT PSECURITY_DESCRIPTOR *pSecurityDescriptor,
  46. IN PACCESS_STATE pAccessState
  47. )
  48. {
  49. NTSTATUS status;
  50. //
  51. // Sanity check.
  52. //
  53. PAGED_CODE();
  54. ASSERT( pSecurityDescriptor != NULL );
  55. ASSERT( pAccessState != NULL );
  56. //
  57. // Assign the security descriptor.
  58. //
  59. SeLockSubjectContext( &pAccessState->SubjectSecurityContext );
  60. status = SeAssignSecurity(
  61. NULL, // ParentDescriptor
  62. pAccessState->SecurityDescriptor,
  63. pSecurityDescriptor,
  64. FALSE, // IsDirectoryObject
  65. &pAccessState->SubjectSecurityContext,
  66. IoGetFileObjectGenericMapping(),
  67. PagedPool
  68. );
  69. SeUnlockSubjectContext( &pAccessState->SubjectSecurityContext );
  70. return status;
  71. } // UlAssignSecurity
  72. /***************************************************************************++
  73. Routine Description:
  74. Deletes a security descriptor.
  75. Arguments:
  76. pSecurityDescriptor - Supplies a pointer to the current security
  77. descriptor pointer. The current security descriptor pointer
  78. will be deleted.
  79. --***************************************************************************/
  80. VOID
  81. UlDeassignSecurity(
  82. IN OUT PSECURITY_DESCRIPTOR *pSecurityDescriptor
  83. )
  84. {
  85. //
  86. // Sanity check.
  87. //
  88. PAGED_CODE();
  89. ASSERT( pSecurityDescriptor != NULL );
  90. //
  91. // If there's a security descriptor present, free it.
  92. //
  93. if (*pSecurityDescriptor != NULL)
  94. {
  95. SeDeassignSecurity( pSecurityDescriptor );
  96. }
  97. } // UlDeassignSecurity
  98. /***************************************************************************++
  99. Routine Description:
  100. Sets a new security descriptor.
  101. Arguments:
  102. pSecurityDescriptor - Supplies a pointer to the current security
  103. descriptor pointer. The current security descriptor will be
  104. updated with the new security information.
  105. pSecurityInformation - Indicates which security information is
  106. to be applied to the object.
  107. pNewSecurityDescriptor - Pointer to the new security descriptor
  108. to be applied to the object.
  109. Return Value:
  110. NTSTATUS - Completion status.
  111. --***************************************************************************/
  112. NTSTATUS
  113. UlSetSecurity(
  114. IN OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
  115. IN PSECURITY_INFORMATION pSecurityInformation,
  116. IN PSECURITY_DESCRIPTOR pNewSecurityDescriptor
  117. )
  118. {
  119. NTSTATUS status;
  120. PSECURITY_DESCRIPTOR pOldSecurityDescriptor;
  121. SECURITY_SUBJECT_CONTEXT securitySubjectContext;
  122. PAGED_CODE();
  123. pOldSecurityDescriptor = *ppSecurityDescriptor;
  124. SeCaptureSubjectContext(&securitySubjectContext);
  125. SeLockSubjectContext(&securitySubjectContext);
  126. status = SeSetSecurityDescriptorInfo(
  127. NULL,
  128. pSecurityInformation,
  129. pNewSecurityDescriptor,
  130. ppSecurityDescriptor,
  131. PagedPool,
  132. IoGetFileObjectGenericMapping()
  133. );
  134. SeUnlockSubjectContext(&securitySubjectContext);
  135. SeReleaseSubjectContext(&securitySubjectContext);
  136. if (NT_SUCCESS(status))
  137. {
  138. SeDeassignSecurity(&pOldSecurityDescriptor);
  139. }
  140. return status;
  141. }
  142. /***************************************************************************++
  143. Routine Description:
  144. Query for security descriptor information for an object.
  145. Arguments:
  146. pSecurityInformation - specifies what information is being queried.
  147. pSecurityDescriptor - Supplies a pointer to the security descriptor
  148. to be filled in.
  149. pLength - Address of variable containing length of the above security
  150. descriptor buffer. Upon return, this will contain the length needed
  151. to store the requested information.
  152. ppSecurityDescriptor - Address of a pointer to the objects security
  153. descriptor.
  154. Return Value:
  155. NTSTATUS - Completion status.
  156. --***************************************************************************/
  157. NTSTATUS
  158. UlQuerySecurity(
  159. IN PSECURITY_INFORMATION pSecurityInformation,
  160. OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
  161. IN OUT PULONG pLength,
  162. IN PSECURITY_DESCRIPTOR *ppSecurityDescriptor
  163. )
  164. {
  165. NTSTATUS status;
  166. SECURITY_SUBJECT_CONTEXT securitySubjectContext;
  167. PAGED_CODE();
  168. SeCaptureSubjectContext(&securitySubjectContext);
  169. SeLockSubjectContext(&securitySubjectContext);
  170. status = SeQuerySecurityDescriptorInfo(
  171. pSecurityInformation,
  172. pSecurityDescriptor,
  173. pLength,
  174. ppSecurityDescriptor
  175. );
  176. SeUnlockSubjectContext(&securitySubjectContext);
  177. SeReleaseSubjectContext(&securitySubjectContext);
  178. return status;
  179. }
  180. /***************************************************************************++
  181. Routine Description:
  182. Determines if a user has access to the specified resource.
  183. Arguments:
  184. pSecurityDescriptor - Supplies the security descriptor protecting
  185. the resource.
  186. pAccessState - Supplies the ACCESS_STATE structure containing
  187. the state of an access in progress.
  188. DesiredAccess - Supplies an access mask describing the user's
  189. desired access to the resource. This mask is assumed to not
  190. contain generic access types.
  191. RequestorMode - Supplies the processor mode by which the access is
  192. being requested.
  193. pObjectName - Supplies the name of the object being referenced.
  194. Return Value:
  195. NTSTATUS - Completion status.
  196. --***************************************************************************/
  197. NTSTATUS
  198. UlAccessCheck(
  199. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  200. IN PACCESS_STATE pAccessState,
  201. IN ACCESS_MASK DesiredAccess,
  202. IN KPROCESSOR_MODE RequestorMode,
  203. IN PCWSTR pObjectName
  204. )
  205. {
  206. NTSTATUS status, aaStatus;
  207. BOOLEAN accessGranted;
  208. PPRIVILEGE_SET pPrivileges = NULL;
  209. ACCESS_MASK grantedAccess;
  210. UNICODE_STRING objectName;
  211. UNICODE_STRING typeName;
  212. //
  213. // Sanity check.
  214. //
  215. PAGED_CODE();
  216. ASSERT( pSecurityDescriptor != NULL );
  217. ASSERT( pAccessState != NULL );
  218. //
  219. // Perform the access check.
  220. //
  221. SeLockSubjectContext( &pAccessState->SubjectSecurityContext );
  222. accessGranted = SeAccessCheck(
  223. pSecurityDescriptor,
  224. &pAccessState->SubjectSecurityContext,
  225. TRUE, // SubjectContextLocked
  226. DesiredAccess,
  227. 0, // PreviouslyGrantedAccess
  228. &pPrivileges,
  229. IoGetFileObjectGenericMapping(),
  230. RequestorMode,
  231. &grantedAccess,
  232. &status
  233. );
  234. if (pPrivileges != NULL)
  235. {
  236. SeAppendPrivileges( pAccessState, pPrivileges );
  237. SeFreePrivileges( pPrivileges );
  238. }
  239. if (accessGranted)
  240. {
  241. pAccessState->PreviouslyGrantedAccess |= grantedAccess;
  242. pAccessState->RemainingDesiredAccess &= ~(grantedAccess | MAXIMUM_ALLOWED);
  243. }
  244. aaStatus = UlInitUnicodeStringEx( &typeName, L"Ul" );
  245. if ( NT_SUCCESS(aaStatus) )
  246. {
  247. aaStatus = UlInitUnicodeStringEx( &objectName, pObjectName );
  248. if ( NT_SUCCESS(aaStatus) )
  249. {
  250. SeOpenObjectAuditAlarm(
  251. &typeName,
  252. NULL, // Object
  253. &objectName,
  254. pSecurityDescriptor,
  255. pAccessState,
  256. FALSE, // ObjectCreated
  257. accessGranted,
  258. RequestorMode,
  259. &pAccessState->GenerateOnClose
  260. );
  261. }
  262. }
  263. SeUnlockSubjectContext( &pAccessState->SubjectSecurityContext );
  264. if (accessGranted)
  265. {
  266. status = STATUS_SUCCESS;
  267. }
  268. else
  269. {
  270. //
  271. // SeAccessCheck() should have set the completion status.
  272. //
  273. ASSERT( !NT_SUCCESS(status) );
  274. }
  275. return status;
  276. } // UlAccessCheck
  277. NTSTATUS
  278. UlSetSecurityDispatch(
  279. IN PDEVICE_OBJECT pDeviceObject,
  280. IN PIRP pIrp
  281. )
  282. {
  283. NTSTATUS status;
  284. PIO_STACK_LOCATION pIrpSp;
  285. PFILE_OBJECT pFileObject;
  286. PUL_APP_POOL_PROCESS pProcess;
  287. UNREFERENCED_PARAMETER(pDeviceObject);
  288. PAGED_CODE();
  289. UL_ENTER_DRIVER( "UlSetSecurityDispatch", pIrp );
  290. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  291. pFileObject = pIrpSp->FileObject;
  292. //
  293. // We only allow changing the security descriptor on app
  294. // pool handles.
  295. //
  296. if (!IS_APP_POOL_FO(pFileObject))
  297. {
  298. status = STATUS_INVALID_PARAMETER;
  299. goto complete;
  300. }
  301. pProcess = GET_APP_POOL_PROCESS(pFileObject);
  302. status = UlSetSecurity(
  303. &pProcess->pAppPool->pSecurityDescriptor,
  304. &pIrpSp->Parameters.SetSecurity.SecurityInformation,
  305. pIrpSp->Parameters.SetSecurity.SecurityDescriptor
  306. );
  307. complete:
  308. pIrp->IoStatus.Status = status;
  309. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  310. UL_LEAVE_DRIVER( "UlSetSecurityDispatch" );
  311. RETURN(status);
  312. } // UlSetSecurityDispatch
  313. NTSTATUS
  314. UlQuerySecurityDispatch(
  315. IN PDEVICE_OBJECT pDeviceObject,
  316. IN PIRP pIrp
  317. )
  318. {
  319. NTSTATUS status;
  320. PIO_STACK_LOCATION pIrpSp;
  321. PFILE_OBJECT pFileObject;
  322. PUL_APP_POOL_PROCESS pProcess;
  323. UNREFERENCED_PARAMETER(pDeviceObject);
  324. PAGED_CODE();
  325. UL_ENTER_DRIVER( "UlQuerySecurityDispatch", pIrp );
  326. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  327. pFileObject = pIrpSp->FileObject;
  328. //
  329. // We only allow querying the security descriptor on app
  330. // pool handles.
  331. //
  332. if (!IS_APP_POOL_FO(pFileObject))
  333. {
  334. status = STATUS_INVALID_PARAMETER;
  335. goto complete;
  336. }
  337. pProcess = GET_APP_POOL_PROCESS(pFileObject);
  338. status = UlQuerySecurity(
  339. &pIrpSp->Parameters.QuerySecurity.SecurityInformation,
  340. pIrp->UserBuffer,
  341. &pIrpSp->Parameters.QuerySecurity.Length,
  342. &pProcess->pAppPool->pSecurityDescriptor
  343. );
  344. if (pIrp->UserIosb)
  345. {
  346. pIrp->UserIosb->Information = pIrpSp->Parameters.QuerySecurity.Length;
  347. }
  348. complete:
  349. pIrp->IoStatus.Status = status;
  350. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  351. UL_LEAVE_DRIVER( "UlQuerySecurityDispatch" );
  352. RETURN(status);
  353. } // UlQuerySecurityDispatch
  354. /***************************************************************************++
  355. Routine Description:
  356. Determines if this is a thread with Admin/LocalSystem privileges.
  357. Arguments:
  358. DesiredAccess - Supplies an access mask describing the user's
  359. desired access to the resource. This mask is assumed to not
  360. contain generic access types.
  361. RequestorMode - Supplies the processor mode by which the access is
  362. being requested.
  363. pObjectName - Supplies the name of the object being referenced.
  364. Return Value:
  365. NTSTATUS - Completion status.
  366. --***************************************************************************/
  367. NTSTATUS
  368. UlThreadAdminCheck(
  369. IN ACCESS_MASK DesiredAccess,
  370. IN KPROCESSOR_MODE RequestorMode,
  371. IN PCWSTR pObjectName
  372. )
  373. {
  374. ACCESS_STATE AccessState;
  375. AUX_ACCESS_DATA AuxData;
  376. NTSTATUS Status;
  377. Status = SeCreateAccessState(
  378. &AccessState,
  379. &AuxData,
  380. DesiredAccess,
  381. NULL
  382. );
  383. if(NT_SUCCESS(Status))
  384. {
  385. Status = UlAccessCheck(
  386. g_pAdminAllSystemAll,
  387. &AccessState,
  388. DesiredAccess,
  389. RequestorMode,
  390. pObjectName
  391. );
  392. SeDeleteAccessState(&AccessState);
  393. }
  394. return Status;
  395. }
  396. /***************************************************************************++
  397. Routine Description:
  398. Allocates and initializes a security descriptor with the specified
  399. attributes.
  400. Arguments:
  401. pSecurityDescriptor - Supplies a pointer to the security descriptor
  402. to initialize.
  403. pSidMaskPairs - Supplies an array of SID/ACCESS_MASK pairs.
  404. NumSidMaskPairs - Supplies the number of SID/ACESS_MASK pairs.
  405. Return Value:
  406. NTSTATUS - Completion status.
  407. --***************************************************************************/
  408. NTSTATUS
  409. UlCreateSecurityDescriptor(
  410. OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
  411. IN PSID_MASK_PAIR pSidMaskPairs,
  412. IN ULONG NumSidMaskPairs
  413. )
  414. {
  415. NTSTATUS status;
  416. PACL pDacl;
  417. ULONG daclLength;
  418. ULONG i;
  419. //
  420. // Sanity check.
  421. //
  422. PAGED_CODE();
  423. ASSERT( pSecurityDescriptor != NULL );
  424. ASSERT( pSidMaskPairs != NULL );
  425. ASSERT( NumSidMaskPairs > 0 );
  426. //
  427. // Setup locals so we know how to cleanup on exit.
  428. //
  429. pDacl = NULL;
  430. //
  431. // Initialize the security descriptor.
  432. //
  433. status = RtlCreateSecurityDescriptor(
  434. pSecurityDescriptor, // SecurityDescriptor
  435. SECURITY_DESCRIPTOR_REVISION // Revision
  436. );
  437. if (!NT_SUCCESS(status))
  438. {
  439. goto cleanup;
  440. }
  441. //
  442. // Calculate the DACL length.
  443. //
  444. daclLength = sizeof(ACL);
  445. for (i = 0 ; i < NumSidMaskPairs ; i++)
  446. {
  447. daclLength += sizeof(ACCESS_ALLOWED_ACE);
  448. daclLength += RtlLengthSid( pSidMaskPairs[i].pSid );
  449. }
  450. //
  451. // Allocate & initialize the DACL.
  452. //
  453. pDacl = (PACL) UL_ALLOCATE_POOL(
  454. PagedPool,
  455. daclLength,
  456. UL_SECURITY_DATA_POOL_TAG
  457. );
  458. if (pDacl == NULL)
  459. {
  460. status = STATUS_INSUFFICIENT_RESOURCES;
  461. goto cleanup;
  462. }
  463. status = RtlCreateAcl(
  464. pDacl, // Acl
  465. daclLength, // AclLength
  466. ACL_REVISION // AclRevision
  467. );
  468. if (!NT_SUCCESS(status))
  469. {
  470. goto cleanup;
  471. }
  472. //
  473. // Add the necessary access-allowed ACEs to the DACL.
  474. //
  475. for (i = 0 ; i < NumSidMaskPairs ; i++)
  476. {
  477. status = RtlAddAccessAllowedAceEx(
  478. pDacl, // Acl
  479. ACL_REVISION, // AceRevision
  480. pSidMaskPairs[i].AceFlags, // Inheritance flags
  481. pSidMaskPairs[i].AccessMask, // AccessMask
  482. pSidMaskPairs[i].pSid // Sid
  483. );
  484. if (!NT_SUCCESS(status))
  485. {
  486. goto cleanup;
  487. }
  488. }
  489. //
  490. // Attach the DACL to the security descriptor.
  491. //
  492. status = RtlSetDaclSecurityDescriptor(
  493. pSecurityDescriptor, // SecurityDescriptor
  494. TRUE, // DaclPresent
  495. pDacl, // Dacl
  496. FALSE // DaclDefaulted
  497. );
  498. if (!NT_SUCCESS(status))
  499. {
  500. goto cleanup;
  501. }
  502. //
  503. // Success!
  504. //
  505. ASSERT( NT_SUCCESS(status) );
  506. return STATUS_SUCCESS;
  507. cleanup:
  508. ASSERT( !NT_SUCCESS(status) );
  509. if (pDacl != NULL)
  510. {
  511. UL_FREE_POOL(
  512. pDacl,
  513. UL_SECURITY_DATA_POOL_TAG
  514. );
  515. }
  516. return status;
  517. } // UlpCreateSecurityDescriptor
  518. /***************************************************************************++
  519. Routine Description:
  520. Frees any resources associated with the security descriptor created
  521. by UlpCreateSecurityDescriptor().
  522. Arguments:
  523. pSecurityDescriptor - Supplies the security descriptor to cleanup.
  524. --***************************************************************************/
  525. VOID
  526. UlCleanupSecurityDescriptor(
  527. IN PSECURITY_DESCRIPTOR pSecurityDescriptor
  528. )
  529. {
  530. NTSTATUS status;
  531. PACL pDacl;
  532. BOOLEAN daclPresent;
  533. BOOLEAN daclDefaulted;
  534. //
  535. // Sanity check.
  536. //
  537. PAGED_CODE();
  538. ASSERT( RtlValidSecurityDescriptor( pSecurityDescriptor ) );
  539. //
  540. // Try to retrieve the DACL from the security descriptor.
  541. //
  542. status = RtlGetDaclSecurityDescriptor(
  543. pSecurityDescriptor, // SecurityDescriptor
  544. &daclPresent, // DaclPresent
  545. &pDacl, // Dacl
  546. &daclDefaulted // DaclDefaulted
  547. );
  548. if (NT_SUCCESS(status))
  549. {
  550. if (daclPresent && (pDacl != NULL))
  551. {
  552. UL_FREE_POOL(
  553. pDacl,
  554. UL_SECURITY_DATA_POOL_TAG
  555. );
  556. }
  557. }
  558. } // UlCleanupSecurityDescriptor
  559. /**************************************************************************++
  560. Routine Description:
  561. This routine maps the generic access masks of the ACE's present in the
  562. DACL of the supplied security descriptor.
  563. CODEWORK: Get RtlpApplyAclToObject exported.
  564. Arguments:
  565. pSecurityDescriptor - Supplies security descriptor.
  566. Return Value:
  567. NTSTATUS.
  568. --**************************************************************************/
  569. NTSTATUS
  570. UlMapGenericMask(
  571. PSECURITY_DESCRIPTOR pSecurityDescriptor
  572. )
  573. {
  574. ULONG i;
  575. PACE_HEADER Ace;
  576. PACL Dacl;
  577. NTSTATUS Status;
  578. BOOLEAN Ignore;
  579. BOOLEAN DaclPresent = FALSE;
  580. //
  581. // Get the DACL.
  582. //
  583. Status = RtlGetDaclSecurityDescriptor(
  584. pSecurityDescriptor,
  585. &DaclPresent,
  586. &Dacl,
  587. &Ignore
  588. );
  589. if (!NT_SUCCESS(Status))
  590. {
  591. return Status;
  592. }
  593. if (DaclPresent)
  594. {
  595. //
  596. // RtlpApplyAclToObject(Acl, GenericMapping) is cloned below since
  597. // it is not exported.
  598. //
  599. //
  600. // Now walk the ACL, mapping each ACE as we go.
  601. //
  602. for (i = 0, Ace = FirstAce(Dacl);
  603. i < Dacl->AceCount;
  604. i += 1, Ace = NextAce(Ace))
  605. {
  606. if (IsMSAceType(Ace))
  607. {
  608. RtlApplyAceToObject(Ace, &g_UrlAccessGenericMapping);
  609. }
  610. }
  611. }
  612. return STATUS_SUCCESS;
  613. }
  614. //
  615. // Private functions.
  616. //