Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4414 lines
137 KiB

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