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.

2624 lines
65 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. registry.c
  5. Abstract:
  6. Domain Name System (DNS) API
  7. Registry management routines.
  8. Author:
  9. Jim Gilroy (jamesg) March, 2000
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. #include "registry.h"
  14. //
  15. // Globals
  16. //
  17. // DWORD globals blob
  18. //
  19. // g_IsRegReady protects needs init and protects (requires)
  20. // global init.
  21. //
  22. // See registry.h for discussion of how these globals are
  23. // exposed both internal to the DLL and external.
  24. //
  25. DNS_GLOBALS_BLOB DnsGlobals;
  26. BOOL g_IsRegReady = FALSE;
  27. PWSTR g_pwsRemoteResolver = NULL;
  28. //
  29. // Property table
  30. //
  31. //
  32. // WARNING: table must be in sync with DNS_REGID definitions
  33. //
  34. // For simplicity I did not provide a separate index field and
  35. // a lookup function (or alternatively a function that returned
  36. // all the properties or a property pointer).
  37. //
  38. // The DNS_REGID values ARE the INDEXES!
  39. // Hence the table MUST be in sync or the whole deal blows up
  40. // If you make a change to either -- you must change the other!
  41. //
  42. REG_PROPERTY RegPropertyTable[] =
  43. {
  44. // Basic
  45. HOST_NAME ,
  46. 0 , // Default FALSE
  47. 0 , // No policy
  48. 1 , // Client
  49. 1 , // TcpIp
  50. 0 , // No Cache
  51. DOMAIN_NAME ,
  52. 0 , // Default FALSE
  53. 1 , // Policy
  54. 0 , // No Client
  55. 1 , // TcpIp
  56. 0 , // No Cache
  57. DHCP_DOMAIN_NAME ,
  58. 0 , // Default FALSE
  59. 1 , // Policy
  60. 0 , // No Client
  61. 1 , // TcpIp
  62. 0 , // No Cache
  63. ADAPTER_DOMAIN_NAME ,
  64. 0 , // Default FALSE
  65. 1 , // Policy
  66. 1 , // Client
  67. 0 , // No TcpIp
  68. 0 , // No Cache
  69. PRIMARY_DOMAIN_NAME ,
  70. 0 , // Default FALSE
  71. 1 , // Policy
  72. 1 , // Client
  73. 0 , // No TcpIp
  74. 0 , // No Cache
  75. PRIMARY_SUFFIX ,
  76. 0 , // Default FALSE
  77. 1 , // Policy
  78. 1 , // Client
  79. 1 , // TcpIp
  80. 0 , // No Cache
  81. ALTERNATE_NAMES ,
  82. 0 , // Default NULL
  83. 0 , // No Policy
  84. 0 , // No Client
  85. 0 , // No TcpIp
  86. 1 , // Cache
  87. DNS_SERVERS ,
  88. 0 , // Default FALSE
  89. 1 , // Policy
  90. 0 , // Client
  91. 0 , // TcpIp
  92. 0 , // No Cache
  93. SEARCH_LIST_KEY ,
  94. 0 , // Default FALSE
  95. 1 , // Policy
  96. 1 , // Client
  97. 1 , // TcpIp
  98. 0 , // No Cache
  99. UPDATE_ZONE_EXCLUSIONS ,
  100. 0 , // Default
  101. 1 , // Policy
  102. 1 , // Client
  103. 0 , // No TcpIp
  104. 0 , // No Cache
  105. // Query
  106. QUERY_ADAPTER_NAME ,
  107. 1 , // Default TRUE
  108. 1 , // Policy
  109. 1 , // Client
  110. 0 , // No TcpIp
  111. 1 , // Cache
  112. USE_DOMAIN_NAME_DEVOLUTION ,
  113. 1 , // Default TRUE
  114. 1 , // Policy
  115. 1 , // Client
  116. 1 , // TcpIp
  117. 1 , // Cache
  118. PRIORITIZE_RECORD_DATA ,
  119. 1 , // Default TRUE
  120. 1 , // Policy
  121. 1 , // Client
  122. 1 , // TcpIp
  123. 1 , // Cache
  124. ALLOW_UNQUALIFIED_QUERY ,
  125. 0 , // Default FALSE
  126. 1 , // Policy
  127. 1 , // Client
  128. 1 , // TcpIp
  129. 1 , // Cache
  130. APPEND_TO_MULTI_LABEL_NAME ,
  131. 1 , // Default TRUE
  132. 1 , // Policy
  133. 1 , // Client
  134. 0 , // No TcpIp
  135. 1 , // Cache
  136. SCREEN_BAD_TLDS ,
  137. DNS_TLD_SCREEN_DEFAULT , // Default
  138. 1 , // Policy
  139. 1 , // Client
  140. 0 , // No TcpIp
  141. 1 , // Cache
  142. SCREEN_UNREACHABLE_SERVERS ,
  143. 1 , // Default TRUE
  144. 1 , // Policy
  145. 1 , // Client
  146. 0 , // No TcpIp
  147. 1 , // Cache
  148. FILTER_CLUSTER_IP ,
  149. 0 , // Default FALSE
  150. 1 , // Policy
  151. 1 , // Client
  152. 0 , // No TcpIp
  153. 1 , // Cache
  154. WAIT_FOR_NAME_ERROR_ON_ALL ,
  155. 1 , // Default TRUE
  156. 1 , // Policy
  157. 1 , // Client
  158. 0 , // No TcpIp
  159. 1 , // Cache
  160. USE_EDNS ,
  161. //REG_EDNS_TRY , // Default TRY EDNS
  162. 0 , // Default FALSE
  163. 1 , // Policy
  164. 1 , // Client
  165. 0 , // No TcpIp
  166. 1 , // Cache
  167. // Update
  168. REGISTRATION_ENABLED ,
  169. 1 , // Default TRUE
  170. 1 , // Policy
  171. 1 , // Client
  172. 0 , // No TcpIp
  173. 1 , // No Cache
  174. REGISTER_PRIMARY_NAME ,
  175. 1 , // Default TRUE
  176. 1 , // Policy
  177. 1 , // Client
  178. 0 , // No TcpIp
  179. 1 , // No Cache
  180. REGISTER_ADAPTER_NAME ,
  181. 1 , // Default TRUE
  182. 1 , // Policy
  183. 1 , // Client
  184. 0 , // No TcpIp
  185. 1 , // No Cache
  186. REGISTER_REVERSE_LOOKUP ,
  187. 1 , // Default TRUE
  188. 1 , // Policy
  189. 1 , // Client
  190. 0 , // No TcpIp
  191. 1 , // No Cache
  192. REGISTER_WAN_ADAPTERS ,
  193. 1 , // Default TRUE
  194. 1 , // Policy
  195. 1 , // Client
  196. 0 , // No TcpIp
  197. 1 , // No Cache
  198. REGISTRATION_OVERWRITES_IN_CONFLICT ,
  199. 1 , // Default TRUE
  200. 1 , // Policy
  201. 1 , // Client
  202. 0 , // No TcpIp
  203. 1 , // No Cache
  204. REGISTRATION_TTL ,
  205. REGDEF_REGISTRATION_TTL ,
  206. 1 , // Policy
  207. 1 , // Client
  208. 0 , // No TcpIp
  209. 1 , // No Cache
  210. REGISTRATION_REFRESH_INTERVAL ,
  211. REGDEF_REGISTRATION_REFRESH_INTERVAL ,
  212. 1 , // Policy
  213. 1 , // Client
  214. 0 , // No TcpIp
  215. 1 , // No Cache
  216. REGISTRATION_MAX_ADDRESS_COUNT ,
  217. 1 , // Default register 1 address
  218. 1 , // Policy
  219. 1 , // Client
  220. 0 , // No TcpIp
  221. 1 , // No Cache
  222. UPDATE_SECURITY_LEVEL ,
  223. DNS_UPDATE_SECURITY_USE_DEFAULT ,
  224. 1 , // Policy
  225. 1 , // Client
  226. 1 , // TcpIp
  227. 1 , // No Cache
  228. UPDATE_ZONE_EXCLUDE_FILE ,
  229. 1 , // Default ON
  230. 1 , // Policy
  231. 1 , // Client
  232. 0 , // No TcpIp
  233. 1 , // No Cache
  234. UPDATE_TOP_LEVEL_DOMAINS ,
  235. 0 , // Default OFF
  236. 1 , // Policy
  237. 1 , // Client
  238. 0 , // No TcpIp
  239. 1 , // No Cache
  240. //
  241. // Backcompat
  242. //
  243. // DCR: once policy fixed, policy should be OFF on all backcompat
  244. //
  245. DISABLE_ADAPTER_DOMAIN_NAME ,
  246. 0 , // Default FALSE
  247. 0 , // Policy
  248. 0 , // Client
  249. 1 , // TcpIp
  250. 0 , // No Cache
  251. DISABLE_DYNAMIC_UPDATE ,
  252. 0 , // Default FALSE
  253. 0 , // Policy
  254. 0 , // Client
  255. 1 , // TcpIp
  256. 0 , // No Cache
  257. ENABLE_ADAPTER_DOMAIN_NAME_REGISTRATION ,
  258. 0 , // Default TRUE
  259. 0 , // Policy
  260. 0 , // Client
  261. 1 , // TcpIp
  262. 0 , // No Cache
  263. DISABLE_REVERSE_ADDRESS_REGISTRATIONS ,
  264. 0 , // Default FALSE
  265. 0 , // Policy
  266. 0 , // Client
  267. 1 , // TcpIp
  268. 0 , // No Cache
  269. DISABLE_WAN_DYNAMIC_UPDATE ,
  270. 0 , // Default FALSE
  271. 0 , // Policy OFF
  272. 0 , // Client
  273. 1 , // TcpIp
  274. 0 , // No Cache
  275. ENABLE_WAN_UPDATE_EVENT_LOG ,
  276. 0 , // Default FALSE
  277. 0 , // Policy OFF
  278. 0 , // Client
  279. 1 , // TcpIp
  280. 0 , // No Cache
  281. DISABLE_REPLACE_ADDRESSES_IN_CONFLICTS ,
  282. 0 , // Default FALSE
  283. 0 , // Policy
  284. 0 , // Client
  285. 1 , // TcpIp
  286. 0 , // No Cache
  287. DEFAULT_REGISTRATION_TTL ,
  288. REGDEF_REGISTRATION_TTL ,
  289. 0 , // Policy OFF
  290. 0 , // Client
  291. 1 , // TcpIp
  292. 0 , // No Cache
  293. DEFAULT_REGISTRATION_REFRESH_INTERVAL ,
  294. REGDEF_REGISTRATION_REFRESH_INTERVAL ,
  295. 0 , // Policy
  296. 0 , // Client
  297. 1 , // TcpIp
  298. 0 , // No Cache
  299. MAX_NUMBER_OF_ADDRESSES_TO_REGISTER ,
  300. 1 , // Default register 1 address
  301. 0 , // Policy
  302. 0 , // Client
  303. 1 , // TcpIp
  304. 0 , // No Cache
  305. // Micellaneous
  306. NT_SETUP_MODE ,
  307. 0 , // Default FALSE
  308. 0 , // No policy
  309. 0 , // Client
  310. 0 , // No TcpIp
  311. 0 , // No Cache
  312. DNS_TEST_MODE ,
  313. 0 , // Default FALSE
  314. 0 , // No policy
  315. 0 , // No Client
  316. 0 , // No TcpIp
  317. 1 , // In Cache
  318. REMOTE_DNS_RESOLVER ,
  319. 0 , // Default FALSE
  320. 1 , // Policy
  321. 1 , // Client
  322. 0 , // No TcpIp
  323. 1 , // In Cache
  324. // Resolver
  325. MAX_CACHE_SIZE ,
  326. 1000 , // Default 1000 record sets
  327. 1 , // Policy
  328. 1 , // Client
  329. 0 , // No TcpIp
  330. 1 , // Cache
  331. MAX_CACHE_TTL ,
  332. 86400 , // Default 1 day
  333. 1 , // Policy
  334. 1 , // Client
  335. 0 , // No TcpIp
  336. 1 , // Cache
  337. MAX_NEGATIVE_CACHE_TTL ,
  338. 900 , // Default 15 minutes
  339. 1 , // Policy
  340. 1 , // Client
  341. 0 , // No TcpIp
  342. 1 , // Cache
  343. ADAPTER_TIMEOUT_LIMIT ,
  344. 600 , // Default 10 minutes
  345. 1 , // Policy
  346. 1 , // Client
  347. 0 , // No TcpIp
  348. 1 , // Cache
  349. SERVER_PRIORITY_TIME_LIMIT ,
  350. //3600 , // Default 1 hour
  351. // DCR: change once registry change notify
  352. // while no change-notify, this is essentially registry
  353. // check time so use 15 minutes
  354. 900 , // Default 15 minutes
  355. 1 , // Policy
  356. 1 , // Client
  357. 0 , // No TcpIp
  358. 1 , // Cache
  359. MAX_CACHED_SOCKETS ,
  360. 10 , // Default 10
  361. 1 , // Policy
  362. 1 , // Client
  363. 0 , // No TcpIp
  364. 1 , // Cache
  365. // Multicast
  366. USE_MULTICAST ,
  367. 0 , // Default OFF
  368. //1 , // Default ON
  369. 1 , // Policy
  370. 1 , // Client
  371. 0 , // No TcpIp
  372. 1 , // Cache
  373. MULTICAST_ON_NAME_ERROR ,
  374. 0 , // Default OFF
  375. //1 , // Default ON
  376. 1 , // Policy
  377. 1 , // Client
  378. 0 , // No TcpIp
  379. 1 , // Cache
  380. USE_DOT_LOCAL_DOMAIN ,
  381. 0 , // Default OFF
  382. //1 , // Default ON
  383. 1 , // Policy
  384. 1 , // Client
  385. 0 , // No TcpIp
  386. 1 , // Cache
  387. LISTEN_ON_MULTICAST ,
  388. 0 , // Default OFF
  389. //1 , // Default ON
  390. 1 , // Policy
  391. 1 , // Client
  392. 0 , // No TcpIp
  393. 1 , // Cache
  394. // Termination
  395. NULL, 0, 0, 0, 0, 0
  396. };
  397. //
  398. // Backward compatibility list
  399. //
  400. // Maps new reg id to old reg id.
  401. // Flag fReverse indicates need to reverse (!) the value.
  402. //
  403. #define NO_BACK_VALUE ((DWORD)(0xffffffff))
  404. typedef struct _Backpat
  405. {
  406. DWORD NewId;
  407. DWORD OldId;
  408. BOOL fReverse;
  409. }
  410. BACKPAT;
  411. BACKPAT BackpatArray[] =
  412. {
  413. RegIdQueryAdapterName,
  414. RegIdDisableAdapterDomainName,
  415. TRUE,
  416. RegIdRegistrationEnabled,
  417. RegIdDisableDynamicUpdate,
  418. TRUE,
  419. RegIdRegisterAdapterName,
  420. RegIdEnableAdapterDomainNameRegistration,
  421. FALSE,
  422. RegIdRegisterReverseLookup,
  423. RegIdDisableReverseAddressRegistrations,
  424. TRUE,
  425. RegIdRegisterWanAdapters,
  426. RegIdDisableWanDynamicUpdate,
  427. TRUE,
  428. RegIdRegistrationOverwritesInConflict,
  429. RegIdDisableReplaceAddressesInConflicts,
  430. TRUE,
  431. RegIdRegistrationTtl,
  432. RegIdDefaultRegistrationTTL,
  433. FALSE,
  434. RegIdRegistrationRefreshInterval,
  435. RegIdDefaultRegistrationRefreshInterval,
  436. FALSE,
  437. RegIdRegistrationMaxAddressCount,
  438. RegIdMaxNumberOfAddressesToRegister,
  439. FALSE,
  440. NO_BACK_VALUE, 0, 0
  441. };
  442. VOID
  443. Reg_Init(
  444. VOID
  445. )
  446. /*++
  447. Routine Description:
  448. Init DNS registry stuff.
  449. Essentially this means get system version info.
  450. Arguments:
  451. None.
  452. Globals:
  453. Sets the system info globals above:
  454. g_IsWin9X
  455. g_IsWin2000
  456. g_IsNT4
  457. g_IsWorkstation
  458. g_IsServer
  459. g_IsDomainController
  460. g_IsRegReady
  461. Return Value:
  462. None.
  463. --*/
  464. {
  465. OSVERSIONINFOEX osvi;
  466. BOOL bversionInfoEx;
  467. //
  468. // do this just once
  469. //
  470. if ( g_IsRegReady )
  471. {
  472. return;
  473. }
  474. //
  475. // code validity check
  476. // property table should have entry for every reg value plus an
  477. // extra one for the terminator
  478. //
  479. #if DBG
  480. DNS_ASSERT( (RegIdValueCount+1)*sizeof(REG_PROPERTY) ==
  481. sizeof(RegPropertyTable) );
  482. #endif
  483. //
  484. // clear globals blob
  485. //
  486. // DCR: warning clearing DnsGlobals but don't read them all
  487. // this is protected by read-once deal but still kind of
  488. //
  489. RtlZeroMemory(
  490. & DnsGlobals,
  491. sizeof(DnsGlobals) );
  492. //
  493. // get version info
  494. // - Win2000 supports OSVERSIONINFOEX
  495. // try first with it, then fail back to standard
  496. //
  497. ZeroMemory( &osvi, sizeof(OSVERSIONINFOEX) );
  498. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  499. bversionInfoEx = GetVersionEx( (OSVERSIONINFO*) &osvi );
  500. if ( !bversionInfoEx)
  501. {
  502. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  503. if ( ! GetVersionEx( (OSVERSIONINFO *) &osvi ) )
  504. {
  505. DNS_ASSERT( FALSE );
  506. return;
  507. }
  508. }
  509. #if DNSBUILDOLD
  510. //
  511. // suck out system info
  512. //
  513. // if Win9x -- that's it done
  514. //
  515. if ( osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
  516. {
  517. g_IsWin9X = TRUE;
  518. goto Done;
  519. }
  520. //
  521. // assume anything else is NT, this gets around WIN32 tag
  522. // leaving in Win64 versions
  523. //
  524. // DCR: WinCE issue here?
  525. // DCR: Win64 issue here?
  526. //
  527. DNS_ASSERT( osvi.dwPlatformId == VER_PLATFORM_WIN32_NT );
  528. if ( osvi.dwMajorVersion >= 5 )
  529. {
  530. g_IsWin2000 = TRUE;
  531. }
  532. else
  533. {
  534. g_IsNT4 = TRUE;
  535. }
  536. #else
  537. // set Win2K flag
  538. // - easier to keep this flag then to #ifdef the remaining uses
  539. g_IsWin2000 = TRUE;
  540. #endif
  541. //
  542. // get system type -- workstation, server, DC
  543. //
  544. if ( bversionInfoEx )
  545. {
  546. if ( osvi.wProductType == VER_NT_WORKSTATION )
  547. {
  548. g_IsWorkstation = TRUE;
  549. }
  550. else if ( osvi.wProductType == VER_NT_SERVER )
  551. {
  552. g_IsServer = TRUE;
  553. }
  554. else if ( osvi.wProductType == VER_NT_DOMAIN_CONTROLLER )
  555. {
  556. g_IsServer = TRUE;
  557. g_IsDomainController = TRUE;
  558. }
  559. ELSE_ASSERT( FALSE );
  560. }
  561. #if DNSNT4
  562. //
  563. // no osviEX (NT4), must suck product from registry
  564. //
  565. else
  566. {
  567. HKEY hkey = NULL;
  568. CHAR productType[MAX_PATH] = "0";
  569. DWORD bufLength = MAX_PATH;
  570. RegOpenKeyExW(
  571. HKEY_LOCAL_MACHINE,
  572. L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
  573. 0,
  574. KEY_QUERY_VALUE,
  575. & hkey );
  576. if ( !hkey )
  577. {
  578. DNS_ASSERT( FALSE );
  579. goto Done;
  580. }
  581. RegQueryValueExA(
  582. hkey,
  583. "ProductType",
  584. NULL,
  585. NULL,
  586. (LPBYTE) productType,
  587. & bufLength );
  588. RegCloseKey( hkey );
  589. if ( lstrcmpi( "WINNT", productType) == 0 )
  590. {
  591. g_IsWorkstation = TRUE;
  592. }
  593. else if ( lstrcmpi( "SERVERNT", productType) == 0 )
  594. {
  595. g_IsServer = TRUE;
  596. }
  597. else if ( lstrcmpi( "LANMANNT", productType) == 0 )
  598. {
  599. g_IsDomainController = TRUE;
  600. }
  601. }
  602. Done:
  603. #endif
  604. g_IsRegReady = TRUE;
  605. #if DNSBUILDOLD
  606. DNSDBG( REGISTRY, (
  607. "DNS API registry init:\n"
  608. "\tWin9X = %d\n"
  609. "\tNT4 = %d\n"
  610. "\tWin2000 = %d\n"
  611. "\tWorksta = %d\n"
  612. "\tServer = %d\n"
  613. "\tDC = %d\n",
  614. g_IsWin9X,
  615. g_IsNT4,
  616. g_IsWin2000,
  617. g_IsWorkstation,
  618. g_IsServer,
  619. g_IsDomainController ));
  620. #endif
  621. DNSDBG( REGISTRY, (
  622. "DNS registry init:\n"
  623. "\tWin2000 = %d\n"
  624. "\tWorksta = %d\n"
  625. "\tServer = %d\n"
  626. "\tDC = %d\n",
  627. g_IsWin2000,
  628. g_IsWorkstation,
  629. g_IsServer,
  630. g_IsDomainController ));
  631. }
  632. //
  633. // Registry table routines
  634. //
  635. PSTR
  636. regValueNameForId(
  637. IN DWORD RegId
  638. )
  639. /*++
  640. Routine Description:
  641. Return registry value name for reg ID
  642. Arguments:
  643. RegId -- ID for value
  644. Return Value:
  645. Ptr to reg value name.
  646. NULL on error.
  647. --*/
  648. {
  649. DNSDBG( REGISTRY, (
  650. "regValueNameForId( id=%d )\n",
  651. RegId ));
  652. //
  653. // validate ID
  654. //
  655. if ( RegId > RegIdValueMax )
  656. {
  657. return( NULL );
  658. }
  659. //
  660. // index into table
  661. //
  662. return( (PSTR)REGPROP_NAME(RegId) );
  663. }
  664. DWORD
  665. checkBackCompat(
  666. IN DWORD NewId,
  667. OUT PBOOL pfReverse
  668. )
  669. /*++
  670. Routine Description:
  671. Check if have backward compatible regkey.
  672. Arguments:
  673. NewId -- id to check for old backward compatible id
  674. pfReverse -- addr to receive reverse flag
  675. Return Value:
  676. Reg Id of old backward compatible value.
  677. NO_BACK_VALUE if no old value.
  678. --*/
  679. {
  680. DWORD i = 0;
  681. DWORD id;
  682. //
  683. // loop through backcompat list looking for value
  684. //
  685. while ( 1 )
  686. {
  687. id = BackpatArray[i].NewId;
  688. if ( id == NO_BACK_VALUE )
  689. {
  690. return( NO_BACK_VALUE );
  691. }
  692. if ( id != NewId )
  693. {
  694. i++;
  695. continue;
  696. }
  697. // found value in backcompat array
  698. break;
  699. }
  700. *pfReverse = BackpatArray[i].fReverse;
  701. return BackpatArray[i].OldId;
  702. }
  703. //
  704. // Registry session handle
  705. //
  706. DNS_STATUS
  707. WINAPI
  708. Reg_OpenSession(
  709. OUT PREG_SESSION pRegSession,
  710. IN DWORD Level,
  711. IN DWORD RegId
  712. )
  713. /*++
  714. Routine Description:
  715. Open registry for DNS client info.
  716. Arguments:
  717. pRegSession -- ptr to unitialize reg session blob
  718. Level -- level of access to get
  719. RegId -- ID of value we're interested in
  720. Return Value:
  721. None.
  722. --*/
  723. {
  724. DWORD status = NO_ERROR;
  725. HKEY hkey = NULL;
  726. DWORD disposition;
  727. // auto init
  728. Reg_Init();
  729. //
  730. // clear handles
  731. //
  732. RtlZeroMemory(
  733. pRegSession,
  734. sizeof( REG_SESSION ) );
  735. //
  736. // DCR: handle multiple access levels
  737. //
  738. // For know assume that if getting access to "standard"
  739. // section we'll need both policy and regular.
  740. //
  741. //
  742. // Win95
  743. // - TCP/IP location slightly different than NT
  744. //
  745. // Devnote: we could collapse these using all _A calls
  746. // (all key names are ANSI) but we gain some perf
  747. // by calling NT wide; and since we currently have
  748. // to do that, it seems worth it
  749. //
  750. #if DNSWIN9X
  751. if ( g_IsWin9X )
  752. {
  753. status = RegCreateKeyExA(
  754. HKEY_LOCAL_MACHINE,
  755. WIN95_TCPIP_KEY_A,
  756. 0,
  757. "Class",
  758. REG_OPTION_NON_VOLATILE,
  759. KEY_READ,
  760. NULL,
  761. &hkey,
  762. &disposition );
  763. }
  764. else
  765. #endif
  766. //
  767. // NT
  768. // - Win2000
  769. // - open TCPIP
  770. // note, always open TCPIP as may not be any policy
  771. // for some or all of our desired reg values, even
  772. // if policy key is available
  773. // - open policy (only if standard successful)
  774. //
  775. // - NT4
  776. // - open TCPIP (no policy)
  777. //
  778. {
  779. status = RegCreateKeyExW(
  780. HKEY_LOCAL_MACHINE,
  781. TCPIP_PARAMETERS_KEY,
  782. 0,
  783. L"Class",
  784. REG_OPTION_NON_VOLATILE,
  785. KEY_READ,
  786. NULL,
  787. &hkey,
  788. &disposition );
  789. if ( !g_IsWin2000 || status != ERROR_SUCCESS )
  790. {
  791. goto Done;
  792. }
  793. #ifdef DNSCLIENTKEY
  794. // open DNS client key
  795. //
  796. // DCR: currently no DNSClient regkey
  797. RegOpenKeyExW(
  798. HKEY_LOCAL_MACHINE,
  799. DNS_CLIENT_KEY,
  800. 0,
  801. KEY_READ,
  802. & pRegSession->hClient );
  803. #endif
  804. // open DNS cache key
  805. RegOpenKeyExW(
  806. HKEY_LOCAL_MACHINE,
  807. DNS_CACHE_KEY,
  808. 0,
  809. KEY_READ,
  810. & pRegSession->hCache );
  811. // open DNS policy key
  812. RegOpenKeyExW(
  813. HKEY_LOCAL_MACHINE,
  814. DNS_POLICY_KEY,
  815. 0,
  816. KEY_READ,
  817. & pRegSession->hPolicy );
  818. }
  819. Done:
  820. //
  821. // all OS versions return TCP/IP key
  822. //
  823. if ( status == ERROR_SUCCESS )
  824. {
  825. pRegSession->hTcpip = hkey;
  826. }
  827. else
  828. {
  829. Reg_CloseSession( pRegSession );
  830. }
  831. DNSDBG( TRACE, (
  832. "Leave: Reg_OpenSession( s=%d, t=%p, p=%p, c=%p )\n",
  833. status,
  834. pRegSession->hTcpip,
  835. pRegSession->hPolicy,
  836. pRegSession->hClient ));
  837. return( status );
  838. }
  839. VOID
  840. WINAPI
  841. Reg_CloseSession(
  842. IN OUT PREG_SESSION pRegSession
  843. )
  844. /*++
  845. Routine Description:
  846. Close registry session handle.
  847. This means close underlying regkeys.
  848. Arguments:
  849. pSessionHandle -- ptr to registry session handle
  850. Return Value:
  851. None.
  852. --*/
  853. {
  854. //
  855. // allow sloppy cleanup
  856. //
  857. if ( !pRegSession )
  858. {
  859. return;
  860. }
  861. //
  862. // close any non-NULL handles
  863. //
  864. if ( pRegSession->hPolicy )
  865. {
  866. RegCloseKey( pRegSession->hPolicy );
  867. }
  868. if ( pRegSession->hTcpip )
  869. {
  870. RegCloseKey( pRegSession->hTcpip );
  871. }
  872. #ifdef DNSCLIENTKEY
  873. if ( pRegSession->hClient )
  874. {
  875. RegCloseKey( pRegSession->hClient );
  876. }
  877. #endif
  878. if ( pRegSession->hCache )
  879. {
  880. RegCloseKey( pRegSession->hCache );
  881. }
  882. //
  883. // clear handles (just for safety)
  884. //
  885. RtlZeroMemory(
  886. pRegSession,
  887. sizeof(REG_SESSION) );
  888. }
  889. //
  890. // Registry reading routines
  891. //
  892. DNS_STATUS
  893. Reg_GetDword(
  894. IN PREG_SESSION pRegSession, OPTIONAL
  895. IN HKEY hRegKey, OPTIONAL
  896. IN PWSTR pwsKeyName, OPTIONAL
  897. IN DWORD RegId,
  898. OUT PDWORD pResult
  899. //OUT PDWORD pfRead
  900. )
  901. /*++
  902. Routine Description:
  903. Read REG_DWORD value from registry.
  904. //
  905. // DCR: do we need to expose location result?
  906. // (explicit, policy, defaulted)
  907. //
  908. Arguments:
  909. pRegSession -- ptr to reg session already opened (OPTIONAL)
  910. hRegKey -- explicit regkey
  911. pwsKeyName -- key name OR dummy key
  912. RegId -- ID for value
  913. pResult -- addr of DWORD to recv result
  914. pfRead -- addr to recv result of how value read
  915. 0 -- defaulted
  916. 1 -- read
  917. Currently just use ERROR_SUCCESS to mean read rather
  918. than defaulted.
  919. Return Value:
  920. ERROR_SUCCESS on success.
  921. ErrorCode on failure -- value is then defaulted.
  922. --*/
  923. {
  924. DNS_STATUS status;
  925. REG_SESSION session;
  926. PREG_SESSION psession = pRegSession;
  927. PBYTE pname;
  928. DWORD regType = REG_DWORD;
  929. DWORD dataLength = sizeof(DWORD);
  930. HKEY hkey;
  931. HKEY hlocalKey = NULL;
  932. DNSDBG( REGISTRY, (
  933. "Reg_GetDword( s=%p, k=%p, a=%p, id=%d )\n",
  934. pRegSession,
  935. hRegKey,
  936. pwsKeyName,
  937. RegId ));
  938. // auto init
  939. Reg_Init();
  940. //
  941. // clear result for error case
  942. //
  943. *pResult = 0;
  944. //
  945. // get proper regval name
  946. // - wide for NT
  947. // - narrow for 9X
  948. //
  949. pname = regValueNameForId( RegId );
  950. if ( !pname )
  951. {
  952. DNS_ASSERT( FALSE );
  953. return( ERROR_INVALID_PARAMETER );
  954. }
  955. //
  956. // DCR: can use function pointers for wide narrow
  957. //
  958. //
  959. // three paradigms
  960. //
  961. // 1) specific key (adapter or something else)
  962. // => use it
  963. //
  964. // 2) specific key name (adapter or dummy key location)
  965. // => open key
  966. // => use it
  967. // => close
  968. //
  969. // 3) session -- passed in or created (default)
  970. // => use pRegSession or open new
  971. // => try policy first then TCPIP parameters
  972. // => close if open
  973. //
  974. if ( hRegKey )
  975. {
  976. hkey = hRegKey;
  977. }
  978. else if ( pwsKeyName )
  979. {
  980. hkey = Reg_CreateKey(
  981. pwsKeyName,
  982. FALSE // read access
  983. );
  984. if ( !hkey )
  985. {
  986. status = GetLastError();
  987. goto Done;
  988. }
  989. hlocalKey = hkey;
  990. }
  991. else
  992. {
  993. // open reg handle if not open
  994. if ( !psession )
  995. {
  996. status = Reg_OpenSession(
  997. &session,
  998. 0, // standard level
  999. RegId // target key
  1000. );
  1001. if ( status != ERROR_SUCCESS )
  1002. {
  1003. goto Done;
  1004. }
  1005. psession = &session;
  1006. }
  1007. // try policy section -- if available
  1008. hkey = psession->hPolicy;
  1009. if ( hkey && REGPROP_POLICY(RegId) )
  1010. {
  1011. //status = DnsShimRegQueryValueExW(
  1012. status = RegQueryValueExW(
  1013. hkey,
  1014. (PWSTR) pname,
  1015. 0,
  1016. & regType,
  1017. (PBYTE) pResult,
  1018. & dataLength
  1019. );
  1020. if ( status == ERROR_SUCCESS )
  1021. {
  1022. goto DoneSuccess;
  1023. }
  1024. }
  1025. // unsuccessful -- try DnsClient
  1026. #ifdef DNSCLIENTKEY
  1027. hkey = psession->hClient;
  1028. if ( hkey && REGPROP_CLIENT(RegId) )
  1029. {
  1030. //status = DnsShimRegQueryValueExW(
  1031. status = RegQueryValueExW(
  1032. hkey,
  1033. (PWSTR) pname,
  1034. 0,
  1035. & regType,
  1036. (PBYTE) pResult,
  1037. & dataLength
  1038. );
  1039. if ( status == ERROR_SUCCESS )
  1040. {
  1041. goto DoneSuccess;
  1042. }
  1043. }
  1044. #endif
  1045. // unsuccessful -- try DnsCache
  1046. hkey = psession->hCache;
  1047. if ( hkey && REGPROP_CACHE(RegId) )
  1048. {
  1049. //status = DnsShimRegQueryValueExW(
  1050. status = RegQueryValueExW(
  1051. hkey,
  1052. (PWSTR) pname,
  1053. 0,
  1054. & regType,
  1055. (PBYTE) pResult,
  1056. & dataLength
  1057. );
  1058. if ( status == ERROR_SUCCESS )
  1059. {
  1060. goto DoneSuccess;
  1061. }
  1062. }
  1063. // unsuccessful -- try TCPIP key
  1064. // - if have open session it MUST include TCPIP key
  1065. hkey = psession->hTcpip;
  1066. if ( hkey && REGPROP_TCPIP(RegId) )
  1067. {
  1068. //status = DnsShimRegQueryValueExW(
  1069. status = RegQueryValueExW(
  1070. hkey,
  1071. (PWSTR) pname,
  1072. 0,
  1073. & regType,
  1074. (PBYTE) pResult,
  1075. & dataLength
  1076. );
  1077. if ( status == ERROR_SUCCESS )
  1078. {
  1079. goto DoneSuccess;
  1080. }
  1081. }
  1082. status = ERROR_FILE_NOT_FOUND;
  1083. goto Done;
  1084. }
  1085. //
  1086. // explict key (passed in or from name)
  1087. //
  1088. if ( hkey )
  1089. {
  1090. //status = DnsShimRegQueryValueExW(
  1091. status = RegQueryValueExW(
  1092. hkey,
  1093. (PWSTR) pname,
  1094. 0,
  1095. & regType,
  1096. (PBYTE) pResult,
  1097. & dataLength
  1098. );
  1099. }
  1100. ELSE_ASSERT_FALSE;
  1101. Done:
  1102. //
  1103. // if value not found, check for backward compatibility value
  1104. //
  1105. if ( status != ERROR_SUCCESS )
  1106. {
  1107. DWORD oldId;
  1108. BOOL freverse;
  1109. oldId = checkBackCompat( RegId, &freverse );
  1110. if ( oldId != NO_BACK_VALUE )
  1111. {
  1112. DWORD backValue;
  1113. status = Reg_GetDword(
  1114. psession,
  1115. ( psession ) ? NULL : hkey,
  1116. ( psession ) ? NULL : pwsKeyName,
  1117. oldId,
  1118. & backValue );
  1119. if ( status == ERROR_SUCCESS )
  1120. {
  1121. if ( freverse )
  1122. {
  1123. backValue = !backValue;
  1124. }
  1125. *pResult = backValue;
  1126. }
  1127. }
  1128. }
  1129. // default the value if read failed
  1130. if ( status != ERROR_SUCCESS )
  1131. {
  1132. *pResult = REGPROP_DEFAULT( RegId );
  1133. }
  1134. DoneSuccess:
  1135. // cleanup any regkey's opened
  1136. if ( psession == &session )
  1137. {
  1138. Reg_CloseSession( psession );
  1139. }
  1140. else if ( hlocalKey )
  1141. {
  1142. RegCloseKey( hlocalKey );
  1143. }
  1144. return( status );
  1145. }
  1146. //
  1147. // DCR_CLEANUP: cleanup Reg_ReadValue()
  1148. // this is a slightly altered version of Glenn's
  1149. // routine to "do it all" -- stripped of the
  1150. // unnecessary Win9x flag;
  1151. // it does not do policy or use the RegHandle yet
  1152. //
  1153. // DCR_PERF: it also makes a bunch of unnecessary
  1154. // heap allocations
  1155. //
  1156. DNS_STATUS
  1157. privateRegReadValue(
  1158. IN HKEY hKey,
  1159. IN DWORD RegId,
  1160. IN DWORD Flag,
  1161. OUT PBYTE * ppBuffer,
  1162. OUT PDWORD pBufferLength
  1163. )
  1164. /*++
  1165. Routine Description:
  1166. Arguments:
  1167. hKey -- handle of the key whose value field is retrieved.
  1168. RegId -- reg value ID, assumed to be validated (in table)
  1169. ppBuffer -- ptr to address to receive buffer ptr
  1170. pBufferLength -- addr to receive buffer length
  1171. Return Value:
  1172. ERROR_SUCCESS if successful.
  1173. ErrorCode on failure.
  1174. --*/
  1175. {
  1176. DWORD status;
  1177. PSTR pname;
  1178. DWORD valueType = 0; // prefix
  1179. DWORD valueSize = 0; // prefix
  1180. PBYTE pdataBuffer;
  1181. PBYTE pallocBuffer = NULL;
  1182. //
  1183. // query for buffer size
  1184. //
  1185. pname = (PSTR) REGPROP_NAME( RegId );
  1186. //status = DnsShimRegQueryValueExW(
  1187. status = RegQueryValueExW(
  1188. hKey,
  1189. (PWSTR) pname,
  1190. 0,
  1191. &valueType,
  1192. NULL,
  1193. &valueSize );
  1194. if ( status != ERROR_SUCCESS )
  1195. {
  1196. return( status );
  1197. }
  1198. //
  1199. // setup result buffer
  1200. //
  1201. switch( valueType )
  1202. {
  1203. case REG_DWORD:
  1204. pdataBuffer = (PBYTE) ppBuffer;
  1205. break;
  1206. case REG_SZ:
  1207. case REG_MULTI_SZ:
  1208. case REG_EXPAND_SZ:
  1209. case REG_BINARY:
  1210. // if size is zero, still allocate empty string
  1211. // - min alloc DWORD
  1212. // - can't possibly alloc smaller
  1213. // - good clean init to zero includes MULTISZ zero
  1214. // - need at least WCHAR string zero init
  1215. // and much catch small regbinary (1,2,3)
  1216. if ( valueSize <= sizeof(DWORD) )
  1217. {
  1218. valueSize = sizeof(DWORD);
  1219. }
  1220. pallocBuffer = pdataBuffer = ALLOCATE_HEAP( valueSize );
  1221. if ( !pdataBuffer )
  1222. {
  1223. return( DNS_ERROR_NO_MEMORY );
  1224. }
  1225. *(PDWORD)pdataBuffer = 0;
  1226. break;
  1227. default:
  1228. return( ERROR_INVALID_PARAMETER );
  1229. }
  1230. //
  1231. // query for data
  1232. //
  1233. //status = DnsShimRegQueryValueExW(
  1234. status = RegQueryValueExW(
  1235. hKey,
  1236. (PWSTR) pname,
  1237. 0,
  1238. &valueType,
  1239. pdataBuffer,
  1240. &valueSize );
  1241. //
  1242. // setup return buffer
  1243. //
  1244. switch( valueType )
  1245. {
  1246. case REG_DWORD:
  1247. case REG_BINARY:
  1248. break;
  1249. case REG_SZ:
  1250. case REG_EXPAND_SZ:
  1251. case REG_MULTI_SZ:
  1252. //
  1253. // dump empty strings?
  1254. //
  1255. // note: we always allocate at least a DWORD and
  1256. // set it NULL, so rather than a complex test for
  1257. // different reg types and char sets, can just test
  1258. // if that DWORD is still NULL
  1259. //
  1260. // DCR: do we want to screen whitespace-empty strings
  1261. // - example blank string
  1262. //
  1263. if ( Flag & DNSREG_FLAG_DUMP_EMPTY )
  1264. {
  1265. if ( valueSize==0 ||
  1266. *(PDWORD)pdataBuffer == 0 )
  1267. {
  1268. status = ERROR_INVALID_DATA;
  1269. goto Cleanup;
  1270. }
  1271. }
  1272. //
  1273. // by default we return strings as UTF8
  1274. //
  1275. // if flagged, return in unicode
  1276. //
  1277. if ( Flag & DNSREG_FLAG_GET_UNICODE )
  1278. {
  1279. // no-op, keep unicode string
  1280. }
  1281. //
  1282. // do default convert to UTF8
  1283. //
  1284. else
  1285. {
  1286. PBYTE putf8Buffer = ALLOCATE_HEAP( valueSize * 2 );
  1287. if ( !putf8Buffer )
  1288. {
  1289. status = DNS_ERROR_NO_MEMORY;
  1290. goto Cleanup;
  1291. }
  1292. if ( !Dns_UnicodeToUtf8(
  1293. (PWSTR) pdataBuffer,
  1294. valueSize / sizeof(WCHAR),
  1295. putf8Buffer,
  1296. valueSize * 2 ) )
  1297. {
  1298. FREE_HEAP( putf8Buffer );
  1299. status = ERROR_INVALID_DATA;
  1300. goto Cleanup;
  1301. }
  1302. FREE_HEAP( pallocBuffer );
  1303. pallocBuffer = NULL;
  1304. pdataBuffer = putf8Buffer;
  1305. }
  1306. break;
  1307. default:
  1308. break;
  1309. }
  1310. Cleanup:
  1311. //
  1312. // set return
  1313. // - REG_DWORD writes DWORD to ppBuffer directly
  1314. // - otherwise ppBuffer set to allocated buffer ptr
  1315. // or cleanup
  1316. // - on failure dump allocated buffer
  1317. //
  1318. if ( status == ERROR_SUCCESS )
  1319. {
  1320. if ( valueType != REG_DWORD )
  1321. {
  1322. *ppBuffer = pdataBuffer;
  1323. }
  1324. *pBufferLength = valueSize;
  1325. }
  1326. else
  1327. {
  1328. *ppBuffer = NULL;
  1329. *pBufferLength = 0;
  1330. FREE_HEAP( pallocBuffer );
  1331. }
  1332. return( status );
  1333. }
  1334. DNS_STATUS
  1335. Reg_GetValueEx(
  1336. IN PREG_SESSION pRegSession, OPTIONAL
  1337. IN HKEY hRegKey, OPTIONAL
  1338. IN LPSTR pwsAdapter, OPTIONAL
  1339. IN DWORD RegId,
  1340. IN DWORD ValueType,
  1341. IN DWORD Flag,
  1342. OUT PBYTE * ppBuffer
  1343. )
  1344. /*++
  1345. Routine Description:
  1346. Arguments:
  1347. pRegSession -- ptr to registry session, OPTIONAL
  1348. hRegKey -- handle to open regkey OPTIONAL
  1349. pwsAdapter -- name of adapter to query under OPTIONAL
  1350. RegId -- value ID
  1351. ValueType -- reg type of value
  1352. Flag -- flags with tweaks to lookup
  1353. ppBuffer -- addr to receive buffer ptr
  1354. Note, for REG_DWORD, DWORD data is written directly to this
  1355. location instead of a buffer being allocated and it's ptr
  1356. being written.
  1357. Return Value:
  1358. ERROR_SUCCESS if successful.
  1359. Registry error code on failure.
  1360. --*/
  1361. {
  1362. DNS_STATUS status = ERROR_FILE_NOT_FOUND;
  1363. REG_SESSION session;
  1364. PREG_SESSION psession = pRegSession;
  1365. PBYTE pname;
  1366. DWORD regType = REG_DWORD;
  1367. DWORD dataLength;
  1368. HKEY hkey;
  1369. HKEY hadapterKey = NULL;
  1370. DNSDBG( REGISTRY, (
  1371. "Reg_GetValueEx( s=%p, k=%p, id=%d )\n",
  1372. pRegSession,
  1373. hRegKey,
  1374. RegId ));
  1375. ASSERT( !pwsAdapter );
  1376. // auto init
  1377. Reg_Init();
  1378. //
  1379. // get proper regval name
  1380. // - wide for NT
  1381. // - narrow for 9X
  1382. //
  1383. pname = regValueNameForId( RegId );
  1384. if ( !pname )
  1385. {
  1386. DNS_ASSERT( FALSE );
  1387. status = ERROR_INVALID_PARAMETER;
  1388. goto FailedDone;
  1389. }
  1390. //
  1391. // DCR: can use fucntion pointers for wide narrow
  1392. //
  1393. //
  1394. // two paradigms
  1395. //
  1396. // 1) specific key (adapter or something else)
  1397. // => use it
  1398. // => open adapter subkey if necessary
  1399. //
  1400. // 2) standard
  1401. // => try policy first, then DNSCache, then TCPIP
  1402. // => use pRegSession or open it
  1403. //
  1404. if ( hRegKey )
  1405. {
  1406. hkey = hRegKey;
  1407. // need to open adapter subkey
  1408. if ( pwsAdapter )
  1409. {
  1410. status = RegOpenKeyExA(
  1411. hkey,
  1412. (PCSTR) pwsAdapter,
  1413. 0,
  1414. KEY_QUERY_VALUE,
  1415. & hadapterKey );
  1416. if ( status != ERROR_SUCCESS )
  1417. {
  1418. goto FailedDone;
  1419. }
  1420. }
  1421. }
  1422. else
  1423. {
  1424. // open reg handle if not open
  1425. if ( !pRegSession )
  1426. {
  1427. status = Reg_OpenSession(
  1428. &session,
  1429. 0, // standard level
  1430. RegId // target key
  1431. );
  1432. if ( status != ERROR_SUCCESS )
  1433. {
  1434. goto FailedDone;
  1435. }
  1436. psession = &session;
  1437. }
  1438. // try policy section -- if available
  1439. hkey = psession->hPolicy;
  1440. if ( hkey && REGPROP_POLICY(RegId) )
  1441. {
  1442. status = privateRegReadValue(
  1443. hkey,
  1444. RegId,
  1445. Flag,
  1446. ppBuffer,
  1447. & dataLength
  1448. );
  1449. if ( status == ERROR_SUCCESS )
  1450. {
  1451. goto Done;
  1452. }
  1453. }
  1454. // try DNS cache -- if available
  1455. hkey = psession->hCache;
  1456. if ( hkey && REGPROP_CACHE(RegId) )
  1457. {
  1458. status = privateRegReadValue(
  1459. hkey,
  1460. RegId,
  1461. Flag,
  1462. ppBuffer,
  1463. & dataLength
  1464. );
  1465. if ( status == ERROR_SUCCESS )
  1466. {
  1467. goto Done;
  1468. }
  1469. }
  1470. // unsuccessful -- use TCPIP key
  1471. hkey = psession->hTcpip;
  1472. if ( !hkey )
  1473. {
  1474. goto Done;
  1475. }
  1476. }
  1477. //
  1478. // explict key OR standard key case
  1479. //
  1480. status = privateRegReadValue(
  1481. hkey,
  1482. RegId,
  1483. Flag,
  1484. ppBuffer,
  1485. & dataLength
  1486. );
  1487. if ( status == ERROR_SUCCESS )
  1488. {
  1489. goto Done;
  1490. }
  1491. FailedDone:
  1492. //
  1493. // if failed
  1494. // - for REG_DWORD, default the value
  1495. // - for strings, ensure NULL return buffer
  1496. // this takes care of cases where privateRegReadValue()
  1497. // never got called
  1498. //
  1499. if ( status != ERROR_SUCCESS )
  1500. {
  1501. if ( ValueType == REG_DWORD )
  1502. {
  1503. *(PDWORD) ppBuffer = REGPROP_DEFAULT( RegId );
  1504. }
  1505. else
  1506. {
  1507. *ppBuffer = NULL;
  1508. }
  1509. }
  1510. Done:
  1511. // cleanup any regkey's opened
  1512. if ( psession == &session )
  1513. {
  1514. Reg_CloseSession( psession );
  1515. }
  1516. if ( hadapterKey )
  1517. {
  1518. RegCloseKey( hadapterKey );
  1519. }
  1520. return( status );
  1521. }
  1522. DNS_STATUS
  1523. Reg_GetIpArray(
  1524. IN PREG_SESSION pRegSession, OPTIONAL
  1525. IN HKEY hRegKey, OPTIONAL
  1526. IN LPSTR pwsAdapter, OPTIONAL
  1527. IN DWORD RegId,
  1528. IN DWORD ValueType,
  1529. OUT PIP_ARRAY * ppIpArray
  1530. )
  1531. /*++
  1532. Routine Description:
  1533. Arguments:
  1534. pRegSession -- ptr to registry session, OPTIONAL
  1535. hRegKey -- handle to open regkey OPTIONAL
  1536. pwsAdapter -- name of adapter to query under OPTIONAL
  1537. RegId -- value ID
  1538. ValueType -- currently ignored, but could later use
  1539. to distinguish REG_SZ from REG_MULTI_SZ
  1540. processing
  1541. ppIpArray -- addr to receive IP array ptr
  1542. - array is allocated with Dns_Alloc(),
  1543. caller must free with Dns_Free()
  1544. Return Value:
  1545. ERROR_SUCCESS if successful.
  1546. Registry error code on failure.
  1547. --*/
  1548. {
  1549. DNS_STATUS status;
  1550. PSTR pstring = NULL;
  1551. DNSDBG( REGISTRY, (
  1552. "Reg_GetIpArray( s=%p, k=%p, id=%d )\n",
  1553. pRegSession,
  1554. hRegKey,
  1555. RegId ));
  1556. //
  1557. // make call to get IP array as string
  1558. //
  1559. status = Reg_GetValueEx(
  1560. pRegSession,
  1561. hRegKey,
  1562. pwsAdapter,
  1563. RegId,
  1564. REG_SZ, // only supported type is REG_SZ
  1565. 0, // no flag
  1566. & pstring );
  1567. if ( status != ERROR_SUCCESS )
  1568. {
  1569. ASSERT( pstring == NULL );
  1570. return( status );
  1571. }
  1572. //
  1573. // convert from string to IP array
  1574. //
  1575. // note: this call is limited to a parsing limit
  1576. // but it is a large number suitable for stuff
  1577. // like DNS server lists
  1578. //
  1579. // DCR: use IP array builder for local IP address
  1580. // then need Dns_CreateIpArrayFromMultiIpString()
  1581. // to use count\alloc method when buffer overflows
  1582. //
  1583. status = Dns_CreateIpArrayFromMultiIpString(
  1584. pstring,
  1585. ppIpArray );
  1586. // cleanup
  1587. if ( pstring )
  1588. {
  1589. FREE_HEAP( pstring );
  1590. }
  1591. return( status );
  1592. }
  1593. //
  1594. // Registry writing routines
  1595. //
  1596. HKEY
  1597. WINAPI
  1598. Reg_CreateKey(
  1599. IN PWSTR pwsKeyName,
  1600. IN BOOL bWrite
  1601. )
  1602. /*++
  1603. Routine Description:
  1604. Open registry key.
  1605. The purpose of this routine is simply to functionalize
  1606. opening with\without an adapter name.
  1607. So caller can pass through adapter name argument instead
  1608. of building key name or doing two opens for adapter
  1609. present\absent.
  1610. This is NT only.
  1611. Arguments:
  1612. pwsKeyName -- key "name"
  1613. this is one of the REGKEY_X from registry.h
  1614. OR
  1615. adapter name
  1616. bWrite -- TRUE for write access, FALSE for read
  1617. Return Value:
  1618. New opened key.
  1619. --*/
  1620. {
  1621. HKEY hkey = NULL;
  1622. DWORD disposition;
  1623. DWORD status;
  1624. PWSTR pnameKey;
  1625. WCHAR nameBuffer[ MAX_PATH ];
  1626. //
  1627. // don't bother for Win9x
  1628. //
  1629. // DCR_QUESTION: any need for use with Win9x
  1630. //
  1631. #if DNSWIN9X
  1632. if ( g_IsWin9X )
  1633. {
  1634. ASSERT( FALSE );
  1635. SetLastError( ERROR_INVALID_PARAMETER );
  1636. return( NULL );
  1637. }
  1638. #endif
  1639. //
  1640. // determine key name
  1641. //
  1642. // this is either DNSKEY_X dummy pointer from registry.h
  1643. // OR
  1644. // is an adapter name;
  1645. //
  1646. // - if adapter given, open under it
  1647. // adapters are under TCPIP\Interfaces
  1648. // - any other specific key
  1649. // - default is TCPIP params key
  1650. //
  1651. // note: if if grows too big, turn into table
  1652. //
  1653. if ( pwsKeyName <= REGKEY_DNS_MAX )
  1654. {
  1655. if ( pwsKeyName == REGKEY_TCPIP_PARAMETERS )
  1656. {
  1657. pnameKey = TCPIP_PARAMETERS_KEY;
  1658. }
  1659. else if ( pwsKeyName == REGKEY_DNS_CACHE )
  1660. {
  1661. pnameKey = DNS_CACHE_KEY;
  1662. }
  1663. else if ( pwsKeyName == REGKEY_DNS_POLICY )
  1664. {
  1665. pnameKey = DNS_POLICY_KEY;
  1666. }
  1667. else if ( pwsKeyName == REGKEY_SETUP_MODE_LOCATION )
  1668. {
  1669. pnameKey = NT_SETUP_MODE_KEY;
  1670. }
  1671. else
  1672. {
  1673. pnameKey = TCPIP_PARAMETERS_KEY;
  1674. }
  1675. }
  1676. else // adapter name
  1677. {
  1678. wcscpy( nameBuffer, TCPIP_INTERFACES_KEY );
  1679. wcscat( nameBuffer, pwsKeyName );
  1680. pnameKey = nameBuffer;
  1681. }
  1682. //
  1683. // create\open key
  1684. //
  1685. if ( bWrite )
  1686. {
  1687. status = RegCreateKeyExW(
  1688. HKEY_LOCAL_MACHINE,
  1689. pnameKey,
  1690. 0,
  1691. L"Class",
  1692. REG_OPTION_NON_VOLATILE,
  1693. KEY_WRITE,
  1694. NULL,
  1695. & hkey,
  1696. & disposition );
  1697. }
  1698. else
  1699. {
  1700. status = RegOpenKeyExW(
  1701. HKEY_LOCAL_MACHINE,
  1702. pnameKey,
  1703. 0,
  1704. KEY_QUERY_VALUE,
  1705. & hkey );
  1706. }
  1707. if ( status != ERROR_SUCCESS )
  1708. {
  1709. SetLastError( status );
  1710. }
  1711. ELSE_ASSERT( hkey != NULL );
  1712. return( hkey );
  1713. }
  1714. DNS_STATUS
  1715. WINAPI
  1716. Reg_SetDwordValueByName(
  1717. IN PVOID pReserved,
  1718. IN HKEY hRegKey,
  1719. IN PWSTR pwsNameKey, OPTIONAL
  1720. IN PWSTR pwsNameValue, OPTIONAL
  1721. IN DWORD dwValue
  1722. )
  1723. /*++
  1724. Routine Description:
  1725. Set DWORD regkey.
  1726. Arguments:
  1727. pReserved -- reserved (may become session)
  1728. hRegKey -- existing key to set under OPTIONAL
  1729. pwsNameKey -- name of key or adapter to set under
  1730. pwsNameValue -- name of reg value to set
  1731. dwValue -- value to set
  1732. Return Value:
  1733. ERROR_SUCCESS if successful.
  1734. ErrorCode on failure.
  1735. --*/
  1736. {
  1737. HKEY hkey;
  1738. DNS_STATUS status;
  1739. //
  1740. // don't bother for Win9x
  1741. //
  1742. #if DNSWIN9X
  1743. if ( g_IsWin9X )
  1744. {
  1745. ASSERT( FALSE );
  1746. return( ERROR_INVALID_PARAMETER );
  1747. }
  1748. #endif
  1749. //
  1750. // open key, if not provided
  1751. // - if adapter given, open under it
  1752. // - otherwise TCPIP params key
  1753. //
  1754. hkey = hRegKey;
  1755. if ( !hkey )
  1756. {
  1757. hkey = Reg_CreateKey(
  1758. pwsNameKey,
  1759. TRUE // open for write
  1760. );
  1761. if ( !hkey )
  1762. {
  1763. return( GetLastError() );
  1764. }
  1765. }
  1766. //
  1767. // write back value
  1768. //
  1769. status = RegSetValueExW(
  1770. hkey,
  1771. pwsNameValue,
  1772. 0,
  1773. REG_DWORD,
  1774. (LPBYTE) &dwValue,
  1775. sizeof(DWORD) );
  1776. if ( !hRegKey )
  1777. {
  1778. RegCloseKey( hkey );
  1779. }
  1780. return status;
  1781. }
  1782. DNS_STATUS
  1783. WINAPI
  1784. Reg_SetDwordValue(
  1785. IN PVOID pReserved,
  1786. IN HKEY hRegKey,
  1787. IN PWSTR pwsNameKey, OPTIONAL
  1788. IN DWORD RegId,
  1789. IN DWORD dwValue
  1790. )
  1791. /*++
  1792. Routine Description:
  1793. Set DWORD regkey.
  1794. Arguments:
  1795. pReserved -- reserved (may become session)
  1796. hRegKey -- existing key to set under OPTIONAL
  1797. pwsNameKey -- name of key or adapter to set under
  1798. RegId -- id of value to set
  1799. dwValue -- value to set
  1800. Return Value:
  1801. ERROR_SUCCESS if successful.
  1802. ErrorCode on failure.
  1803. --*/
  1804. {
  1805. //
  1806. // write back value using name of id
  1807. //
  1808. return Reg_SetDwordValueByName(
  1809. pReserved,
  1810. hRegKey,
  1811. pwsNameKey,
  1812. REGPROP_NAME( RegId ),
  1813. dwValue );
  1814. }
  1815. #if DNSWIN9X
  1816. //
  1817. // Removed with Win95 support
  1818. // Further Win95 support is doubtful -- but this works if needed.
  1819. //
  1820. //
  1821. // Registry shims
  1822. // Win9x in not providing wide reg calls.
  1823. //
  1824. PCHAR
  1825. standardWideToAnsiConvert(
  1826. IN PWSTR pWide,
  1827. OUT PCHAR pAnsiBuf
  1828. )
  1829. /*++
  1830. Routine Description:
  1831. Standard conversion of wide to narron for shimming registry calls.
  1832. Arguments:
  1833. pWide -- parameter in wide call
  1834. pAnsiBuf -- buffer to hold ANSI param; assumed to be max path
  1835. Return Value:
  1836. Ptr to converted buffer.
  1837. NULL if pWide NULL or error in conversion.
  1838. --*/
  1839. {
  1840. DWORD length;
  1841. DWORD result;
  1842. // no wide param, no ANSI param
  1843. if ( !pWide )
  1844. {
  1845. return NULL;
  1846. }
  1847. // copy\convert to ANSI buf
  1848. length = MAX_PATH;
  1849. result = Dns_StringCopy(
  1850. pAnsiBuf,
  1851. &length,
  1852. (PSTR) pWide,
  1853. 0, // calc length
  1854. DnsCharSetUnicode,
  1855. DnsCharSetAnsi
  1856. );
  1857. if ( result == 0 )
  1858. {
  1859. return( NULL );
  1860. }
  1861. else
  1862. {
  1863. return( pAnsiBuf );
  1864. }
  1865. }
  1866. //WINADVAPI
  1867. LONG
  1868. WINAPI
  1869. DnsShimRegCreateKeyExW(
  1870. IN HKEY hKey,
  1871. IN LPCWSTR lpSubKey,
  1872. IN DWORD Reserved,
  1873. IN LPWSTR lpClass,
  1874. IN DWORD dwOptions,
  1875. IN REGSAM samDesired,
  1876. IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  1877. OUT PHKEY phkResult,
  1878. OUT LPDWORD lpdwDisposition
  1879. )
  1880. /*++
  1881. Routine Description:
  1882. Shim RegCreateKeyExW()
  1883. Arguments:
  1884. See SDK doc.
  1885. Return Value:
  1886. ERROR_SUCCESS if successful.
  1887. Error code on failure.
  1888. --*/
  1889. {
  1890. // for NT it's a dumb stub
  1891. if ( !g_IsWin9X )
  1892. {
  1893. return RegCreateKeyExW(
  1894. hKey,
  1895. lpSubKey,
  1896. Reserved,
  1897. lpClass,
  1898. dwOptions,
  1899. samDesired,
  1900. lpSecurityAttributes,
  1901. phkResult,
  1902. lpdwDisposition );
  1903. }
  1904. // for Win9x, convert to ANSI and call
  1905. else
  1906. {
  1907. PCHAR pclass;
  1908. PCHAR psubKey;
  1909. CHAR class[ MAX_PATH ];
  1910. CHAR subKey[ MAX_PATH ];
  1911. psubKey = standardWideToAnsiConvert(
  1912. (PWSTR) lpSubKey,
  1913. subKey );
  1914. if ( !psubKey )
  1915. {
  1916. return ERROR_INVALID_PARAMETER;
  1917. }
  1918. pclass = standardWideToAnsiConvert(
  1919. (PWSTR) lpClass,
  1920. class );
  1921. return RegCreateKeyExA(
  1922. hKey,
  1923. (LPCSTR) psubKey,
  1924. Reserved,
  1925. pclass,
  1926. dwOptions,
  1927. samDesired,
  1928. lpSecurityAttributes,
  1929. phkResult,
  1930. lpdwDisposition );
  1931. }
  1932. }
  1933. //WINADVAPI
  1934. LONG
  1935. WINAPI
  1936. DnsShimRegOpenKeyExW(
  1937. IN HKEY hKey,
  1938. IN LPCWSTR lpSubKey,
  1939. IN DWORD dwOptions,
  1940. IN REGSAM samDesired,
  1941. OUT PHKEY phkResult
  1942. )
  1943. /*++
  1944. Routine Description:
  1945. Shim RegOpenKeyExW()
  1946. Arguments:
  1947. See SDK doc.
  1948. Return Value:
  1949. ERROR_SUCCESS if successful.
  1950. Error code on failure.
  1951. --*/
  1952. {
  1953. // for NT it's a dumb stub
  1954. if ( !g_IsWin9X )
  1955. {
  1956. return RegOpenKeyExW(
  1957. hKey,
  1958. lpSubKey,
  1959. dwOptions,
  1960. samDesired,
  1961. phkResult );
  1962. }
  1963. // for Win9x, convert to ANSI and call
  1964. else
  1965. {
  1966. PCHAR psubKey;
  1967. CHAR subKey[ MAX_PATH ];
  1968. psubKey = standardWideToAnsiConvert(
  1969. (PWSTR) lpSubKey,
  1970. subKey );
  1971. return RegOpenKeyExA(
  1972. hKey,
  1973. (LPCSTR) psubKey,
  1974. dwOptions,
  1975. samDesired,
  1976. phkResult );
  1977. }
  1978. }
  1979. LONG
  1980. WINAPI
  1981. DnsShimRegQueryValueExW(
  1982. IN HKEY hKey,
  1983. IN LPCWSTR lpValueName,
  1984. IN LPDWORD lpReserved,
  1985. IN LPDWORD lpType,
  1986. IN LPBYTE lpData,
  1987. IN LPDWORD lpcbData
  1988. )
  1989. /*++
  1990. Routine Description:
  1991. Shim RegQueryValueExW()
  1992. Arguments:
  1993. See SDK doc.
  1994. Return Value:
  1995. ERROR_SUCCESS if successful.
  1996. Error code on failure.
  1997. --*/
  1998. {
  1999. // for NT it's a dumb stub
  2000. if ( !g_IsWin9X )
  2001. {
  2002. return RegQueryValueExW(
  2003. hKey,
  2004. lpValueName,
  2005. lpReserved,
  2006. lpType,
  2007. lpData,
  2008. lpcbData );
  2009. }
  2010. // for Win9x, convert to ANSI and call
  2011. else
  2012. {
  2013. LONG status;
  2014. DWORD type = 0;
  2015. DWORD length = 0;
  2016. PDWORD plength = &length;
  2017. PCHAR pvalueName;
  2018. CHAR valueName[ MAX_PATH ];
  2019. // convert value name
  2020. pvalueName = standardWideToAnsiConvert(
  2021. (PWSTR) lpValueName,
  2022. valueName );
  2023. // use start length
  2024. if ( lpcbData )
  2025. {
  2026. length = *lpcbData;
  2027. plength = NULL;
  2028. }
  2029. // make ANSI call
  2030. status = RegQueryValueExA(
  2031. hKey,
  2032. pvalueName,
  2033. lpReserved,
  2034. & type,
  2035. lpData,
  2036. plength );
  2037. // return type
  2038. if ( lpType )
  2039. {
  2040. *lpType = type;
  2041. }
  2042. //
  2043. // setup length\data return
  2044. // - no length call => just status
  2045. // - no data return or non-string data => set length
  2046. // - string data => convert
  2047. //
  2048. if ( !lpcbData )
  2049. {
  2050. // no-op, this kind of call just gets status
  2051. }
  2052. //
  2053. // no data conversion -- set length
  2054. // - unicode length required at twice ANSI length
  2055. // - DWORD and binary length unchanged
  2056. else if ( !lpData ||
  2057. status != ERROR_SUCCESS ||
  2058. type == REG_DWORD ||
  2059. type == REG_BINARY )
  2060. {
  2061. if ( type == REG_DWORD || type == REG_BINARY )
  2062. {
  2063. *lpcbData = length;
  2064. }
  2065. else
  2066. {
  2067. *lpcbData = length * 2;
  2068. }
  2069. }
  2070. //
  2071. // convert ANSI data to unicode
  2072. //
  2073. else
  2074. {
  2075. PBYTE pdataUnicode;
  2076. DWORD unicodeLength;
  2077. pdataUnicode = (PBYTE) ALLOCATE_HEAP( *lpcbData );
  2078. if ( !pdataUnicode )
  2079. {
  2080. return( DNS_ERROR_NO_MEMORY );
  2081. }
  2082. unicodeLength = Dns_StringCopy(
  2083. pdataUnicode,
  2084. lpcbData,
  2085. lpData, // ANSI data
  2086. length, // ANSI length
  2087. DnsCharSetAnsi,
  2088. DnsCharSetUnicode );
  2089. if ( unicodeLength == 0 )
  2090. {
  2091. status = GetLastError();
  2092. ASSERT( status != ERROR_SUCCESS );
  2093. unicodeLength = length * 2;
  2094. }
  2095. *lpcbData = unicodeLength;
  2096. FREE_HEAP( pdataUnicode );
  2097. }
  2098. return( status );
  2099. }
  2100. }
  2101. #endif // Win95 registry shims
  2102. //
  2103. // End registry.c
  2104. //