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.

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