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.

4614 lines
139 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. devintrf.c
  5. Abstract:
  6. This module contains APIs and routines for handling Device Interfaces.
  7. Author:
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. --*/
  12. #include "pnpmgrp.h"
  13. #pragma hdrstop
  14. //
  15. // Guid related definitions
  16. //
  17. #define GUID_STRING_LENGTH 38
  18. #define GUID_STRING_SIZE GUID_STRING_LENGTH * sizeof(WCHAR)
  19. //
  20. // Definitions for IoGetDeviceInterfaces
  21. //
  22. #define INITIAL_INFO_BUFFER_SIZE 512
  23. #define INFO_BUFFER_GROW_SIZE 64
  24. #define INITIAL_SYMLINK_BUFFER_SIZE 1024
  25. #define SYMLINK_BUFFER_GROW_SIZE 128
  26. #define INITIAL_RETURN_BUFFER_SIZE 4096
  27. #define RETURN_BUFFER_GROW_SIZE 512
  28. //
  29. // This should never have to grow, since it accomodates the maximum length of a
  30. // device instance name.
  31. //
  32. #define INITIAL_DEVNODE_NAME_BUFFER_SIZE (FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + (MAX_DEVICE_ID_LEN * sizeof(WCHAR)))
  33. //
  34. // Definitions for IoOpenDeviceInterfaceRegistryKey
  35. //
  36. #define KEY_STRING_PREFIX TEXT("##?#")
  37. //
  38. // Definitions for IoRegisterDeviceInterface
  39. //
  40. #define SEPERATOR_STRING TEXT("\\")
  41. #define SEPERATOR_CHAR (L'\\')
  42. #define ALT_SEPERATOR_CHAR (L'/')
  43. #define REPLACED_SEPERATOR_STRING TEXT("#")
  44. #define REPLACED_SEPERATOR_CHAR (L'#')
  45. #define USER_SYMLINK_STRING_PREFIX TEXT("\\\\?\\")
  46. #define KERNEL_SYMLINK_STRING_PREFIX TEXT("\\??\\")
  47. #define GLOBAL_SYMLINK_STRING_PREFIX TEXT("\\GLOBAL??\\")
  48. #define REFSTRING_PREFIX_CHAR (L'#')
  49. //
  50. // Prototypes
  51. //
  52. NTSTATUS
  53. IopAppendBuffer(
  54. IN PBUFFER_INFO Info,
  55. IN PVOID Data,
  56. IN ULONG DataSize
  57. );
  58. NTSTATUS
  59. IopOverwriteBuffer(
  60. IN PBUFFER_INFO Info,
  61. IN PVOID Data,
  62. IN ULONG DataSize
  63. );
  64. NTSTATUS
  65. IopRealloc(
  66. IN OUT PVOID *Buffer,
  67. IN ULONG OldSize,
  68. IN ULONG NewSize
  69. );
  70. NTSTATUS
  71. IopBuildSymbolicLinkStrings(
  72. IN PUNICODE_STRING DeviceString,
  73. IN PUNICODE_STRING GuidString,
  74. IN PUNICODE_STRING ReferenceString OPTIONAL,
  75. OUT PUNICODE_STRING UserString,
  76. OUT PUNICODE_STRING KernelString
  77. );
  78. NTSTATUS
  79. IopBuildGlobalSymbolicLinkString(
  80. IN PUNICODE_STRING SymbolicLinkName,
  81. OUT PUNICODE_STRING GlobalString
  82. );
  83. NTSTATUS
  84. IopDeviceInterfaceKeysFromSymbolicLink(
  85. IN PUNICODE_STRING SymbolicLinkName,
  86. IN ACCESS_MASK DesiredAccess,
  87. OUT PHANDLE DeviceInterfaceClassKey OPTIONAL,
  88. OUT PHANDLE DeviceInterfaceKey OPTIONAL,
  89. OUT PHANDLE DeviceInterfaceInstanceKey OPTIONAL
  90. );
  91. NTSTATUS
  92. IopDropReferenceString(
  93. OUT PUNICODE_STRING OutString,
  94. IN PUNICODE_STRING InString
  95. );
  96. NTSTATUS
  97. IopOpenOrCreateDeviceInterfaceSubKeys(
  98. OUT PHANDLE InterfaceKeyHandle OPTIONAL,
  99. OUT PULONG InterfaceKeyDisposition OPTIONAL,
  100. OUT PHANDLE InterfaceInstanceKeyHandle OPTIONAL,
  101. OUT PULONG InterfaceInstanceDisposition OPTIONAL,
  102. IN HANDLE InterfaceClassKeyHandle,
  103. IN PUNICODE_STRING DeviceInterfaceName,
  104. IN ACCESS_MASK DesiredAccess,
  105. IN BOOLEAN Create
  106. );
  107. NTSTATUS
  108. IopParseSymbolicLinkName(
  109. IN PUNICODE_STRING SymbolicLinkName,
  110. OUT PUNICODE_STRING PrefixString OPTIONAL,
  111. OUT PUNICODE_STRING MungedPathString OPTIONAL,
  112. OUT PUNICODE_STRING GuidString OPTIONAL,
  113. OUT PUNICODE_STRING RefString OPTIONAL,
  114. OUT PBOOLEAN RefStringPresent OPTIONAL,
  115. OUT LPGUID Guid OPTIONAL
  116. );
  117. NTSTATUS
  118. IopReplaceSeperatorWithPound(
  119. OUT PUNICODE_STRING OutString,
  120. IN PUNICODE_STRING InString
  121. );
  122. NTSTATUS
  123. IopSetRegistryStringValue(
  124. IN HANDLE KeyHandle,
  125. IN PUNICODE_STRING ValueName,
  126. IN PUNICODE_STRING ValueData
  127. );
  128. #ifdef ALLOC_PRAGMA
  129. #pragma alloc_text(PAGE, IoGetDeviceInterfaceAlias)
  130. #pragma alloc_text(PAGE, IoGetDeviceInterfaces)
  131. #pragma alloc_text(PAGE, IoOpenDeviceInterfaceRegistryKey)
  132. #pragma alloc_text(PAGE, IoRegisterDeviceInterface)
  133. #pragma alloc_text(PAGE, IoSetDeviceInterfaceState)
  134. #pragma alloc_text(PAGE, IopAllocateBuffer)
  135. #pragma alloc_text(PAGE, IopAllocateUnicodeString)
  136. #pragma alloc_text(PAGE, IopAppendBuffer)
  137. #pragma alloc_text(PAGE, IopBuildSymbolicLinkStrings)
  138. #pragma alloc_text(PAGE, IopBuildGlobalSymbolicLinkString)
  139. #pragma alloc_text(PAGE, IopDeviceInterfaceKeysFromSymbolicLink)
  140. #pragma alloc_text(PAGE, IopDropReferenceString)
  141. #pragma alloc_text(PAGE, IopFreeAllocatedUnicodeString)
  142. #pragma alloc_text(PAGE, IopFreeBuffer)
  143. #pragma alloc_text(PAGE, IopGetDeviceInterfaces)
  144. #pragma alloc_text(PAGE, IopOpenOrCreateDeviceInterfaceSubKeys)
  145. #pragma alloc_text(PAGE, IopOverwriteBuffer)
  146. #pragma alloc_text(PAGE, IopParseSymbolicLinkName)
  147. #pragma alloc_text(PAGE, IopProcessSetInterfaceState)
  148. #pragma alloc_text(PAGE, IopRealloc)
  149. #pragma alloc_text(PAGE, IopRegisterDeviceInterface)
  150. #pragma alloc_text(PAGE, IopRemoveDeviceInterfaces)
  151. #pragma alloc_text(PAGE, IopDisableDeviceInterfaces)
  152. #pragma alloc_text(PAGE, IopReplaceSeperatorWithPound)
  153. #pragma alloc_text(PAGE, IopResizeBuffer)
  154. #pragma alloc_text(PAGE, IopSetRegistryStringValue)
  155. #pragma alloc_text(PAGE, IopUnregisterDeviceInterface)
  156. #endif // ALLOC_PRAGMA
  157. NTSTATUS
  158. IopAllocateBuffer(
  159. IN PBUFFER_INFO Info,
  160. IN ULONG Size
  161. )
  162. /*++
  163. Routine Description:
  164. Allocates a buffer of Size bytes and initialises the BUFFER_INFO
  165. structure so the current position is at the start of the buffer.
  166. Parameters:
  167. Info - Pointer to a buffer info structure to be used to manage the new
  168. buffer
  169. Size - The number of bytes to be allocated for the buffer
  170. Return Value:
  171. Status code that indicates whether or not the function was successful.
  172. --*/
  173. {
  174. ASSERT(Info);
  175. Info->Buffer = ExAllocatePool(PagedPool, Size);
  176. if (Info->Buffer == NULL) {
  177. return STATUS_INSUFFICIENT_RESOURCES;
  178. }
  179. Info->Current = Info->Buffer;
  180. Info->MaxSize = Size;
  181. return STATUS_SUCCESS;
  182. }
  183. NTSTATUS
  184. IopResizeBuffer(
  185. IN PBUFFER_INFO Info,
  186. IN ULONG NewSize,
  187. IN BOOLEAN CopyContents
  188. )
  189. /*++
  190. Routine Description:
  191. Allocates a new buffer of NewSize bytes and associates it with Info, freeing the
  192. old buffer. It will optionally copy the data stored in the old buffer into the
  193. new buffer and update the current position.
  194. Parameters:
  195. Info - Pointer to a buffer info structure to be used to manage the buffer
  196. NewSize - The new size of the buffer in bytes
  197. CopyContents - If TRUE indicates that the contents of the old buffer should be
  198. copied to the new buffer
  199. Return Value:
  200. Status code that indicates whether or not the function was successful.
  201. --*/
  202. {
  203. ULONG used;
  204. PCHAR newBuffer;
  205. ASSERT(Info);
  206. used = (ULONG)(Info->Current - Info->Buffer);
  207. newBuffer = ExAllocatePool(PagedPool, NewSize);
  208. if (newBuffer == NULL) {
  209. return STATUS_INSUFFICIENT_RESOURCES;
  210. }
  211. if (CopyContents) {
  212. //
  213. // Assert there is room in the buffer
  214. //
  215. ASSERT(used < NewSize);
  216. RtlCopyMemory(newBuffer,
  217. Info->Buffer,
  218. used);
  219. Info->Current = newBuffer + used;
  220. } else {
  221. Info->Current = newBuffer;
  222. }
  223. ExFreePool(Info->Buffer);
  224. Info->Buffer = newBuffer;
  225. Info->MaxSize = NewSize;
  226. return STATUS_SUCCESS;
  227. }
  228. VOID
  229. IopFreeBuffer(
  230. IN PBUFFER_INFO Info
  231. )
  232. /*++
  233. Routine Description:
  234. Frees the buffer associated with Info and resets all Info fields
  235. Parameters:
  236. Info - Pointer to a buffer info structure to be used to manage the buffer
  237. Return Value:
  238. Status code that indicates whether or not the function was successful.
  239. --*/
  240. {
  241. ASSERT(Info);
  242. //
  243. // Free the buffer
  244. //
  245. ExFreePool(Info->Buffer);
  246. //
  247. // Zero out the info parameters so we can't accidently used the free buffer
  248. //
  249. Info->Buffer = NULL;
  250. Info->Current = NULL;
  251. Info->MaxSize = 0;
  252. }
  253. NTSTATUS
  254. IopAppendBuffer(
  255. IN PBUFFER_INFO Info,
  256. IN PVOID Data,
  257. IN ULONG DataSize
  258. )
  259. /*++
  260. Routine Description:
  261. Copies the data to the end of the buffer, resizing if necessary. The current
  262. position is set to the end of the data just added.
  263. Parameters:
  264. Info - Pointer to a buffer info structure to be used to manage the buffer
  265. Data - Pointer to the data to be added to the buffer
  266. DataSize - The size of the data pointed to by Data in bytes
  267. Return Value:
  268. Status code that indicates whether or not the function was successful.
  269. --*/
  270. {
  271. NTSTATUS status = STATUS_SUCCESS;
  272. ULONG free, used;
  273. ASSERT(Info);
  274. used = (ULONG)(Info->Current - Info->Buffer);
  275. free = Info->MaxSize - used;
  276. if (free < DataSize) {
  277. status = IopResizeBuffer(Info, used + DataSize, TRUE);
  278. if (!NT_SUCCESS(status)) {
  279. goto clean0;
  280. }
  281. }
  282. //
  283. // Copy the data into the buffer
  284. //
  285. RtlCopyMemory(Info->Current,
  286. Data,
  287. DataSize);
  288. //
  289. // Advance down the buffer
  290. //
  291. Info->Current += DataSize;
  292. clean0:
  293. return status;
  294. }
  295. NTSTATUS
  296. IopOverwriteBuffer(
  297. IN PBUFFER_INFO Info,
  298. IN PVOID Data,
  299. IN ULONG DataSize
  300. )
  301. /*++
  302. Routine Description:
  303. Copies data into the buffer, overwriting what is currently present,
  304. resising if necessary. The current position is set to the end of the
  305. data just added.
  306. Parameters:
  307. Info - Pointer to a buffer info structure to be used to manage the buffer
  308. Data - Pointer to the data to be added to the buffer
  309. DataSize - The size of the data pointed to by Data in bytes
  310. Return Value:
  311. Status code that indicates whether or not the function was successful.
  312. --*/
  313. {
  314. NTSTATUS status = STATUS_SUCCESS;
  315. ULONG free;
  316. ASSERT(Info);
  317. free = Info->MaxSize;
  318. if (free < DataSize) {
  319. status = IopResizeBuffer(Info, DataSize, FALSE);
  320. if (!NT_SUCCESS(status)) {
  321. goto clean0;
  322. }
  323. }
  324. //
  325. // Copy the data into the buffer
  326. //
  327. RtlCopyMemory(Info->Buffer,
  328. Data,
  329. DataSize);
  330. //
  331. // Advance down the buffer
  332. //
  333. Info->Current += DataSize;
  334. clean0:
  335. return status;
  336. }
  337. NTSTATUS
  338. IopGetDeviceInterfaces(
  339. IN CONST GUID *InterfaceClassGuid,
  340. IN PUNICODE_STRING DevicePath OPTIONAL,
  341. IN ULONG Flags,
  342. IN BOOLEAN UserModeFormat,
  343. OUT PWSTR *SymbolicLinkList,
  344. OUT PULONG SymbolicLinkListSize OPTIONAL
  345. )
  346. /*++
  347. Routine Description:
  348. This API allows a WDM driver to get a list of paths that represent all
  349. devices registered for the specified interface class.
  350. Parameters:
  351. InterfaceClassGuid - Supplies a pointer to a GUID representing the interface class
  352. for whom a list of members is to be retrieved
  353. DevicePath - Optionally, supplies a pointer to a unicode string containing the
  354. enumeration path for a device for whom interfaces of the specified class are
  355. to be re-trieved. If this parameter is not supplied, then all interface
  356. devices (regardless of what physical device exposes them) will be returned.
  357. Flags - Supplies flags that modify the behavior of list retrieval.
  358. The following flags are presently defined:
  359. DEVICE_INTERFACE_INCLUDE_NONACTIVE -- If this flag is specified, then all
  360. interface devices, whether currently active or not, will be returned
  361. (potentially filtered based on the Physi-calDeviceObject, if specified).
  362. UserModeFormat - If TRUE the multi-sz returned will have user mode prefixes
  363. (\\?\) otherwise they will have kernel mode prefixes (\??\).
  364. SymbolicLinkList - Supplies the address of a character pointer, that on
  365. success will contain a multi-sz list of \??\ symbolic link
  366. names that provide the requested functionality. The caller is
  367. responsible for freeing the memory via ExFreePool.
  368. Return Value:
  369. Status code that indicates whether or not the function was successful.
  370. --*/
  371. {
  372. NTSTATUS status;
  373. UNICODE_STRING guidString, tempString, defaultString, symLinkString, devnodeString;
  374. BUFFER_INFO returnBuffer, infoBuffer, symLinkBuffer, devnodeNameBuffer;
  375. PKEY_VALUE_FULL_INFORMATION pDefaultInfo;
  376. ULONG keyIndex, instanceKeyIndex, resultSize;
  377. HANDLE hDeviceClasses, hClass, hKey, hInstanceKey, hControl;
  378. BOOLEAN defaultPresent = FALSE;
  379. PAGED_CODE();
  380. //
  381. // Initialise out parameters
  382. //
  383. *SymbolicLinkList = NULL;
  384. //
  385. // Convert the GUID into a string
  386. //
  387. status = RtlStringFromGUID(InterfaceClassGuid, &guidString);
  388. if (!NT_SUCCESS(status)) {
  389. goto finalClean;
  390. }
  391. //
  392. // Allocate initial buffers
  393. //
  394. status = IopAllocateBuffer(&returnBuffer,
  395. INITIAL_RETURN_BUFFER_SIZE
  396. );
  397. if (!NT_SUCCESS(status)) {
  398. goto clean0;
  399. }
  400. status = IopAllocateBuffer(&infoBuffer,
  401. INITIAL_INFO_BUFFER_SIZE
  402. );
  403. if (!NT_SUCCESS(status)) {
  404. goto clean1;
  405. }
  406. status = IopAllocateBuffer(&symLinkBuffer,
  407. INITIAL_SYMLINK_BUFFER_SIZE
  408. );
  409. if (!NT_SUCCESS(status)) {
  410. goto clean2;
  411. }
  412. status = IopAllocateBuffer(&devnodeNameBuffer,
  413. INITIAL_DEVNODE_NAME_BUFFER_SIZE
  414. );
  415. if (!NT_SUCCESS(status)) {
  416. goto clean2a;
  417. }
  418. //
  419. // Enter critical section and acquire a lock on the registry. Both these
  420. // mechanisms are required to prevent deadlock in the case where an APC
  421. // routine calls this routine after the registry resource has been claimed
  422. // in this case it would wait blocking this thread so the registry would
  423. // never be released -> deadlock. Critical sectioning the registry manipulation
  424. // portion solves this problem
  425. //
  426. PiLockPnpRegistry(TRUE);
  427. //
  428. // Open HKLM\System\CurrentControlSet\Control\DeviceClasses key
  429. //
  430. PiWstrToUnicodeString(&tempString, REGSTR_FULL_PATH_DEVICE_CLASSES);
  431. status = IopCreateRegistryKeyEx( &hDeviceClasses,
  432. NULL,
  433. &tempString,
  434. KEY_ALL_ACCESS,
  435. REG_OPTION_NON_VOLATILE,
  436. NULL
  437. );
  438. if (!NT_SUCCESS(status)) {
  439. goto clean3;
  440. }
  441. //
  442. // Open function class GUID key
  443. //
  444. status = IopOpenRegistryKeyEx( &hClass,
  445. hDeviceClasses,
  446. &guidString,
  447. KEY_ALL_ACCESS
  448. );
  449. ZwClose(hDeviceClasses);
  450. if(status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND) {
  451. //
  452. // The path does not exist - return a single null character buffer
  453. //
  454. status = STATUS_SUCCESS;
  455. goto clean5;
  456. } else if (!NT_SUCCESS(status)) {
  457. goto clean3;
  458. }
  459. //
  460. // Get the default value if it exists
  461. //
  462. status = IopGetRegistryValue(hClass,
  463. REGSTR_VAL_DEFAULT,
  464. &pDefaultInfo
  465. );
  466. if (NT_SUCCESS(status)
  467. && pDefaultInfo->Type == REG_SZ
  468. && pDefaultInfo->DataLength >= sizeof(WCHAR)) {
  469. //
  470. // We have a default - construct a counted string from the default
  471. //
  472. defaultPresent = TRUE;
  473. defaultString.Buffer = (PWSTR) KEY_VALUE_DATA(pDefaultInfo);
  474. defaultString.Length = (USHORT) pDefaultInfo->DataLength - sizeof(UNICODE_NULL);
  475. defaultString.MaximumLength = defaultString.Length;
  476. //
  477. // Open the device interface instance key for the default name.
  478. //
  479. status = IopOpenOrCreateDeviceInterfaceSubKeys(NULL,
  480. NULL,
  481. &hKey,
  482. NULL,
  483. hClass,
  484. &defaultString,
  485. KEY_READ,
  486. FALSE
  487. );
  488. if (!NT_SUCCESS(status)) {
  489. defaultPresent = FALSE;
  490. ExFreePool(pDefaultInfo);
  491. //
  492. // Continue with the call but ignore the invalid default entry
  493. //
  494. } else {
  495. //
  496. // If we are just supposed to return live interfaces, then make sure this default
  497. // interface is linked.
  498. //
  499. if (!(Flags & DEVICE_INTERFACE_INCLUDE_NONACTIVE)) {
  500. defaultPresent = FALSE;
  501. //
  502. // Open the control subkey
  503. //
  504. PiWstrToUnicodeString(&tempString, REGSTR_KEY_CONTROL);
  505. status = IopOpenRegistryKeyEx( &hControl,
  506. hKey,
  507. &tempString,
  508. KEY_ALL_ACCESS
  509. );
  510. if (NT_SUCCESS(status)) {
  511. //
  512. // Get the linked value
  513. //
  514. PiWstrToUnicodeString(&tempString, REGSTR_VAL_LINKED);
  515. ASSERT(infoBuffer.MaxSize >= sizeof(KEY_VALUE_PARTIAL_INFORMATION));
  516. status = ZwQueryValueKey(hControl,
  517. &tempString,
  518. KeyValuePartialInformation,
  519. (PVOID) infoBuffer.Buffer,
  520. infoBuffer.MaxSize,
  521. &resultSize
  522. );
  523. //
  524. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  525. // was not enough room for even the fixed portions of the structure.
  526. //
  527. ASSERT(status != STATUS_BUFFER_TOO_SMALL);
  528. ZwClose(hControl);
  529. //
  530. // We don't need to check the buffer was big enough because it starts
  531. // off that way and doesn't get any smaller!
  532. //
  533. if (NT_SUCCESS(status)
  534. && (((PKEY_VALUE_PARTIAL_INFORMATION)(infoBuffer.Buffer))->Type == REG_DWORD)
  535. && (((PKEY_VALUE_PARTIAL_INFORMATION)(infoBuffer.Buffer))->DataLength == sizeof(ULONG))) {
  536. defaultPresent = *(PULONG)(((PKEY_VALUE_PARTIAL_INFORMATION)(infoBuffer.Buffer))->Data)
  537. ? TRUE
  538. : FALSE;
  539. }
  540. }
  541. }
  542. ZwClose(hKey);
  543. if(defaultPresent) {
  544. //
  545. // Add the default as the first entry in the return buffer and patch to usermode if necessary
  546. //
  547. status = IopAppendBuffer(&returnBuffer,
  548. defaultString.Buffer,
  549. defaultString.Length + sizeof(UNICODE_NULL)
  550. );
  551. if (!UserModeFormat) {
  552. RtlCopyMemory(returnBuffer.Buffer,
  553. KERNEL_SYMLINK_STRING_PREFIX,
  554. IopConstStringLength(KERNEL_SYMLINK_STRING_PREFIX)
  555. );
  556. }
  557. } else {
  558. //
  559. // The default device interface isn't active--free the memory for the name buffer now.
  560. //
  561. ExFreePool(pDefaultInfo);
  562. }
  563. }
  564. } else if (status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND) {
  565. //
  566. // Do nothing - there is no default
  567. //
  568. } else {
  569. //
  570. // An unexpected error occured - clean up
  571. //
  572. if (NT_SUCCESS(status)) {
  573. ExFreePool(pDefaultInfo);
  574. status = STATUS_UNSUCCESSFUL;
  575. }
  576. ZwClose(hClass);
  577. goto clean4;
  578. }
  579. //
  580. // Iterate through the subkeys under this interface class key.
  581. //
  582. keyIndex = 0;
  583. ASSERT(infoBuffer.MaxSize >= sizeof(KEY_BASIC_INFORMATION));
  584. while((status = ZwEnumerateKey(hClass,
  585. keyIndex,
  586. KeyBasicInformation,
  587. (PVOID) infoBuffer.Buffer,
  588. infoBuffer.MaxSize,
  589. &resultSize
  590. )) != STATUS_NO_MORE_ENTRIES) {
  591. //
  592. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  593. // was not enough room for even the fixed portions of the structure.
  594. //
  595. ASSERT(status != STATUS_BUFFER_TOO_SMALL);
  596. if (status == STATUS_BUFFER_OVERFLOW) {
  597. status = IopResizeBuffer(&infoBuffer, resultSize, FALSE);
  598. continue;
  599. } else if (!NT_SUCCESS(status)) {
  600. ZwClose(hClass);
  601. goto clean4;
  602. }
  603. //
  604. // Open up this interface key.
  605. //
  606. tempString.Length = (USHORT) ((PKEY_BASIC_INFORMATION)(infoBuffer.Buffer))->NameLength;
  607. tempString.MaximumLength = tempString.Length;
  608. tempString.Buffer = ((PKEY_BASIC_INFORMATION)(infoBuffer.Buffer))->Name;
  609. //
  610. // Open the associated key
  611. //
  612. status = IopOpenRegistryKeyEx( &hKey,
  613. hClass,
  614. &tempString,
  615. KEY_READ
  616. );
  617. if (!NT_SUCCESS(status)) {
  618. //
  619. // For some reason we couldn't open this key--skip it and move on.
  620. //
  621. keyIndex++;
  622. continue;
  623. }
  624. //
  625. // If we're filtering on a particular PDO, then retrieve the owning device
  626. // instance name for this interface key, and make sure they match.
  627. //
  628. PiWstrToUnicodeString(&tempString, REGSTR_VAL_DEVICE_INSTANCE);
  629. ASSERT(devnodeNameBuffer.MaxSize >= sizeof(KEY_VALUE_PARTIAL_INFORMATION));
  630. while ((status = ZwQueryValueKey(hKey,
  631. &tempString,
  632. KeyValuePartialInformation,
  633. devnodeNameBuffer.Buffer,
  634. devnodeNameBuffer.MaxSize,
  635. &resultSize
  636. )) == STATUS_BUFFER_OVERFLOW) {
  637. status = IopResizeBuffer(&devnodeNameBuffer, resultSize, FALSE);
  638. if (!NT_SUCCESS(status)) {
  639. ZwClose(hKey);
  640. ZwClose(hClass);
  641. goto clean4;
  642. }
  643. }
  644. //
  645. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  646. // was not enough room for even the fixed portions of the structure.
  647. //
  648. ASSERT(status != STATUS_BUFFER_TOO_SMALL);
  649. if (!(NT_SUCCESS(status)
  650. && ((PKEY_VALUE_PARTIAL_INFORMATION)(devnodeNameBuffer.Buffer))->Type == REG_SZ
  651. && ((PKEY_VALUE_PARTIAL_INFORMATION)(devnodeNameBuffer.Buffer))->DataLength > sizeof(WCHAR))) {
  652. goto CloseInterfaceKeyAndContinue;
  653. }
  654. //
  655. // Build counted string
  656. //
  657. devnodeString.Length = (USHORT) ((PKEY_VALUE_PARTIAL_INFORMATION)(devnodeNameBuffer.Buffer))->DataLength - sizeof(UNICODE_NULL);
  658. devnodeString.MaximumLength = tempString.Length;
  659. devnodeString.Buffer = (PWSTR) ((PKEY_VALUE_PARTIAL_INFORMATION)(devnodeNameBuffer.Buffer))->Data;
  660. //
  661. // Enumerate each interface instance subkey under this PDO's interface key.
  662. //
  663. instanceKeyIndex = 0;
  664. ASSERT(infoBuffer.MaxSize >= sizeof(KEY_BASIC_INFORMATION));
  665. while((status = ZwEnumerateKey(hKey,
  666. instanceKeyIndex,
  667. KeyBasicInformation,
  668. (PVOID) infoBuffer.Buffer,
  669. infoBuffer.MaxSize,
  670. &resultSize
  671. )) != STATUS_NO_MORE_ENTRIES) {
  672. //
  673. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  674. // was not enough room for even the fixed portions of the structure.
  675. //
  676. ASSERT(status != STATUS_BUFFER_TOO_SMALL);
  677. if (status == STATUS_BUFFER_OVERFLOW) {
  678. status = IopResizeBuffer(&infoBuffer, resultSize, FALSE);
  679. continue;
  680. } else if (!NT_SUCCESS(status)) {
  681. ZwClose(hKey);
  682. ZwClose(hClass);
  683. goto clean4;
  684. }
  685. //
  686. // Open up this interface instance key.
  687. //
  688. tempString.Length = (USHORT) ((PKEY_BASIC_INFORMATION)(infoBuffer.Buffer))->NameLength;
  689. tempString.MaximumLength = tempString.Length;
  690. tempString.Buffer = ((PKEY_BASIC_INFORMATION)(infoBuffer.Buffer))->Name;
  691. //
  692. // Open the associated key
  693. //
  694. status = IopOpenRegistryKeyEx( &hInstanceKey,
  695. hKey,
  696. &tempString,
  697. KEY_READ
  698. );
  699. if (!NT_SUCCESS(status)) {
  700. //
  701. // For some reason we couldn't open this key--skip it and move on.
  702. //
  703. instanceKeyIndex++;
  704. continue;
  705. }
  706. if (!(Flags & DEVICE_INTERFACE_INCLUDE_NONACTIVE)) {
  707. //
  708. // Open the control subkey
  709. //
  710. PiWstrToUnicodeString(&tempString, REGSTR_KEY_CONTROL);
  711. status = IopOpenRegistryKeyEx( &hControl,
  712. hInstanceKey,
  713. &tempString,
  714. KEY_READ
  715. );
  716. if (!NT_SUCCESS(status)) {
  717. //
  718. // We have no control subkey so can't be linked -
  719. // continue enumerating the keys ignoring this one
  720. //
  721. goto CloseInterfaceInstanceKeyAndContinue;
  722. }
  723. //
  724. // Get the linked value
  725. //
  726. PiWstrToUnicodeString(&tempString, REGSTR_VAL_LINKED);
  727. ASSERT(infoBuffer.MaxSize >= sizeof(KEY_VALUE_PARTIAL_INFORMATION));
  728. status = ZwQueryValueKey(hControl,
  729. &tempString,
  730. KeyValuePartialInformation,
  731. (PVOID) infoBuffer.Buffer,
  732. infoBuffer.MaxSize,
  733. &resultSize
  734. );
  735. //
  736. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  737. // was not enough room for even the fixed portions of the structure.
  738. //
  739. ASSERT(status != STATUS_BUFFER_TOO_SMALL);
  740. ZwClose(hControl);
  741. //
  742. // We don't need to check the buffer was big enough because it starts
  743. // off that way and doesn't get any smaller!
  744. //
  745. if (!NT_SUCCESS(status)
  746. || (((PKEY_VALUE_PARTIAL_INFORMATION)(infoBuffer.Buffer))->Type != REG_DWORD)
  747. || (((PKEY_VALUE_PARTIAL_INFORMATION)(infoBuffer.Buffer))->DataLength != sizeof(ULONG))
  748. || !*(PULONG)(((PKEY_VALUE_PARTIAL_INFORMATION)(infoBuffer.Buffer))->Data)) {
  749. //
  750. // We are NOT linked so continue enumerating the keys ignoring this one
  751. //
  752. goto CloseInterfaceInstanceKeyAndContinue;
  753. }
  754. }
  755. //
  756. // Open the "SymbolicLink" value and place the information into the symLink buffer
  757. //
  758. PiWstrToUnicodeString(&tempString, REGSTR_VAL_SYMBOLIC_LINK);
  759. ASSERT(symLinkBuffer.MaxSize >= sizeof(KEY_VALUE_PARTIAL_INFORMATION));
  760. while ((status = ZwQueryValueKey(hInstanceKey,
  761. &tempString,
  762. KeyValuePartialInformation,
  763. symLinkBuffer.Buffer,
  764. symLinkBuffer.MaxSize,
  765. &resultSize
  766. )) == STATUS_BUFFER_OVERFLOW) {
  767. status = IopResizeBuffer(&symLinkBuffer, resultSize, FALSE);
  768. if (!NT_SUCCESS(status)) {
  769. ZwClose(hInstanceKey);
  770. ZwClose(hKey);
  771. ZwClose(hClass);
  772. goto clean4;
  773. }
  774. }
  775. //
  776. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  777. // was not enough room for even the fixed portions of the structure.
  778. //
  779. ASSERT(status != STATUS_BUFFER_TOO_SMALL);
  780. if (!(NT_SUCCESS(status)
  781. && ((PKEY_VALUE_PARTIAL_INFORMATION)(symLinkBuffer.Buffer))->Type == REG_SZ
  782. && ((PKEY_VALUE_PARTIAL_INFORMATION)(symLinkBuffer.Buffer))->DataLength > sizeof(WCHAR))) {
  783. goto CloseInterfaceInstanceKeyAndContinue;
  784. }
  785. //
  786. // Build counted string from value data
  787. //
  788. symLinkString.Length = (USHORT) ((PKEY_VALUE_PARTIAL_INFORMATION)(symLinkBuffer.Buffer))->DataLength - sizeof(UNICODE_NULL);
  789. symLinkString.MaximumLength = symLinkString.Length;
  790. symLinkString.Buffer = (PWSTR) ((PKEY_VALUE_PARTIAL_INFORMATION)(symLinkBuffer.Buffer))->Data;
  791. //
  792. // If we have a default, check this is not it
  793. //
  794. if (defaultPresent) {
  795. if (RtlCompareUnicodeString(&defaultString, &symLinkString, TRUE) == 0) {
  796. //
  797. // We have already added the default to the beginning of the buffer so skip it
  798. //
  799. goto CloseInterfaceInstanceKeyAndContinue;
  800. }
  801. }
  802. //
  803. // If we are only returning interfaces for a particular PDO then check
  804. // this is from that PDO
  805. //
  806. if (ARGUMENT_PRESENT(DevicePath)) {
  807. //
  808. // Check if it is from the same PDO
  809. //
  810. if (RtlCompareUnicodeString(DevicePath, &devnodeString, TRUE) != 0) {
  811. //
  812. // If not then go onto the next key
  813. //
  814. goto CloseInterfaceInstanceKeyAndContinue;
  815. }
  816. }
  817. //
  818. // Copy the symLink string to the return buffer including the NULL termination
  819. //
  820. status = IopAppendBuffer(&returnBuffer,
  821. symLinkString.Buffer,
  822. symLinkString.Length + sizeof(UNICODE_NULL)
  823. );
  824. ASSERT(((PWSTR) returnBuffer.Current)[-1] == UNICODE_NULL);
  825. //
  826. // If we are returning KM strings then patch the prefix
  827. //
  828. if (!UserModeFormat) {
  829. RtlCopyMemory(returnBuffer.Current - (symLinkString.Length + sizeof(UNICODE_NULL)),
  830. KERNEL_SYMLINK_STRING_PREFIX,
  831. IopConstStringLength(KERNEL_SYMLINK_STRING_PREFIX)
  832. );
  833. }
  834. CloseInterfaceInstanceKeyAndContinue:
  835. ZwClose(hInstanceKey);
  836. instanceKeyIndex++;
  837. }
  838. CloseInterfaceKeyAndContinue:
  839. ZwClose(hKey);
  840. keyIndex++;
  841. }
  842. ZwClose(hClass);
  843. clean5:
  844. //
  845. // We've got then all! Resize to leave space for a terminating NULL.
  846. //
  847. status = IopResizeBuffer(&returnBuffer,
  848. (ULONG) (returnBuffer.Current - returnBuffer.Buffer + sizeof(UNICODE_NULL)),
  849. TRUE
  850. );
  851. if (NT_SUCCESS(status)) {
  852. //
  853. // Terminate the buffer
  854. //
  855. *((PWSTR) returnBuffer.Current) = UNICODE_NULL;
  856. }
  857. clean4:
  858. if (defaultPresent) {
  859. ExFreePool(pDefaultInfo);
  860. }
  861. clean3:
  862. PiUnlockPnpRegistry();
  863. IopFreeBuffer(&devnodeNameBuffer);
  864. clean2a:
  865. IopFreeBuffer(&symLinkBuffer);
  866. clean2:
  867. IopFreeBuffer(&infoBuffer);
  868. clean1:
  869. if (!NT_SUCCESS(status)) {
  870. IopFreeBuffer(&returnBuffer);
  871. }
  872. clean0:
  873. RtlFreeUnicodeString(&guidString);
  874. finalClean:
  875. if (NT_SUCCESS(status)) {
  876. *SymbolicLinkList = (PWSTR) returnBuffer.Buffer;
  877. if (ARGUMENT_PRESENT(SymbolicLinkListSize)) {
  878. *SymbolicLinkListSize = returnBuffer.MaxSize;
  879. }
  880. } else {
  881. *SymbolicLinkList = NULL;
  882. if (ARGUMENT_PRESENT(SymbolicLinkListSize)) {
  883. *SymbolicLinkListSize = 0;
  884. }
  885. }
  886. return status;
  887. }
  888. NTSTATUS
  889. IoGetDeviceInterfaces(
  890. IN CONST GUID *InterfaceClassGuid,
  891. IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
  892. IN ULONG Flags,
  893. OUT PWSTR *SymbolicLinkList
  894. )
  895. /*++
  896. Routine Description:
  897. This API allows a WDM driver to get a list of paths that represent all
  898. device interfaces registered for the specified interface class.
  899. Parameters:
  900. InterfaceClassGuid - Supplies a pointer to a GUID representing the interface class
  901. for whom a list of members is to be retrieved
  902. PhysicalDeviceObject - Optionally, supplies a pointer to the PDO for whom
  903. interfaces of the specified class are to be re-trieved. If this parameter
  904. is not supplied, then all interface devices (regardless of what physical
  905. device exposes them) will be returned.
  906. Flags - Supplies flags that modify the behavior of list retrieval.
  907. The following flags are presently defined:
  908. DEVICE_INTERFACE_INCLUDE_NONACTIVE -- If this flag is specified, then all
  909. device interfaces, whether currently active or not, will be returned
  910. (potentially filtered based on the PhysicalDeviceObject, if specified).
  911. SymbolicLinkList - Supplies the address of a character pointer, that on
  912. success will contain a multi-sz list of \DosDevices\ symbolic link
  913. names that provide the requested functionality. The caller is
  914. responsible for freeing the memory via ExFreePool
  915. Return Value:
  916. Status code that indicates whether or not the function was successful.
  917. --*/
  918. {
  919. NTSTATUS status;
  920. PUNICODE_STRING pDeviceName = NULL;
  921. PDEVICE_NODE pDeviceNode;
  922. PAGED_CODE();
  923. //
  924. // Check we have a PDO and if so extract the instance path from it
  925. //
  926. if (ARGUMENT_PRESENT(PhysicalDeviceObject)) {
  927. ASSERT_PDO(PhysicalDeviceObject);
  928. pDeviceNode = (PDEVICE_NODE) PhysicalDeviceObject->DeviceObjectExtension->DeviceNode;
  929. pDeviceName = &pDeviceNode->InstancePath;
  930. }
  931. status = IopGetDeviceInterfaces(InterfaceClassGuid,
  932. pDeviceName,
  933. Flags,
  934. FALSE,
  935. SymbolicLinkList,
  936. NULL
  937. );
  938. return status;
  939. }
  940. NTSTATUS
  941. IopRealloc(
  942. IN OUT PVOID *Buffer,
  943. IN ULONG OldSize,
  944. IN ULONG NewSize
  945. )
  946. /*++
  947. Routine Description:
  948. This implements a variation of the traditional C realloc routine.
  949. Parameters:
  950. Buffer - Supplies a pointer to a pointer to the buffer that is being
  951. reallocated. On sucessful completion it the pointer will be updated
  952. to point to the new buffer, on failure it will still point to the old
  953. buffer.
  954. OldSize - The size in bytes of the memory block referenced by Buffer
  955. NewSize - The desired new size in bytes of the buffer. This can be larger
  956. or smaller than the OldSize
  957. Return Value:
  958. Status code that indicates whether or not the function was successful.
  959. --*/
  960. {
  961. PVOID newBuffer;
  962. PAGED_CODE();
  963. ASSERT(*Buffer);
  964. //
  965. // Allocate a new buffer
  966. //
  967. newBuffer = ExAllocatePool(PagedPool, NewSize);
  968. if (newBuffer == NULL) {
  969. return STATUS_INSUFFICIENT_RESOURCES;
  970. }
  971. //
  972. // Copy the contents of the old buffer
  973. //
  974. if(OldSize <= NewSize) {
  975. RtlCopyMemory(newBuffer, *Buffer , OldSize);
  976. } else {
  977. RtlCopyMemory(newBuffer, *Buffer , NewSize);
  978. }
  979. //
  980. // Free up the old buffer
  981. //
  982. ExFreePool(*Buffer);
  983. //
  984. // Hand the new buffer back to the caller
  985. //
  986. *Buffer = newBuffer;
  987. return STATUS_SUCCESS;
  988. }
  989. NTSTATUS
  990. IoSetDeviceInterfaceState(
  991. IN PUNICODE_STRING SymbolicLinkName,
  992. IN BOOLEAN Enable
  993. )
  994. /*++
  995. Routine Description:
  996. This DDI allows a device class to activate and deactivate an association
  997. previously registered using IoRegisterDeviceInterface
  998. Parameters:
  999. SymbolicLinkName - Supplies a pointer to the symbolic link name which was
  1000. returned by IoRegisterDeviceInterface when the interface was registered,
  1001. or as returned by IoGetDeviceInterfaces.
  1002. Enable - If TRUE (non-zero), the interface will be enabled. If FALSE, it
  1003. will be disabled.
  1004. Return Value:
  1005. Status code that indicates whether or not the function was successful.
  1006. --*/
  1007. {
  1008. NTSTATUS status;
  1009. PAGED_CODE();
  1010. //
  1011. // Enter critical section and acquire a lock on the registry. Both these
  1012. // mechanisms are required to prevent deadlock in the case where an APC
  1013. // routine calls this routine after the registry resource has been claimed
  1014. // in this case it would wait blocking this thread so the registry would
  1015. // never be released -> deadlock. Critical sectioning the registry manipulation
  1016. // portion solves this problem
  1017. //
  1018. PiLockPnpRegistry(TRUE);
  1019. status = IopProcessSetInterfaceState(SymbolicLinkName, Enable, TRUE);
  1020. PiUnlockPnpRegistry();
  1021. if (!NT_SUCCESS(status) && !Enable) {
  1022. //
  1023. // If we failed to disable an interface (most likely because the
  1024. // interface keys have already been deleted) report success.
  1025. //
  1026. status = STATUS_SUCCESS;
  1027. }
  1028. return status;
  1029. }
  1030. NTSTATUS
  1031. IoOpenDeviceInterfaceRegistryKey(
  1032. IN PUNICODE_STRING SymbolicLinkName,
  1033. IN ACCESS_MASK DesiredAccess,
  1034. OUT PHANDLE DeviceInterfaceKey
  1035. )
  1036. /*++
  1037. Routine Description:
  1038. This routine will open the registry key where the data associated with a
  1039. specific device interface can be stored.
  1040. Parameters:
  1041. SymbolicLinkName - Supplies a pointer to the symbolic link name which was
  1042. returned by IoRegisterDeviceInterface when the device class was registered.
  1043. DesiredAccess - Supplies the access privileges to the key the caller wants.
  1044. DeviceInterfaceKey - Supplies a pointer to a handle which on success will
  1045. contain the handle to the requested registry key.
  1046. Return Value:
  1047. Status code that indicates whether or not the function was successful.
  1048. --*/
  1049. {
  1050. NTSTATUS status;
  1051. HANDLE hKey;
  1052. UNICODE_STRING unicodeString;
  1053. PAGED_CODE();
  1054. //
  1055. // Enter critical section and acquire a lock on the registry. Both these
  1056. // mechanisms are required to prevent deadlock in the case where an APC
  1057. // routine calls this routine after the registry resource has been claimed
  1058. // in this case it would wait blocking this thread so the registry would
  1059. // never be released -> deadlock. Critical sectioning the registry manipulation
  1060. // portion solves this problem
  1061. //
  1062. PiLockPnpRegistry(TRUE);
  1063. //
  1064. // Open the interface device key
  1065. //
  1066. status = IopDeviceInterfaceKeysFromSymbolicLink(SymbolicLinkName,
  1067. KEY_READ,
  1068. NULL,
  1069. NULL,
  1070. &hKey
  1071. );
  1072. if(!NT_SUCCESS(status)) {
  1073. goto clean0;
  1074. }
  1075. //
  1076. // Open the "Device Parameters" subkey.
  1077. //
  1078. PiWstrToUnicodeString(&unicodeString, REGSTR_KEY_DEVICEPARAMETERS);
  1079. status = IopCreateRegistryKeyEx( DeviceInterfaceKey,
  1080. hKey,
  1081. &unicodeString,
  1082. DesiredAccess,
  1083. REG_OPTION_NON_VOLATILE,
  1084. NULL
  1085. );
  1086. ZwClose(hKey);
  1087. clean0:
  1088. PiUnlockPnpRegistry();
  1089. return status;
  1090. }
  1091. NTSTATUS
  1092. IopDeviceInterfaceKeysFromSymbolicLink(
  1093. IN PUNICODE_STRING SymbolicLinkName,
  1094. IN ACCESS_MASK DesiredAccess,
  1095. OUT PHANDLE DeviceInterfaceClassKey OPTIONAL,
  1096. OUT PHANDLE DeviceInterfaceKey OPTIONAL,
  1097. OUT PHANDLE DeviceInterfaceInstanceKey OPTIONAL
  1098. )
  1099. /*++
  1100. Routine Description:
  1101. This routine will open the registry key where the data associated with the
  1102. device pointed to by SymbolicLinkName is stored. If the path does not exist
  1103. it will not be created.
  1104. Parameters:
  1105. SymbolicLinkName - Supplies a pointer to the symbolic link name.
  1106. DesiredAccess - Supplies the access privto the function class instance key the
  1107. caller wants.
  1108. DeviceInterfaceClassKey - Optionally, supplies the address of a variable that
  1109. receives a handle to the device class key for the interface.
  1110. DeviceInterfaceKey - Optionally, supplies the address of a variable that receives
  1111. a handle to the device interface (parent) key.
  1112. DeviceInterfaceInstanceKey - Optionally, Supplies the address of a variable that
  1113. receives a handle to the device interface instance key (i.e., the
  1114. refstring-specific one).
  1115. Return Value:
  1116. Status code that indicates whether or not the function was successful.
  1117. --*/
  1118. {
  1119. NTSTATUS status;
  1120. UNICODE_STRING guidString, tempString;
  1121. HANDLE hDeviceClasses, hFunctionClass;
  1122. PAGED_CODE();
  1123. //
  1124. // Check that the supplied symbolic link can be parsed to extract the device
  1125. // class guid string - note that this is also a way of verifying that the
  1126. // SymbolicLinkName string is valid.
  1127. //
  1128. status = IopParseSymbolicLinkName(SymbolicLinkName,
  1129. NULL,
  1130. NULL,
  1131. &guidString,
  1132. NULL,
  1133. NULL,
  1134. NULL);
  1135. if(!NT_SUCCESS(status)){
  1136. goto clean0;
  1137. }
  1138. //
  1139. // Enter critical section and acquire a lock on the registry. Both these
  1140. // mechanisms are required to prevent deadlock in the case where an APC
  1141. // routine calls this routine after the registry resource has been claimed
  1142. // in this case it would wait blocking this thread so the registry would
  1143. // never be released -> deadlock. Critical sectioning the registry manipulation
  1144. // portion solves this problem
  1145. //
  1146. PiLockPnpRegistry(TRUE);
  1147. //
  1148. // Open HKLM\System\CurrentControlSet\Control\DeviceClasses key
  1149. //
  1150. PiWstrToUnicodeString(&tempString, REGSTR_FULL_PATH_DEVICE_CLASSES);
  1151. status = IopOpenRegistryKeyEx( &hDeviceClasses,
  1152. NULL,
  1153. &tempString,
  1154. KEY_READ
  1155. );
  1156. if( !NT_SUCCESS(status) ){
  1157. goto clean1;
  1158. }
  1159. //
  1160. // Open function class GUID key
  1161. //
  1162. status = IopOpenRegistryKeyEx( &hFunctionClass,
  1163. hDeviceClasses,
  1164. &guidString,
  1165. KEY_READ
  1166. );
  1167. if( !NT_SUCCESS(status) ){
  1168. goto clean2;
  1169. }
  1170. //
  1171. // Open device interface instance key
  1172. //
  1173. status = IopOpenOrCreateDeviceInterfaceSubKeys(DeviceInterfaceKey,
  1174. NULL,
  1175. DeviceInterfaceInstanceKey,
  1176. NULL,
  1177. hFunctionClass,
  1178. SymbolicLinkName,
  1179. DesiredAccess,
  1180. FALSE
  1181. );
  1182. if((!NT_SUCCESS(status)) || (!ARGUMENT_PRESENT(DeviceInterfaceClassKey))) {
  1183. ZwClose(hFunctionClass);
  1184. } else {
  1185. *DeviceInterfaceClassKey = hFunctionClass;
  1186. }
  1187. clean2:
  1188. ZwClose(hDeviceClasses);
  1189. clean1:
  1190. PiUnlockPnpRegistry();
  1191. clean0:
  1192. return status;
  1193. }
  1194. NTSTATUS
  1195. IoRegisterDeviceInterface(
  1196. IN PDEVICE_OBJECT PhysicalDeviceObject,
  1197. IN CONST GUID *InterfaceClassGuid,
  1198. IN PUNICODE_STRING ReferenceString OPTIONAL,
  1199. OUT PUNICODE_STRING SymbolicLinkName
  1200. )
  1201. /*++
  1202. Routine Description:
  1203. This device driver interface allows a WDM driver to register a particular
  1204. interface of its underlying hardware (ie PDO) as a member of a function class.
  1205. Parameters:
  1206. PhysicalDeviceObject - Supplies a pointer to the PDO for the P&P device
  1207. instance associated with the functionality being registered
  1208. InterfaceClassGuid - Supplies a pointer to the GUID representring the functionality
  1209. to be registered
  1210. ReferenceString - Optionally, supplies an additional context string which is
  1211. appended to the enumeration path of the device
  1212. SymbolicLinkName - Supplies a pointer to a string which on success will contain the
  1213. kernel mode path of the symbolic link used to open this device.
  1214. Return Value:
  1215. Status code that indicates whether or not the function was successful.
  1216. --*/
  1217. {
  1218. PDEVICE_NODE pDeviceNode;
  1219. PUNICODE_STRING pDeviceString;
  1220. NTSTATUS status;
  1221. PWSTR pRefString;
  1222. USHORT count;
  1223. PAGED_CODE();
  1224. //
  1225. // Until PartMgr/Disk stop registering non PDOs allow the system to boot.
  1226. //
  1227. // ASSERT_PDO(PhysicalDeviceObject);
  1228. //
  1229. //
  1230. // Ensure we have a PDO - only PDO's have a device node attached
  1231. //
  1232. pDeviceNode = (PDEVICE_NODE) PhysicalDeviceObject->DeviceObjectExtension->DeviceNode;
  1233. if (pDeviceNode) {
  1234. //
  1235. // Get the instance path string
  1236. //
  1237. pDeviceString = &pDeviceNode->InstancePath;
  1238. if (pDeviceNode->InstancePath.Length == 0) {
  1239. return STATUS_INVALID_DEVICE_REQUEST;
  1240. }
  1241. //
  1242. // Make sure the ReferenceString does not contain any path seperator characters
  1243. //
  1244. if (ReferenceString) {
  1245. pRefString = ReferenceString->Buffer;
  1246. count = ReferenceString->Length / sizeof(WCHAR);
  1247. while (count--) {
  1248. if((*pRefString == SEPERATOR_CHAR) || (*pRefString == ALT_SEPERATOR_CHAR)) {
  1249. status = STATUS_INVALID_DEVICE_REQUEST;
  1250. IopDbgPrint(( IOP_ERROR_LEVEL,
  1251. "IoRegisterDeviceInterface: Invalid RefString!! failed with status = %8.8X\n", status));
  1252. return status;
  1253. }
  1254. pRefString++;
  1255. }
  1256. }
  1257. return IopRegisterDeviceInterface(pDeviceString,
  1258. InterfaceClassGuid,
  1259. ReferenceString,
  1260. FALSE, // kernel-mode format
  1261. SymbolicLinkName
  1262. );
  1263. } else {
  1264. return STATUS_INVALID_DEVICE_REQUEST;
  1265. }
  1266. }
  1267. NTSTATUS
  1268. IopRegisterDeviceInterface(
  1269. IN PUNICODE_STRING DeviceInstanceName,
  1270. IN CONST GUID *InterfaceClassGuid,
  1271. IN PUNICODE_STRING ReferenceString OPTIONAL,
  1272. IN BOOLEAN UserModeFormat,
  1273. OUT PUNICODE_STRING SymbolicLinkName
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. This is the worker routine for IoRegisterDeviceInterface. It is also
  1278. called by the user-mode ConfigMgr (via an NtPlugPlayControl), which is why it
  1279. must take a device instance name instead of a PDO (since the device instance
  1280. may not currently be 'live'), and also why it must optionally return the user-
  1281. mode form of the interface device name (i.e., "\\?\" instead of "\??\").
  1282. Parameters:
  1283. DeviceInstanceName - Supplies the name of the device instance for which a
  1284. device interface is being registered.
  1285. InterfaceClassGuid - Supplies a pointer to the GUID representring the class
  1286. of the device interface being registered.
  1287. ReferenceString - Optionally, supplies an additional context string which is
  1288. appended to the enumeration path of the device
  1289. UserModeFormat - If non-zero, then the symbolic link name returned for the
  1290. interface device is in user-mode form (i.e., "\\?\"). If zero (FALSE),
  1291. it is in kernel-mode form (i.e., "\??\").
  1292. SymbolicLinkName - Supplies a pointer to a string which on success will contain
  1293. either the kernel-mode or user-mode path of the symbolic link used to open
  1294. this device.
  1295. Return Value:
  1296. Status code that indicates whether or not the function was successful.
  1297. --*/
  1298. {
  1299. NTSTATUS status;
  1300. UNICODE_STRING tempString, guidString, otherString;
  1301. PUNICODE_STRING pUserString, pKernelString;
  1302. HANDLE hTemp1, hTemp2, hInterfaceInstanceKey;
  1303. ULONG InterfaceDisposition, InterfaceInstanceDisposition;
  1304. PAGED_CODE();
  1305. //
  1306. // Convert the class guid into string form
  1307. //
  1308. status = RtlStringFromGUID(InterfaceClassGuid, &guidString);
  1309. if( !NT_SUCCESS(status) ){
  1310. goto clean0;
  1311. }
  1312. //
  1313. // Construct both flavors of symbolic link name (go ahead and store the form
  1314. // that the user wants in the SymbolicLinkName parameter they supplied--this
  1315. // saves us from having to copy the appropriate string over to their string
  1316. // later).
  1317. //
  1318. if(UserModeFormat) {
  1319. pUserString = SymbolicLinkName;
  1320. pKernelString = &otherString;
  1321. } else {
  1322. pKernelString = SymbolicLinkName;
  1323. pUserString = &otherString;
  1324. }
  1325. status = IopBuildSymbolicLinkStrings(DeviceInstanceName,
  1326. &guidString,
  1327. ReferenceString,
  1328. pUserString,
  1329. pKernelString
  1330. );
  1331. if (!NT_SUCCESS(status)) {
  1332. goto clean1;
  1333. }
  1334. //
  1335. // Enter critical section and acquire a lock on the registry. Both these
  1336. // mechanisms are required to prevent deadlock in the case where an APC
  1337. // routine calls this routine after the registry resource has been claimed
  1338. // in this case it would wait blocking this thread so the registry would
  1339. // never be released -> deadlock. Critical sectioning the registry manipulation
  1340. // portion solves this problem
  1341. //
  1342. PiLockPnpRegistry(TRUE);
  1343. //
  1344. // Open HKLM\System\CurrentControlSet\Control\DeviceClasses key into hTemp1
  1345. //
  1346. PiWstrToUnicodeString(&tempString, REGSTR_FULL_PATH_DEVICE_CLASSES);
  1347. status = IopCreateRegistryKeyEx( &hTemp1,
  1348. NULL,
  1349. &tempString,
  1350. KEY_CREATE_SUB_KEY,
  1351. REG_OPTION_NON_VOLATILE,
  1352. NULL
  1353. );
  1354. if( !NT_SUCCESS(status) ){
  1355. goto clean2;
  1356. }
  1357. //
  1358. // Open/create function class GUID key into hTemp2
  1359. //
  1360. status = IopCreateRegistryKeyEx( &hTemp2,
  1361. hTemp1,
  1362. &guidString,
  1363. KEY_CREATE_SUB_KEY,
  1364. REG_OPTION_NON_VOLATILE,
  1365. NULL
  1366. );
  1367. ZwClose(hTemp1);
  1368. if( !NT_SUCCESS(status) ){
  1369. goto clean2;
  1370. }
  1371. //
  1372. // Now open/create the two-level device interface hierarchy underneath this
  1373. // interface class key.
  1374. //
  1375. status = IopOpenOrCreateDeviceInterfaceSubKeys(&hTemp1,
  1376. &InterfaceDisposition,
  1377. &hInterfaceInstanceKey,
  1378. &InterfaceInstanceDisposition,
  1379. hTemp2,
  1380. pUserString,
  1381. KEY_WRITE | DELETE,
  1382. TRUE
  1383. );
  1384. ZwClose(hTemp2);
  1385. if(!NT_SUCCESS(status)) {
  1386. goto clean2;
  1387. }
  1388. //
  1389. // Create the device instance value under the device interface key
  1390. //
  1391. PiWstrToUnicodeString(&tempString, REGSTR_VAL_DEVICE_INSTANCE);
  1392. status = IopSetRegistryStringValue(hTemp1,
  1393. &tempString,
  1394. DeviceInstanceName
  1395. );
  1396. if(!NT_SUCCESS(status)) {
  1397. goto clean3;
  1398. }
  1399. //
  1400. // Create symbolic link value under interface instance subkey
  1401. //
  1402. PiWstrToUnicodeString(&tempString, REGSTR_VAL_SYMBOLIC_LINK);
  1403. status = IopSetRegistryStringValue(hInterfaceInstanceKey,
  1404. &tempString,
  1405. pUserString
  1406. );
  1407. clean3:
  1408. if (!NT_SUCCESS(status)) {
  1409. //
  1410. // Since we failed to register the device interface, delete any keys
  1411. // that were newly created in the attempt.
  1412. //
  1413. if(InterfaceInstanceDisposition == REG_CREATED_NEW_KEY) {
  1414. ZwDeleteKey(hInterfaceInstanceKey);
  1415. }
  1416. if(InterfaceDisposition == REG_CREATED_NEW_KEY) {
  1417. ZwDeleteKey(hTemp1);
  1418. }
  1419. }
  1420. ZwClose(hInterfaceInstanceKey);
  1421. ZwClose(hTemp1);
  1422. clean2:
  1423. PiUnlockPnpRegistry();
  1424. IopFreeAllocatedUnicodeString(&otherString);
  1425. if (!NT_SUCCESS(status)) {
  1426. IopFreeAllocatedUnicodeString(SymbolicLinkName);
  1427. }
  1428. clean1:
  1429. RtlFreeUnicodeString(&guidString);
  1430. clean0:
  1431. return status;
  1432. }
  1433. NTSTATUS
  1434. IopUnregisterDeviceInterface(
  1435. IN PUNICODE_STRING SymbolicLinkName
  1436. )
  1437. /*++
  1438. Routine Description:
  1439. This routine removes the interface instance subkey of
  1440. ReferenceString from the interface for DeviceInstanceName to the
  1441. given InterfaceClassGuid. If the interface instance specified by
  1442. the Reference String portion of SymbolicLinkName is the only
  1443. instance of the interface, the interface subkey is removed from
  1444. the device class key as well.
  1445. Parameters:
  1446. SymbolicLinkName - Supplies a pointer to a unicode string which
  1447. contains the symbolic link name of the device to unregister.
  1448. Return Value:
  1449. Status code that indicates whether or not the function was successful.
  1450. --*/
  1451. {
  1452. NTSTATUS status = STATUS_SUCCESS;
  1453. HANDLE hInterfaceClassKey=NULL, hInterfaceKey=NULL,
  1454. hInterfaceInstanceKey=NULL, hControl=NULL;
  1455. UNICODE_STRING tempString, mungedPathString, guidString, refString;
  1456. BOOLEAN refStringPresent;
  1457. GUID guid;
  1458. UNICODE_STRING interfaceKeyName, instanceKeyName;
  1459. ULONG linked, remainingSubKeys;
  1460. USHORT length;
  1461. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1462. PKEY_FULL_INFORMATION keyInformation;
  1463. PAGED_CODE();
  1464. //
  1465. // Check that the supplied symbolic link can be parsed - note that this is
  1466. // also a way of verifying that the SymbolicLinkName string is valid.
  1467. //
  1468. status = IopParseSymbolicLinkName(SymbolicLinkName,
  1469. NULL,
  1470. &mungedPathString,
  1471. &guidString,
  1472. &refString,
  1473. &refStringPresent,
  1474. &guid);
  1475. if (!NT_SUCCESS(status)) {
  1476. status = STATUS_INVALID_PARAMETER;
  1477. goto clean0;
  1478. }
  1479. //
  1480. // Allocate a unicode string for the interface instance key name.
  1481. // (includes the REFSTRING_PREFIX_CHAR, and ReferenceString, if present)
  1482. //
  1483. length = sizeof(WCHAR) + refString.Length;
  1484. status = IopAllocateUnicodeString(&instanceKeyName,
  1485. length);
  1486. if(!NT_SUCCESS(status)) {
  1487. goto clean0;
  1488. }
  1489. //
  1490. // Set the MaximumLength of the Buffer, and append the
  1491. // REFSTRING_PREFIX_CHAR to it.
  1492. //
  1493. *instanceKeyName.Buffer = REFSTRING_PREFIX_CHAR;
  1494. instanceKeyName.Length = sizeof(WCHAR);
  1495. instanceKeyName.MaximumLength = length + sizeof(UNICODE_NULL);
  1496. //
  1497. // Append the ReferenceString to the prefix char, if necessary.
  1498. //
  1499. if (refStringPresent) {
  1500. RtlAppendUnicodeStringToString(&instanceKeyName, &refString);
  1501. }
  1502. instanceKeyName.Buffer[instanceKeyName.Length/sizeof(WCHAR)] = UNICODE_NULL;
  1503. //
  1504. // Allocate a unicode string for the interface key name.
  1505. // (includes KEY_STRING_PREFIX, mungedPathString, separating '#'
  1506. // char, and the guidString)
  1507. //
  1508. length = IopConstStringSize(KEY_STRING_PREFIX) + mungedPathString.Length +
  1509. sizeof(WCHAR) + guidString.Length;
  1510. status = IopAllocateUnicodeString(&interfaceKeyName,
  1511. length);
  1512. if(!NT_SUCCESS(status)) {
  1513. goto clean1;
  1514. }
  1515. interfaceKeyName.MaximumLength = length + sizeof(UNICODE_NULL);
  1516. //
  1517. // Copy the symbolic link name (without refString) to the interfaceKeyNam
  1518. //
  1519. RtlCopyMemory(interfaceKeyName.Buffer, SymbolicLinkName->Buffer, length);
  1520. interfaceKeyName.Length = length;
  1521. interfaceKeyName.Buffer[interfaceKeyName.Length/sizeof(WCHAR)] = UNICODE_NULL;
  1522. //
  1523. // Replace the "\??\" or "\\?\" symbolic link name prefix with "##?#"
  1524. //
  1525. RtlCopyMemory(interfaceKeyName.Buffer,
  1526. KEY_STRING_PREFIX,
  1527. IopConstStringSize(KEY_STRING_PREFIX));
  1528. //
  1529. // Enter critical section and acquire a lock on the registry. Both these
  1530. // mechanisms are required to prevent deadlock in the case where an APC
  1531. // routine calls this routine after the registry resource has been claimed
  1532. // in this case it would wait blocking this thread so the registry would
  1533. // never be released -> deadlock. Critical sectioning the registry manipulation
  1534. // portion solves this problem
  1535. //
  1536. PiLockPnpRegistry(TRUE);
  1537. //
  1538. // Get class, interface, and instance handles
  1539. //
  1540. status = IopDeviceInterfaceKeysFromSymbolicLink(SymbolicLinkName,
  1541. KEY_ALL_ACCESS,
  1542. &hInterfaceClassKey,
  1543. &hInterfaceKey,
  1544. &hInterfaceInstanceKey
  1545. );
  1546. if (!NT_SUCCESS(status)) {
  1547. goto clean2;
  1548. }
  1549. //
  1550. // Determine whether this interface is currently "enabled"
  1551. //
  1552. linked = 0;
  1553. PiWstrToUnicodeString(&tempString, REGSTR_KEY_CONTROL);
  1554. status = IopOpenRegistryKeyEx( &hControl,
  1555. hInterfaceInstanceKey,
  1556. &tempString,
  1557. KEY_ALL_ACCESS
  1558. );
  1559. if (NT_SUCCESS(status)) {
  1560. //
  1561. // Check the "linked" value under the "Control" subkey of this
  1562. // interface instance
  1563. //
  1564. keyValueInformation=NULL;
  1565. status = IopGetRegistryValue(hControl,
  1566. REGSTR_VAL_LINKED,
  1567. &keyValueInformation);
  1568. if(NT_SUCCESS(status)) {
  1569. if (keyValueInformation->Type == REG_DWORD &&
  1570. keyValueInformation->DataLength == sizeof(ULONG)) {
  1571. linked = *((PULONG) KEY_VALUE_DATA(keyValueInformation));
  1572. ExFreePool(keyValueInformation);
  1573. }
  1574. }
  1575. ZwClose(hControl);
  1576. hControl = NULL;
  1577. }
  1578. //
  1579. // Ignore any status code returned while attempting to retieve the
  1580. // state of the device. The value of linked will tell us if we
  1581. // need to disable the interface instance first.
  1582. //
  1583. // If no instance "Control" subkey or "linked" value was present
  1584. // (status == STATUS_OBJECT_NAME_NOT_FOUND), this interface instance
  1585. // is not currently enabled -- ok to delete.
  1586. //
  1587. // If the attempt to retrieve these values failed with some other error,
  1588. // any attempt to disable the interface will also likely fail,
  1589. // so we'll just have to delete this instance anyways.
  1590. //
  1591. status = STATUS_SUCCESS;
  1592. if (linked) {
  1593. //
  1594. // Disabled the active interface before unregistering it, ignore any
  1595. // status returned, we'll delete this interface instance key anyways.
  1596. //
  1597. IoSetDeviceInterfaceState(SymbolicLinkName, FALSE);
  1598. }
  1599. //
  1600. // Recursively delete the interface instance key, if it exists.
  1601. //
  1602. ZwClose(hInterfaceInstanceKey);
  1603. hInterfaceInstanceKey = NULL;
  1604. IopDeleteKeyRecursive (hInterfaceKey, instanceKeyName.Buffer);
  1605. //
  1606. // Find out how many subkeys to the interface key remain.
  1607. //
  1608. status = IopGetRegistryKeyInformation(hInterfaceKey,
  1609. &keyInformation);
  1610. if (!NT_SUCCESS(status)) {
  1611. goto clean3;
  1612. }
  1613. remainingSubKeys = keyInformation->SubKeys;
  1614. ExFreePool(keyInformation);
  1615. //
  1616. // See if a volatile "Control" subkey exists under this interface key
  1617. //
  1618. PiWstrToUnicodeString(&tempString, REGSTR_KEY_CONTROL);
  1619. status = IopOpenRegistryKeyEx( &hControl,
  1620. hInterfaceKey,
  1621. &tempString,
  1622. KEY_READ
  1623. );
  1624. if (NT_SUCCESS(status)) {
  1625. ZwClose(hControl);
  1626. hControl = NULL;
  1627. }
  1628. if ((remainingSubKeys==0) ||
  1629. ((remainingSubKeys==1) && (NT_SUCCESS(status)))) {
  1630. //
  1631. // If the interface key has no subkeys, or the only the remaining subkey
  1632. // is the volatile interface "Control" subkey, then there are no more
  1633. // instances to this interface. We should delete the interface key
  1634. // itself also.
  1635. //
  1636. ZwClose(hInterfaceKey);
  1637. hInterfaceKey = NULL;
  1638. IopDeleteKeyRecursive (hInterfaceClassKey, interfaceKeyName.Buffer);
  1639. }
  1640. status = STATUS_SUCCESS;
  1641. clean3:
  1642. if (hControl) {
  1643. ZwClose(hControl);
  1644. }
  1645. if (hInterfaceInstanceKey) {
  1646. ZwClose(hInterfaceInstanceKey);
  1647. }
  1648. if (hInterfaceKey) {
  1649. ZwClose(hInterfaceKey);
  1650. }
  1651. if (hInterfaceClassKey) {
  1652. ZwClose(hInterfaceClassKey);
  1653. }
  1654. clean2:
  1655. PiUnlockPnpRegistry();
  1656. IopFreeAllocatedUnicodeString(&interfaceKeyName);
  1657. clean1:
  1658. IopFreeAllocatedUnicodeString(&instanceKeyName);
  1659. clean0:
  1660. return status;
  1661. }
  1662. NTSTATUS
  1663. IopRemoveDeviceInterfaces(
  1664. IN PUNICODE_STRING DeviceInstancePath
  1665. )
  1666. /*++
  1667. Routine Description:
  1668. This routine checks all device class keys under
  1669. HKLM\SYSTEM\CCS\Control\DeviceClasses for interfaces for which the
  1670. DeviceInstance value matches the supplied DeviceInstancePath. Instances of
  1671. such device interfaces are unregistered, and the device interface subkey
  1672. itself is removed.
  1673. Note that a lock on the registry must have already been acquired,
  1674. by the caller of this routine.
  1675. Parameters:
  1676. DeviceInterfacePath - Supplies a pointer to a unicode string which
  1677. contains the DeviceInterface name of the device for which
  1678. interfaces to are to be removed.
  1679. Return Value:
  1680. Status code that indicates whether or not the function was
  1681. successful.
  1682. --*/
  1683. {
  1684. NTSTATUS status;
  1685. HANDLE hDeviceClasses=NULL, hClassGUID=NULL, hInterface=NULL;
  1686. UNICODE_STRING tempString, guidString, interfaceString, deviceInstanceString;
  1687. ULONG resultSize, classIndex, interfaceIndex;
  1688. ULONG symbolicLinkListSize;
  1689. PWCHAR symbolicLinkList, symLink;
  1690. BUFFER_INFO classInfoBuffer, interfaceInfoBuffer;
  1691. PKEY_VALUE_FULL_INFORMATION deviceInstanceInfo;
  1692. BOOLEAN deletedInterface;
  1693. GUID classGUID;
  1694. PAGED_CODE();
  1695. //
  1696. // Allocate initial buffers
  1697. //
  1698. status = IopAllocateBuffer(&classInfoBuffer,
  1699. INITIAL_INFO_BUFFER_SIZE);
  1700. if (!NT_SUCCESS(status)) {
  1701. goto clean0;
  1702. }
  1703. status = IopAllocateBuffer(&interfaceInfoBuffer,
  1704. INITIAL_INFO_BUFFER_SIZE);
  1705. if (!NT_SUCCESS(status)) {
  1706. IopFreeBuffer(&classInfoBuffer);
  1707. goto clean0;
  1708. }
  1709. //
  1710. // Open HKLM\System\CurrentControlSet\Control\DeviceClasses
  1711. //
  1712. PiWstrToUnicodeString(&tempString, REGSTR_FULL_PATH_DEVICE_CLASSES);
  1713. status = IopOpenRegistryKeyEx( &hDeviceClasses,
  1714. NULL,
  1715. &tempString,
  1716. KEY_READ
  1717. );
  1718. if(!NT_SUCCESS(status)){
  1719. goto clean1;
  1720. }
  1721. //
  1722. // Enumerate all device classes
  1723. //
  1724. classIndex = 0;
  1725. ASSERT(classInfoBuffer.MaxSize >= sizeof(KEY_BASIC_INFORMATION));
  1726. while((status = ZwEnumerateKey(hDeviceClasses,
  1727. classIndex,
  1728. KeyBasicInformation,
  1729. (PVOID) classInfoBuffer.Buffer,
  1730. classInfoBuffer.MaxSize,
  1731. &resultSize
  1732. )) != STATUS_NO_MORE_ENTRIES) {
  1733. //
  1734. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  1735. // was not enough room for even the fixed portions of the structure.
  1736. //
  1737. ASSERT(status != STATUS_BUFFER_TOO_SMALL);
  1738. if (status == STATUS_BUFFER_OVERFLOW) {
  1739. status = IopResizeBuffer(&classInfoBuffer, resultSize, FALSE);
  1740. continue;
  1741. } else if (!NT_SUCCESS(status)) {
  1742. goto clean1;
  1743. }
  1744. //
  1745. // Get the key name for this device class
  1746. //
  1747. guidString.Length = (USHORT)((PKEY_BASIC_INFORMATION)(classInfoBuffer.Buffer))->NameLength;
  1748. guidString.MaximumLength = guidString.Length;
  1749. guidString.Buffer = ((PKEY_BASIC_INFORMATION)(classInfoBuffer.Buffer))->Name;
  1750. //
  1751. // Open the key for this device class
  1752. //
  1753. status = IopOpenRegistryKeyEx( &hClassGUID,
  1754. hDeviceClasses,
  1755. &guidString,
  1756. KEY_ALL_ACCESS
  1757. );
  1758. if (!NT_SUCCESS(status)) {
  1759. //
  1760. // Couldn't open key for this device class -- skip it and move on.
  1761. //
  1762. goto CloseClassKeyAndContinue;
  1763. }
  1764. //
  1765. // Enumerate all device interfaces for this device class
  1766. //
  1767. interfaceIndex = 0;
  1768. ASSERT(interfaceInfoBuffer.MaxSize >= sizeof(KEY_BASIC_INFORMATION));
  1769. while((status = ZwEnumerateKey(hClassGUID,
  1770. interfaceIndex,
  1771. KeyBasicInformation,
  1772. (PVOID) interfaceInfoBuffer.Buffer,
  1773. interfaceInfoBuffer.MaxSize,
  1774. &resultSize
  1775. )) != STATUS_NO_MORE_ENTRIES) {
  1776. //
  1777. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  1778. // was not enough room for even the fixed portions of the structure.
  1779. //
  1780. ASSERT(status != STATUS_BUFFER_TOO_SMALL);
  1781. if (status == STATUS_BUFFER_OVERFLOW) {
  1782. status = IopResizeBuffer(&interfaceInfoBuffer, resultSize, FALSE);
  1783. continue;
  1784. } else if (!NT_SUCCESS(status)) {
  1785. goto clean1;
  1786. }
  1787. //
  1788. // This interface key has not yet been deleted
  1789. //
  1790. deletedInterface = FALSE;
  1791. //
  1792. // Create a NULL-terminated unicode string for the interface key name
  1793. //
  1794. status = IopAllocateUnicodeString(&interfaceString,
  1795. (USHORT)((PKEY_BASIC_INFORMATION)(interfaceInfoBuffer.Buffer))->NameLength);
  1796. if (!NT_SUCCESS(status)) {
  1797. goto clean1;
  1798. }
  1799. interfaceString.Length = (USHORT)((PKEY_BASIC_INFORMATION)(interfaceInfoBuffer.Buffer))->NameLength;
  1800. interfaceString.MaximumLength = interfaceString.Length + sizeof(UNICODE_NULL);
  1801. RtlCopyMemory(interfaceString.Buffer,
  1802. ((PKEY_BASIC_INFORMATION)(interfaceInfoBuffer.Buffer))->Name,
  1803. interfaceString.Length);
  1804. interfaceString.Buffer[interfaceString.Length/sizeof(WCHAR)] = UNICODE_NULL;
  1805. //
  1806. // Open the device interface key
  1807. //
  1808. status = IopOpenRegistryKeyEx( &hInterface,
  1809. hClassGUID,
  1810. &interfaceString,
  1811. KEY_ALL_ACCESS
  1812. );
  1813. if (!NT_SUCCESS(status)) {
  1814. //
  1815. // Couldn't open the device interface key -- skip it and move on.
  1816. //
  1817. hInterface = NULL;
  1818. goto CloseInterfaceKeyAndContinue;
  1819. }
  1820. //
  1821. // Get the DeviceInstance value for this interface key
  1822. //
  1823. status = IopGetRegistryValue(hInterface,
  1824. REGSTR_VAL_DEVICE_INSTANCE,
  1825. &deviceInstanceInfo);
  1826. if(!NT_SUCCESS(status)) {
  1827. //
  1828. // Couldn't get the DeviceInstance for this interface --
  1829. // skip it and move on.
  1830. //
  1831. goto CloseInterfaceKeyAndContinue;
  1832. }
  1833. if((deviceInstanceInfo->Type == REG_SZ) &&
  1834. (deviceInstanceInfo->DataLength != 0)) {
  1835. IopRegistryDataToUnicodeString(&deviceInstanceString,
  1836. (PWSTR)KEY_VALUE_DATA(deviceInstanceInfo),
  1837. deviceInstanceInfo->DataLength);
  1838. } else {
  1839. //
  1840. // DeviceInstance value is invalid -- skip it and move on.
  1841. //
  1842. ExFreePool(deviceInstanceInfo);
  1843. goto CloseInterfaceKeyAndContinue;
  1844. }
  1845. //
  1846. // Compare the DeviceInstance of this interface to DeviceInstancePath
  1847. //
  1848. if (RtlEqualUnicodeString(&deviceInstanceString, DeviceInstancePath, TRUE)) {
  1849. ZwClose(hInterface);
  1850. hInterface = NULL;
  1851. //
  1852. // Retrieve all instances of this device interface
  1853. // (active and non-active)
  1854. //
  1855. RtlGUIDFromString(&guidString, &classGUID);
  1856. status = IopGetDeviceInterfaces(&classGUID,
  1857. DeviceInstancePath,
  1858. DEVICE_INTERFACE_INCLUDE_NONACTIVE,
  1859. FALSE, // kernel-mode format
  1860. &symbolicLinkList,
  1861. &symbolicLinkListSize);
  1862. if (NT_SUCCESS(status)) {
  1863. //
  1864. // Iterate through all instances of the interface
  1865. //
  1866. symLink = symbolicLinkList;
  1867. while(*symLink != UNICODE_NULL) {
  1868. RtlInitUnicodeString(&tempString, symLink);
  1869. //
  1870. // Unregister this instance of the interface. Since we are
  1871. // removing the device, ignore any returned status, since
  1872. // there isn't anything we can do about interfaces which
  1873. // fail unregistration.
  1874. //
  1875. IopUnregisterDeviceInterface(&tempString);
  1876. symLink += ((tempString.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR));
  1877. }
  1878. ExFreePool(symbolicLinkList);
  1879. }
  1880. //
  1881. // Recursively delete the interface key, if it still exists.
  1882. // While IopUnregisterDeviceInterface will itself delete the
  1883. // interface key if no interface instance subkeys remain, if any
  1884. // of the above calls to IopUnregisterDeviceInterface failed to
  1885. // delete an interface instance key, subkeys will remain, and
  1886. // the interface key will not have been deleted. We'll catch
  1887. // that here.
  1888. //
  1889. status = IopOpenRegistryKeyEx( &hInterface,
  1890. hClassGUID,
  1891. &interfaceString,
  1892. KEY_READ
  1893. );
  1894. if(NT_SUCCESS(status)){
  1895. if (NT_SUCCESS(IopDeleteKeyRecursive(hClassGUID,
  1896. interfaceString.Buffer))) {
  1897. deletedInterface = TRUE;
  1898. }
  1899. ZwDeleteKey(hInterface);
  1900. ZwClose(hInterface);
  1901. hInterface = NULL;
  1902. } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1903. //
  1904. // Interface was already deleted by IopUnregisterDeviceInterface
  1905. //
  1906. deletedInterface = TRUE;
  1907. }
  1908. }
  1909. //
  1910. // Free allocated key info structure
  1911. //
  1912. ExFreePool(deviceInstanceInfo);
  1913. CloseInterfaceKeyAndContinue:
  1914. if (hInterface != NULL) {
  1915. ZwClose(hInterface);
  1916. hInterface = NULL;
  1917. }
  1918. IopFreeAllocatedUnicodeString(&interfaceString);
  1919. //
  1920. // Only increment the enumeration index for non-deleted keys
  1921. //
  1922. if (!deletedInterface) {
  1923. interfaceIndex++;
  1924. }
  1925. }
  1926. CloseClassKeyAndContinue:
  1927. if (hClassGUID != NULL) {
  1928. ZwClose(hClassGUID);
  1929. hClassGUID = NULL;
  1930. }
  1931. classIndex++;
  1932. }
  1933. clean1:
  1934. if (hInterface) {
  1935. ZwClose(hInterface);
  1936. }
  1937. if (hClassGUID) {
  1938. ZwClose(hClassGUID);
  1939. }
  1940. if (hDeviceClasses) {
  1941. ZwClose(hDeviceClasses);
  1942. }
  1943. IopFreeBuffer(&interfaceInfoBuffer);
  1944. IopFreeBuffer(&classInfoBuffer);
  1945. clean0:
  1946. return status;
  1947. }
  1948. NTSTATUS
  1949. IopDisableDeviceInterfaces(
  1950. IN PUNICODE_STRING DeviceInstancePath
  1951. )
  1952. /*++
  1953. Routine Description:
  1954. This routine disables all enabled device interfaces for a given device
  1955. instance. This is typically done after a device has been removed, in case
  1956. the driver did not disable the interfaces for that device, as it should
  1957. have.
  1958. Note that this routine acquires a lock on the registry.
  1959. Parameters:
  1960. DeviceInterfacePath - Supplies a pointer to a unicode string which contains
  1961. the DeviceInterface name of the device for which
  1962. interfaces to are to be disabled.
  1963. Return Value:
  1964. Status code that indicates whether or not the function was successful.
  1965. --*/
  1966. {
  1967. NTSTATUS status = STATUS_SUCCESS;
  1968. UNICODE_STRING tempString, guidString;
  1969. HANDLE hDeviceClasses = NULL;
  1970. ULONG classIndex, resultSize;
  1971. BUFFER_INFO classInfoBuffer;
  1972. GUID classGuid;
  1973. PWCHAR symbolicLinkList, symLink;
  1974. ULONG symbolicLinkListSize;
  1975. PAGED_CODE();
  1976. //
  1977. // Allocate initial buffer to hold device class GUID subkeys.
  1978. //
  1979. status = IopAllocateBuffer(&classInfoBuffer,
  1980. sizeof(KEY_BASIC_INFORMATION) +
  1981. GUID_STRING_SIZE + sizeof(UNICODE_NULL));
  1982. if (!NT_SUCCESS(status)) {
  1983. return status;
  1984. }
  1985. //
  1986. // Enter critical section and acquire a lock on the registry. Both these
  1987. // mechanisms are required to prevent deadlock in the case where an APC
  1988. // routine calls this routine after the registry resource has been claimed
  1989. // in this case it would wait blocking this thread so the registry would
  1990. // never be released -> deadlock. Critical sectioning the registry manipulation
  1991. // portion solves this problem
  1992. //
  1993. PiLockPnpRegistry(TRUE);
  1994. //
  1995. // Open HKLM\System\CurrentControlSet\Control\DeviceClasses
  1996. //
  1997. PiWstrToUnicodeString(&tempString, REGSTR_FULL_PATH_DEVICE_CLASSES);
  1998. status = IopOpenRegistryKeyEx(&hDeviceClasses,
  1999. NULL,
  2000. &tempString,
  2001. KEY_READ
  2002. );
  2003. if (!NT_SUCCESS(status)){
  2004. goto clean0;
  2005. }
  2006. //
  2007. // Enumerate all device classes
  2008. //
  2009. classIndex = 0;
  2010. ASSERT(classInfoBuffer.MaxSize >= sizeof(KEY_BASIC_INFORMATION));
  2011. while((status = ZwEnumerateKey(hDeviceClasses,
  2012. classIndex,
  2013. KeyBasicInformation,
  2014. (PVOID)classInfoBuffer.Buffer,
  2015. classInfoBuffer.MaxSize,
  2016. &resultSize
  2017. )) != STATUS_NO_MORE_ENTRIES) {
  2018. //
  2019. // A return value of STATUS_BUFFER_TOO_SMALL would mean that there
  2020. // was not enough room for even the fixed portions of the structure.
  2021. //
  2022. ASSERT(status != STATUS_BUFFER_TOO_SMALL);
  2023. if (status == STATUS_BUFFER_OVERFLOW) {
  2024. status = IopResizeBuffer(&classInfoBuffer, resultSize, FALSE);
  2025. continue;
  2026. } else if (!NT_SUCCESS(status)) {
  2027. ZwClose(hDeviceClasses);
  2028. goto clean0;
  2029. }
  2030. //
  2031. // Get the key name for this device class
  2032. //
  2033. guidString.Length = (USHORT)((PKEY_BASIC_INFORMATION)(classInfoBuffer.Buffer))->NameLength;
  2034. guidString.MaximumLength = guidString.Length;
  2035. guidString.Buffer = ((PKEY_BASIC_INFORMATION)(classInfoBuffer.Buffer))->Name;
  2036. //
  2037. // Retrieve all enabled device interfaces for this device class that are
  2038. // exposed by the given device instance.
  2039. //
  2040. RtlGUIDFromString(&guidString, &classGuid);
  2041. status = IopGetDeviceInterfaces(&classGuid,
  2042. DeviceInstancePath,
  2043. 0, // active interfaces only
  2044. FALSE, // kernel-mode format
  2045. &symbolicLinkList,
  2046. &symbolicLinkListSize);
  2047. if (NT_SUCCESS(status)) {
  2048. //
  2049. // Iterate through all enabled instances of this device interface
  2050. // members of this device interface class, exposed by the given
  2051. // device instance.
  2052. //
  2053. symLink = symbolicLinkList;
  2054. while(*symLink != UNICODE_NULL) {
  2055. RtlInitUnicodeString(&tempString, symLink);
  2056. IopDbgPrint((IOP_WARNING_LEVEL,
  2057. "IopDisableDeviceInterfaces: auto-disabling interface %Z for device instance %Z\n",
  2058. tempString,
  2059. DeviceInstancePath));
  2060. //
  2061. // Disable this device interface.
  2062. //
  2063. IoSetDeviceInterfaceState(&tempString, FALSE);
  2064. symLink += ((tempString.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR));
  2065. }
  2066. ExFreePool(symbolicLinkList);
  2067. }
  2068. classIndex++;
  2069. }
  2070. ZwClose(hDeviceClasses);
  2071. clean0:
  2072. IopFreeBuffer(&classInfoBuffer);
  2073. PiUnlockPnpRegistry();
  2074. return status;
  2075. }
  2076. NTSTATUS
  2077. IopOpenOrCreateDeviceInterfaceSubKeys(
  2078. OUT PHANDLE InterfaceKeyHandle OPTIONAL,
  2079. OUT PULONG InterfaceKeyDisposition OPTIONAL,
  2080. OUT PHANDLE InterfaceInstanceKeyHandle OPTIONAL,
  2081. OUT PULONG InterfaceInstanceDisposition OPTIONAL,
  2082. IN HANDLE InterfaceClassKeyHandle,
  2083. IN PUNICODE_STRING DeviceInterfaceName,
  2084. IN ACCESS_MASK DesiredAccess,
  2085. IN BOOLEAN Create
  2086. )
  2087. /*++
  2088. Routine Description:
  2089. This API opens or creates a two-level registry hierarchy underneath the
  2090. specified interface class key for a particular device interface. The first
  2091. level is the (munged) symbolic link name (sans RefString). The second level
  2092. is the refstring, prepended with a '#' sign (if the device interface has no
  2093. refstring, then this key name is simply '#').
  2094. Parameters:
  2095. InterfaceKeyHandle - Optionally, supplies the address of a variable that
  2096. receives a handle to the interface key (1st level in the hierarchy).
  2097. InterfaceKeyDisposition - Optionally, supplies the address of a variable that
  2098. receives either REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY indicating
  2099. whether the interface key was newly-created.
  2100. InterfaceInstanceKeyHandle - Optionally, supplies the address of a variable
  2101. that receives a handle to the interface instance key (2nd level in the
  2102. hierarchy).
  2103. InterfaceInstanceDisposition - Optionally, supplies the address of a variable
  2104. that receives either REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY
  2105. indicating whether the interface instance key was newly-created.
  2106. InterfaceClassKeyHandle - Supplies a handle to the interface class key under
  2107. which the device interface keys are to be opened/created.
  2108. DeviceInterfaceName - Supplies the (user-mode or kernel-mode form) device
  2109. interface name.
  2110. DesiredAccess - Specifies the desired access that the caller needs to the keys.
  2111. Create - Determines if the keys are to be created if they do not exist.
  2112. Return Value:
  2113. Status code that indicates whether or not the function was successful.
  2114. --*/
  2115. {
  2116. NTSTATUS status;
  2117. UNICODE_STRING TempString, RefString;
  2118. WCHAR PoundCharBuffer;
  2119. HANDLE hTempInterface, hTempInterfaceInstance;
  2120. ULONG TempInterfaceDisposition;
  2121. BOOLEAN RefStringPresent=FALSE;
  2122. PAGED_CODE();
  2123. //
  2124. // Make a copy of the device interface name, since we're going to munge it.
  2125. //
  2126. status = IopAllocateUnicodeString(&TempString, DeviceInterfaceName->Length);
  2127. if(!NT_SUCCESS(status)) {
  2128. goto clean0;
  2129. }
  2130. RtlCopyUnicodeString(&TempString, DeviceInterfaceName);
  2131. //
  2132. // Parse the SymbolicLinkName for the refstring component (if there is one).
  2133. // Note that this is also a way of verifying that the string is valid.
  2134. //
  2135. status = IopParseSymbolicLinkName(&TempString,
  2136. NULL,
  2137. NULL,
  2138. NULL,
  2139. &RefString,
  2140. &RefStringPresent,
  2141. NULL);
  2142. ASSERT(NT_SUCCESS(status));
  2143. if(!NT_SUCCESS(status)) {
  2144. goto clean1;
  2145. }
  2146. if(RefStringPresent) {
  2147. //
  2148. // Truncate the device interface name before the refstring separator char.
  2149. //
  2150. RefString.Buffer--;
  2151. RefString.Length += sizeof(WCHAR);
  2152. RefString.MaximumLength += sizeof(WCHAR);
  2153. TempString.MaximumLength = TempString.Length = (USHORT)((PUCHAR)RefString.Buffer - (PUCHAR)TempString.Buffer);
  2154. } else {
  2155. //
  2156. // Set up refstring to point to a temporary character buffer that will hold
  2157. // the single '#' used for the key name when no refstring is present.
  2158. //
  2159. RefString.Buffer = &PoundCharBuffer;
  2160. RefString.Length = RefString.MaximumLength = sizeof(PoundCharBuffer);
  2161. }
  2162. //
  2163. // Replace the "\??\" or "\\?\" symbolic link name prefix with ##?#
  2164. //
  2165. RtlCopyMemory(TempString.Buffer, KEY_STRING_PREFIX, IopConstStringSize(KEY_STRING_PREFIX));
  2166. //
  2167. // Munge the string
  2168. //
  2169. IopReplaceSeperatorWithPound(&TempString, &TempString);
  2170. //
  2171. // Now open/create this subkey under the interface class key.
  2172. //
  2173. if (Create) {
  2174. status = IopCreateRegistryKeyEx( &hTempInterface,
  2175. InterfaceClassKeyHandle,
  2176. &TempString,
  2177. DesiredAccess,
  2178. REG_OPTION_NON_VOLATILE,
  2179. &TempInterfaceDisposition
  2180. );
  2181. } else {
  2182. status = IopOpenRegistryKeyEx( &hTempInterface,
  2183. InterfaceClassKeyHandle,
  2184. &TempString,
  2185. DesiredAccess
  2186. );
  2187. }
  2188. if (!NT_SUCCESS(status)) {
  2189. goto clean1;
  2190. }
  2191. //
  2192. // Store a '#' as the first character of the RefString, and then we're ready to open the
  2193. // refstring subkey.
  2194. //
  2195. *RefString.Buffer = REFSTRING_PREFIX_CHAR;
  2196. //
  2197. // Now open/create the subkey under the interface key representing this interface instance
  2198. // (i.e., differentiated by refstring).
  2199. //
  2200. if (Create) {
  2201. status = IopCreateRegistryKeyEx( &hTempInterfaceInstance,
  2202. hTempInterface,
  2203. &RefString,
  2204. DesiredAccess,
  2205. REG_OPTION_NON_VOLATILE,
  2206. InterfaceInstanceDisposition
  2207. );
  2208. } else {
  2209. status = IopOpenRegistryKeyEx( &hTempInterfaceInstance,
  2210. hTempInterface,
  2211. &RefString,
  2212. DesiredAccess
  2213. );
  2214. TempInterfaceDisposition = REG_OPENED_EXISTING_KEY;
  2215. }
  2216. if (NT_SUCCESS(status)) {
  2217. //
  2218. // Store any requested return values in the caller-supplied buffers.
  2219. //
  2220. if (InterfaceKeyHandle) {
  2221. *InterfaceKeyHandle = hTempInterface;
  2222. } else {
  2223. ZwClose(hTempInterface);
  2224. }
  2225. if (InterfaceKeyDisposition) {
  2226. *InterfaceKeyDisposition = TempInterfaceDisposition;
  2227. }
  2228. if (InterfaceInstanceKeyHandle) {
  2229. *InterfaceInstanceKeyHandle = hTempInterfaceInstance;
  2230. } else {
  2231. ZwClose(hTempInterfaceInstance);
  2232. }
  2233. //
  2234. // (no need to set InterfaceInstanceDisposition--we already set it above)
  2235. //
  2236. } else {
  2237. //
  2238. // If the interface key was newly-created above, then delete it.
  2239. //
  2240. if (TempInterfaceDisposition == REG_CREATED_NEW_KEY) {
  2241. ZwDeleteKey(hTempInterface);
  2242. }
  2243. ZwClose(hTempInterface);
  2244. }
  2245. clean1:
  2246. IopFreeAllocatedUnicodeString(&TempString);
  2247. clean0:
  2248. return status;
  2249. }
  2250. NTSTATUS
  2251. IoGetDeviceInterfaceAlias(
  2252. IN PUNICODE_STRING SymbolicLinkName,
  2253. IN CONST GUID *AliasInterfaceClassGuid,
  2254. OUT PUNICODE_STRING AliasSymbolicLinkName
  2255. )
  2256. /*++
  2257. Routine Description:
  2258. This API returns a symbolic link name (i.e., device interface) of a
  2259. particular interface class that 'aliases' the specified device interface.
  2260. Two device interfaces are considered aliases of each other if the
  2261. following two criteria are met:
  2262. 1. Both interfaces are exposed by the same PDO (devnode).
  2263. 2. Both interfaces share the same RefString.
  2264. Parameters:
  2265. SymbolicLinkName - Supplies the name of the device interface whose alias is
  2266. to be retrieved.
  2267. AliasInterfaceClassGuid - Supplies a pointer to the GUID representing the interface
  2268. class for which an alias is to be retrieved.
  2269. AliasSymbolicLinkName - Supplies a pointer to a string which, upon success,
  2270. will contain the name of the device interface in the specified class that
  2271. aliases the SymbolicLinkName interface. (This symbolic link name will be
  2272. returned in either kernel-mode or user-mode form, depeding upon the form
  2273. of the SymbolicLinkName path).
  2274. It is the caller's responsibility to free the buffer allocated for this
  2275. string via ExFreePool().
  2276. Return Value:
  2277. Status code that indicates whether or not the function was successful.
  2278. --*/
  2279. {
  2280. NTSTATUS status;
  2281. HANDLE hKey;
  2282. PKEY_VALUE_FULL_INFORMATION pDeviceInstanceInfo;
  2283. UNICODE_STRING deviceInstanceString, refString, guidString, otherString;
  2284. PUNICODE_STRING pUserString, pKernelString;
  2285. BOOLEAN refStringPresent, userModeFormat;
  2286. PAGED_CODE();
  2287. //
  2288. // Make sure we have a SymbolicLinkName to parse.
  2289. //
  2290. if ((!ARGUMENT_PRESENT(SymbolicLinkName)) ||
  2291. (SymbolicLinkName->Buffer == NULL)) {
  2292. status = STATUS_INVALID_PARAMETER;
  2293. goto clean0;
  2294. }
  2295. //
  2296. // check that the input buffer really is big enough
  2297. //
  2298. ASSERT(IopConstStringSize(USER_SYMLINK_STRING_PREFIX) == IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX));
  2299. if (SymbolicLinkName->Length < (IopConstStringLength(KERNEL_SYMLINK_STRING_PREFIX)+GUID_STRING_SIZE+1)) {
  2300. status = STATUS_INVALID_PARAMETER;
  2301. goto clean0;
  2302. }
  2303. //
  2304. // Convert the class guid into string form
  2305. //
  2306. status = RtlStringFromGUID(AliasInterfaceClassGuid, &guidString);
  2307. if( !NT_SUCCESS(status) ){
  2308. goto clean0;
  2309. }
  2310. //
  2311. // Enter critical section and acquire a lock on the registry. Both these
  2312. // mechanisms are required to prevent deadlock in the case where an APC
  2313. // routine calls this routine after the registry resource has been claimed
  2314. // in this case it would wait blocking this thread so the registry would
  2315. // never be released -> deadlock. Critical sectioning the registry manipulation
  2316. // portion solves this problem
  2317. //
  2318. PiLockPnpRegistry(TRUE);
  2319. //
  2320. // Open the (parent) device interface key--not the refstring-specific one.
  2321. //
  2322. status = IopDeviceInterfaceKeysFromSymbolicLink(SymbolicLinkName,
  2323. KEY_READ,
  2324. NULL,
  2325. &hKey,
  2326. NULL
  2327. );
  2328. if(!NT_SUCCESS(status)) {
  2329. goto clean1;
  2330. }
  2331. //
  2332. // Get the name of the device instance that 'owns' this interface.
  2333. //
  2334. status = IopGetRegistryValue(hKey, REGSTR_VAL_DEVICE_INSTANCE, &pDeviceInstanceInfo);
  2335. ZwClose(hKey);
  2336. if(!NT_SUCCESS(status)) {
  2337. goto clean1;
  2338. }
  2339. if(pDeviceInstanceInfo->Type == REG_SZ) {
  2340. IopRegistryDataToUnicodeString(&deviceInstanceString,
  2341. (PWSTR)KEY_VALUE_DATA(pDeviceInstanceInfo),
  2342. pDeviceInstanceInfo->DataLength
  2343. );
  2344. } else {
  2345. status = STATUS_INVALID_PARAMETER_1;
  2346. goto clean2;
  2347. }
  2348. //
  2349. // Now parse out the refstring, so that we can construct the name of the interface device's
  2350. // alias. (NOTE: we have not yet verified that the alias actually exists, we're only
  2351. // constructing what its name would be, if it did exist.)
  2352. //
  2353. // Don't bother to check the return code. If this were a bad string, we'd have already
  2354. // failed above when we called IopDeviceInterfaceKeysFromSymbolicLink (since it also
  2355. // calls IopParseSymbolicLinkName internally.)
  2356. //
  2357. status = IopParseSymbolicLinkName(SymbolicLinkName,
  2358. NULL,
  2359. NULL,
  2360. NULL,
  2361. &refString,
  2362. &refStringPresent,
  2363. NULL);
  2364. ASSERT(NT_SUCCESS(status));
  2365. //
  2366. // Did the caller supply us with a user-mode or kernel-mode format path?
  2367. //
  2368. userModeFormat = (BOOLEAN)(IopConstStringSize(USER_SYMLINK_STRING_PREFIX) ==
  2369. RtlCompareMemory(SymbolicLinkName->Buffer,
  2370. USER_SYMLINK_STRING_PREFIX,
  2371. IopConstStringSize(USER_SYMLINK_STRING_PREFIX)
  2372. ));
  2373. if(userModeFormat) {
  2374. pUserString = AliasSymbolicLinkName;
  2375. pKernelString = &otherString;
  2376. } else {
  2377. pKernelString = AliasSymbolicLinkName;
  2378. pUserString = &otherString;
  2379. }
  2380. status = IopBuildSymbolicLinkStrings(&deviceInstanceString,
  2381. &guidString,
  2382. refStringPresent ? &refString : NULL,
  2383. pUserString,
  2384. pKernelString
  2385. );
  2386. if (!NT_SUCCESS(status)) {
  2387. goto clean2;
  2388. }
  2389. //
  2390. // OK, we now have the symbolic link name of the alias, but we don't yet know whether
  2391. // it actually exists. Check this by attempting to open the associated registry key.
  2392. //
  2393. status = IopDeviceInterfaceKeysFromSymbolicLink(AliasSymbolicLinkName,
  2394. KEY_READ,
  2395. NULL,
  2396. NULL,
  2397. &hKey
  2398. );
  2399. if(NT_SUCCESS(status)) {
  2400. //
  2401. // Alias exists--close the key handle.
  2402. //
  2403. ZwClose(hKey);
  2404. } else {
  2405. IopFreeAllocatedUnicodeString(AliasSymbolicLinkName);
  2406. }
  2407. IopFreeAllocatedUnicodeString(&otherString);
  2408. clean2:
  2409. ExFreePool(pDeviceInstanceInfo);
  2410. clean1:
  2411. PiUnlockPnpRegistry();
  2412. RtlFreeUnicodeString(&guidString);
  2413. clean0:
  2414. return status;
  2415. }
  2416. NTSTATUS
  2417. IopBuildSymbolicLinkStrings(
  2418. IN PUNICODE_STRING DeviceString,
  2419. IN PUNICODE_STRING GuidString,
  2420. IN PUNICODE_STRING ReferenceString OPTIONAL,
  2421. OUT PUNICODE_STRING UserString,
  2422. OUT PUNICODE_STRING KernelString
  2423. )
  2424. /*++
  2425. Routine Description:
  2426. This routine will construct various strings used in the registration of
  2427. function device class associations (IoRegisterDeviceClassAssociation).
  2428. The specific strings are detailed below
  2429. Parameters:
  2430. DeviceString - Supplies a pointer to the instance path of the device.
  2431. It is of the form <Enumerator>\<Device>\<Instance>.
  2432. GuidString - Supplies a pointer to the string representation of the
  2433. function class guid.
  2434. ReferenceString - Supplies a pointer to the reference string for the given
  2435. device to exhibit the given function. This is optional
  2436. UserString - Supplies a pointer to an uninitialised string which on success
  2437. will contain the string to be assigned to the "SymbolicLink" value under the
  2438. KeyString. It is of the format \\?\<MungedDeviceString>\<GuidString>\<Reference>
  2439. When no longer required it should be freed using IopFreeAllocatedUnicodeString.
  2440. KernelString - Supplies a pointer to an uninitialised string which on success
  2441. will contain the kernel mode path of the device and is of the format
  2442. \??\<MungedDeviceString>\<GuidString>\<Reference>. When no longer required it
  2443. should be freed using IopFreeAllocatedUnicodeString.
  2444. Return Value:
  2445. Status code that indicates whether or not the function was successful.
  2446. --*/
  2447. {
  2448. NTSTATUS status;
  2449. USHORT length;
  2450. UNICODE_STRING mungedDeviceString;
  2451. PAGED_CODE();
  2452. //
  2453. // The code is optimised to use the fact that \\.\ and \??\ are the same size - if
  2454. // these prefixes change then we need to change the code.
  2455. //
  2456. ASSERT(IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX) == IopConstStringSize(USER_SYMLINK_STRING_PREFIX));
  2457. //
  2458. // Calculate the lengths of the strings
  2459. //
  2460. length = IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX) + DeviceString->Length +
  2461. IopConstStringSize(REPLACED_SEPERATOR_STRING) + GuidString->Length;
  2462. if(ARGUMENT_PRESENT(ReferenceString) && (ReferenceString->Length != 0)) {
  2463. length += IopConstStringSize(SEPERATOR_STRING) + ReferenceString->Length;
  2464. }
  2465. //
  2466. // Allocate space for the strings
  2467. //
  2468. status = IopAllocateUnicodeString(KernelString, length);
  2469. if (!NT_SUCCESS(status)) {
  2470. goto clean0;
  2471. }
  2472. status = IopAllocateUnicodeString(UserString, length);
  2473. if (!NT_SUCCESS(status)) {
  2474. goto clean1;
  2475. }
  2476. //
  2477. // Allocate a temporary string to hold the munged device string
  2478. //
  2479. status = IopAllocateUnicodeString(&mungedDeviceString, DeviceString->Length);
  2480. if (!NT_SUCCESS(status)) {
  2481. goto clean2;
  2482. }
  2483. //
  2484. // Copy and munge the device string
  2485. //
  2486. status = IopReplaceSeperatorWithPound(&mungedDeviceString, DeviceString);
  2487. if (!NT_SUCCESS(status)) {
  2488. goto clean3;
  2489. }
  2490. //
  2491. // Construct the user mode string
  2492. //
  2493. RtlAppendUnicodeToString(UserString, USER_SYMLINK_STRING_PREFIX);
  2494. RtlAppendUnicodeStringToString(UserString, &mungedDeviceString);
  2495. RtlAppendUnicodeToString(UserString, REPLACED_SEPERATOR_STRING);
  2496. RtlAppendUnicodeStringToString(UserString, GuidString);
  2497. if (ARGUMENT_PRESENT(ReferenceString) && (ReferenceString->Length != 0)) {
  2498. RtlAppendUnicodeToString(UserString, SEPERATOR_STRING);
  2499. RtlAppendUnicodeStringToString(UserString, ReferenceString);
  2500. }
  2501. ASSERT( UserString->Length == length );
  2502. //
  2503. // Construct the kernel mode string by replacing the prefix on the value string
  2504. //
  2505. RtlCopyUnicodeString(KernelString, UserString);
  2506. RtlCopyMemory(KernelString->Buffer,
  2507. KERNEL_SYMLINK_STRING_PREFIX,
  2508. IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX)
  2509. );
  2510. clean3:
  2511. IopFreeAllocatedUnicodeString(&mungedDeviceString);
  2512. clean2:
  2513. if (!NT_SUCCESS(status)) {
  2514. IopFreeAllocatedUnicodeString(UserString);
  2515. }
  2516. clean1:
  2517. if (!NT_SUCCESS(status)) {
  2518. IopFreeAllocatedUnicodeString(KernelString);
  2519. }
  2520. clean0:
  2521. return status;
  2522. }
  2523. NTSTATUS
  2524. IopReplaceSeperatorWithPound(
  2525. OUT PUNICODE_STRING OutString,
  2526. IN PUNICODE_STRING InString
  2527. )
  2528. /*++
  2529. Routine Description:
  2530. This routine will copy a string from InString to OutString replacing any occurence of
  2531. '\' or '/' with '#' as it goes.
  2532. Parameters:
  2533. OutString - Supplies a pointer to a string which has already been initialised to
  2534. have a buffer large enough to accomodate the string. The contents of this
  2535. string will be over written
  2536. InString - Supplies a pointer to the string to be munged
  2537. Return Value:
  2538. Status code that indicates whether or not the function was successful.
  2539. Remarks:
  2540. In place munging can be performed - ie. the In and Out strings can be the same.
  2541. --*/
  2542. {
  2543. PWSTR pInPosition, pOutPosition;
  2544. USHORT count;
  2545. PAGED_CODE();
  2546. ASSERT(InString);
  2547. ASSERT(OutString);
  2548. //
  2549. // Ensure we have enough space in the output string
  2550. //
  2551. if(InString->Length > OutString->MaximumLength) {
  2552. return STATUS_BUFFER_TOO_SMALL;
  2553. }
  2554. pInPosition = InString->Buffer;
  2555. pOutPosition = OutString->Buffer;
  2556. count = InString->Length / sizeof(WCHAR);
  2557. //
  2558. // Traverse the in string copying and replacing all occurences of '\' or '/'
  2559. // with '#'
  2560. //
  2561. while (count--) {
  2562. if((*pInPosition == SEPERATOR_CHAR) || (*pInPosition == ALT_SEPERATOR_CHAR)) {
  2563. *pOutPosition = REPLACED_SEPERATOR_CHAR;
  2564. } else {
  2565. *pOutPosition = *pInPosition;
  2566. }
  2567. pInPosition++;
  2568. pOutPosition++;
  2569. }
  2570. OutString->Length = InString->Length;
  2571. return STATUS_SUCCESS;
  2572. }
  2573. NTSTATUS
  2574. IopDropReferenceString(
  2575. OUT PUNICODE_STRING OutString,
  2576. IN PUNICODE_STRING InString
  2577. )
  2578. /*++
  2579. Routine Description:
  2580. This routine removes the reference string from a symbolic link name. No space
  2581. is allocated for the out string so no attempt should be made to free the buffer
  2582. of OutString.
  2583. Parameters:
  2584. SymbolicLinkName - Supplies a pointer to a symbolic link name string.
  2585. Both the prefixed strings are valid.
  2586. GuidReferenceString - Supplies a pointer to an uninitialised string which on
  2587. success will contain the symbolic link name without the reference string.
  2588. See the note on storage allocation above.
  2589. Return Value:
  2590. Status code that indicates whether or not the function was successful.
  2591. Remarks:
  2592. The string returned in OutString is dependant on the buffer of
  2593. InString and is only valid as long as InString is valid.
  2594. --*/
  2595. {
  2596. UNICODE_STRING refString;
  2597. NTSTATUS status;
  2598. BOOLEAN refStringPresent;
  2599. PAGED_CODE();
  2600. ASSERT(InString);
  2601. ASSERT(OutString);
  2602. //
  2603. // Parse the SymbolicLinkName for the refstring component (if there is one).
  2604. // Note that this is also a way of verifying that the string is valid.
  2605. //
  2606. status = IopParseSymbolicLinkName(InString,
  2607. NULL,
  2608. NULL,
  2609. NULL,
  2610. &refString,
  2611. &refStringPresent,
  2612. NULL);
  2613. if (NT_SUCCESS(status)) {
  2614. //
  2615. // The refstring is always at the end, so just use the same buffer and
  2616. // set the length of the output string accordingly.
  2617. //
  2618. OutString->Buffer = InString->Buffer;
  2619. //
  2620. // If we have a refstring then subtract it's length
  2621. //
  2622. if (refStringPresent) {
  2623. OutString->Length = InString->Length - (refString.Length + sizeof(WCHAR));
  2624. } else {
  2625. OutString->Length = InString->Length;
  2626. }
  2627. } else {
  2628. //
  2629. // Invalidate the returned string
  2630. //
  2631. OutString->Buffer = NULL;
  2632. OutString->Length = 0;
  2633. }
  2634. OutString->MaximumLength = OutString->Length;
  2635. return status;
  2636. }
  2637. NTSTATUS
  2638. IopBuildGlobalSymbolicLinkString(
  2639. IN PUNICODE_STRING SymbolicLinkName,
  2640. OUT PUNICODE_STRING GlobalString
  2641. )
  2642. /*++
  2643. Routine Description:
  2644. This routine will construct the global symbolic link name for the given
  2645. kernel-mode or user-mode relative symbolic link name.
  2646. Parameters:
  2647. SymbolicLinkName - Supplies a pointer to a symbolic link name string.
  2648. Both the kernel-mode and user-mode prefixed strings are valid.
  2649. GlobalString - Supplies a pointer to an uninitialised string which on
  2650. success will contain the string that represents the symbolic link
  2651. withing the global namespace. It is of the format
  2652. \GLOBAL??\<MungedDeviceString>\<GuidString>\<Reference>. When no longer
  2653. required it should be freed using IopFreeAllocatedUnicodeString.
  2654. Return Value:
  2655. Status code that indicates whether or not the function was successful.
  2656. --*/
  2657. {
  2658. NTSTATUS status;
  2659. USHORT length;
  2660. UNICODE_STRING tempString;
  2661. PAGED_CODE();
  2662. //
  2663. // The code is optimised to use the fact that \\.\ and \??\ are the same
  2664. // size, and that since we are replacing the prefix, the routine can take
  2665. // either one. If these prefixes change then we need to change the code.
  2666. //
  2667. ASSERT(IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX) == IopConstStringSize(USER_SYMLINK_STRING_PREFIX));
  2668. //
  2669. // Make sure the supplied SymbolicLinkName string begins with either the
  2670. // kernel or user symbolic link prefix. If it does not have a \\?\ or \??\
  2671. // prefix then fail.
  2672. //
  2673. if ((RtlCompareMemory(SymbolicLinkName->Buffer,
  2674. USER_SYMLINK_STRING_PREFIX,
  2675. IopConstStringSize(USER_SYMLINK_STRING_PREFIX))
  2676. != IopConstStringSize(USER_SYMLINK_STRING_PREFIX)) &&
  2677. (RtlCompareMemory(SymbolicLinkName->Buffer,
  2678. KERNEL_SYMLINK_STRING_PREFIX,
  2679. IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX))
  2680. != IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX))) {
  2681. status = STATUS_INVALID_PARAMETER;
  2682. goto clean0;
  2683. }
  2684. //
  2685. // Compute the length of the global symbolic link string.
  2686. //
  2687. length = SymbolicLinkName->Length - IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX) +
  2688. IopConstStringSize(GLOBAL_SYMLINK_STRING_PREFIX);
  2689. //
  2690. // Allocate space for the strings.
  2691. //
  2692. status = IopAllocateUnicodeString(GlobalString, length);
  2693. if (!NT_SUCCESS(status)) {
  2694. goto clean0;
  2695. }
  2696. //
  2697. // Copy the \GLOBAL?? symbolic link name prefix to the string.
  2698. //
  2699. status = RtlAppendUnicodeToString(GlobalString,
  2700. GLOBAL_SYMLINK_STRING_PREFIX);
  2701. ASSERT(NT_SUCCESS(status));
  2702. if (!NT_SUCCESS(status)) {
  2703. IopFreeAllocatedUnicodeString(GlobalString);
  2704. goto clean0;
  2705. }
  2706. //
  2707. // Append the part of the SymbolicLinkName that follows the prefix.
  2708. //
  2709. tempString.Buffer = SymbolicLinkName->Buffer +
  2710. IopConstStringLength(KERNEL_SYMLINK_STRING_PREFIX);
  2711. tempString.Length = SymbolicLinkName->Length -
  2712. IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX);
  2713. tempString.MaximumLength = SymbolicLinkName->MaximumLength -
  2714. IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX);
  2715. status = RtlAppendUnicodeStringToString(GlobalString, &tempString);
  2716. ASSERT(NT_SUCCESS(status));
  2717. if (!NT_SUCCESS(status)) {
  2718. IopFreeAllocatedUnicodeString(GlobalString);
  2719. goto clean0;
  2720. }
  2721. ASSERT(GlobalString->Length == length);
  2722. clean0:
  2723. return status;
  2724. }
  2725. NTSTATUS
  2726. IopParseSymbolicLinkName(
  2727. IN PUNICODE_STRING SymbolicLinkName,
  2728. OUT PUNICODE_STRING PrefixString OPTIONAL,
  2729. OUT PUNICODE_STRING MungedPathString OPTIONAL,
  2730. OUT PUNICODE_STRING GuidString OPTIONAL,
  2731. OUT PUNICODE_STRING RefString OPTIONAL,
  2732. OUT PBOOLEAN RefStringPresent OPTIONAL,
  2733. OUT LPGUID Guid OPTIONAL
  2734. )
  2735. /*++
  2736. Routine Description:
  2737. This routine breaks apart a symbolic link name constructed by
  2738. IopBuildSymbolicLinkNames. Both formats of name are valid - user
  2739. mode \\?\ and kernel mode \??\.
  2740. Parameters:
  2741. SymbolicLinkName - Supplies a pointer to the symbolic link name to
  2742. be analysed.
  2743. PrefixString - Optionally contains a pointer to a string which will contain
  2744. the prefix of the string.
  2745. MungedPathString - Optionally contains a pointer to a string which will contain
  2746. the enumeration path of the device with all occurences of '\' replaced with '#'.
  2747. GuidString - Optionally contains a pointer to a string which will contain
  2748. the device class guid in string format from the string.
  2749. RefString - Optionally contains a pointer to a string which will contain
  2750. the refstring of the string if one is present, otherwise it is undefined.
  2751. RefStringPresent - Optionally contains a pointer to a boolean value which will
  2752. be set to true if a refstring is present.
  2753. Guid - Optionally contains a pointer to a guid which will contain
  2754. the function class guid of the string.
  2755. Return Value:
  2756. Status code that indicates whether or not the function was successful.
  2757. --*/
  2758. {
  2759. NTSTATUS status = STATUS_SUCCESS;
  2760. PWSTR pCurrent;
  2761. USHORT current, path, guid, reference = 0;
  2762. UNICODE_STRING tempString;
  2763. GUID tempGuid;
  2764. BOOLEAN haveRefString;
  2765. PAGED_CODE();
  2766. //
  2767. // Make sure we have a SymbolicLinkName to parse.
  2768. //
  2769. if ((!ARGUMENT_PRESENT(SymbolicLinkName)) ||
  2770. (SymbolicLinkName->Buffer == NULL) ||
  2771. (SymbolicLinkName->Length == 0)) {
  2772. status = STATUS_INVALID_PARAMETER;
  2773. goto clean0;
  2774. }
  2775. //
  2776. // check that the input buffer really is big enough
  2777. //
  2778. ASSERT(IopConstStringSize(USER_SYMLINK_STRING_PREFIX) == IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX));
  2779. if (SymbolicLinkName->Length < (IopConstStringLength(KERNEL_SYMLINK_STRING_PREFIX)+GUID_STRING_SIZE+1)) {
  2780. status = STATUS_INVALID_PARAMETER;
  2781. goto clean0;
  2782. }
  2783. //
  2784. // Sanity check on the incoming string - if it does not have a \\?\ or \??\ prefix then fail
  2785. //
  2786. if ((RtlCompareMemory(SymbolicLinkName->Buffer,
  2787. USER_SYMLINK_STRING_PREFIX,
  2788. IopConstStringSize(USER_SYMLINK_STRING_PREFIX))
  2789. != IopConstStringSize(USER_SYMLINK_STRING_PREFIX)) &&
  2790. (RtlCompareMemory(SymbolicLinkName->Buffer,
  2791. KERNEL_SYMLINK_STRING_PREFIX,
  2792. IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX))
  2793. != IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX))) {
  2794. status = STATUS_INVALID_PARAMETER;
  2795. goto clean0;
  2796. }
  2797. //
  2798. // Break apart the string into it's constituent parts
  2799. //
  2800. path = IopConstStringSize(USER_SYMLINK_STRING_PREFIX) + 1;
  2801. //
  2802. // Find the '\' seperator
  2803. //
  2804. pCurrent = SymbolicLinkName->Buffer + IopConstStringLength(KERNEL_SYMLINK_STRING_PREFIX);
  2805. for (current = 0;
  2806. current < (SymbolicLinkName->Length / sizeof(WCHAR)) - IopConstStringLength(KERNEL_SYMLINK_STRING_PREFIX);
  2807. current++, pCurrent++) {
  2808. if(*pCurrent == SEPERATOR_CHAR) {
  2809. reference = current + 1 + IopConstStringLength(KERNEL_SYMLINK_STRING_PREFIX);
  2810. break;
  2811. }
  2812. }
  2813. //
  2814. // If we don't have a reference string fake it to where it would have been
  2815. //
  2816. if (reference == 0) {
  2817. haveRefString = FALSE;
  2818. reference = SymbolicLinkName->Length / sizeof(WCHAR) + 1;
  2819. } else {
  2820. haveRefString = TRUE;
  2821. }
  2822. //
  2823. // Check the guid looks plausable
  2824. //
  2825. tempString.Length = GUID_STRING_SIZE;
  2826. tempString.MaximumLength = GUID_STRING_SIZE;
  2827. tempString.Buffer = SymbolicLinkName->Buffer + reference - GUID_STRING_LENGTH - 1;
  2828. if (!NT_SUCCESS( RtlGUIDFromString(&tempString, &tempGuid) )) {
  2829. status = STATUS_INVALID_PARAMETER;
  2830. goto clean0;
  2831. }
  2832. guid = reference - GUID_STRING_LENGTH - 1;
  2833. //
  2834. // Setup return strings
  2835. //
  2836. if (ARGUMENT_PRESENT(PrefixString)) {
  2837. PrefixString->Length = IopConstStringSize(KERNEL_SYMLINK_STRING_PREFIX);
  2838. PrefixString->MaximumLength = PrefixString->Length;
  2839. PrefixString->Buffer = SymbolicLinkName->Buffer;
  2840. }
  2841. if (ARGUMENT_PRESENT(MungedPathString)) {
  2842. MungedPathString->Length = (reference - 1 - GUID_STRING_LENGTH - 1 -
  2843. IopConstStringLength(KERNEL_SYMLINK_STRING_PREFIX)) *
  2844. sizeof(WCHAR);
  2845. MungedPathString->MaximumLength = MungedPathString->Length;
  2846. MungedPathString->Buffer = SymbolicLinkName->Buffer +
  2847. IopConstStringLength(KERNEL_SYMLINK_STRING_PREFIX);
  2848. }
  2849. if (ARGUMENT_PRESENT(GuidString)) {
  2850. GuidString->Length = GUID_STRING_SIZE;
  2851. GuidString->MaximumLength = GuidString->Length;
  2852. GuidString->Buffer = SymbolicLinkName->Buffer + reference -
  2853. GUID_STRING_LENGTH - 1;
  2854. }
  2855. if (ARGUMENT_PRESENT(RefString)) {
  2856. //
  2857. // Check if we have a refstring
  2858. //
  2859. if (haveRefString) {
  2860. RefString->Length = SymbolicLinkName->Length -
  2861. (reference * sizeof(WCHAR));
  2862. RefString->MaximumLength = RefString->Length;
  2863. RefString->Buffer = SymbolicLinkName->Buffer + reference;
  2864. } else {
  2865. RefString->Length = 0;
  2866. RefString->MaximumLength = 0;
  2867. RefString->Buffer = NULL;
  2868. }
  2869. }
  2870. if (ARGUMENT_PRESENT(RefStringPresent)) {
  2871. *RefStringPresent = haveRefString;
  2872. }
  2873. if(ARGUMENT_PRESENT(Guid)) {
  2874. *Guid = tempGuid;
  2875. }
  2876. clean0:
  2877. return status;
  2878. }
  2879. NTSTATUS
  2880. IopDoDeferredSetInterfaceState(
  2881. IN PDEVICE_NODE DeviceNode
  2882. )
  2883. /*++
  2884. Routine Description:
  2885. Process the queued IoSetDeviceInterfaceState calls.
  2886. Parameters:
  2887. DeviceNode - Device node which has just been started.
  2888. Return Value:
  2889. Status code that indicates whether or not the function was successful.
  2890. --*/
  2891. {
  2892. KIRQL irql;
  2893. PDEVICE_OBJECT attachedDevice;
  2894. PiLockPnpRegistry(TRUE);
  2895. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  2896. for (attachedDevice = DeviceNode->PhysicalDeviceObject;
  2897. attachedDevice;
  2898. attachedDevice = attachedDevice->AttachedDevice) {
  2899. attachedDevice->DeviceObjectExtension->ExtensionFlags &= ~DOE_START_PENDING;
  2900. }
  2901. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  2902. while (!IsListEmpty(&DeviceNode->PendedSetInterfaceState)) {
  2903. PPENDING_SET_INTERFACE_STATE entry;
  2904. entry = (PPENDING_SET_INTERFACE_STATE)RemoveHeadList(&DeviceNode->PendedSetInterfaceState);
  2905. IopProcessSetInterfaceState(&entry->LinkName, TRUE, FALSE);
  2906. ExFreePool(entry->LinkName.Buffer);
  2907. ExFreePool(entry);
  2908. }
  2909. PiUnlockPnpRegistry();
  2910. return STATUS_SUCCESS;
  2911. }
  2912. NTSTATUS
  2913. IopProcessSetInterfaceState(
  2914. IN PUNICODE_STRING SymbolicLinkName,
  2915. IN BOOLEAN Enable,
  2916. IN BOOLEAN DeferNotStarted
  2917. )
  2918. /*++
  2919. Routine Description:
  2920. This DDI allows a device class to activate and deactivate an association
  2921. previously registered using IoRegisterDeviceInterface
  2922. Parameters:
  2923. SymbolicLinkName - Supplies a pointer to the symbolic link name which was
  2924. returned by IoRegisterDeviceInterface when the interface was registered,
  2925. or as returned by IoGetDeviceInterfaces.
  2926. Enable - If TRUE (non-zero), the interface will be enabled. If FALSE, it
  2927. will be disabled.
  2928. DeferNotStarted - If TRUE then enables will be queued if the PDO isn't
  2929. started. It is FALSE when we've started the PDO and are processing the
  2930. queued enables.
  2931. Return Value:
  2932. Status code that indicates whether or not the function was successful.
  2933. --*/
  2934. {
  2935. NTSTATUS status;
  2936. HANDLE hInterfaceClassKey = NULL;
  2937. HANDLE hInterfaceParentKey= NULL, hInterfaceInstanceKey = NULL;
  2938. HANDLE hInterfaceParentControl = NULL, hInterfaceInstanceControl = NULL;
  2939. UNICODE_STRING tempString, deviceNameString;
  2940. UNICODE_STRING actualSymbolicLinkName, globalSymbolicLinkName;
  2941. PKEY_VALUE_FULL_INFORMATION pKeyValueInfo;
  2942. ULONG linked, refcount;
  2943. GUID guid;
  2944. PDEVICE_OBJECT physicalDeviceObject;
  2945. PWCHAR deviceNameBuffer = NULL;
  2946. ULONG deviceNameBufferLength;
  2947. PAGED_CODE();
  2948. //
  2949. // Check that the supplied symbolic link can be parsed to extract the device
  2950. // class guid - note that this is also a way of verifying that the
  2951. // SymbolicLinkName string is valid.
  2952. //
  2953. status = IopParseSymbolicLinkName(SymbolicLinkName,
  2954. NULL,
  2955. NULL,
  2956. NULL,
  2957. NULL,
  2958. NULL,
  2959. &guid);
  2960. if (!NT_SUCCESS(status)) {
  2961. goto clean0;
  2962. }
  2963. //
  2964. // Get the symbolic link name without the ref string.
  2965. //
  2966. status = IopDropReferenceString(&actualSymbolicLinkName, SymbolicLinkName);
  2967. if (!NT_SUCCESS(status)) {
  2968. goto clean0;
  2969. }
  2970. //
  2971. // Symbolic links created for device interfaces should be visible to all
  2972. // users, in all sessions, so we need to contruct an absolute name for
  2973. // symbolic link in the global DosDevices namespace '\GLOBAL??'. This
  2974. // ensures that a global symbolic link will always be created or deleted by
  2975. // IoSetDeviceInterfaceState, no matter what context it is called in.
  2976. //
  2977. status = IopBuildGlobalSymbolicLinkString(&actualSymbolicLinkName,
  2978. &globalSymbolicLinkName);
  2979. if (!NT_SUCCESS(status)) {
  2980. goto clean0;
  2981. }
  2982. //
  2983. // Get function class instance handle
  2984. //
  2985. status = IopDeviceInterfaceKeysFromSymbolicLink(SymbolicLinkName,
  2986. KEY_READ | KEY_WRITE,
  2987. &hInterfaceClassKey,
  2988. &hInterfaceParentKey,
  2989. &hInterfaceInstanceKey
  2990. );
  2991. if (!NT_SUCCESS(status)) {
  2992. goto clean1;
  2993. }
  2994. //
  2995. // Open the parent interface control subkey
  2996. //
  2997. PiWstrToUnicodeString(&tempString, REGSTR_KEY_CONTROL);
  2998. status = IopCreateRegistryKeyEx( &hInterfaceParentControl,
  2999. hInterfaceParentKey,
  3000. &tempString,
  3001. KEY_READ,
  3002. REG_OPTION_VOLATILE,
  3003. NULL
  3004. );
  3005. if (!NT_SUCCESS(status)) {
  3006. goto clean1;
  3007. }
  3008. //
  3009. // Find out the name of the device instance that 'owns' this interface.
  3010. //
  3011. status = IopGetRegistryValue(hInterfaceParentKey,
  3012. REGSTR_VAL_DEVICE_INSTANCE,
  3013. &pKeyValueInfo
  3014. );
  3015. if(NT_SUCCESS(status)) {
  3016. //
  3017. // Open the device instance control subkey
  3018. //
  3019. PiWstrToUnicodeString(&tempString, REGSTR_KEY_CONTROL);
  3020. status = IopCreateRegistryKeyEx( &hInterfaceInstanceControl,
  3021. hInterfaceInstanceKey,
  3022. &tempString,
  3023. KEY_READ,
  3024. REG_OPTION_VOLATILE,
  3025. NULL
  3026. );
  3027. if(!NT_SUCCESS(status)) {
  3028. ExFreePool(pKeyValueInfo);
  3029. hInterfaceInstanceControl = NULL;
  3030. }
  3031. }
  3032. if (!NT_SUCCESS(status)) {
  3033. goto clean2;
  3034. }
  3035. //
  3036. // Find the PDO corresponding to this device instance name.
  3037. //
  3038. if (pKeyValueInfo->Type == REG_SZ) {
  3039. IopRegistryDataToUnicodeString(&tempString,
  3040. (PWSTR)KEY_VALUE_DATA(pKeyValueInfo),
  3041. pKeyValueInfo->DataLength
  3042. );
  3043. physicalDeviceObject = IopDeviceObjectFromDeviceInstance(&tempString);
  3044. if (physicalDeviceObject) {
  3045. //
  3046. // DeferNotStarted is set TRUE if we are being called from
  3047. // IoSetDeviceInterfaceState. It will be set FALSE if we are
  3048. // processing previously queued operations as we are starting the
  3049. // device.
  3050. //
  3051. if (DeferNotStarted) {
  3052. if (physicalDeviceObject->DeviceObjectExtension->ExtensionFlags & DOE_START_PENDING) {
  3053. PDEVICE_NODE deviceNode;
  3054. PPENDING_SET_INTERFACE_STATE pendingSetState;
  3055. //
  3056. // The device hasn't been started yet. We need to queue
  3057. // any enables and remove items from the queue on a disable.
  3058. //
  3059. deviceNode = (PDEVICE_NODE)physicalDeviceObject->DeviceObjectExtension->DeviceNode;
  3060. if (Enable) {
  3061. pendingSetState = ExAllocatePool( PagedPool,
  3062. sizeof(PENDING_SET_INTERFACE_STATE));
  3063. if (pendingSetState != NULL) {
  3064. pendingSetState->LinkName.Buffer = ExAllocatePool( PagedPool,
  3065. SymbolicLinkName->Length);
  3066. if (pendingSetState->LinkName.Buffer != NULL) {
  3067. //
  3068. // Capture the callers info and queue it to the
  3069. // devnode. Once the device stack is started
  3070. // we will dequeue and process it.
  3071. //
  3072. pendingSetState->LinkName.MaximumLength = SymbolicLinkName->Length;
  3073. pendingSetState->LinkName.Length = SymbolicLinkName->Length;
  3074. RtlCopyMemory( pendingSetState->LinkName.Buffer,
  3075. SymbolicLinkName->Buffer,
  3076. SymbolicLinkName->Length);
  3077. InsertTailList( &deviceNode->PendedSetInterfaceState,
  3078. &pendingSetState->List);
  3079. ExFreePool(pKeyValueInfo);
  3080. ObDereferenceObject(physicalDeviceObject);
  3081. status = STATUS_SUCCESS;
  3082. goto clean2;
  3083. } else {
  3084. //
  3085. // Couldn't allocate a buffer to hold the
  3086. // symbolic link name.
  3087. //
  3088. ExFreePool(pendingSetState);
  3089. status = STATUS_INSUFFICIENT_RESOURCES;
  3090. }
  3091. } else {
  3092. //
  3093. // Couldn't allocate the PENDING_SET_INTERFACE_STATE
  3094. // structure.
  3095. //
  3096. status = STATUS_INSUFFICIENT_RESOURCES;
  3097. }
  3098. } else {
  3099. PLIST_ENTRY entry;
  3100. //
  3101. // We are disabling an interface. Since we aren't
  3102. // started yet we should have queued the enable. Now
  3103. // we go back and find the matching enable and remove
  3104. // it from the queue.
  3105. //
  3106. for (entry = deviceNode->PendedSetInterfaceState.Flink;
  3107. entry != &deviceNode->PendedSetInterfaceState;
  3108. entry = entry->Flink) {
  3109. pendingSetState = CONTAINING_RECORD( entry,
  3110. PENDING_SET_INTERFACE_STATE,
  3111. List );
  3112. if (RtlEqualUnicodeString( &pendingSetState->LinkName,
  3113. SymbolicLinkName,
  3114. TRUE)) {
  3115. //
  3116. // We found it, remove it from the list and
  3117. // free it.
  3118. //
  3119. RemoveEntryList(&pendingSetState->List);
  3120. ExFreePool(pendingSetState->LinkName.Buffer);
  3121. ExFreePool(pendingSetState);
  3122. break;
  3123. }
  3124. }
  3125. #if 0
  3126. //
  3127. // Debug code to catch the case where we couldn't find
  3128. // the entry to remove. This could happen if we messed
  3129. // up adding the entry to the list or the driver disabled
  3130. // an interface without first enabling it. Either way
  3131. // it probably merits some investigation.
  3132. //
  3133. if (entry == &deviceNode->PendedSetInterfaceState) {
  3134. IopDbgPrint((IOP_ERROR_LEVEL,
  3135. "IopProcessSetInterfaceState: Disable couldn't find deferred enable, DeviceNode = 0x%p, SymbolicLink = \"%Z\"\n",
  3136. deviceNode,
  3137. SymbolicLinkName));
  3138. }
  3139. ASSERT(entry != &deviceNode->PendedSetInterfaceState);
  3140. #endif
  3141. ExFreePool(pKeyValueInfo);
  3142. ObDereferenceObject(physicalDeviceObject);
  3143. status = STATUS_SUCCESS;
  3144. goto clean2;
  3145. }
  3146. }
  3147. }
  3148. if (!Enable || !NT_SUCCESS(status)) {
  3149. ObDereferenceObject(physicalDeviceObject);
  3150. }
  3151. } else {
  3152. status = STATUS_INVALID_DEVICE_REQUEST;
  3153. }
  3154. } else {
  3155. //
  3156. // This will only happen if the registry information is messed up.
  3157. //
  3158. physicalDeviceObject = NULL;
  3159. status = STATUS_INVALID_DEVICE_REQUEST;
  3160. }
  3161. if (!Enable) {
  3162. //
  3163. // In the case of Disable we want to continue even if there was an error
  3164. // finding the PDO. Prior to adding support for deferring the
  3165. // IoSetDeviceInterfaceState calls, we never looked up the PDO for
  3166. // disables. This will make sure that we continue to behave the same as
  3167. // we used to in the case where we can't find the PDO.
  3168. //
  3169. status = STATUS_SUCCESS;
  3170. }
  3171. ExFreePool(pKeyValueInfo);
  3172. if (!NT_SUCCESS(status)) {
  3173. goto clean2;
  3174. }
  3175. if (Enable) {
  3176. //
  3177. // Retrieve the PDO's device object name. (Start out with a reasonably-sized
  3178. // buffer so we hopefully only have to retrieve this once.
  3179. //
  3180. deviceNameBufferLength = 256 * sizeof(WCHAR);
  3181. for ( ; ; ) {
  3182. deviceNameBuffer = ExAllocatePool(PagedPool, deviceNameBufferLength);
  3183. if (!deviceNameBuffer) {
  3184. status = STATUS_INSUFFICIENT_RESOURCES;
  3185. break;
  3186. }
  3187. status = IoGetDeviceProperty( physicalDeviceObject,
  3188. DevicePropertyPhysicalDeviceObjectName,
  3189. deviceNameBufferLength,
  3190. deviceNameBuffer,
  3191. &deviceNameBufferLength
  3192. );
  3193. if (NT_SUCCESS(status)) {
  3194. break;
  3195. } else {
  3196. //
  3197. // Free the current buffer before we figure out what went wrong.
  3198. //
  3199. ExFreePool(deviceNameBuffer);
  3200. if (status != STATUS_BUFFER_TOO_SMALL) {
  3201. //
  3202. // Our failure wasn't because the buffer was too small--bail now.
  3203. //
  3204. break;
  3205. }
  3206. //
  3207. // Otherwise, loop back and try again with our new buffer size.
  3208. //
  3209. }
  3210. }
  3211. //
  3212. // OK, we don't need the PDO anymore.
  3213. //
  3214. ObDereferenceObject(physicalDeviceObject);
  3215. if (!NT_SUCCESS(status) || deviceNameBufferLength == 0) {
  3216. goto clean2;
  3217. }
  3218. //
  3219. // Now create a unicode string based on the device object name we just retrieved.
  3220. //
  3221. RtlInitUnicodeString(&deviceNameString, deviceNameBuffer);
  3222. }
  3223. //
  3224. // Retrieve the linked value from the control subkey.
  3225. //
  3226. pKeyValueInfo=NULL;
  3227. status = IopGetRegistryValue(hInterfaceInstanceControl, REGSTR_VAL_LINKED, &pKeyValueInfo);
  3228. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  3229. //
  3230. // The absence of a linked value is taken to mean not linked
  3231. //
  3232. linked = 0;
  3233. } else {
  3234. if (!NT_SUCCESS(status)) {
  3235. //
  3236. // If the call failed, pKeyValueInfo was never allocated
  3237. //
  3238. goto clean3;
  3239. }
  3240. //
  3241. // Check linked is a DWORD
  3242. //
  3243. if(pKeyValueInfo->Type == REG_DWORD && pKeyValueInfo->DataLength == sizeof(ULONG)) {
  3244. linked = *((PULONG) KEY_VALUE_DATA(pKeyValueInfo));
  3245. } else {
  3246. //
  3247. // The registry is messed up - assume linked is 0 and the registry will be fixed when
  3248. // we update linked in a few moments
  3249. //
  3250. linked = 0;
  3251. }
  3252. }
  3253. if (pKeyValueInfo) {
  3254. ExFreePool (pKeyValueInfo);
  3255. }
  3256. //
  3257. // Retrieve the refcount value from the control subkey.
  3258. //
  3259. PiWstrToUnicodeString(&tempString, REGSTR_VAL_REFERENCECOUNT);
  3260. status = IopGetRegistryValue(hInterfaceParentControl,
  3261. tempString.Buffer,
  3262. &pKeyValueInfo
  3263. );
  3264. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  3265. //
  3266. // The absence of a refcount value is taken to mean refcount == 0
  3267. //
  3268. refcount = 0;
  3269. } else {
  3270. if (!NT_SUCCESS(status)) {
  3271. goto clean3;
  3272. }
  3273. //
  3274. // Check refcount is a DWORD
  3275. //
  3276. if(pKeyValueInfo->Type == REG_DWORD && pKeyValueInfo->DataLength == sizeof(ULONG)) {
  3277. refcount = *((PULONG) KEY_VALUE_DATA(pKeyValueInfo));
  3278. } else {
  3279. //
  3280. // The registry is messed up - assume refcount is 0 and the registry will be fixed when
  3281. // we update refcount in a few moments
  3282. //
  3283. refcount = 0;
  3284. }
  3285. ExFreePool(pKeyValueInfo);
  3286. }
  3287. if (Enable) {
  3288. if (!linked) {
  3289. //
  3290. // check and update the reference count
  3291. //
  3292. if (refcount > 0) {
  3293. //
  3294. // Another device instance has already referenced this interface;
  3295. // just increment the reference count; don't try create a symbolic link.
  3296. //
  3297. refcount += 1;
  3298. } else {
  3299. //
  3300. // According to the reference count, no other device instances currently
  3301. // reference this interface, and therefore no symbolic links should exist,
  3302. // so we should create one.
  3303. //
  3304. refcount = 1;
  3305. status = IoCreateSymbolicLink(&globalSymbolicLinkName, &deviceNameString);
  3306. if (status == STATUS_OBJECT_NAME_COLLISION) {
  3307. //
  3308. // The reference count is messed up.
  3309. //
  3310. IopDbgPrint(( IOP_ERROR_LEVEL,
  3311. "IoSetDeviceInterfaceState: symbolic link for %ws already exists! status = %8.8X\n",
  3312. globalSymbolicLinkName.Buffer, status));
  3313. status = STATUS_SUCCESS;
  3314. }
  3315. }
  3316. linked = 1;
  3317. #if 0
  3318. IopSetupDeviceObjectFromDeviceClass(physicalDeviceObject,
  3319. hInterfaceClassKey);
  3320. #endif
  3321. } else {
  3322. //
  3323. // The association already exists - don't perform the notification
  3324. //
  3325. status = STATUS_OBJECT_NAME_EXISTS; // Informational message not error
  3326. goto clean3;
  3327. }
  3328. } else {
  3329. if (linked) {
  3330. //
  3331. // check and update the reference count
  3332. //
  3333. if (refcount > 1) {
  3334. //
  3335. // Another device instance already references this interface;
  3336. // just decrement the reference count; don't try to remove the symbolic link.
  3337. //
  3338. refcount -= 1;
  3339. } else {
  3340. //
  3341. // According to the reference count, only this device instance currently
  3342. // references this interface, so it is ok to delete this symbolic link
  3343. //
  3344. refcount = 0;
  3345. status = IoDeleteSymbolicLink(&globalSymbolicLinkName);
  3346. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  3347. //
  3348. // The reference count is messed up.
  3349. //
  3350. IopDbgPrint(( IOP_ERROR_LEVEL,
  3351. "IoSetDeviceInterfaceState: no symbolic link for %ws to delete! status = %8.8X\n",
  3352. globalSymbolicLinkName.Buffer, status));
  3353. status = STATUS_SUCCESS;
  3354. }
  3355. }
  3356. linked = 0;
  3357. } else {
  3358. //
  3359. // The association does not exists - fail and do not perform notification
  3360. //
  3361. status = STATUS_OBJECT_NAME_NOT_FOUND;
  3362. }
  3363. }
  3364. if (!NT_SUCCESS(status)) {
  3365. goto clean3;
  3366. }
  3367. //
  3368. // Update the value of linked
  3369. //
  3370. PiWstrToUnicodeString(&tempString, REGSTR_VAL_LINKED);
  3371. status = ZwSetValueKey(hInterfaceInstanceControl,
  3372. &tempString,
  3373. 0,
  3374. REG_DWORD,
  3375. &linked,
  3376. sizeof(linked)
  3377. );
  3378. //
  3379. // Update the value of refcount
  3380. //
  3381. PiWstrToUnicodeString(&tempString, REGSTR_VAL_REFERENCECOUNT);
  3382. status = ZwSetValueKey(hInterfaceParentControl,
  3383. &tempString,
  3384. 0,
  3385. REG_DWORD,
  3386. &refcount,
  3387. sizeof(refcount)
  3388. );
  3389. //
  3390. // Notify anyone that is interested
  3391. //
  3392. if (linked) {
  3393. PpSetDeviceClassChange( (LPGUID) &GUID_DEVICE_INTERFACE_ARRIVAL, &guid, SymbolicLinkName);
  3394. } else {
  3395. PpSetDeviceClassChange( (LPGUID) &GUID_DEVICE_INTERFACE_REMOVAL, &guid, SymbolicLinkName);
  3396. }
  3397. clean3:
  3398. if (deviceNameBuffer != NULL) {
  3399. ExFreePool(deviceNameBuffer);
  3400. }
  3401. clean2:
  3402. if (hInterfaceParentControl) {
  3403. ZwClose(hInterfaceParentControl);
  3404. }
  3405. if (hInterfaceInstanceControl) {
  3406. ZwClose(hInterfaceInstanceControl);
  3407. }
  3408. clean1:
  3409. IopFreeAllocatedUnicodeString(&globalSymbolicLinkName);
  3410. if (hInterfaceParentKey) {
  3411. ZwClose(hInterfaceParentKey);
  3412. }
  3413. if (hInterfaceInstanceKey) {
  3414. ZwClose(hInterfaceInstanceKey);
  3415. }
  3416. if(hInterfaceClassKey != NULL) {
  3417. ZwClose(hInterfaceClassKey);
  3418. }
  3419. clean0:
  3420. if (!NT_SUCCESS(status) && !Enable) {
  3421. //
  3422. // If we failed to disable an interface (most likely because the
  3423. // interface keys have already been deleted) report success.
  3424. //
  3425. status = STATUS_SUCCESS;
  3426. }
  3427. return status;
  3428. }
  3429. NTSTATUS
  3430. IopSetRegistryStringValue(
  3431. IN HANDLE KeyHandle,
  3432. IN PUNICODE_STRING ValueName,
  3433. IN PUNICODE_STRING ValueData
  3434. )
  3435. /*++
  3436. Routine Description:
  3437. Sets a value key in the registry to a specific value of string (REG_SZ) type.
  3438. Parameters:
  3439. KeyHandle - A handle to the key under which the value is stored.
  3440. ValueName - Supplies a pointer to the name of the value key
  3441. ValueData - Supplies a pointer to the string to be stored in the key. The data
  3442. will automatically be null terminated for storage in the registry.
  3443. Return Value:
  3444. Status code that indicates whether or not the function was successful.
  3445. --*/
  3446. {
  3447. NTSTATUS status;
  3448. PAGED_CODE();
  3449. ASSERT(ValueName);
  3450. ASSERT(ValueData);
  3451. ASSERT(ValueName->Buffer);
  3452. ASSERT(ValueData->Buffer);
  3453. //
  3454. // Null terminate the string
  3455. //
  3456. if ((ValueData->MaximumLength - ValueData->Length) >= sizeof(UNICODE_NULL)) {
  3457. //
  3458. // There is room in the buffer so just append a null
  3459. //
  3460. ValueData->Buffer[(ValueData->Length / sizeof(WCHAR))] = UNICODE_NULL;
  3461. //
  3462. // Set the registry value
  3463. //
  3464. status = ZwSetValueKey(KeyHandle,
  3465. ValueName,
  3466. 0,
  3467. REG_SZ,
  3468. (PVOID) ValueData->Buffer,
  3469. ValueData->Length + sizeof(UNICODE_NULL)
  3470. );
  3471. } else {
  3472. UNICODE_STRING tempString;
  3473. //
  3474. // There is no room so allocate a new buffer and so we need to build
  3475. // a new string with room
  3476. //
  3477. status = IopAllocateUnicodeString(&tempString, ValueData->Length);
  3478. if (!NT_SUCCESS(status)) {
  3479. goto clean0;
  3480. }
  3481. //
  3482. // Copy the input string to the output string
  3483. //
  3484. tempString.Length = ValueData->Length;
  3485. RtlCopyMemory(tempString.Buffer, ValueData->Buffer, ValueData->Length);
  3486. //
  3487. // Add the null termination
  3488. //
  3489. tempString.Buffer[tempString.Length / sizeof(WCHAR)] = UNICODE_NULL;
  3490. //
  3491. // Set the registry value
  3492. //
  3493. status = ZwSetValueKey(KeyHandle,
  3494. ValueName,
  3495. 0,
  3496. REG_SZ,
  3497. (PVOID) tempString.Buffer,
  3498. tempString.Length + sizeof(UNICODE_NULL)
  3499. );
  3500. //
  3501. // Free the temporary string
  3502. //
  3503. IopFreeAllocatedUnicodeString(&tempString);
  3504. }
  3505. clean0:
  3506. return status;
  3507. }
  3508. NTSTATUS
  3509. IopAllocateUnicodeString(
  3510. IN OUT PUNICODE_STRING String,
  3511. IN USHORT Length
  3512. )
  3513. /*++
  3514. Routine Description:
  3515. This routine allocates a buffer for a unicode string of a given length
  3516. and initialises the UNICODE_STRING structure appropriately. When the
  3517. string is no longer required it can be freed using IopFreeAllocatedString.
  3518. The buffer also be directly deleted by ExFreePool and so can be handed
  3519. back to a caller.
  3520. Parameters:
  3521. String - Supplies a pointer to an uninitialised unicode string which will
  3522. be manipulated by the function.
  3523. Length - The number of BYTES long that the string will be.
  3524. Return Value:
  3525. Either STATUS_INSUFFICIENT_RESOURCES indicating paged pool is exhausted or
  3526. STATUS_SUCCESS.
  3527. Remarks:
  3528. The buffer allocated will be one character (2 bytes) more than length specified.
  3529. This is to allow for easy null termination of the strings - eg for registry
  3530. storage.
  3531. --*/
  3532. {
  3533. PAGED_CODE();
  3534. String->Length = 0;
  3535. String->MaximumLength = Length + sizeof(UNICODE_NULL);
  3536. String->Buffer = ExAllocatePool(PagedPool, Length + sizeof(UNICODE_NULL));
  3537. if (String->Buffer == NULL) {
  3538. return STATUS_INSUFFICIENT_RESOURCES;
  3539. } else {
  3540. return STATUS_SUCCESS;
  3541. }
  3542. }
  3543. VOID
  3544. IopFreeAllocatedUnicodeString(
  3545. PUNICODE_STRING String
  3546. )
  3547. /*++
  3548. Routine Description:
  3549. This routine frees a string previously allocated with IopAllocateUnicodeString.
  3550. Parameters:
  3551. String - Supplies a pointer to the string that has been previously allocated.
  3552. Return Value:
  3553. None
  3554. --*/
  3555. {
  3556. PAGED_CODE();
  3557. ASSERT(String);
  3558. RtlFreeUnicodeString(String);
  3559. }