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

907 lines
24 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 1985-2000 Microsoft Corporation
  4. //
  5. // This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  6. // You should have received a copy of the Microsoft End-User License Agreement
  7. // for this software along with this release; see the file "license.txt".
  8. // If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  9. // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  10. //
  11. // Abstract:
  12. //
  13. // This source file contains the routines to access the NT Registry for
  14. // configuration info.
  15. //
  16. #include <oscfg.h>
  17. #include <ndis.h>
  18. #include <ip6imp.h>
  19. #include "ip6def.h"
  20. #include <ntddip6.h>
  21. #include <string.h>
  22. #include <wchar.h>
  23. #include "ntreg.h"
  24. #define WORK_BUFFER_SIZE 512
  25. #ifdef ALLOC_PRAGMA
  26. //
  27. // This code is pagable.
  28. //
  29. #pragma alloc_text(PAGE, GetRegDWORDValue)
  30. #pragma alloc_text(PAGE, SetRegDWORDValue)
  31. #pragma alloc_text(PAGE, InitRegDWORDParameter)
  32. #pragma alloc_text(PAGE, OpenRegKey)
  33. #if 0
  34. #pragma alloc_text(PAGE, GetRegStringValue)
  35. #pragma alloc_text(PAGE, GetRegSZValue)
  36. #pragma alloc_text(PAGE, GetRegMultiSZValue)
  37. #endif
  38. #endif // ALLOC_PRAGMA
  39. WCHAR Tcpip6Parameters[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\" TCPIPV6_NAME L"\\Parameters";
  40. //* OpenRegKey
  41. //
  42. // Opens a Registry key and returns a handle to it.
  43. //
  44. // Returns (plus other failure codes):
  45. // STATUS_OBJECT_NAME_NOT_FOUND
  46. // STATUS_SUCCESS
  47. //
  48. NTSTATUS
  49. OpenRegKey(
  50. PHANDLE HandlePtr, // Where to write the opened handle.
  51. HANDLE Parent,
  52. const WCHAR *KeyName, // Name of Registry key to open.
  53. OpenRegKeyAction Action)
  54. {
  55. NTSTATUS Status;
  56. OBJECT_ATTRIBUTES ObjectAttributes;
  57. UNICODE_STRING UKeyName;
  58. PAGED_CODE();
  59. RtlInitUnicodeString(&UKeyName, KeyName);
  60. memset(&ObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  61. InitializeObjectAttributes(&ObjectAttributes, &UKeyName,
  62. OBJ_CASE_INSENSITIVE, Parent, NULL);
  63. switch (Action) {
  64. case OpenRegKeyRead:
  65. Status = ZwOpenKey(HandlePtr, KEY_READ, &ObjectAttributes);
  66. break;
  67. case OpenRegKeyCreate:
  68. Status = ZwCreateKey(HandlePtr, KEY_WRITE, &ObjectAttributes,
  69. 0, // TitleIndex
  70. NULL, // Class
  71. REG_OPTION_NON_VOLATILE,
  72. NULL); // Disposition
  73. break;
  74. case OpenRegKeyDeleting:
  75. Status = ZwOpenKey(HandlePtr, KEY_ALL_ACCESS, &ObjectAttributes);
  76. break;
  77. }
  78. return Status;
  79. }
  80. //* RegDeleteValue
  81. //
  82. // Deletes a value from the key.
  83. //
  84. NTSTATUS
  85. RegDeleteValue(
  86. HANDLE KeyHandle,
  87. const WCHAR *ValueName)
  88. {
  89. NTSTATUS status;
  90. UNICODE_STRING UValueName;
  91. PAGED_CODE();
  92. RtlInitUnicodeString(&UValueName, ValueName);
  93. status = ZwDeleteValueKey(KeyHandle, &UValueName);
  94. return status;
  95. }
  96. //* GetRegDWORDValue
  97. //
  98. // Reads a REG_DWORD value from the registry into the supplied variable.
  99. //
  100. NTSTATUS // Returns: STATUS_SUCCESS or an appropriate failure code.
  101. GetRegDWORDValue(
  102. HANDLE KeyHandle, // Open handle to the parent key of the value to read.
  103. const WCHAR *ValueName, // Name of the value to read.
  104. PULONG ValueData) // Variable into which to read the data.
  105. {
  106. NTSTATUS status;
  107. ULONG resultLength;
  108. PKEY_VALUE_FULL_INFORMATION keyValueFullInformation;
  109. UCHAR keybuf[WORK_BUFFER_SIZE];
  110. UNICODE_STRING UValueName;
  111. PAGED_CODE();
  112. RtlInitUnicodeString(&UValueName, ValueName);
  113. keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)keybuf;
  114. RtlZeroMemory(keyValueFullInformation, sizeof(keyValueFullInformation));
  115. status = ZwQueryValueKey(KeyHandle, &UValueName, KeyValueFullInformation,
  116. keyValueFullInformation, WORK_BUFFER_SIZE,
  117. &resultLength);
  118. if (NT_SUCCESS(status)) {
  119. if (keyValueFullInformation->Type != REG_DWORD) {
  120. status = STATUS_INVALID_PARAMETER_MIX;
  121. } else {
  122. *ValueData = *((ULONG UNALIGNED *)
  123. ((PCHAR)keyValueFullInformation +
  124. keyValueFullInformation->DataOffset));
  125. }
  126. }
  127. return status;
  128. }
  129. //* SetRegDWORDValue
  130. //
  131. // Writes the contents of a variable to a REG_DWORD value.
  132. //
  133. NTSTATUS // Returns: STATUS_SUCCESS or an appropriate failure code.
  134. SetRegDWORDValue(
  135. HANDLE KeyHandle, // Open handle to the parent key of the value to write.
  136. const WCHAR *ValueName, // Name of the value to write.
  137. ULONG ValueData) // Variable from which to write the data.
  138. {
  139. NTSTATUS status;
  140. UNICODE_STRING UValueName;
  141. PAGED_CODE();
  142. RtlInitUnicodeString(&UValueName, ValueName);
  143. status = ZwSetValueKey(KeyHandle, &UValueName, 0, REG_DWORD,
  144. &ValueData, sizeof ValueData);
  145. return status;
  146. }
  147. //* SetRegQUADValue
  148. //
  149. // Writes the contents of a variable to a REG_BINARY value.
  150. //
  151. NTSTATUS // Returns: STATUS_SUCCESS or an appropriate failure code.
  152. SetRegQUADValue(
  153. HANDLE KeyHandle, // Open handle to the parent key of the value to write.
  154. const WCHAR *ValueName, // Name of the value to write.
  155. const LARGE_INTEGER *ValueData) // Variable from which to write the data.
  156. {
  157. NTSTATUS status;
  158. UNICODE_STRING UValueName;
  159. PAGED_CODE();
  160. RtlInitUnicodeString(&UValueName, ValueName);
  161. status = ZwSetValueKey(KeyHandle, &UValueName, 0, REG_BINARY,
  162. (void *)ValueData, sizeof *ValueData);
  163. return status;
  164. }
  165. //* GetRegIPAddrValue
  166. //
  167. // Reads a REG_SZ value from the registry into the supplied variable.
  168. //
  169. NTSTATUS // Returns: STATUS_SUCCESS or an appropriate failure code.
  170. GetRegIPAddrValue(
  171. HANDLE KeyHandle, // Open handle to the parent key of the value to read.
  172. const WCHAR *ValueName, // Name of the value to read.
  173. IPAddr *Addr) // Variable into which to read the data.
  174. {
  175. NTSTATUS status;
  176. ULONG resultLength;
  177. PKEY_VALUE_PARTIAL_INFORMATION info;
  178. UCHAR keybuf[WORK_BUFFER_SIZE];
  179. UNICODE_STRING UValueName;
  180. WCHAR *string;
  181. PAGED_CODE();
  182. RtlInitUnicodeString(&UValueName, ValueName);
  183. info = (PKEY_VALUE_PARTIAL_INFORMATION)keybuf;
  184. status = ZwQueryValueKey(KeyHandle, &UValueName,
  185. KeyValuePartialInformation,
  186. info, WORK_BUFFER_SIZE,
  187. &resultLength);
  188. if (! NT_SUCCESS(status))
  189. return status;
  190. if (info->Type != REG_SZ)
  191. return STATUS_INVALID_PARAMETER_MIX;
  192. string = (WCHAR *)info->Data;
  193. if ((info->DataLength < sizeof(WCHAR)) ||
  194. (string[(info->DataLength/sizeof(WCHAR)) - 1] != UNICODE_NULL))
  195. return STATUS_INVALID_PARAMETER_MIX;
  196. if (! ParseV4Address(string, &string, Addr) ||
  197. (*string != UNICODE_NULL))
  198. return STATUS_INVALID_PARAMETER;
  199. return STATUS_SUCCESS;
  200. }
  201. //* SetRegIPAddrValue
  202. //
  203. // Writes the contents of a variable to a REG_SZ value.
  204. //
  205. NTSTATUS // Returns: STATUS_SUCCESS or an appropriate failure code.
  206. SetRegIPAddrValue(
  207. HANDLE KeyHandle, // Open handle to the parent key of the value to write.
  208. const WCHAR *ValueName, // Name of the value to write.
  209. IPAddr Addr) // Variable from which to write the data.
  210. {
  211. NTSTATUS status;
  212. UNICODE_STRING UValueName;
  213. char AddrStr[16];
  214. WCHAR ValueData[16];
  215. uint len;
  216. PAGED_CODE();
  217. RtlInitUnicodeString(&UValueName, ValueName);
  218. FormatV4AddressWorker(AddrStr, Addr);
  219. for (len = 0;; len++) {
  220. if ((ValueData[len] = (WCHAR)AddrStr[len]) == UNICODE_NULL)
  221. break;
  222. }
  223. status = ZwSetValueKey(KeyHandle, &UValueName, 0, REG_SZ,
  224. ValueData, (len + 1) * sizeof(WCHAR));
  225. return status;
  226. }
  227. #if 0
  228. //* GetRegStringValue
  229. //
  230. // Reads a REG_*_SZ string value from the Registry into the supplied
  231. // key value buffer. If the buffer string buffer is not large enough,
  232. // it is reallocated.
  233. //
  234. NTSTATUS // Returns: STATUS_SUCCESS or an appropriate failure code.
  235. GetRegStringValue(
  236. HANDLE KeyHandle, // Open handle to the parent key of the value to read.
  237. const WCHAR *ValueName, // Name of the value to read.
  238. PKEY_VALUE_PARTIAL_INFORMATION *ValueData, // Destination of read data.
  239. PUSHORT ValueSize) // Size of the ValueData buffer. Updated on output.
  240. {
  241. NTSTATUS status;
  242. ULONG resultLength;
  243. UNICODE_STRING UValueName;
  244. PAGED_CODE();
  245. RtlInitUnicodeString(&UValueName, ValueName);
  246. status = ZwQueryValueKey(KeyHandle, &UValueName,
  247. KeyValuePartialInformation, *ValueData,
  248. (ULONG) *ValueSize, &resultLength);
  249. if ((status == STATUS_BUFFER_OVERFLOW) ||
  250. (status == STATUS_BUFFER_TOO_SMALL)) {
  251. PVOID temp;
  252. //
  253. // Free the old buffer and allocate a new one of the
  254. // appropriate size.
  255. //
  256. ASSERT(resultLength > (ULONG) *ValueSize);
  257. if (resultLength <= 0xFFFF) {
  258. temp = ExAllocatePool(NonPagedPool, resultLength);
  259. if (temp != NULL) {
  260. if (*ValueData != NULL) {
  261. ExFreePool(*ValueData);
  262. }
  263. *ValueData = temp;
  264. *ValueSize = (USHORT) resultLength;
  265. status = ZwQueryValueKey(KeyHandle, &UValueName,
  266. KeyValuePartialInformation,
  267. *ValueData, *ValueSize,
  268. &resultLength);
  269. ASSERT((status != STATUS_BUFFER_OVERFLOW) &&
  270. (status != STATUS_BUFFER_TOO_SMALL));
  271. } else {
  272. status = STATUS_INSUFFICIENT_RESOURCES;
  273. }
  274. } else {
  275. status = STATUS_BUFFER_TOO_SMALL;
  276. }
  277. }
  278. return status;
  279. }
  280. #endif // 0
  281. #if 0
  282. //* GetRegMultiSZValue
  283. //
  284. // Reads a REG_MULTI_SZ string value from the Registry into the supplied
  285. // Unicode string. If the Unicode string buffer is not large enough,
  286. // it is reallocated.
  287. //
  288. NTSTATUS // Returns: STATUS_SUCCESS or an appropriate failure code.
  289. GetRegMultiSZValue(
  290. HANDLE KeyHandle, // Open handle to parent key of value to read.
  291. const WCHAR *ValueName, // Name of value to read.
  292. PUNICODE_STRING ValueData) // Destination string for the value data.
  293. {
  294. NTSTATUS status;
  295. ULONG resultLength;
  296. PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
  297. UNICODE_STRING UValueName;
  298. PAGED_CODE();
  299. ValueData->Length = 0;
  300. status = GetRegStringValue(KeyHandle, ValueName,
  301. (PKEY_VALUE_PARTIAL_INFORMATION *)
  302. &(ValueData->Buffer),
  303. &(ValueData->MaximumLength));
  304. if (NT_SUCCESS(status)) {
  305. keyValuePartialInformation =
  306. (PKEY_VALUE_PARTIAL_INFORMATION) ValueData->Buffer;
  307. if (keyValuePartialInformation->Type == REG_MULTI_SZ) {
  308. ValueData->Length = (USHORT)
  309. keyValuePartialInformation->DataLength;
  310. RtlCopyMemory(ValueData->Buffer,
  311. &(keyValuePartialInformation->Data),
  312. ValueData->Length);
  313. } else {
  314. status = STATUS_INVALID_PARAMETER_MIX;
  315. }
  316. }
  317. return status;
  318. } // GetRegMultiSZValue
  319. #endif // 0
  320. #if 0
  321. //* GetRegSZValue
  322. //
  323. // Reads a REG_SZ string value from the Registry into the supplied
  324. // Unicode string. If the Unicode string buffer is not large enough,
  325. // it is reallocated.
  326. //
  327. NTSTATUS // Returns: STATUS_SUCCESS or an appropriate failure code.
  328. GetRegSZValue(
  329. HANDLE KeyHandle, // Open handle to the parent key of the value to read.
  330. const WCHAR *ValueName, // Name of the value to read.
  331. PUNICODE_STRING ValueData, // Destination string for the value data.
  332. PULONG ValueType) // On return, contains Registry type of value read.
  333. {
  334. NTSTATUS status;
  335. ULONG resultLength;
  336. PKEY_VALUE_PARTIAL_INFORMATION keyValuePartialInformation;
  337. UNICODE_STRING UValueName;
  338. PAGED_CODE();
  339. ValueData->Length = 0;
  340. status = GetRegStringValue(KeyHandle, ValueName,
  341. (PKEY_VALUE_PARTIAL_INFORMATION *)
  342. &(ValueData->Buffer),
  343. &(ValueData->MaximumLength));
  344. if (NT_SUCCESS(status)) {
  345. keyValuePartialInformation =
  346. (PKEY_VALUE_PARTIAL_INFORMATION)ValueData->Buffer;
  347. if ((keyValuePartialInformation->Type == REG_SZ) ||
  348. (keyValuePartialInformation->Type == REG_EXPAND_SZ)) {
  349. WCHAR *src;
  350. WCHAR *dst;
  351. ULONG dataLength;
  352. *ValueType = keyValuePartialInformation->Type;
  353. dataLength = keyValuePartialInformation->DataLength;
  354. ASSERT(dataLength <= ValueData->MaximumLength);
  355. dst = ValueData->Buffer;
  356. src = (PWCHAR) &(keyValuePartialInformation->Data);
  357. while (ValueData->Length <= dataLength) {
  358. if ((*dst++ = *src++) == UNICODE_NULL) {
  359. break;
  360. }
  361. ValueData->Length += sizeof(WCHAR);
  362. }
  363. if (ValueData->Length < (ValueData->MaximumLength - 1)) {
  364. ValueData->Buffer[ValueData->Length/sizeof(WCHAR)] =
  365. UNICODE_NULL;
  366. }
  367. } else {
  368. status = STATUS_INVALID_PARAMETER_MIX;
  369. }
  370. }
  371. return status;
  372. }
  373. #endif // 0
  374. //* InitRegDWORDParameter
  375. //
  376. // Reads a REG_DWORD parameter from the Registry into a variable. If the
  377. // read fails, the variable is initialized to a default.
  378. //
  379. VOID
  380. InitRegDWORDParameter(
  381. HANDLE RegKey, // Open handle to the parent key of the value to read.
  382. const WCHAR *ValueName, // The name of the value to read.
  383. UINT *Value, // Destination variable into which to read the data.
  384. UINT DefaultValue) // Default to assign if the read fails.
  385. {
  386. PAGED_CODE();
  387. if ((RegKey == NULL) ||
  388. !NT_SUCCESS(GetRegDWORDValue(RegKey, ValueName, Value))) {
  389. //
  390. // These registry parameters override the defaults, so their
  391. // absence is not an error.
  392. //
  393. *Value = DefaultValue;
  394. }
  395. }
  396. //* InitRegQUADParameter
  397. //
  398. // Reads a REG_BINARY value from the registry into the supplied variable.
  399. //
  400. // Upon failure, the variable is left untouched.
  401. //
  402. VOID
  403. InitRegQUADParameter(
  404. HANDLE RegKey, // Open handle to the parent key of the value to read.
  405. const WCHAR *ValueName, // Name of the value to read.
  406. LARGE_INTEGER *Value) // Variable into which to read the data.
  407. {
  408. NTSTATUS status;
  409. ULONG resultLength;
  410. UCHAR keybuf[WORK_BUFFER_SIZE];
  411. PKEY_VALUE_PARTIAL_INFORMATION value =
  412. (PKEY_VALUE_PARTIAL_INFORMATION) keybuf;
  413. UNICODE_STRING UValueName;
  414. PAGED_CODE();
  415. if (RegKey == NULL)
  416. return;
  417. RtlInitUnicodeString(&UValueName, ValueName);
  418. status = ZwQueryValueKey(RegKey, &UValueName,
  419. KeyValuePartialInformation,
  420. value, WORK_BUFFER_SIZE,
  421. &resultLength);
  422. if (NT_SUCCESS(status) &&
  423. (value->Type == REG_BINARY) &&
  424. (value->DataLength == sizeof *Value)) {
  425. RtlCopyMemory(Value, value->Data, sizeof *Value);
  426. }
  427. }
  428. #if 0
  429. //* EnumRegMultiSz
  430. //
  431. // Parses a REG_MULTI_SZ string and returns the specified substring.
  432. //
  433. // Note: This code is called at raised IRQL. It is not pageable.
  434. //
  435. const WCHAR *
  436. EnumRegMultiSz(
  437. IN const WCHAR *MszString, // Pointer to the REG_MULTI_SZ string.
  438. IN ULONG MszStringLength, // Length of above, including terminating null.
  439. IN ULONG StringIndex) // Index number of substring to return.
  440. {
  441. const WCHAR *string = MszString;
  442. if (MszStringLength < (2 * sizeof(WCHAR))) {
  443. return NULL;
  444. }
  445. //
  446. // Find the start of the desired string.
  447. //
  448. while (StringIndex) {
  449. while (MszStringLength >= sizeof(WCHAR)) {
  450. MszStringLength -= sizeof(WCHAR);
  451. if (*string++ == UNICODE_NULL) {
  452. break;
  453. }
  454. }
  455. //
  456. // Check for index out of range.
  457. //
  458. if (MszStringLength < (2 * sizeof(UNICODE_NULL))) {
  459. return NULL;
  460. }
  461. StringIndex--;
  462. }
  463. if (MszStringLength < (2 * sizeof(UNICODE_NULL))) {
  464. return NULL;
  465. }
  466. return string;
  467. }
  468. #endif // 0
  469. //* OpenTopLevelRegKey
  470. //
  471. // Given the name of a top-level registry key (under Parameters),
  472. // opens the registry key.
  473. //
  474. // Callable from thread context, not DPC context.
  475. //
  476. NTSTATUS
  477. OpenTopLevelRegKey(const WCHAR *Name,
  478. OUT HANDLE *RegKey, OpenRegKeyAction Action)
  479. {
  480. HANDLE ParametersKey;
  481. NTSTATUS Status;
  482. PAGED_CODE();
  483. Status = OpenRegKey(&ParametersKey, NULL, Tcpip6Parameters,
  484. OpenRegKeyRead);
  485. if (! NT_SUCCESS(Status))
  486. return Status;
  487. Status = OpenRegKey(RegKey, ParametersKey, Name, Action);
  488. ZwClose(ParametersKey);
  489. return Status;
  490. }
  491. //* DeleteTopLevelRegKey
  492. //
  493. // Given the name of a top-level registry key (under Parameters),
  494. // deletes the registry key and all subkeys and values.
  495. //
  496. // Callable from thread context, not DPC context.
  497. //
  498. NTSTATUS
  499. DeleteTopLevelRegKey(const WCHAR *Name)
  500. {
  501. HANDLE RegKey;
  502. NTSTATUS Status;
  503. Status = OpenTopLevelRegKey(Name, &RegKey, OpenRegKeyDeleting);
  504. if (! NT_SUCCESS(Status)) {
  505. //
  506. // If the registry key does not exist, that's OK.
  507. //
  508. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  509. Status = STATUS_SUCCESS;
  510. }
  511. else {
  512. //
  513. // DeleteRegKey always closes the key.
  514. //
  515. Status = DeleteRegKey(RegKey);
  516. }
  517. return Status;
  518. }
  519. //* EnumRegKeyIndex
  520. //
  521. // Enumerates the specified subkey of the registry key.
  522. // Calls the callback function on the subkey.
  523. //
  524. // Callable from thread context, not DPC context.
  525. //
  526. NTSTATUS
  527. EnumRegKeyIndex(
  528. HANDLE RegKey,
  529. uint Index,
  530. EnumRegKeysCallback Callback,
  531. void *Context)
  532. {
  533. KEY_BASIC_INFORMATION *Info;
  534. uint InfoLength;
  535. uint ResultLength;
  536. NTSTATUS Status;
  537. PAGED_CODE();
  538. #if DBG
  539. //
  540. // Start with no buffer, to exercise the retry code.
  541. //
  542. Info = NULL;
  543. InfoLength = 0;
  544. #else
  545. //
  546. // Start with a decent-sized buffer.
  547. //
  548. ResultLength = WORK_BUFFER_SIZE;
  549. goto AllocBuffer;
  550. #endif
  551. //
  552. // Get basic information about the subkey.
  553. //
  554. for (;;) {
  555. //
  556. // The documentation for ZwEnumerateKey says
  557. // that it returns STATUS_BUFFER_TOO_SMALL
  558. // to indicate that the buffer is too small
  559. // but it can also return STATUS_BUFFER_OVERFLOW.
  560. //
  561. Status = ZwEnumerateKey(RegKey, Index, KeyBasicInformation,
  562. Info, InfoLength, &ResultLength);
  563. if (NT_SUCCESS(Status)) {
  564. break;
  565. }
  566. else if ((Status == STATUS_BUFFER_TOO_SMALL) ||
  567. (Status == STATUS_BUFFER_OVERFLOW)) {
  568. //
  569. // We need a larger buffer.
  570. // Leave space for a null character at the end.
  571. //
  572. #if DBG
  573. if (Info != NULL)
  574. ExFreePool(Info);
  575. #else
  576. ExFreePool(Info);
  577. AllocBuffer:
  578. #endif
  579. Info = ExAllocatePool(PagedPool, ResultLength+sizeof(WCHAR));
  580. if (Info == NULL) {
  581. Status = STATUS_INSUFFICIENT_RESOURCES;
  582. goto ErrorReturn;
  583. }
  584. InfoLength = ResultLength;
  585. }
  586. else
  587. goto ErrorReturn;
  588. }
  589. //
  590. // Null-terminate the name and call the callback function.
  591. //
  592. Info->Name[Info->NameLength/sizeof(WCHAR)] = UNICODE_NULL;
  593. Status = (*Callback)(Context, RegKey, Info->Name);
  594. ErrorReturn:
  595. if (Info != NULL)
  596. ExFreePool(Info);
  597. return Status;
  598. }
  599. //* EnumRegKeys
  600. //
  601. // Enumerate the subkeys of the specified registry key.
  602. // Calls the callback function for each subkey.
  603. //
  604. // Callable from thread context, not DPC context.
  605. //
  606. NTSTATUS
  607. EnumRegKeys(
  608. HANDLE RegKey,
  609. EnumRegKeysCallback Callback,
  610. void *Context)
  611. {
  612. uint Index;
  613. NTSTATUS Status;
  614. PAGED_CODE();
  615. for (Index = 0;; Index++) {
  616. Status = EnumRegKeyIndex(RegKey, Index, Callback, Context);
  617. if (! NT_SUCCESS(Status)) {
  618. if (Status == STATUS_NO_MORE_ENTRIES)
  619. Status = STATUS_SUCCESS;
  620. break;
  621. }
  622. }
  623. return Status;
  624. }
  625. #define MAX_DELETE_REGKEY_ATTEMPTS 10
  626. typedef struct DeleteRegKeyContext {
  627. struct DeleteRegKeyContext *Next;
  628. HANDLE RegKey;
  629. uint Attempts;
  630. } DeleteRegKeyContext;
  631. //* DeleteRegKeyCallback
  632. //
  633. // Opens a subkey of the parent and pushes a new record onto the list.
  634. //
  635. NTSTATUS
  636. DeleteRegKeyCallback(
  637. void *Context,
  638. HANDLE ParentKey,
  639. WCHAR *SubKeyName)
  640. {
  641. DeleteRegKeyContext **pList = (DeleteRegKeyContext **) Context;
  642. DeleteRegKeyContext *Record;
  643. HANDLE SubKey;
  644. NTSTATUS Status;
  645. PAGED_CODE();
  646. Status = OpenRegKey(&SubKey, ParentKey, SubKeyName, OpenRegKeyDeleting);
  647. if (! NT_SUCCESS(Status))
  648. return Status;
  649. Record = ExAllocatePool(PagedPool, sizeof *Record);
  650. if (Record == NULL) {
  651. ZwClose(SubKey);
  652. return STATUS_INSUFFICIENT_RESOURCES;
  653. }
  654. Record->RegKey = SubKey;
  655. Record->Attempts = 0;
  656. Record->Next = *pList;
  657. *pList = Record;
  658. return STATUS_SUCCESS;
  659. }
  660. //* DeleteRegKey
  661. //
  662. // Deletes a registry key and all subkeys.
  663. //
  664. // Uses depth-first iterative traversal instead of recursion,
  665. // to avoid blowing out the kernel stack.
  666. //
  667. // Always closes the supplied registry key, even upon failure.
  668. //
  669. // Callable from thread context, not DPC context.
  670. //
  671. NTSTATUS
  672. DeleteRegKey(HANDLE RegKey)
  673. {
  674. DeleteRegKeyContext *List;
  675. DeleteRegKeyContext *This;
  676. NTSTATUS Status;
  677. PAGED_CODE();
  678. //
  679. // Start the iteration by creating a record for the parent key.
  680. //
  681. List = ExAllocatePool(PagedPool, sizeof *List);
  682. if (List == NULL) {
  683. ZwClose(RegKey);
  684. Status = STATUS_INSUFFICIENT_RESOURCES;
  685. goto ErrorReturn;
  686. }
  687. List->Next = NULL;
  688. List->RegKey = RegKey;
  689. List->Attempts = 0;
  690. while ((This = List) != NULL) {
  691. //
  692. // Try to delete the key at the front of the list.
  693. //
  694. This->Attempts++;
  695. Status = ZwDeleteKey(This->RegKey);
  696. if (NT_SUCCESS(Status)) {
  697. //
  698. // Remove the key from the list and repeat.
  699. //
  700. List = This->Next;
  701. ZwClose(This->RegKey);
  702. ExFreePool(This);
  703. continue;
  704. }
  705. //
  706. // If the deletion failed for some reason
  707. // other than the presence of subkeys, stop now.
  708. //
  709. if (Status != STATUS_CANNOT_DELETE)
  710. goto ErrorReturn;
  711. //
  712. // Limit the number of attempts to delete a key,
  713. // to avoid an infinite loop. However we do want
  714. // to try more than once, in case there is concurrent
  715. // activity.
  716. //
  717. if (This->Attempts >= MAX_DELETE_REGKEY_ATTEMPTS)
  718. goto ErrorReturn;
  719. //
  720. // Enumerate the child keys, pushing them on the list
  721. // in front of the parent key.
  722. //
  723. Status = EnumRegKeys(This->RegKey, DeleteRegKeyCallback, &List);
  724. if (! NT_SUCCESS(Status))
  725. goto ErrorReturn;
  726. //
  727. // After the child keys are deleted, we will try again
  728. // to delete the parent key.
  729. //
  730. }
  731. return STATUS_SUCCESS;
  732. ErrorReturn:
  733. //
  734. // Cleanup remaining records.
  735. //
  736. while ((This = List) != NULL) {
  737. List = This->Next;
  738. ZwClose(This->RegKey);
  739. ExFreePool(This);
  740. }
  741. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  742. "DeleteRegKey(%p) failed %x\n", RegKey, Status));
  743. return Status;
  744. }