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.

1598 lines
47 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. Secure.c
  5. Abstract:
  6. Security implementation for WMI objects
  7. WMI security is guid based, that is each guid can be assigned a security
  8. descriptor. There is also a default security descriptor that applies
  9. to any guid that does not have its own specific security descriptor.
  10. Security is enforced by relying upon the object manager. We define the
  11. WmiGuid object type and require all WMI requests to have a handle to the
  12. WmiGuid object. In this way the guid is opened with a specific ACCESS_MASK
  13. and if the caller is permitted those rights (as specified in the specific
  14. or default security descriptor) then a handle is returned. When the
  15. caller wants to do an operation he must pass the handle and before the
  16. operation is performed we check that the handle has the allowed access.
  17. Guid security descriptors are serialized as REG_BINARY values under the
  18. registry key HKLM\CurrentControlSet\Control\Wmi\Security. If no specific
  19. or default security descriptor for a guid exists then the all access
  20. is available for anyone. For this reason this registry key must be
  21. protected.
  22. WMI implements its own security method for the WmiGuid object type to
  23. allow it to intercept any changes to an objects security descriptor. By
  24. doing this we allow the standard security apis
  25. (Get/SetKernelObjectSecurity) to query and set the WMI security
  26. descriptors.
  27. A guid security descriptor contains the following specific rights:
  28. WMIGUID_QUERY 0x0001
  29. WMIGUID_SET 0x0002
  30. WMIGUID_NOTIFICATION 0x0004
  31. WMIGUID_READ_DESCRIPTION 0x0008
  32. WMIGUID_EXECUTE 0x0010
  33. TRACELOG_CREATE_REALTIME 0x0020
  34. TRACELOG_CREATE_ONDISK 0x0040
  35. TRACELOG_GUID_ENABLE 0x0080
  36. TRACELOG_ACCESS_KERNEL_LOGGER 0x0100
  37. Security is only implemented for NT and not MEMPHIS
  38. Author:
  39. AlanWar
  40. Environment:
  41. Kernel mode
  42. Revision History:
  43. --*/
  44. #ifndef MEMPHIS
  45. #include "wmikmp.h"
  46. NTSTATUS
  47. WmipSecurityMethod (
  48. IN PVOID Object,
  49. IN SECURITY_OPERATION_CODE OperationCode,
  50. IN PSECURITY_INFORMATION SecurityInformation,
  51. IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  52. IN OUT PULONG CapturedLength,
  53. IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
  54. IN POOL_TYPE PoolType,
  55. IN PGENERIC_MAPPING GenericMapping
  56. );
  57. VOID WmipDeleteMethod(
  58. IN PVOID Object
  59. );
  60. VOID WmipCloseMethod(
  61. IN PEPROCESS Process OPTIONAL,
  62. IN PVOID Object,
  63. IN ACCESS_MASK GrantedAccess,
  64. IN ULONG ProcessHandleCount,
  65. IN ULONG SystemHandleCount
  66. );
  67. NTSTATUS
  68. WmipGetGuidSecurityDescriptor(
  69. PUNICODE_STRING GuidName,
  70. PSECURITY_DESCRIPTOR *SecurityDescriptor
  71. );
  72. NTSTATUS
  73. WmipSaveGuidSecurityDescriptor(
  74. PUNICODE_STRING GuidName,
  75. PSECURITY_DESCRIPTOR SecurityDescriptor
  76. );
  77. NTSTATUS
  78. WmipSDRegistryQueryRoutine(
  79. IN PWSTR ValueName,
  80. IN ULONG ValueType,
  81. IN PVOID ValueData,
  82. IN ULONG ValueLength,
  83. IN PVOID Context,
  84. IN PVOID EntryContext
  85. );
  86. NTSTATUS
  87. WmipCreateGuidObject(
  88. IN POBJECT_ATTRIBUTES ObjectAttributes,
  89. IN ACCESS_MASK DesiredAccess,
  90. IN LPGUID Guid,
  91. OUT PHANDLE CreatorHandle,
  92. OUT PWMIGUIDOBJECT *Object
  93. );
  94. NTSTATUS
  95. WmipUuidFromString (
  96. IN PWCHAR StringUuid,
  97. OUT LPGUID Uuid
  98. );
  99. BOOLEAN
  100. WmipHexStringToDword(
  101. IN PWCHAR lpsz,
  102. OUT PULONG RetValue,
  103. IN ULONG cDigits,
  104. IN WCHAR chDelim
  105. );
  106. VOID WmipCloseMethod(
  107. IN PEPROCESS Process OPTIONAL,
  108. IN PVOID Object,
  109. IN ACCESS_MASK GrantedAccess,
  110. IN ULONG ProcessHandleCount,
  111. IN ULONG SystemHandleCount
  112. );
  113. #ifdef ALLOC_PRAGMA
  114. #pragma alloc_text(INIT,WmipInitializeSecurity)
  115. #pragma alloc_text(PAGE,WmipGetGuidSecurityDescriptor)
  116. #pragma alloc_text(PAGE,WmipSaveGuidSecurityDescriptor)
  117. #pragma alloc_text(PAGE,WmipOpenGuidObject)
  118. #pragma alloc_text(PAGE,WmipCheckGuidAccess)
  119. #pragma alloc_text(PAGE,WmipSDRegistryQueryRoutine)
  120. #pragma alloc_text(PAGE,WmipSecurityMethod)
  121. #pragma alloc_text(PAGE,WmipDeleteMethod)
  122. #pragma alloc_text(PAGE,WmipCreateGuidObject)
  123. #pragma alloc_text(PAGE,WmipUuidFromString)
  124. #pragma alloc_text(PAGE,WmipHexStringToDword)
  125. #pragma alloc_text(PAGE,WmipCloseMethod)
  126. #endif
  127. #ifdef ALLOC_DATA_PRAGMA
  128. #pragma const_seg("PAGECONST")
  129. #pragma data_seg("PAGEDATA")
  130. #endif
  131. //
  132. // Subject context for the System process, captured at boot
  133. SECURITY_SUBJECT_CONTEXT WmipSystemSubjectContext;
  134. //
  135. // Object type object created by Ob when registering WmiGuid object type
  136. POBJECT_TYPE WmipGuidObjectType;
  137. //
  138. // SD attached to a guid when no specific or default SD exists in the
  139. // registry. Created at boot, it allows all WMI access to WORLD and full
  140. // access to System and Administrators group.
  141. SECURITY_DESCRIPTOR WmipAnyoneAccessSecurityDescriptor;
  142. PSECURITY_DESCRIPTOR WmipAnyoneAccessSd;
  143. //
  144. // Generic mapping for specific rights
  145. const GENERIC_MAPPING WmipGenericMapping =
  146. {
  147. STANDARD_RIGHTS_READ | // GENERIC_READ <--> WMIGUID_QUERY
  148. WMIGUID_QUERY,
  149. STANDARD_RIGHTS_WRITE | // GENERIC_WRUTE <--> WMIGUID_SET
  150. WMIGUID_SET,
  151. STANDARD_RIGHTS_EXECUTE | // GENERIC_EXECUTE <--> WMIGUID_EXECUTE
  152. WMIGUID_EXECUTE,
  153. WMIGUID_ALL_ACCESS | STANDARD_RIGHTS_READ
  154. };
  155. NTSTATUS
  156. WmipSecurityMethod (
  157. IN PVOID Object,
  158. IN SECURITY_OPERATION_CODE OperationCode,
  159. IN PSECURITY_INFORMATION SecurityInformation,
  160. IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  161. IN OUT PULONG CapturedLength,
  162. IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
  163. IN POOL_TYPE PoolType,
  164. IN PGENERIC_MAPPING GenericMapping
  165. )
  166. /*++
  167. Routine Description:
  168. This is the WMI security method for objects. It is responsible
  169. for either retrieving, setting, and deleting the security descriptor of
  170. an object. It is not used to assign the original security descriptor
  171. to an object (use SeAssignSecurity for that purpose).
  172. IT IS ASSUMED THAT THE OBJECT MANAGER HAS ALREADY DONE THE ACCESS
  173. VALIDATIONS NECESSARY TO ALLOW THE REQUESTED OPERATIONS TO BE PERFORMED.
  174. This code stolen directly from SeDefaultObjectMethod in
  175. \nt\private\ntos\se\semethod.c. It does not do anything special except
  176. serialize any SD that is being set for an object.
  177. Arguments:
  178. Object - Supplies a pointer to the object being used.
  179. OperationCode - Indicates if the operation is for setting, querying, or
  180. deleting the object's security descriptor.
  181. SecurityInformation - Indicates which security information is being
  182. queried or set. This argument is ignored for the delete operation.
  183. SecurityDescriptor - The meaning of this parameter depends on the
  184. OperationCode:
  185. QuerySecurityDescriptor - For the query operation this supplies the
  186. buffer to copy the descriptor into. The security descriptor is
  187. assumed to have been probed up to the size passed in in Length.
  188. Since it still points into user space, it must always be
  189. accessed in a try clause in case it should suddenly disappear.
  190. SetSecurityDescriptor - For a set operation this supplies the
  191. security descriptor to copy into the object. The security
  192. descriptor must be captured before this routine is called.
  193. DeleteSecurityDescriptor - It is ignored when deleting a security
  194. descriptor.
  195. AssignSecurityDescriptor - For assign operations this is the
  196. security descriptor that will be assigned to the object.
  197. It is assumed to be in kernel space, and is therefore not
  198. probed or captured.
  199. CapturedLength - For the query operation this specifies the length, in
  200. bytes, of the security descriptor buffer, and upon return contains
  201. the number of bytes needed to store the descriptor. If the length
  202. needed is greater than the length supplied the operation will fail.
  203. It is ignored in the set and delete operation.
  204. This parameter is assumed to be captured and probed as appropriate.
  205. ObjectsSecurityDescriptor - For the Set operation this supplies the address
  206. of a pointer to the object's current security descriptor. This routine
  207. will either modify the security descriptor in place or allocate a new
  208. security descriptor and use this variable to indicate its new location.
  209. For the query operation it simply supplies the security descriptor
  210. being queried. The caller is responsible for freeing the old security
  211. descriptor.
  212. PoolType - For the set operation this specifies the pool type to use if
  213. a new security descriptor needs to be allocated. It is ignored
  214. in the query and delete operation.
  215. the mapping of generic to specific/standard access types for the object
  216. being accessed. This mapping structure is expected to be safe to
  217. access (i.e., captured if necessary) prior to be passed to this routine.
  218. Return Value:
  219. NTSTATUS - STATUS_SUCCESS if the operation is successful and an
  220. appropriate error status otherwise.
  221. --*/
  222. {
  223. NTSTATUS Status;
  224. PAGED_CODE();
  225. //
  226. // If the object's security descriptor is null, then object is not
  227. // one that has security information associated with it. Return
  228. // an error.
  229. //
  230. //
  231. // Make sure the common parts of our input are proper
  232. //
  233. ASSERT( (OperationCode == SetSecurityDescriptor) ||
  234. (OperationCode == QuerySecurityDescriptor) ||
  235. (OperationCode == AssignSecurityDescriptor) ||
  236. (OperationCode == DeleteSecurityDescriptor) );
  237. //
  238. // This routine simply cases off of the operation code to decide
  239. // which support routine to call
  240. //
  241. switch (OperationCode) {
  242. case SetSecurityDescriptor:
  243. {
  244. UNICODE_STRING GuidName;
  245. WCHAR GuidBuffer[38];
  246. LPGUID Guid;
  247. SECURITY_INFORMATION LocalSecInfo;
  248. PSECURITY_DESCRIPTOR SecurityDescriptorCopy;
  249. ULONG SecurityDescriptorLength;
  250. ULONG Status2;
  251. ASSERT( (PoolType == PagedPool) || (PoolType == NonPagedPool) );
  252. Status = ObReferenceObjectByPointer(Object,
  253. 0,
  254. WmipGuidObjectType,
  255. KernelMode);
  256. ASSERT(Status == STATUS_SUCCESS);
  257. if (NT_SUCCESS(Status))
  258. {
  259. Status = ObSetSecurityDescriptorInfo( Object,
  260. SecurityInformation,
  261. SecurityDescriptor,
  262. ObjectsSecurityDescriptor,
  263. PoolType,
  264. GenericMapping
  265. );
  266. if (NT_SUCCESS(Status))
  267. {
  268. //
  269. // Serialize the guid's new security descriptor in
  270. // the registry. But first we need to get a copy of
  271. // it.
  272. SecurityDescriptorLength = 1024;
  273. do
  274. {
  275. SecurityDescriptorCopy = ExAllocatePoolWithTag(
  276. PoolType,
  277. SecurityDescriptorLength,
  278. WMIPOOLTAG);
  279. if (SecurityDescriptorCopy == NULL)
  280. {
  281. Status2 = STATUS_INSUFFICIENT_RESOURCES;
  282. break;
  283. }
  284. LocalSecInfo = 0xffffffff;
  285. Status2 = ObQuerySecurityDescriptorInfo( Object,
  286. &LocalSecInfo,
  287. SecurityDescriptorCopy,
  288. &SecurityDescriptorLength,
  289. ObjectsSecurityDescriptor);
  290. if (Status2 == STATUS_BUFFER_TOO_SMALL)
  291. {
  292. ExFreePool(SecurityDescriptorCopy);
  293. } else {
  294. break;
  295. }
  296. } while (TRUE);
  297. if (NT_SUCCESS(Status2))
  298. {
  299. Guid = &((PWMIGUIDOBJECT)Object)->Guid;
  300. swprintf(GuidBuffer,
  301. L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  302. Guid->Data1, Guid->Data2,
  303. Guid->Data3,
  304. Guid->Data4[0], Guid->Data4[1],
  305. Guid->Data4[2], Guid->Data4[3],
  306. Guid->Data4[4], Guid->Data4[5],
  307. Guid->Data4[6], Guid->Data4[7]);
  308. RtlInitUnicodeString(&GuidName, GuidBuffer);
  309. WmipSaveGuidSecurityDescriptor(&GuidName,
  310. SecurityDescriptorCopy);
  311. }
  312. if (SecurityDescriptorCopy != NULL)
  313. {
  314. ExFreePool(SecurityDescriptorCopy);
  315. }
  316. }
  317. ObDereferenceObject(Object);
  318. }
  319. return(Status);
  320. }
  321. case QuerySecurityDescriptor:
  322. {
  323. //
  324. // check the rest of our input and call the default query security
  325. // method
  326. //
  327. ASSERT( CapturedLength != NULL );
  328. return ObQuerySecurityDescriptorInfo( Object,
  329. SecurityInformation,
  330. SecurityDescriptor,
  331. CapturedLength,
  332. ObjectsSecurityDescriptor );
  333. return(Status);
  334. }
  335. case DeleteSecurityDescriptor:
  336. {
  337. //
  338. // call the default delete security method
  339. //
  340. Status = ObDeassignSecurity(ObjectsSecurityDescriptor);
  341. return(Status);
  342. }
  343. case AssignSecurityDescriptor:
  344. ObAssignObjectSecurityDescriptor( Object,
  345. SecurityDescriptor,
  346. PoolType );
  347. return( STATUS_SUCCESS );
  348. default:
  349. //
  350. // Bugcheck on any other operation code, We won't get here if
  351. // the earlier asserts are still checked.
  352. //
  353. KeBugCheckEx( SECURITY_SYSTEM, 1, STATUS_INVALID_PARAMETER, 0, 0 );
  354. return (0); // bash compiler
  355. }
  356. }
  357. NTSTATUS WmipInitializeSecurity(
  358. void
  359. )
  360. /*++
  361. Routine Description:
  362. This routine will initialize WMI security subsystem. Basically we
  363. create the WMIGUID object type, obtain the SECURITY_SUBJECT_CONTEXT for
  364. the System process and establish a SD that allows all access that is used
  365. when no default or specific SD is assigned to a guid.
  366. Arguments:
  367. Return Value:
  368. NT Status code
  369. --*/
  370. {
  371. NTSTATUS Status;
  372. UNICODE_STRING ObjectTypeName;
  373. POBJECT_TYPE ObjectType;
  374. OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
  375. OBJECT_ATTRIBUTES ObjectAttributes;
  376. HANDLE Handle;
  377. ULONG DaclLength;
  378. PACL AnyoneAccessDacl;
  379. PAGED_CODE();
  380. //
  381. // Establish a SD for those guids with no specific or default SD
  382. DaclLength = (ULONG)sizeof(ACL) +
  383. (3*((ULONG)sizeof(ACCESS_ALLOWED_ACE))) +
  384. SeLengthSid( SeLocalSystemSid ) +
  385. SeLengthSid( SeAliasAdminsSid ) +
  386. SeLengthSid( SeWorldSid ) +
  387. 8; // The 8 is just for good measure
  388. AnyoneAccessDacl = (PACL)ExAllocatePoolWithTag(PagedPool,
  389. DaclLength,
  390. WMIPOOLTAG);
  391. if (AnyoneAccessDacl == NULL)
  392. {
  393. return(STATUS_INSUFFICIENT_RESOURCES);
  394. }
  395. Status = RtlCreateAcl( AnyoneAccessDacl,
  396. DaclLength,
  397. ACL_REVISION2);
  398. if (! NT_SUCCESS(Status))
  399. {
  400. goto Cleanup;
  401. }
  402. Status = RtlAddAccessAllowedAce (
  403. AnyoneAccessDacl,
  404. ACL_REVISION2,
  405. (STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL),
  406. SeLocalSystemSid
  407. );
  408. if (! NT_SUCCESS(Status))
  409. {
  410. goto Cleanup;
  411. }
  412. Status = RtlAddAccessAllowedAce (
  413. AnyoneAccessDacl,
  414. ACL_REVISION2,
  415. (STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL),
  416. SeAliasAdminsSid
  417. );
  418. if (! NT_SUCCESS(Status))
  419. {
  420. goto Cleanup;
  421. }
  422. Status = RtlAddAccessAllowedAce (
  423. AnyoneAccessDacl,
  424. ACL_REVISION2,
  425. WMIGUID_ALL_ACCESS,
  426. SeWorldSid
  427. );
  428. if (! NT_SUCCESS(Status))
  429. {
  430. goto Cleanup;
  431. }
  432. WmipAnyoneAccessSd = &WmipAnyoneAccessSecurityDescriptor;
  433. Status = RtlCreateSecurityDescriptor(
  434. WmipAnyoneAccessSd,
  435. SECURITY_DESCRIPTOR_REVISION1
  436. );
  437. Status = RtlSetDaclSecurityDescriptor(
  438. WmipAnyoneAccessSd,
  439. TRUE, // DaclPresent
  440. AnyoneAccessDacl,
  441. FALSE // DaclDefaulted
  442. );
  443. if (! NT_SUCCESS(Status))
  444. {
  445. goto Cleanup;
  446. }
  447. Status = RtlSetOwnerSecurityDescriptor(WmipAnyoneAccessSd,
  448. SeAliasAdminsSid,
  449. FALSE);
  450. if (! NT_SUCCESS(Status))
  451. {
  452. goto Cleanup;
  453. }
  454. Status = RtlSetGroupSecurityDescriptor(WmipAnyoneAccessSd,
  455. SeAliasAdminsSid,
  456. FALSE);
  457. if (! NT_SUCCESS(Status))
  458. {
  459. Cleanup:
  460. ExFreePool(AnyoneAccessDacl);
  461. WmipAnyoneAccessSd = NULL;
  462. return(Status);
  463. }
  464. //
  465. // Remember System process subject context
  466. SeCaptureSubjectContext(&WmipSystemSubjectContext);
  467. //
  468. // Establish WmiGuid object type
  469. RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
  470. ObjectTypeInitializer.Length = sizeof(OBJECT_TYPE_INITIALIZER);
  471. ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
  472. ObjectTypeInitializer.GenericMapping = WmipGenericMapping;
  473. ObjectTypeInitializer.ValidAccessMask = WMIGUID_ALL_ACCESS | STANDARD_RIGHTS_ALL;
  474. //
  475. // All named objects may (must ?) have security descriptors attached
  476. // to them. If unnamed objects also must have security descriptors
  477. // attached then this must be TRUE
  478. ObjectTypeInitializer.SecurityRequired = TRUE;
  479. //
  480. // Tracks # handles open for object within a process
  481. ObjectTypeInitializer.MaintainHandleCount = FALSE;
  482. //
  483. // Need to be in non paged pool since KEVENT contained within the
  484. // object must be in non paged pool
  485. //
  486. ObjectTypeInitializer.PoolType = NonPagedPool;
  487. ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(WMIGUIDOBJECT);
  488. //
  489. // Use a custom security procedure so that we can serialize any
  490. // changes to the security descriptor.
  491. ObjectTypeInitializer.SecurityProcedure = WmipSecurityMethod;
  492. //
  493. // We need to know when an object is being deleted
  494. //
  495. ObjectTypeInitializer.DeleteProcedure = WmipDeleteMethod;
  496. ObjectTypeInitializer.CloseProcedure = WmipCloseMethod;
  497. RtlInitUnicodeString(&ObjectTypeName, L"WmiGuid");
  498. Status = ObCreateObjectType(&ObjectTypeName,
  499. &ObjectTypeInitializer,
  500. NULL,
  501. &WmipGuidObjectType);
  502. if (! NT_SUCCESS(Status))
  503. {
  504. goto Cleanup;
  505. }
  506. #if 0
  507. //
  508. // don't need to create obejct dir
  509. //
  510. RtlInitUnicodeString( &ObjectTypeName, L"\\WmiGuid" );
  511. InitializeObjectAttributes( &ObjectAttributes,
  512. &ObjectTypeName,
  513. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  514. NULL,
  515. SePublicDefaultSd );
  516. Status = NtCreateDirectoryObject( &Handle,
  517. DIRECTORY_ALL_ACCESS,
  518. &ObjectAttributes );
  519. if (NT_SUCCESS(Status))
  520. {
  521. NtClose(Handle);
  522. }
  523. #endif
  524. return(Status);
  525. }
  526. NTSTATUS WmipSDRegistryQueryRoutine(
  527. IN PWSTR ValueName,
  528. IN ULONG ValueType,
  529. IN PVOID ValueData,
  530. IN ULONG ValueLength,
  531. IN PVOID Context,
  532. IN PVOID EntryContext
  533. )
  534. /*++
  535. Routine Description:
  536. Registry query values callback routine for reading SDs for guids
  537. Arguments:
  538. ValueName - the name of the value
  539. ValueType - the type of the value
  540. ValueData - the data in the value (unicode string data)
  541. ValueLength - the number of bytes in the value data
  542. Context - Not used
  543. EntryContext - Pointer to PSECURITTY_DESCRIPTOR to store a pointer to
  544. store the security descriptor read from the registry value
  545. Return Value:
  546. NT Status code
  547. --*/
  548. {
  549. PSECURITY_DESCRIPTOR *SecurityDescriptor;
  550. NTSTATUS Status;
  551. PAGED_CODE();
  552. Status = STATUS_SUCCESS;
  553. if ((ValueType == REG_BINARY) &&
  554. (ValueData != NULL))
  555. {
  556. //
  557. // If a SD is specified in the registry then copy it
  558. SecurityDescriptor = (PSECURITY_DESCRIPTOR *)EntryContext;
  559. *SecurityDescriptor = ExAllocatePoolWithTag(PagedPool,
  560. ValueLength,
  561. WMIPOOLTAG);
  562. if (*SecurityDescriptor != NULL)
  563. {
  564. RtlCopyMemory(*SecurityDescriptor,
  565. ValueData,
  566. ValueLength);
  567. } else {
  568. Status = STATUS_INSUFFICIENT_RESOURCES;
  569. }
  570. }
  571. return(Status);
  572. }
  573. NTSTATUS WmipSaveGuidSecurityDescriptor(
  574. PUNICODE_STRING GuidName,
  575. PSECURITY_DESCRIPTOR SecurityDescriptor
  576. )
  577. /*++
  578. Routine Description:
  579. This routine will serialize the security descriptor associated with a
  580. guid.
  581. Security descriptors are maintained as REG_BINARY values named by the guid
  582. in the registry under
  583. HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Wmi\Security
  584. Arguments:
  585. GuidName is a pointer to a unicode string that represents the guid
  586. SecurityDescriptor points at a self relative security descriptor
  587. Return Value:
  588. NT Status code
  589. --*/
  590. {
  591. ULONG SecurityDescriptorLength;
  592. NTSTATUS Status;
  593. PAGED_CODE();
  594. SecurityDescriptorLength = RtlLengthSecurityDescriptor(SecurityDescriptor);
  595. Status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL,
  596. L"WMI\\Security",
  597. GuidName->Buffer,
  598. REG_BINARY,
  599. SecurityDescriptor,
  600. SecurityDescriptorLength);
  601. return(Status);
  602. }
  603. NTSTATUS WmipGetGuidSecurityDescriptor(
  604. PUNICODE_STRING GuidName,
  605. PSECURITY_DESCRIPTOR *SecurityDescriptor
  606. )
  607. /*++
  608. Routine Description:
  609. This routine will retrieve the security descriptor associated with a
  610. guid. First it looks for a security descriptor specifically for the
  611. guid and if not found then looks for the default security descriptor.
  612. Security descriptors are maintained as REG_BINARY values named by the guid
  613. in the registry under
  614. HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Wmi\Security
  615. Arguments:
  616. GuidName is a pointer to a unicode string that represents the guid
  617. *SecurityDescriptor returns the security descriptor for the guid. It
  618. must be freed back to pool unless it is the same value as that in
  619. WmipAnyoneAccessSd which must NOT be freed.
  620. Return Value:
  621. NT Status code
  622. --*/
  623. {
  624. RTL_QUERY_REGISTRY_TABLE QueryRegistryTable[3];
  625. NTSTATUS Status;
  626. PSECURITY_DESCRIPTOR GuidSecurityDescriptor = NULL;
  627. PSECURITY_DESCRIPTOR DefaultSecurityDescriptor = NULL;
  628. PAGED_CODE();
  629. RtlZeroMemory(QueryRegistryTable, sizeof(QueryRegistryTable));
  630. QueryRegistryTable[0].QueryRoutine = WmipSDRegistryQueryRoutine;
  631. QueryRegistryTable[0].EntryContext = &GuidSecurityDescriptor;
  632. QueryRegistryTable[0].Name = GuidName->Buffer;
  633. QueryRegistryTable[0].DefaultType = REG_BINARY;
  634. QueryRegistryTable[1].QueryRoutine = WmipSDRegistryQueryRoutine;
  635. QueryRegistryTable[1].Flags = 0;
  636. QueryRegistryTable[1].EntryContext = &DefaultSecurityDescriptor;
  637. QueryRegistryTable[1].Name = DefaultSecurityGuidName;
  638. QueryRegistryTable[1].DefaultType = REG_BINARY;
  639. Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
  640. L"WMI\\Security",
  641. QueryRegistryTable,
  642. NULL,
  643. NULL);
  644. *SecurityDescriptor = NULL;
  645. if (NT_SUCCESS(Status))
  646. {
  647. //
  648. // If there is a guid specific SD then choose that and free any
  649. // default SD. Else we use the default SD unless that doesn't
  650. // exist and so there is no security
  651. if (GuidSecurityDescriptor != NULL)
  652. {
  653. *SecurityDescriptor = GuidSecurityDescriptor;
  654. if (DefaultSecurityDescriptor != NULL)
  655. {
  656. ExFreePool(DefaultSecurityDescriptor);
  657. }
  658. } else if (DefaultSecurityDescriptor != NULL) {
  659. *SecurityDescriptor = DefaultSecurityDescriptor;
  660. }
  661. } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  662. Status = STATUS_SUCCESS;
  663. }
  664. if (*SecurityDescriptor == NULL)
  665. {
  666. *SecurityDescriptor = WmipAnyoneAccessSd;
  667. }
  668. return(Status);
  669. }
  670. NTSTATUS WmipOpenGuidObject(
  671. IN POBJECT_ATTRIBUTES CapturedObjectAttributes,
  672. IN ACCESS_MASK DesiredAccess,
  673. IN KPROCESSOR_MODE AccessMode,
  674. OUT PHANDLE Handle,
  675. OUT PWMIGUIDOBJECT *ObjectPtr
  676. )
  677. /*++
  678. Routine Description:
  679. This routine will open a handle to a WmiGuid object with the access rights
  680. specified. WmiGuid objects are temporary objects that are created on an
  681. as needed basis. We will always create a new unnamed guid object each time
  682. a guid is opened.
  683. Arguments:
  684. GuidString is the string representation for the guid that refers to
  685. the object to open. Note that this parameter has NOT been probed.
  686. Parse UUID such as \WmiGuid\00000000-0000-0000-0000-000000000000
  687. DesiredAccess specifies the access requested
  688. *Handle returns a handle to the guid object
  689. *ObjectPtr returns containing a pointer to the object. This object
  690. will have a reference attached to it that must be derefed by
  691. the calling code.
  692. Return Value:
  693. NT Status code
  694. --*/
  695. {
  696. NTSTATUS Status;
  697. GUID Guid;
  698. PWMIGUIDOBJECT GuidObject;
  699. HANDLE CreatorHandle;
  700. PUNICODE_STRING CapturedGuidString;
  701. PAGED_CODE();
  702. //
  703. // Validate guid object name passed by insuring that it is in the
  704. // correct object directory and the correct format for a uuid
  705. CapturedGuidString = CapturedObjectAttributes->ObjectName;
  706. if (RtlEqualMemory(CapturedGuidString->Buffer,
  707. WmiGuidObjectDirectory,
  708. (WmiGuidObjectDirectoryLength-1) * sizeof(WCHAR)) == 0)
  709. {
  710. return(STATUS_INVALID_PARAMETER);
  711. }
  712. Status = WmipUuidFromString(&CapturedGuidString->Buffer[9], &Guid);
  713. if (! NT_SUCCESS(Status))
  714. {
  715. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Invalid uuid format for guid object %ws\n", CapturedGuidString->Buffer));
  716. return(Status);
  717. }
  718. //
  719. // If it does not exist then create an object for the guid ....
  720. //
  721. Status = WmipCreateGuidObject(CapturedObjectAttributes,
  722. DesiredAccess,
  723. &Guid,
  724. &CreatorHandle,
  725. &GuidObject);
  726. if (NT_SUCCESS(Status))
  727. {
  728. //
  729. // .... and try again to open it
  730. //
  731. Status = ObOpenObjectByPointer(GuidObject,
  732. 0,
  733. NULL,
  734. DesiredAccess,
  735. WmipGuidObjectType,
  736. AccessMode,
  737. Handle);
  738. if (! NT_SUCCESS(Status))
  739. {
  740. //
  741. // Remove extra ref count taken by ObInsertObject since we
  742. // are returning an error
  743. //
  744. ObDereferenceObject(GuidObject);
  745. }
  746. //
  747. // Make sure to close handle obtained in creating object. We
  748. // attach to the system process since the handle was created in
  749. // its handle table.
  750. //
  751. KeAttachProcess( &PsInitialSystemProcess->Pcb );
  752. ZwClose(CreatorHandle);
  753. KeDetachProcess( );
  754. *ObjectPtr = GuidObject;
  755. }
  756. return(Status);
  757. }
  758. NTSTATUS WmipCreateGuidObject(
  759. IN OUT POBJECT_ATTRIBUTES ObjectAttributes,
  760. IN ACCESS_MASK DesiredAccess,
  761. IN LPGUID Guid,
  762. OUT PHANDLE CreatorHandle,
  763. OUT PWMIGUIDOBJECT *Object
  764. )
  765. /*++
  766. Routine Description:
  767. This routine will create a new guid object for
  768. the guid passed. The handle returned is the handle issued to the creator
  769. of the object and should be closed after the object is opened.
  770. Guid Objects are created on the fly, but
  771. Arguments:
  772. ObjectAttributes - Describes object being created. ObjectAttributes
  773. is modified in this call.
  774. Guid is the guid for which the object is being created
  775. *CreatorHandle returns a handle to the created guid object. This handle
  776. is in the system process handle table
  777. *Object returns with a pointer to the object
  778. Return Value:
  779. NT Status code
  780. --*/
  781. {
  782. PSECURITY_DESCRIPTOR SecurityDescriptor;
  783. UNICODE_STRING UnicodeString;
  784. WCHAR *ObjectNameBuffer;
  785. WCHAR *GuidBuffer;
  786. NTSTATUS Status;
  787. ACCESS_STATE LocalAccessState;
  788. AUX_ACCESS_DATA AuxData;
  789. SECURITY_SUBJECT_CONTEXT SavedSubjectContext;
  790. PSECURITY_SUBJECT_CONTEXT SubjectContext;
  791. PWMIGUIDOBJECT NewObject;
  792. OBJECT_ATTRIBUTES UnnamedObjectAttributes;
  793. PAGED_CODE();
  794. ObjectNameBuffer = ObjectAttributes->ObjectName->Buffer;
  795. GuidBuffer = &ObjectNameBuffer[9];
  796. RtlInitUnicodeString(&UnicodeString, GuidBuffer);
  797. //
  798. // Obtain security descriptor associated with the guid
  799. Status = WmipGetGuidSecurityDescriptor(&UnicodeString,
  800. &SecurityDescriptor);
  801. if (NT_SUCCESS(Status))
  802. {
  803. WmipAssert(SecurityDescriptor != NULL);
  804. //
  805. // Establish ObjectAttributes for the newly created object
  806. RtlInitUnicodeString(&UnicodeString, ObjectNameBuffer);
  807. UnnamedObjectAttributes = *ObjectAttributes;
  808. UnnamedObjectAttributes.Attributes = OBJ_OPENIF;
  809. UnnamedObjectAttributes.SecurityDescriptor = SecurityDescriptor;
  810. UnnamedObjectAttributes.ObjectName = NULL;
  811. //
  812. // Create an AccessState and wack on the token
  813. Status = SeCreateAccessState(&LocalAccessState,
  814. &AuxData,
  815. DesiredAccess,
  816. (PGENERIC_MAPPING)&WmipGenericMapping);
  817. if (NT_SUCCESS(Status))
  818. {
  819. SubjectContext = &LocalAccessState.SubjectSecurityContext;
  820. SavedSubjectContext = *SubjectContext;
  821. *SubjectContext = WmipSystemSubjectContext;
  822. //
  823. // Attach to system process so that the initial handle created
  824. // by ObInsertObject is not available to user mode. This handle
  825. // allows full access to the object.
  826. KeAttachProcess( &PsInitialSystemProcess->Pcb );
  827. Status = ObCreateObject(KernelMode,
  828. WmipGuidObjectType,
  829. &UnnamedObjectAttributes,
  830. KernelMode,
  831. NULL,
  832. sizeof(WMIGUIDOBJECT),
  833. 0,
  834. 0,
  835. (PVOID *)Object);
  836. if (NT_SUCCESS(Status))
  837. {
  838. //
  839. // Initialize WMIGUIDOBJECT structure
  840. //
  841. RtlZeroMemory(*Object, sizeof(WMIGUIDOBJECT));
  842. KeInitializeEvent(&(*Object)->Event,
  843. NotificationEvent,
  844. FALSE);
  845. (*Object)->HiPriority.MaxBufferSize = 0x1000;
  846. (*Object)->LoPriority.MaxBufferSize = 0x1000;
  847. (*Object)->Guid = *Guid;
  848. //
  849. // Take an extra refcount when inserting the object. We
  850. // need this ref count so that we can ensure that the
  851. // object will stick around while we are using it, but
  852. // after a handle has been made available to user mode
  853. // code. User mode can guess the handle and close it
  854. // even before we return it.
  855. //
  856. Status = ObInsertObject(*Object,
  857. &LocalAccessState,
  858. DesiredAccess,
  859. 1,
  860. &NewObject,
  861. CreatorHandle);
  862. WmipAssert(Status != STATUS_OBJECT_NAME_EXISTS);
  863. }
  864. *SubjectContext = SavedSubjectContext;
  865. SeDeleteAccessState(&LocalAccessState);
  866. KeDetachProcess( );
  867. }
  868. if (SecurityDescriptor != WmipAnyoneAccessSd)
  869. {
  870. ExFreePool(SecurityDescriptor);
  871. }
  872. }
  873. return(Status);
  874. }
  875. VOID WmipCloseMethod(
  876. IN PEPROCESS Process OPTIONAL,
  877. IN PVOID Object,
  878. IN ACCESS_MASK GrantedAccess,
  879. IN ULONG ProcessHandleCount,
  880. IN ULONG SystemHandleCount
  881. )
  882. /*++
  883. Routine Description:
  884. This routine is called whenever a guid object handle is closed. We
  885. only need to worry about this for reply object and then only when the
  886. last handle to it is closed.
  887. Arguments:
  888. Process
  889. Object
  890. GrantedAccess
  891. ProcessHandleCount
  892. SystemHandleCount
  893. Return Value:
  894. --*/
  895. {
  896. PWMIGUIDOBJECT ReplyObject, RequestObject;
  897. PLIST_ENTRY RequestList;
  898. PMBREQUESTS MBRequest;
  899. PAGED_CODE();
  900. if (SystemHandleCount == 1)
  901. {
  902. //
  903. // Only clean up if there are no more valid handles left
  904. //
  905. ReplyObject = (PWMIGUIDOBJECT)Object;
  906. if (ReplyObject->Flags & WMIGUID_FLAG_REPLY_OBJECT)
  907. {
  908. //
  909. // When a reply object is closed we need to make sure that
  910. // any referenece to it by a request object is cleaned up
  911. //
  912. ASSERT(ReplyObject->GuidEntry == NULL);
  913. WmipEnterSMCritSection();
  914. RequestList = ReplyObject->RequestListHead.Flink;
  915. while (RequestList != &ReplyObject->RequestListHead)
  916. {
  917. //
  918. //
  919. MBRequest = CONTAINING_RECORD(RequestList,
  920. MBREQUESTS,
  921. RequestListEntry);
  922. if (MBRequest->ReplyObject == ReplyObject)
  923. {
  924. RemoveEntryList(&MBRequest->RequestListEntry);
  925. MBRequest->ReplyObject = NULL;
  926. ObDereferenceObject(ReplyObject);
  927. break;
  928. }
  929. RequestList = RequestList->Flink;
  930. }
  931. WmipLeaveSMCritSection();
  932. }
  933. }
  934. }
  935. VOID WmipDeleteMethod(
  936. IN PVOID Object
  937. )
  938. {
  939. PIRP Irp;
  940. PWMIGUIDOBJECT GuidObject, ReplyObject;
  941. PMBREQUESTS MBRequest;
  942. WNODE_HEADER Wnode;
  943. PREGENTRY RegEntry;
  944. PBDATASOURCE DataSource;
  945. ULONG i;
  946. PAGED_CODE();
  947. GuidObject = (PWMIGUIDOBJECT)Object;
  948. if (GuidObject->Flags & WMIGUID_FLAG_REQUEST_OBJECT)
  949. {
  950. //
  951. // This is a request object that is going away so we need to
  952. //
  953. ASSERT(GuidObject->GuidEntry == NULL);
  954. //
  955. // First reply to all reply objects that are waiting for
  956. // a reply
  957. //
  958. WmipEnterSMCritSection();
  959. for (i = 0; i < MAXREQREPLYSLOTS; i++)
  960. {
  961. MBRequest = &GuidObject->MBRequests[i];
  962. ReplyObject = MBRequest->ReplyObject;
  963. if (ReplyObject != NULL)
  964. {
  965. Wnode.BufferSize = sizeof(WNODE_HEADER);
  966. Wnode.Flags = WNODE_FLAG_INTERNAL;
  967. Wnode.ProviderId = WmiRequestDied;
  968. WmipWriteWnodeToObject(ReplyObject,
  969. &Wnode,
  970. TRUE);
  971. RemoveEntryList(&MBRequest->RequestListEntry);
  972. MBRequest->ReplyObject = NULL;
  973. ObDereferenceObject(ReplyObject);
  974. }
  975. }
  976. //
  977. // next, unreference the regentry which will cause the regentry
  978. // to get a ref count of 0 and then ultimately remove the
  979. // DATASOURCE and all related data structures. But first make
  980. // sure to remove the pointer from the datasource to the
  981. // regentry
  982. //
  983. RegEntry = GuidObject->RegEntry;
  984. if (RegEntry != NULL)
  985. {
  986. DataSource = RegEntry->DataSource;
  987. if (DataSource != NULL)
  988. {
  989. DataSource->RequestObject = NULL;
  990. }
  991. RegEntry->Flags |= (REGENTRY_FLAG_RUNDOWN |
  992. REGENTRY_FLAG_NOT_ACCEPTING_IRPS);
  993. WmipUnreferenceRegEntry(RegEntry);
  994. }
  995. WmipLeaveSMCritSection();
  996. } else if (GuidObject->Flags & WMIGUID_FLAG_REPLY_OBJECT) {
  997. //
  998. // This is a reply obejct that is going away
  999. //
  1000. ASSERT(GuidObject->GuidEntry == NULL);
  1001. } else if (GuidObject->GuidEntry != NULL) {
  1002. //
  1003. // If there is a guid entry associated with the object
  1004. // then we need to see if we should disable collection
  1005. // or events and then remove the obejct from the
  1006. // guidentry list and finally remove the refcount on the guid
  1007. // entry held by the object
  1008. //
  1009. if (GuidObject->EnableRequestSent)
  1010. {
  1011. WmipDisableCollectOrEvent(GuidObject->GuidEntry,
  1012. GuidObject->Type,
  1013. 0);
  1014. }
  1015. WmipEnterSMCritSection();
  1016. RemoveEntryList(&GuidObject->GEObjectList);
  1017. WmipLeaveSMCritSection();
  1018. WmipUnreferenceGE(GuidObject->GuidEntry);
  1019. }
  1020. if ((GuidObject->Flags & WMIGUID_FLAG_KERNEL_NOTIFICATION) == 0)
  1021. {
  1022. //
  1023. // Clean up any queued events and irps for UM objects
  1024. //
  1025. if (GuidObject->HiPriority.Buffer != NULL)
  1026. {
  1027. WmipFree(GuidObject->HiPriority.Buffer);
  1028. }
  1029. if (GuidObject->LoPriority.Buffer != NULL)
  1030. {
  1031. WmipFree(GuidObject->LoPriority.Buffer);
  1032. }
  1033. WmipEnterSMCritSection();
  1034. if (GuidObject->EventQueueAction == RECEIVE_ACTION_NONE)
  1035. {
  1036. Irp = GuidObject->Irp;
  1037. if (Irp != NULL)
  1038. {
  1039. //
  1040. // Since this object is going away and there is an irp waiting for
  1041. // we need to make sure that the object is removed from the
  1042. // irp's list.
  1043. //
  1044. WmipClearIrpObjectList(Irp);
  1045. if (IoSetCancelRoutine(Irp, NULL))
  1046. {
  1047. //
  1048. // If the irp has not been completed yet then we
  1049. // complete it now with an error
  1050. //
  1051. Irp->IoStatus.Information = 0;
  1052. Irp->IoStatus.Status = STATUS_INVALID_HANDLE;
  1053. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1054. }
  1055. }
  1056. } else if (GuidObject->EventQueueAction == RECEIVE_ACTION_CREATE_THREAD) {
  1057. //
  1058. // If the object is going away and is part of a list of
  1059. // objects waiting for an event to start a thread, all we
  1060. // need to do is to removed the object from the list
  1061. //
  1062. WmipAssert(GuidObject->UserModeProcess != NULL);
  1063. WmipAssert(GuidObject->UserModeCallback != NULL);
  1064. WmipClearObjectFromThreadList(GuidObject);
  1065. }
  1066. WmipLeaveSMCritSection();
  1067. }
  1068. }
  1069. //
  1070. // The routines below were blantenly stolen without remorse from the ole
  1071. // sources in \nt\private\ole32\com\class\compapi.cxx. They are copied here
  1072. // so that WMI doesn't need to load in ole32 only to convert a guid string
  1073. // into its binary representation.
  1074. //
  1075. //+-------------------------------------------------------------------------
  1076. //
  1077. // Function: HexStringToDword (private)
  1078. //
  1079. // Synopsis: scan lpsz for a number of hex digits (at most 8); update lpsz
  1080. // return value in Value; check for chDelim;
  1081. //
  1082. // Arguments: [lpsz] - the hex string to convert
  1083. // [Value] - the returned value
  1084. // [cDigits] - count of digits
  1085. //
  1086. // Returns: TRUE for success
  1087. //
  1088. //--------------------------------------------------------------------------
  1089. BOOLEAN
  1090. WmipHexStringToDword(
  1091. IN PWCHAR lpsz,
  1092. OUT PULONG RetValue,
  1093. IN ULONG cDigits,
  1094. IN WCHAR chDelim
  1095. )
  1096. {
  1097. ULONG Count;
  1098. ULONG Value;
  1099. PAGED_CODE();
  1100. Value = 0;
  1101. for (Count = 0; Count < cDigits; Count++, lpsz++)
  1102. {
  1103. if (*lpsz >= '0' && *lpsz <= '9')
  1104. Value = (Value << 4) + *lpsz - '0';
  1105. else if (*lpsz >= 'A' && *lpsz <= 'F')
  1106. Value = (Value << 4) + *lpsz - 'A' + 10;
  1107. else if (*lpsz >= 'a' && *lpsz <= 'f')
  1108. Value = (Value << 4) + *lpsz - 'a' + 10;
  1109. else
  1110. return(FALSE);
  1111. }
  1112. *RetValue = Value;
  1113. if (chDelim != 0)
  1114. return *lpsz++ == chDelim;
  1115. else
  1116. return TRUE;
  1117. }
  1118. NTSTATUS
  1119. WmipUuidFromString (
  1120. IN PWCHAR StringUuid,
  1121. OUT LPGUID Uuid
  1122. )
  1123. /*++
  1124. Routine Description:
  1125. We convert a UUID from its string representation into the binary
  1126. representation. Parse UUID such as 00000000-0000-0000-0000-000000000000
  1127. Arguments:
  1128. StringUuid - supplies the string representation of the UUID. It is
  1129. assumed that this parameter has been probed and captured
  1130. Uuid - Returns the binary representation of the UUID.
  1131. Return Value:
  1132. STATUS_SUCCESS or STATUS_INVALID_PARAMETER
  1133. --*/
  1134. {
  1135. ULONG dw;
  1136. PWCHAR lpsz = StringUuid;
  1137. PAGED_CODE();
  1138. if (!WmipHexStringToDword(lpsz, &Uuid->Data1, sizeof(ULONG)*2, '-'))
  1139. {
  1140. return(STATUS_INVALID_PARAMETER);
  1141. }
  1142. lpsz += sizeof(ULONG)*2 + 1;
  1143. if (!WmipHexStringToDword(lpsz, &dw, sizeof(USHORT)*2, '-'))
  1144. {
  1145. return(STATUS_INVALID_PARAMETER);
  1146. }
  1147. Uuid->Data2 = (USHORT)dw;
  1148. lpsz += sizeof(USHORT)*2 + 1;
  1149. if (!WmipHexStringToDword(lpsz, &dw, sizeof(USHORT)*2, '-'))
  1150. {
  1151. return(STATUS_INVALID_PARAMETER);
  1152. }
  1153. Uuid->Data3 = (USHORT)dw;
  1154. lpsz += sizeof(USHORT)*2 + 1;
  1155. if (!WmipHexStringToDword(lpsz, &dw, sizeof(UCHAR)*2, 0))
  1156. {
  1157. return(STATUS_INVALID_PARAMETER);
  1158. }
  1159. Uuid->Data4[0] = (UCHAR)dw;
  1160. lpsz += sizeof(UCHAR)*2;
  1161. if (!WmipHexStringToDword(lpsz, &dw, sizeof(UCHAR)*2, '-'))
  1162. {
  1163. return(STATUS_INVALID_PARAMETER);
  1164. }
  1165. Uuid->Data4[1] = (UCHAR)dw;
  1166. lpsz += sizeof(UCHAR)*2+1;
  1167. if (!WmipHexStringToDword(lpsz, &dw, sizeof(UCHAR)*2, 0))
  1168. {
  1169. return(STATUS_INVALID_PARAMETER);
  1170. }
  1171. Uuid->Data4[2] = (UCHAR)dw;
  1172. lpsz += sizeof(UCHAR)*2;
  1173. if (!WmipHexStringToDword(lpsz, &dw, sizeof(UCHAR)*2, 0))
  1174. {
  1175. return(STATUS_INVALID_PARAMETER);
  1176. }
  1177. Uuid->Data4[3] = (UCHAR)dw;
  1178. lpsz += sizeof(UCHAR)*2;
  1179. if (!WmipHexStringToDword(lpsz, &dw, sizeof(UCHAR)*2, 0))
  1180. {
  1181. return(STATUS_INVALID_PARAMETER);
  1182. }
  1183. Uuid->Data4[4] = (UCHAR)dw;
  1184. lpsz += sizeof(UCHAR)*2;
  1185. if (!WmipHexStringToDword(lpsz, &dw, sizeof(UCHAR)*2, 0))
  1186. {
  1187. return(STATUS_INVALID_PARAMETER);
  1188. }
  1189. Uuid->Data4[5] = (UCHAR)dw;
  1190. lpsz += sizeof(UCHAR)*2;
  1191. if (!WmipHexStringToDword(lpsz, &dw, sizeof(UCHAR)*2, 0))
  1192. {
  1193. return(STATUS_INVALID_PARAMETER);
  1194. }
  1195. Uuid->Data4[6] = (UCHAR)dw;
  1196. lpsz += sizeof(UCHAR)*2;
  1197. if (!WmipHexStringToDword(lpsz, &dw, sizeof(UCHAR)*2, 0))
  1198. {
  1199. return(STATUS_INVALID_PARAMETER);
  1200. }
  1201. Uuid->Data4[7] = (UCHAR)dw;
  1202. return(STATUS_SUCCESS);
  1203. }
  1204. NTSTATUS
  1205. WmipCheckGuidAccess(
  1206. IN LPGUID Guid,
  1207. IN ACCESS_MASK DesiredAccess
  1208. )
  1209. /*++
  1210. Routine Description:
  1211. Allows checking if the current user has the rights to access a guid.
  1212. Arguments:
  1213. Guid is the guid whose security is to be checked
  1214. DesiredAccess is the access that is desired by the user.
  1215. NOTE: This does not support GENERIC_* mappings or
  1216. ASSIGN_SYSTEM_SECURITY
  1217. Return Value:
  1218. STATUS_SUCCESS or error
  1219. --*/
  1220. {
  1221. BOOLEAN Granted;
  1222. ACCESS_MASK PreviousGrantedAccess = 0;
  1223. NTSTATUS Status;
  1224. ACCESS_MASK GrantedAccess;
  1225. PSECURITY_DESCRIPTOR SecurityDescriptor;
  1226. UNICODE_STRING GuidString;
  1227. WCHAR GuidBuffer[38];
  1228. SECURITY_SUBJECT_CONTEXT SecuritySubjectContext;
  1229. PAGED_CODE();
  1230. swprintf(GuidBuffer,
  1231. L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  1232. Guid->Data1, Guid->Data2,
  1233. Guid->Data3,
  1234. Guid->Data4[0], Guid->Data4[1],
  1235. Guid->Data4[2], Guid->Data4[3],
  1236. Guid->Data4[4], Guid->Data4[5],
  1237. Guid->Data4[6], Guid->Data4[7]);
  1238. RtlInitUnicodeString(&GuidString, GuidBuffer);
  1239. Status = WmipGetGuidSecurityDescriptor(&GuidString,
  1240. &SecurityDescriptor);
  1241. if (NT_SUCCESS(Status))
  1242. {
  1243. SeCaptureSubjectContext(&SecuritySubjectContext);
  1244. Granted = SeAccessCheck (SecurityDescriptor,
  1245. &SecuritySubjectContext,
  1246. FALSE,
  1247. DesiredAccess,
  1248. PreviousGrantedAccess,
  1249. NULL,
  1250. (PGENERIC_MAPPING)&WmipGenericMapping,
  1251. UserMode,
  1252. &GrantedAccess,
  1253. &Status);
  1254. SeReleaseSubjectContext(&SecuritySubjectContext);
  1255. if (SecurityDescriptor != WmipAnyoneAccessSd)
  1256. {
  1257. ExFreePool(SecurityDescriptor);
  1258. }
  1259. }
  1260. return(Status);
  1261. }
  1262. #endif