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.

2032 lines
62 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. Registry.c
  5. Abstract:
  6. This contains all routines necessary to load device pathnames from the
  7. registry.
  8. Author:
  9. Jim Stewart (Jimst) October 9 1992
  10. Revision History:
  11. Jiandong Ruan (jruan) April 6 2000 Add NbtReadRegistryCleanup
  12. Notes:
  13. --*/
  14. #include "precomp.h"
  15. //
  16. // Local functions used to access the registry.
  17. //
  18. NTSTATUS
  19. NbtOpenRegistry(
  20. IN HANDLE NbConfigHandle,
  21. IN PWSTR String,
  22. OUT PHANDLE pHandle
  23. );
  24. VOID
  25. NbtCloseRegistry(
  26. IN HANDLE LinkageHandle,
  27. IN HANDLE ParametersHandle
  28. );
  29. NTSTATUS
  30. NbtReadLinkageInformation(
  31. IN PWSTR pName,
  32. IN HANDLE LinkageHandle,
  33. IN ULONG MaxBindings,
  34. OUT tDEVICES *pDevices, // place to put read in config data
  35. OUT ULONG *pNumDevices
  36. );
  37. NTSTATUS
  38. OpenAndReadElement(
  39. IN PUNICODE_STRING pucRootPath,
  40. IN PWSTR pwsValueName,
  41. OUT PUNICODE_STRING pucString
  42. );
  43. NTSTATUS
  44. GetIpAddressesList (
  45. IN HANDLE ParametersHandle,
  46. IN PWSTR pwsKeyName,
  47. IN ULONG MaxAddresses,
  48. OUT tIPADDRESS *pAddrArray,
  49. OUT ULONG *pNumGoodAddresses
  50. );
  51. NTSTATUS
  52. GetServerAddress (
  53. IN HANDLE ParametersHandle,
  54. IN PWSTR KeyName,
  55. OUT PULONG pIpAddr
  56. );
  57. NTSTATUS
  58. NbtAppendString (
  59. IN PWSTR FirstString,
  60. IN PWSTR SecondString,
  61. OUT PUNICODE_STRING pucString
  62. );
  63. NTSTATUS
  64. ReadStringRelative(
  65. IN PUNICODE_STRING pRegistryPath,
  66. IN PWSTR pRelativePath,
  67. IN PWSTR pValueName,
  68. OUT PUNICODE_STRING pOutString
  69. );
  70. VOID
  71. NbtFindLastSlash(
  72. IN PUNICODE_STRING pucRegistryPath,
  73. OUT PWSTR *ppucLastElement,
  74. IN int *piLength
  75. );
  76. NTSTATUS
  77. ReadSmbDeviceInfo(
  78. IN HANDLE NbConfigHandle
  79. );
  80. //******************* Pageable Routine Declarations ****************
  81. #ifdef ALLOC_PRAGMA
  82. #pragma CTEMakePageable(PAGE, NbtReadRegistry)
  83. #pragma CTEMakePageable(PAGE, NbtReadRegistryCleanup)
  84. #pragma CTEMakePageable(PAGE, ReadNameServerAddresses)
  85. #pragma CTEMakePageable(PAGE, GetIpAddressesList)
  86. #pragma CTEMakePageable(PAGE, GetServerAddress)
  87. #pragma CTEMakePageable(PAGE, NTReadIniString)
  88. #pragma CTEMakePageable(PAGE, GetIPFromRegistry)
  89. #pragma CTEMakePageable(PAGE, NbtOpenRegistry)
  90. #pragma CTEMakePageable(PAGE, NbtParseMultiSzEntries)
  91. #pragma CTEMakePageable(PAGE, NbtReadLinkageInformation)
  92. #pragma CTEMakePageable(PAGE, NbtReadSingleParameter)
  93. #pragma CTEMakePageable(PAGE, OpenAndReadElement)
  94. #pragma CTEMakePageable(PAGE, ReadElement)
  95. #pragma CTEMakePageable(PAGE, NTGetLmHostPath)
  96. #pragma CTEMakePageable(PAGE, ReadStringRelative)
  97. #pragma CTEMakePageable(PAGE, NbtFindLastSlash)
  98. #pragma CTEMakePageable(PAGE, ReadSmbDeviceInfo)
  99. #endif
  100. //******************* Pageable Routine Declarations ****************
  101. //----------------------------------------------------------------------------
  102. NTSTATUS
  103. NbtReadRegistry(
  104. OUT tDEVICES **ppBindDevices,
  105. OUT tDEVICES **ppExportDevices,
  106. OUT tADDRARRAY **ppAddrArray
  107. )
  108. /*++
  109. Routine Description:
  110. This routine is called to get information from the registry,
  111. starting at RegistryPath to get the parameters.
  112. This routine must be called with the NbtConfig.Resource lock HELD
  113. Arguments:
  114. Before calling this routine, the following Global parameters
  115. must have been initialized (in DriverEntry):
  116. NbtConfig.pRegistry
  117. Return Value:
  118. NTSTATUS - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
  119. otherwise.
  120. --*/
  121. {
  122. NTSTATUS OpenStatus;
  123. HANDLE LinkageHandle;
  124. HANDLE ParametersHandle;
  125. HANDLE NbtConfigHandle;
  126. NTSTATUS Status;
  127. ULONG Disposition;
  128. OBJECT_ATTRIBUTES TmpObjectAttributes;
  129. PWSTR LinkageString = L"Linkage";
  130. PWSTR ParametersString = L"Parameters";
  131. tDEVICES *pBindDevices;
  132. tDEVICES *pExportDevices;
  133. UNICODE_STRING ucString;
  134. ULONG NumBindings;
  135. CTEPagedCode();
  136. *ppExportDevices = *ppBindDevices = NULL;
  137. *ppAddrArray = NULL;
  138. //
  139. // Open the registry.
  140. //
  141. InitializeObjectAttributes (&TmpObjectAttributes,
  142. &NbtConfig.pRegistry, // name
  143. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
  144. NULL, // root
  145. NULL); // security descriptor
  146. Status = ZwCreateKey (&NbtConfigHandle,
  147. KEY_READ,
  148. &TmpObjectAttributes,
  149. 0, // title index
  150. NULL, // class
  151. 0, // create options
  152. &Disposition); // disposition
  153. if (!NT_SUCCESS(Status))
  154. {
  155. KdPrint (("Nbt.NbtReadRegistry: ZwCreateKey FAILed, status=<%x>\n", Status));
  156. NbtLogEvent (EVENT_NBT_CREATE_DRIVER, Status, 0x114);
  157. return STATUS_UNSUCCESSFUL;
  158. }
  159. OpenStatus = NbtOpenRegistry (NbtConfigHandle, LinkageString, &LinkageHandle);
  160. if (NT_SUCCESS(OpenStatus))
  161. {
  162. OpenStatus = NbtOpenRegistry (NbtConfigHandle, ParametersString, &ParametersHandle);
  163. if (NT_SUCCESS(OpenStatus))
  164. {
  165. //
  166. // Read in the binding information (if none is present
  167. // the array will be filled with all known drivers).
  168. //
  169. if (pBindDevices = NbtAllocMem ((sizeof(tDEVICES)+2*NBT_MAXIMUM_BINDINGS*sizeof(UNICODE_STRING)),
  170. NBT_TAG2('25')))
  171. {
  172. if (pExportDevices=NbtAllocMem((sizeof(tDEVICES)+2*NBT_MAXIMUM_BINDINGS*sizeof(UNICODE_STRING)),
  173. NBT_TAG2('26')))
  174. {
  175. ReadParameters (&NbtConfig, ParametersHandle);// Read various parameters from the registry
  176. ReadSmbDeviceInfo (NbtConfigHandle); // Set the information for the SmbDevice
  177. //
  178. // From now on, the only failures we can encounter are in reading the
  179. // Bind, Export or Name Server address entries, hence if we fail here,
  180. // we will still return success, but will assume 0 devices configured!
  181. //
  182. pBindDevices->RegistryData = pExportDevices->RegistryData = NULL;
  183. Status = NbtReadLinkageInformation (NBT_BIND,
  184. LinkageHandle,
  185. 2*NBT_MAXIMUM_BINDINGS,
  186. pBindDevices,
  187. &NumBindings);
  188. if (!NT_SUCCESS(Status))
  189. {
  190. KdPrint (("Nbt.NbtReadRegistry: NbtReadLinkageInformation FAILed - BIND <%x>\n",
  191. Status));
  192. NbtLogEvent (EVENT_NBT_READ_BIND, Status, 0x115);
  193. }
  194. else // if (NT_SUCCESS(Status))
  195. {
  196. IF_DBG(NBT_DEBUG_NTUTIL)
  197. KdPrint(("Binddevice = %ws\n",pBindDevices->Names[0].Buffer));
  198. NbtConfig.uNumDevicesInRegistry = (USHORT) NumBindings;
  199. NumBindings = 0;
  200. // Read the EXPORT information as well.
  201. Status = NbtReadLinkageInformation (NBT_EXPORT,
  202. LinkageHandle,
  203. 2*NBT_MAXIMUM_BINDINGS,
  204. pExportDevices,
  205. &NumBindings);
  206. if (NT_SUCCESS(Status))
  207. {
  208. // we want the lowest number for num devices in case there
  209. // are more bindings than exports or viceversa
  210. //
  211. // ASSERT (NumBindings == NbtConfig.uNumDevicesInRegistry);
  212. NbtConfig.uNumDevicesInRegistry = (USHORT)
  213. (NbtConfig.uNumDevicesInRegistry > NumBindings ?
  214. NumBindings : NbtConfig.uNumDevicesInRegistry);
  215. if (NbtConfig.uNumDevicesInRegistry == 0)
  216. {
  217. KdPrint (("Nbt.NbtReadRegistry: WARNING - NumDevicesInRegistry = 0\n"));
  218. }
  219. }
  220. else
  221. {
  222. KdPrint (("Nbt.NbtReadRegistry: NbtReadLinkageInformation FAILed - EXPORT <%x>\n",
  223. Status));
  224. NbtLogEvent (EVENT_NBT_READ_EXPORT, Status, 0x116);
  225. }
  226. }
  227. if ((NT_SUCCESS(Status)) &&
  228. (NbtConfig.uNumDevicesInRegistry))
  229. {
  230. IF_DBG(NBT_DEBUG_NTUTIL)
  231. KdPrint(("Exportdevice = %ws\n",pExportDevices->Names[0].Buffer));
  232. //
  233. // read in the NameServer IP address now
  234. //
  235. Status = ReadNameServerAddresses (NbtConfigHandle,
  236. pBindDevices,
  237. NbtConfig.uNumDevicesInRegistry,
  238. ppAddrArray);
  239. if (!NT_SUCCESS(Status))
  240. {
  241. if (!(NodeType & BNODE)) // Post Warning!
  242. {
  243. NbtLogEvent (EVENT_NBT_NAME_SERVER_ADDRS, Status, 0x118);
  244. }
  245. KdPrint(("Nbt.NbtReadRegistry: ReadNameServerAddresses returned <%x>\n", Status));
  246. }
  247. else // if (NT_SUCCESS(Status))
  248. {
  249. //
  250. // check if any WINS servers have been configured change
  251. // to Hnode
  252. //
  253. if (NodeType & (BNODE | DEFAULT_NODE_TYPE))
  254. {
  255. ULONG i;
  256. for (i=0; i<NbtConfig.uNumDevicesInRegistry; i++)
  257. {
  258. if (((*ppAddrArray)[i].NameServerAddress != LOOP_BACK) ||
  259. ((*ppAddrArray)[i].BackupServer != LOOP_BACK))
  260. {
  261. NodeType = MSNODE | (NodeType & PROXY);
  262. break;
  263. }
  264. }
  265. }
  266. }
  267. }
  268. if ((!NT_SUCCESS(Status)) ||
  269. (0 == NbtConfig.uNumDevicesInRegistry))
  270. {
  271. //
  272. // We had problems reading the Bind or Export or Address entries
  273. //
  274. if (pBindDevices->RegistryData)
  275. {
  276. CTEMemFree(pBindDevices->RegistryData);
  277. }
  278. CTEMemFree(pBindDevices);
  279. if (pExportDevices->RegistryData)
  280. {
  281. CTEMemFree(pExportDevices->RegistryData);
  282. }
  283. CTEMemFree(pExportDevices);
  284. pBindDevices = pExportDevices = NULL;
  285. NbtConfig.uNumDevicesInRegistry = 0;
  286. Status = STATUS_SUCCESS;
  287. }
  288. //
  289. // we have done the check for default node so turn off
  290. // the flag
  291. //
  292. NodeType &= ~DEFAULT_NODE_TYPE;
  293. //
  294. // A Bnode cannot be a proxy too
  295. //
  296. if (NodeType & BNODE)
  297. {
  298. if (NodeType & PROXY)
  299. {
  300. NodeType &= ~PROXY;
  301. }
  302. }
  303. // keep the size around for allocating memory, so that when we run over
  304. // OSI, only this value should change (in theory at least)
  305. NbtConfig.SizeTransportAddress = sizeof(TDI_ADDRESS_IP);
  306. // fill in the node type value that is put into all name service Pdus
  307. // that go out identifying this node type
  308. switch (NodeType & NODE_MASK)
  309. {
  310. case BNODE:
  311. NbtConfig.PduNodeType = 0;
  312. break;
  313. case PNODE:
  314. NbtConfig.PduNodeType = 1 << 13;
  315. break;
  316. case MNODE:
  317. NbtConfig.PduNodeType = 1 << 14;
  318. break;
  319. case MSNODE:
  320. NbtConfig.PduNodeType = 3 << 13;
  321. break;
  322. }
  323. // read the name of the transport to bind to
  324. //
  325. if (NT_SUCCESS(ReadElement(ParametersHandle, WS_TRANSPORT_BIND_NAME, &ucString)))
  326. {
  327. UNICODE_STRING StreamsString;
  328. //
  329. // if there is already a bind string, free it before
  330. // allocating another
  331. //
  332. if (NbtConfig.pTcpBindName)
  333. {
  334. //
  335. // CreateDeviceString in tdicnct.c could access the pTcpBindName right
  336. // after it is freed. The right way is using a lock. But, ...
  337. //
  338. // Hack!!!:
  339. // Although this doesn't completely fix the problem, it has the minimum
  340. // side-effect.
  341. //
  342. // The value of WS_TRANSPORT_BIND_NAME won't change. By doing this,
  343. // we avoid the possible access-after-free problem in most cases.
  344. //
  345. RtlInitUnicodeString(&StreamsString, NbtConfig.pTcpBindName);
  346. if (RtlCompareUnicodeString(&ucString,&StreamsString,TRUE)) {
  347. CTEMemFree(NbtConfig.pTcpBindName);
  348. NbtConfig.pTcpBindName = ucString.Buffer;
  349. } else {
  350. CTEMemFree(ucString.Buffer);
  351. ucString = StreamsString;
  352. }
  353. } else {
  354. NbtConfig.pTcpBindName = ucString.Buffer;
  355. }
  356. // ********** REMOVE LATER ***********
  357. RtlInitUnicodeString(&StreamsString,NBT_TCP_BIND_NAME);
  358. if (RtlCompareUnicodeString(&ucString,&StreamsString,TRUE))
  359. {
  360. StreamsStack = FALSE;
  361. }
  362. else
  363. {
  364. StreamsStack = TRUE;
  365. }
  366. }
  367. else
  368. {
  369. StreamsStack = TRUE;
  370. }
  371. ZwClose(ParametersHandle);
  372. ZwClose(LinkageHandle);
  373. ZwClose(NbtConfigHandle);
  374. *ppExportDevices = pExportDevices;
  375. *ppBindDevices = pBindDevices;
  376. return (Status);
  377. }
  378. else
  379. {
  380. KdPrint (("Nbt.NbtReadRegistry: FAILed to allocate pExportDevices\n"));
  381. }
  382. CTEMemFree(pBindDevices);
  383. }
  384. else
  385. {
  386. KdPrint (("Nbt.NbtReadRegistry: FAILed to allocate pBindDevices\n"));
  387. }
  388. ZwClose(ParametersHandle);
  389. }
  390. else
  391. {
  392. KdPrint (("Nbt.NbtReadRegistry: NbtOpenRegistry FAILed for PARAMETERS, status=<%x>\n", Status));
  393. NbtLogEvent (EVENT_NBT_OPEN_REG_PARAMS, OpenStatus, 0x119);
  394. }
  395. ZwClose(LinkageHandle);
  396. }
  397. else
  398. {
  399. KdPrint (("Nbt.NbtReadRegistry: NbtOpenRegistry FAILed for LINKAGE, status=<%x>\n", Status));
  400. NbtLogEvent (EVENT_NBT_OPEN_REG_LINKAGE, OpenStatus, 0x120);
  401. }
  402. ZwClose (NbtConfigHandle);
  403. return STATUS_UNSUCCESSFUL;
  404. }
  405. //----------------------------------------------------------------------------
  406. VOID
  407. NbtReadRegistryCleanup(
  408. IN tDEVICES **ppBindDevices,
  409. IN tDEVICES **ppExportDevices,
  410. IN tADDRARRAY **ppAddrArray
  411. )
  412. /*++
  413. Routine Description:
  414. This routine is called to release resources allocated by NbtReadRegistry
  415. ++*/
  416. {
  417. CTEPagedCode();
  418. if (ppBindDevices[0]) {
  419. CTEMemFree((PVOID)ppBindDevices[0]->RegistryData);
  420. CTEMemFree((PVOID)ppBindDevices[0]);
  421. ppBindDevices[0] = NULL;
  422. }
  423. if (ppExportDevices[0]) {
  424. CTEMemFree((PVOID)ppExportDevices[0]->RegistryData);
  425. CTEMemFree((PVOID)ppExportDevices[0]);
  426. ppExportDevices[0] = NULL;
  427. }
  428. if (ppAddrArray[0]) {
  429. CTEMemFree((PVOID)ppAddrArray[0]);
  430. ppAddrArray[0] = NULL;
  431. }
  432. }
  433. NTSTATUS
  434. ReadSmbDeviceInfo(
  435. IN HANDLE NbtConfigHandle
  436. )
  437. {
  438. HANDLE SmbHandle;
  439. NTSTATUS Status;
  440. CTEPagedCode();
  441. Status = NbtOpenRegistry (NbtConfigHandle, WC_SMB_PARAMETERS_LOCATION, &SmbHandle);
  442. if (NT_SUCCESS(Status))
  443. {
  444. NbtConfig.DefaultSmbSessionPort = (USHORT) CTEReadSingleIntParameter (SmbHandle,
  445. SESSION_PORT,
  446. NBT_SMB_SESSION_TCP_PORT,
  447. 1);
  448. NbtConfig.DefaultSmbDatagramPort = (USHORT) CTEReadSingleIntParameter (SmbHandle,
  449. DATAGRAM_PORT,
  450. NBT_SMB_DATAGRAM_UDP_PORT,
  451. 1);
  452. ZwClose (SmbHandle);
  453. }
  454. else
  455. {
  456. NbtConfig.DefaultSmbSessionPort = NBT_SMB_SESSION_TCP_PORT;
  457. NbtConfig.DefaultSmbDatagramPort = NBT_SMB_DATAGRAM_UDP_PORT;
  458. }
  459. return (Status);
  460. }
  461. //----------------------------------------------------------------------------
  462. NTSTATUS
  463. ReadNameServerAddresses (
  464. IN HANDLE NbtConfigHandle,
  465. IN tDEVICES *BindDevices,
  466. IN ULONG NumberDevices,
  467. OUT tADDRARRAY **ppAddrArray
  468. )
  469. /*++
  470. Routine Description:
  471. This routine is called to read the name server addresses from the registry.
  472. It stores them in a data structure that it allocates. This memory is
  473. subsequently freed in driver.c when the devices have been created.
  474. Arguments:
  475. ConfigurationInfo - A pointer to the configuration information structure.
  476. Return Value:
  477. None.
  478. --*/
  479. {
  480. #define ADAPTER_SIZE_MAX 400
  481. UNICODE_STRING ucString;
  482. NTSTATUS status = STATUS_UNSUCCESSFUL;
  483. HANDLE Handle;
  484. LONG i,j,Len;
  485. PWSTR pwsAdapter = L"Parameters\\Interfaces\\";
  486. PWSTR BackSlash = L"\\";
  487. tADDRARRAY *pAddrArray;
  488. ULONG LenAdapter;
  489. #ifdef _NETBIOSLESS
  490. ULONG Options;
  491. #endif
  492. ULONG NumNameServerAddresses = 0;
  493. CTEPagedCode();
  494. *ppAddrArray = NULL;
  495. // this is large enough for 400 characters of adapter name.
  496. ucString.Buffer = NbtAllocMem (ADAPTER_SIZE_MAX, NBT_TAG2('27'));
  497. if (!ucString.Buffer)
  498. {
  499. return(STATUS_INSUFFICIENT_RESOURCES);
  500. }
  501. pAddrArray = NbtAllocMem (sizeof(tADDRARRAY)*NumberDevices, NBT_TAG2('28'));
  502. if (!pAddrArray)
  503. {
  504. CTEMemFree(ucString.Buffer);
  505. return(STATUS_INSUFFICIENT_RESOURCES);
  506. }
  507. CTEZeroMemory(pAddrArray,sizeof(tADDRARRAY)*NumberDevices);
  508. *ppAddrArray = pAddrArray;
  509. // get the adapter name out of the Bind string, and use it to open
  510. // a key by the same name, to get the name server addresses
  511. //
  512. for (i = 0;i < (LONG)NumberDevices ;i ++ )
  513. {
  514. WCHAR *pBuffer;
  515. Len = BindDevices->Names[i].Length/sizeof(WCHAR);
  516. Len--;
  517. //
  518. // start at the end a work backwards looking for a '\'
  519. //
  520. j = Len;
  521. pBuffer = &BindDevices->Names[i].Buffer[j];
  522. while (j)
  523. {
  524. if (*pBuffer != *BackSlash)
  525. {
  526. j--;
  527. pBuffer--;
  528. }
  529. else
  530. break;
  531. }
  532. // if we don't find a backslash or at least one
  533. // character name then continue around again, or the name
  534. // is longer than the buffer, then go to the next device in the
  535. // bind list
  536. //
  537. if ((j == 0) ||
  538. (j == Len) ||
  539. (j == Len -1) ||
  540. ((Len - j) > ADAPTER_SIZE_MAX))
  541. {
  542. continue;
  543. }
  544. // copy the string "Adapter\" to the buffer since the adapters all
  545. // appear under this key in the registery
  546. //
  547. LenAdapter = wcslen(pwsAdapter);
  548. CTEMemCopy(ucString.Buffer, pwsAdapter, LenAdapter*sizeof(WCHAR));
  549. //
  550. // copy just the adapter name from the Bind string, since that is
  551. // the name of the key to open to find the name server ip addresses
  552. //
  553. CTEMemCopy(&ucString.Buffer[LenAdapter], ++pBuffer, (Len - j)*sizeof(WCHAR));
  554. ucString.Buffer[Len - j + LenAdapter] = 0;
  555. pAddrArray->NameServerAddress = LOOP_BACK;
  556. pAddrArray->BackupServer = LOOP_BACK;
  557. #ifdef MULTIPLE_WINS
  558. pAddrArray->Others[0] = LOOP_BACK; // For Safety
  559. pAddrArray->NumOtherServers = 0;
  560. pAddrArray->LastResponsive = 0;
  561. #endif
  562. status = NbtOpenRegistry (NbtConfigHandle, ucString.Buffer, &Handle);
  563. if (NT_SUCCESS(status))
  564. {
  565. status = GetIpAddressesList(Handle, // Generic routine to read in list of Ip addresses
  566. PWS_NAME_SERVER_LIST,
  567. 2+MAX_NUM_OTHER_NAME_SERVERS,
  568. pAddrArray->AllNameServers,
  569. &NumNameServerAddresses);
  570. if (!NT_SUCCESS(status) ||
  571. (pAddrArray->NameServerAddress == LOOP_BACK))
  572. {
  573. NumNameServerAddresses = 0;
  574. status = GetIpAddressesList(Handle,
  575. PWS_DHCP_NAME_SERVER_LIST,
  576. 2+MAX_NUM_OTHER_NAME_SERVERS,
  577. pAddrArray->AllNameServers,
  578. &NumNameServerAddresses);
  579. }
  580. //
  581. // Continue even if we failed to read in any IP addresses
  582. //
  583. if (NumNameServerAddresses > 2)
  584. {
  585. pAddrArray->NumOtherServers = (USHORT) NumNameServerAddresses - 2;
  586. }
  587. #ifdef _NETBIOSLESS
  588. // NbtReadSingle doesn't quite do what we want. In this case, if the non-dhcp-
  589. // decorated option is present but zero, we DO want to go on to the dhcp-
  590. // decorated one. So, try the dhcp-decorated one explicitly if we get back zero.
  591. Options = NbtReadSingleParameter( Handle, PWS_NETBIOS_OPTIONS, 0, 0 );
  592. if (Options == 0)
  593. {
  594. Options = NbtReadSingleParameter( Handle, PWS_DHCP_NETBIOS_OPTIONS, 0, 0 );
  595. }
  596. // Options is encoded as four bytes
  597. // Each byte can be an independent set of flags
  598. // The high order three bytes can be used for controlling other aspects
  599. // Enabled option, default is TRUE
  600. pAddrArray->NetbiosEnabled = ((Options & 0xff) != NETBT_MODE_NETBIOS_DISABLED);
  601. #endif
  602. pAddrArray->RasProxyFlags = NbtReadSingleParameter(Handle, PWS_RAS_PROXY_FLAGS, 0, 0);
  603. pAddrArray->EnableNagling = (NbtReadSingleParameter(Handle, PWS_ENABLE_NAGLING, 0, 0) != FALSE);
  604. // don't want to fail this routine just because the
  605. // name server address was not set
  606. status = STATUS_SUCCESS;
  607. ZwClose(Handle);
  608. }
  609. pAddrArray++;
  610. }
  611. CTEMemFree(ucString.Buffer);
  612. return(STATUS_SUCCESS);
  613. }
  614. //----------------------------------------------------------------------------
  615. NTSTATUS
  616. GetIpAddressesList (
  617. IN HANDLE ParametersHandle,
  618. IN PWSTR pwsKeyName,
  619. IN ULONG MaxAddresses,
  620. OUT tIPADDRESS *pAddrArray,
  621. OUT ULONG *pNumGoodAddresses
  622. )
  623. /*++
  624. Routine Description:
  625. This routine is called to read a list of Ip addresses from the registry.
  626. Arguments:
  627. Return Value:
  628. None.
  629. --*/
  630. {
  631. ULONG NumEntriesRead, NumGoodAddresses, NumAddressesAttempted;
  632. tDEVICES *pucAddressList;
  633. NTSTATUS Status;
  634. STRING String;
  635. ULONG IpAddr;
  636. PWSTR DhcpName = L"Dhcp";
  637. UNICODE_STRING DhcpKeyName;
  638. CTEPagedCode();
  639. pucAddressList=NbtAllocMem((sizeof(tDEVICES)+2*NBT_MAXIMUM_BINDINGS*sizeof(UNICODE_STRING)),NBT_TAG('i'));
  640. if (!pucAddressList)
  641. {
  642. return STATUS_INSUFFICIENT_RESOURCES;
  643. }
  644. //
  645. // Since NbtReadLinkageInformation very conveniently reads in the values for
  646. // a MULTI_SZ registry entry, we will re-use this function here!
  647. //
  648. //
  649. NumEntriesRead = 0;
  650. Status = NbtReadLinkageInformation (pwsKeyName,
  651. ParametersHandle,
  652. 2*NBT_MAXIMUM_BINDINGS,
  653. pucAddressList,
  654. &NumEntriesRead);
  655. if ((STATUS_ILL_FORMED_SERVICE_ENTRY == Status) || (!NT_SUCCESS(Status)))
  656. {
  657. IF_DBG(NBT_DEBUG_NTUTIL)
  658. KdPrint(("GetIpAddressesList: ERROR -- NbtReadLinkageInformation=<%x>, <%ws>\n",
  659. Status, pwsKeyName));
  660. CTEMemFree(pucAddressList);
  661. return STATUS_UNSUCCESSFUL;
  662. }
  663. String.Buffer = NbtAllocMem (REGISTRY_BUFF_SIZE, NBT_TAG2('29'));
  664. if (!String.Buffer)
  665. {
  666. KdPrint(("GetNameServerAddresses: Failed to Allocate memory\n"));
  667. CTEMemFree((PVOID)pucAddressList->RegistryData);
  668. CTEMemFree(pucAddressList);
  669. return STATUS_INSUFFICIENT_RESOURCES;
  670. }
  671. String.MaximumLength = REGISTRY_BUFF_SIZE;
  672. //
  673. // NumGoodAddresses will be bound by MaxAddresses, while
  674. // NumAddressesAttempted will be bound by NumEntriesRead
  675. // Also, we could have read NumEntriesRead > MaxAddresses
  676. // (some of the entries could be invalid), but we will not
  677. // attempt to read > 2*MaxAddresses entires
  678. //
  679. NumGoodAddresses = 0;
  680. NumAddressesAttempted = 0;
  681. while ((NumGoodAddresses < MaxAddresses) &&
  682. (NumAddressesAttempted < NumEntriesRead) &&
  683. (NumAddressesAttempted < (2*MaxAddresses)))
  684. {
  685. Status = RtlUnicodeStringToAnsiString(&String, &pucAddressList->Names[NumAddressesAttempted], FALSE);
  686. if (NT_SUCCESS(Status))
  687. {
  688. Status = ConvertDottedDecimalToUlong((PUCHAR) String.Buffer, &IpAddr);
  689. if (NT_SUCCESS(Status) && IpAddr)
  690. {
  691. pAddrArray[NumGoodAddresses++] = IpAddr;
  692. }
  693. }
  694. NumAddressesAttempted++;
  695. }
  696. CTEMemFree ((PVOID)String.Buffer);
  697. CTEMemFree ((PVOID)pucAddressList->RegistryData);
  698. CTEMemFree ((PVOID)pucAddressList);
  699. //
  700. // If we were able to read in at least 1 good Ip address,
  701. // return success, otherwise return failure!
  702. //
  703. if (NumGoodAddresses)
  704. {
  705. Status = STATUS_SUCCESS;
  706. }
  707. else
  708. {
  709. Status = STATUS_INVALID_ADDRESS;
  710. }
  711. *pNumGoodAddresses = NumGoodAddresses;
  712. return(Status);
  713. }
  714. NTSTATUS
  715. GetServerAddress (
  716. IN HANDLE ParametersHandle,
  717. IN PWSTR KeyName,
  718. OUT PULONG pIpAddr
  719. )
  720. /*++
  721. Routine Description:
  722. This routine is called to read the name server addresses from the registry.
  723. Arguments:
  724. ConfigurationInfo - A pointer to the configuration information structure.
  725. Return Value:
  726. None.
  727. --*/
  728. {
  729. NTSTATUS status;
  730. ULONG IpAddr;
  731. PUCHAR NameServer;
  732. CTEPagedCode();
  733. status = CTEReadIniString(ParametersHandle,KeyName,&NameServer);
  734. if (NT_SUCCESS(status))
  735. {
  736. status = ConvertDottedDecimalToUlong(NameServer,&IpAddr);
  737. if (NT_SUCCESS(status) && IpAddr)
  738. {
  739. *pIpAddr = IpAddr;
  740. }
  741. else
  742. {
  743. if (IpAddr != 0)
  744. {
  745. NbtLogEvent (EVENT_NBT_BAD_PRIMARY_WINS_ADDR, 0, 0x121);
  746. }
  747. *pIpAddr = LOOP_BACK;
  748. }
  749. CTEMemFree((PVOID)NameServer);
  750. }
  751. else
  752. {
  753. *pIpAddr = LOOP_BACK;
  754. }
  755. return(status);
  756. }
  757. //----------------------------------------------------------------------------
  758. NTSTATUS
  759. NbtAppendString (
  760. IN PWSTR FirstString,
  761. IN PWSTR SecondString,
  762. OUT PUNICODE_STRING pucString
  763. )
  764. /*++
  765. Routine Description:
  766. This routine is called to append the second string to the first string.
  767. It allocates memory for this, so the caller must be sure to free it.
  768. Arguments:
  769. Return Value:
  770. None.
  771. --*/
  772. {
  773. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  774. ULONG Length;
  775. PWSTR pDhcpKeyName;
  776. CTEPagedCode();
  777. Length = (wcslen(FirstString) + wcslen(SecondString) + 1)*sizeof(WCHAR);
  778. pDhcpKeyName = NbtAllocMem (Length, NBT_TAG2('30'));
  779. if (pDhcpKeyName)
  780. {
  781. pucString->Buffer = pDhcpKeyName;
  782. pucString->Length = (USHORT)0;
  783. pucString->MaximumLength = (USHORT)Length;
  784. pucString->Buffer[0] = UNICODE_NULL;
  785. status = RtlAppendUnicodeToString(pucString,FirstString);
  786. if (NT_SUCCESS(status))
  787. {
  788. status = RtlAppendUnicodeToString(pucString,SecondString);
  789. if (NT_SUCCESS(status))
  790. {
  791. return status;
  792. }
  793. }
  794. CTEMemFree(pDhcpKeyName);
  795. }
  796. return(status);
  797. }
  798. //----------------------------------------------------------------------------
  799. NTSTATUS
  800. NTReadIniString (
  801. IN HANDLE ParametersHandle,
  802. IN PWSTR KeyName,
  803. OUT PUCHAR *ppString
  804. )
  805. /*++
  806. Routine Description:
  807. This routine is called to read a string of configuration information from
  808. the registry.
  809. Arguments:
  810. ParametersHandle - handle to open key in registry
  811. KeyName - key to read
  812. ppString - returned string
  813. Return Value:
  814. None.
  815. --*/
  816. {
  817. UNICODE_STRING ucString;
  818. STRING String;
  819. NTSTATUS status;
  820. PUCHAR pBuffer;
  821. PWSTR Dhcp = L"Dhcp";
  822. CTEPagedCode();
  823. //
  824. // read in the Scope Id
  825. //
  826. // if the key is not there or it is set to a null string try to read the
  827. // dhcp key
  828. //
  829. status = ReadElement (ParametersHandle, KeyName, &ucString);
  830. if (!NT_SUCCESS(status) || (ucString.Length == 0))
  831. {
  832. UNICODE_STRING String;
  833. // free the string allocated in ReadElement
  834. if (NT_SUCCESS(status))
  835. {
  836. CTEMemFree(ucString.Buffer);
  837. }
  838. //
  839. // try to read a similar string that is prefixed with "DHCP"
  840. // incase there is only the DHCP configuration information present
  841. // and not overrides keys.
  842. //
  843. status = NbtAppendString(Dhcp,KeyName,&String);
  844. if (NT_SUCCESS(status))
  845. {
  846. status = ReadElement (ParametersHandle, String.Buffer, &ucString);
  847. CTEMemFree(String.Buffer); // Free the buffer allocated in NbtAppendString
  848. }
  849. }
  850. // the scope must be less than
  851. // 255-16 characters since the whole name is limited to 255 as per the
  852. // RFC
  853. //
  854. IF_DBG(NBT_DEBUG_NTUTIL)
  855. KdPrint(("Nbt: ReadIniString = %ws\n",ucString.Buffer));
  856. if (NT_SUCCESS(status))
  857. {
  858. if ((ucString.Length > 0) &&
  859. (ucString.Length <= (255 - NETBIOS_NAME_SIZE)*sizeof(WCHAR)))
  860. {
  861. pBuffer = NbtAllocMem (ucString.MaximumLength/sizeof(WCHAR), NBT_TAG2('31'));
  862. if (pBuffer)
  863. {
  864. // convert to an ascii string and store in the config data structure
  865. // increment pBuffer to leave room for the length byte
  866. //
  867. String.Buffer = pBuffer;
  868. String.MaximumLength = ucString.MaximumLength/sizeof(WCHAR);
  869. status = RtlUnicodeStringToAnsiString (&String, &ucString, FALSE);
  870. if (NT_SUCCESS(status))
  871. {
  872. *ppString = pBuffer;
  873. }
  874. else
  875. {
  876. CTEMemFree(pBuffer);
  877. }
  878. }
  879. else
  880. {
  881. status = STATUS_UNSUCCESSFUL;
  882. }
  883. }
  884. else if (NT_SUCCESS(status))
  885. {
  886. // force the code to setup a null scope since the one in the
  887. // registry is null
  888. //
  889. status = STATUS_UNSUCCESSFUL;
  890. }
  891. // free the string allocated in ReadElement
  892. CTEMemFree(ucString.Buffer);
  893. }
  894. return(status);
  895. }
  896. VOID
  897. NbtFreeRegistryInfo (
  898. )
  899. /*++
  900. Routine Description:
  901. This routine is called by Nbt to free any storage that was allocated
  902. by NbConfigureTransport in producing the specified CONFIG_DATA structure.
  903. Arguments:
  904. ConfigurationInfo - A pointer to the configuration information structure.
  905. Return Value:
  906. None.
  907. --*/
  908. {
  909. }
  910. //----------------------------------------------------------------------------
  911. NTSTATUS
  912. GetIPFromRegistry(
  913. IN PUNICODE_STRING pucBindDevice,
  914. OUT tIPADDRESS *pIpAddresses,
  915. OUT tIPADDRESS *pSubnetMask,
  916. IN ULONG MaxIpAddresses,
  917. OUT ULONG *pNumIpAddresses,
  918. IN enum eNbtIPAddressType IPAddressType
  919. )
  920. /*++
  921. Routine Description:
  922. This routine is called to get the IP address of an adapter from the
  923. Registry. The Registry path variable contains the path name
  924. for NBT's registry entries. The last element of this path name is
  925. removed to give the path to any card in the registry.
  926. The BindDevice path contains a Bind string for NBT. We remove the last
  927. element of this path (which is the adapter name \Elnkii01) and tack it
  928. onto the modified registry path from above. We then tack on
  929. \Parameters which will give the full path to the Tcpip key, which
  930. we open to get the Ip address.
  931. Arguments:
  932. Before calling this routine, the following Global parameters
  933. must have been initialized (in DriverEntry):
  934. NbtConfig.pRegistry
  935. Return Value:
  936. NTSTATUS - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
  937. otherwise.
  938. --*/
  939. {
  940. ULONG i, Len, Disposition;
  941. PVOID pBuffer;
  942. NTSTATUS Status = STATUS_UNSUCCESSFUL; // by default
  943. PWSTR pwsIpAddressName, pwsSubnetMask;
  944. PWSTR pwsAdapterGuid, pwsLastSlash;
  945. PWSTR pwsTcpParams = L"Tcpip\\Parameters\\Interfaces\\"; // key to open
  946. PWSTR pwsUnderScore = L"_";
  947. UNICODE_STRING Path;
  948. HANDLE TcpGuidHandle;
  949. OBJECT_ATTRIBUTES TmpObjectAttributes;
  950. CTEPagedCode();
  951. switch (IPAddressType)
  952. {
  953. case (NBT_IP_STATIC):
  954. pwsIpAddressName = STATIC_IPADDRESS_NAME;
  955. pwsSubnetMask = STATIC_IPADDRESS_SUBNET;
  956. break;
  957. case (NBT_IP_DHCP):
  958. pwsIpAddressName = DHCP_IPADDRESS_NAME;
  959. pwsSubnetMask = DHCP_IPADDRESS_SUBNET;
  960. break;
  961. case (NBT_IP_AUTOCONFIGURATION):
  962. pwsIpAddressName = DHCP_IPAUTOCONFIGURATION_NAME;
  963. pwsSubnetMask = DHCP_IPAUTOCONFIGURATION_SUBNET;
  964. break;
  965. default:
  966. IF_DBG(NBT_DEBUG_NTUTIL)
  967. KdPrint(("Invalid IP Address Type <%x>\n", IPAddressType));
  968. return STATUS_INVALID_ADDRESS;
  969. }
  970. // Extract the Adapter Guid from the BindDevice name
  971. // pucBindDevice: \Device\TCPIP_<AdapterGuid>
  972. // Find the last back slash in the path name to the bind device
  973. NbtFindLastSlash (pucBindDevice, &pwsAdapterGuid, &Len);
  974. if (pwsAdapterGuid)
  975. {
  976. //
  977. // Now, search the string to find the first underscore in "TCPIP_"
  978. //
  979. Len = wcslen(pwsAdapterGuid);
  980. for(i=0; i<Len; i++)
  981. {
  982. if (pwsAdapterGuid[i] == *pwsUnderScore)
  983. {
  984. // want ptr to point at character after the slash
  985. pwsAdapterGuid = &pwsAdapterGuid[i+1];
  986. break;
  987. }
  988. }
  989. //
  990. // If we found the underscore, then we have found the Guid!
  991. //
  992. if (i < Len-1)
  993. {
  994. Status = STATUS_SUCCESS;
  995. }
  996. }
  997. if (Status != STATUS_SUCCESS)
  998. {
  999. //
  1000. // We could not find the Guid!
  1001. //
  1002. return Status;
  1003. }
  1004. // Initialize the Registry key name
  1005. // Get the total length of the Registry key to open (+1 for unicode null)
  1006. Len = NbtConfig.pRegistry.MaximumLength
  1007. + (wcslen(pwsTcpParams) + wcslen(pwsAdapterGuid) + 1) * sizeof(WCHAR);
  1008. pBuffer = NbtAllocMem (Len, NBT_TAG2('32'));
  1009. if (!pBuffer)
  1010. {
  1011. return(STATUS_INSUFFICIENT_RESOURCES);
  1012. }
  1013. Path.Buffer = pBuffer;
  1014. Path.MaximumLength = (USHORT)Len;
  1015. Path.Length = 0;
  1016. RtlCopyUnicodeString(&Path, &NbtConfig.pRegistry); // \REGISTRY\Machine\System\ControlSet\Services\NetBT
  1017. NbtFindLastSlash(&Path, &pwsLastSlash, &Len); // \REGISTRY\Machine\System\ControlSet\Services
  1018. Path.Length = (USHORT)Len;
  1019. *pwsLastSlash = UNICODE_NULL;
  1020. RtlAppendUnicodeToString(&Path, pwsTcpParams); // ...Tcpip\Parameters\Interfaces
  1021. RtlAppendUnicodeToString(&Path, pwsAdapterGuid); // ......AdapterGuid
  1022. //
  1023. // Open the registry.
  1024. //
  1025. InitializeObjectAttributes (&TmpObjectAttributes,
  1026. &Path, // name
  1027. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
  1028. NULL, // root
  1029. NULL); // security descriptor
  1030. Status = ZwCreateKey (&TcpGuidHandle,
  1031. KEY_READ, // We don't need to write any values
  1032. &TmpObjectAttributes,
  1033. 0, // title index
  1034. NULL, // class
  1035. 0, // create options
  1036. &Disposition); // disposition
  1037. // We are done with the Path buffer, so free it
  1038. CTEMemFree(pBuffer);
  1039. if (!NT_SUCCESS(Status))
  1040. {
  1041. KdPrint(("Nbt.GetIPFromRegistry: Error, ZwCreateKey <%x>\n", Status));
  1042. return STATUS_UNSUCCESSFUL;
  1043. }
  1044. Status = STATUS_INVALID_ADDRESS;
  1045. *pNumIpAddresses = 0;
  1046. if (NT_SUCCESS (GetIpAddressesList(TcpGuidHandle,
  1047. pwsIpAddressName,
  1048. MaxIpAddresses,
  1049. pIpAddresses,
  1050. pNumIpAddresses)))
  1051. {
  1052. //
  1053. // DHCP may put a 0 Ip address in the registry - we don't want to
  1054. // set the address under these conditions.
  1055. //
  1056. if ((*pNumIpAddresses) && (*pIpAddresses))
  1057. {
  1058. i = 0;
  1059. if (NT_SUCCESS (GetIpAddressesList(TcpGuidHandle,
  1060. pwsSubnetMask,
  1061. 1,
  1062. pSubnetMask,
  1063. &i)))
  1064. {
  1065. Status = STATUS_SUCCESS;
  1066. }
  1067. }
  1068. }
  1069. ZwClose (TcpGuidHandle);
  1070. return Status;
  1071. } // GetIPFromRegistry
  1072. //----------------------------------------------------------------------------
  1073. NTSTATUS
  1074. NbtOpenRegistry(
  1075. IN HANDLE NbConfigHandle,
  1076. IN PWSTR String,
  1077. OUT PHANDLE pHandle
  1078. )
  1079. /*++
  1080. Routine Description:
  1081. This routine is called by Nbt to open the registry. If the registry
  1082. tree for Nbt exists, then it opens it and returns TRUE. If not, it
  1083. creates the appropriate keys in the registry, opens it, and
  1084. returns FALSE.
  1085. Arguments:
  1086. NbConfigHandle - this is the root handle which String is relative to
  1087. String - the name of the key to open below the root handle
  1088. pHandle - returns the handle to the String key.
  1089. Return Value:
  1090. The status of the request.
  1091. --*/
  1092. {
  1093. NTSTATUS Status;
  1094. UNICODE_STRING KeyName;
  1095. OBJECT_ATTRIBUTES TmpObjectAttributes;
  1096. CTEPagedCode();
  1097. //
  1098. // Open the Nbt key.
  1099. //
  1100. RtlInitUnicodeString (&KeyName, String);
  1101. InitializeObjectAttributes (&TmpObjectAttributes,
  1102. &KeyName, // name
  1103. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
  1104. NbConfigHandle, // root
  1105. NULL); // security descriptor
  1106. Status = ZwOpenKey (pHandle, KEY_READ, &TmpObjectAttributes);
  1107. return Status;
  1108. } /* NbOpenRegistry */
  1109. NTSTATUS
  1110. NbtParseMultiSzEntries(
  1111. IN PWSTR StartBindValue,
  1112. IN PWSTR EndBindValue,
  1113. IN ULONG MaxBindings,
  1114. OUT tDEVICES *pDevices,
  1115. OUT ULONG *pNumDevices
  1116. )
  1117. {
  1118. USHORT ConfigBindings = 0;
  1119. NTSTATUS status = STATUS_SUCCESS;
  1120. CTEPagedCode();
  1121. try {
  1122. while ((StartBindValue < EndBindValue) && (*StartBindValue != 0)) {
  1123. if (ConfigBindings >= MaxBindings) {
  1124. status = STATUS_BUFFER_OVERFLOW;
  1125. break;
  1126. }
  1127. // this sets the buffer ptr in Names to point to CurBindValue, so
  1128. // this value must be real memory and not stack, hence the need
  1129. // to allocate memory above...
  1130. RtlInitUnicodeString (&pDevices->Names[ConfigBindings], (PCWSTR)StartBindValue);
  1131. ++ConfigBindings;
  1132. //
  1133. // Now advance the "Bind" value.
  1134. //
  1135. // wcslen => wide character string length for a unicode string
  1136. StartBindValue += wcslen((PCWSTR)StartBindValue) + 1;
  1137. }
  1138. *pNumDevices = ConfigBindings;
  1139. return (status);
  1140. } except(EXCEPTION_EXECUTE_HANDLER) {
  1141. KdPrint (("Nbt.NbtParseMultiSzEntries: Exception <0x%x>\n", GetExceptionCode()));
  1142. for (ConfigBindings = 0; ConfigBindings < MaxBindings; ConfigBindings++) {
  1143. pDevices->Names[ConfigBindings].Buffer = NULL;
  1144. pDevices->Names[ConfigBindings].Length = pDevices->Names[ConfigBindings].MaximumLength = 0;
  1145. }
  1146. *pNumDevices = 0;
  1147. return STATUS_ACCESS_VIOLATION;
  1148. }
  1149. }
  1150. //----------------------------------------------------------------------------
  1151. NTSTATUS
  1152. NbtReadLinkageInformation(
  1153. IN PWSTR pName,
  1154. IN HANDLE LinkageHandle,
  1155. IN ULONG MaxBindings,
  1156. OUT tDEVICES *pDevices, // place to put read in config data
  1157. OUT ULONG *pNumDevices
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. This routine is called by Nbt to read its linkage information
  1162. from the registry. If there is none present, then ConfigData
  1163. is filled with a list of all the adapters that are known
  1164. to Nbt.
  1165. Arguments:
  1166. RegistryHandle - A pointer to the open registry.
  1167. Return Value:
  1168. Status
  1169. --*/
  1170. {
  1171. NTSTATUS RegistryStatus;
  1172. UNICODE_STRING BindString;
  1173. ULONG BytesWritten = 0;
  1174. PKEY_VALUE_FULL_INFORMATION RegistryData;
  1175. CTEPagedCode();
  1176. pDevices->RegistryData = NULL;
  1177. RtlInitUnicodeString (&BindString, pName); // copy "Bind" or "Export" into the unicode string
  1178. //
  1179. // Determine how many bytes we need to allocate for the Read buffer
  1180. RegistryStatus = ZwQueryValueKey (LinkageHandle,
  1181. &BindString, // string to retrieve
  1182. KeyValueFullInformation,
  1183. NULL,
  1184. 0,
  1185. &BytesWritten); // # of bytes to read
  1186. if ((RegistryStatus != STATUS_BUFFER_TOO_SMALL) ||
  1187. (BytesWritten == 0))
  1188. {
  1189. return STATUS_ILL_FORMED_SERVICE_ENTRY;
  1190. }
  1191. if (!(RegistryData = (PKEY_VALUE_FULL_INFORMATION) NbtAllocMem (BytesWritten, NBT_TAG2('33'))))
  1192. {
  1193. return(STATUS_INSUFFICIENT_RESOURCES);
  1194. }
  1195. RegistryStatus = ZwQueryValueKey (LinkageHandle,
  1196. &BindString, // string to retrieve
  1197. KeyValueFullInformation,
  1198. (PVOID) RegistryData, // returned info
  1199. BytesWritten,
  1200. &BytesWritten); // # of bytes valid data
  1201. if (!NT_SUCCESS(RegistryStatus) ||
  1202. (RegistryStatus == STATUS_BUFFER_OVERFLOW))
  1203. {
  1204. CTEMemFree(RegistryData);
  1205. return RegistryStatus;
  1206. }
  1207. if (BytesWritten == 0)
  1208. {
  1209. CTEMemFree(RegistryData);
  1210. return STATUS_ILL_FORMED_SERVICE_ENTRY;
  1211. }
  1212. pDevices->RegistryData = RegistryData;
  1213. NbtParseMultiSzEntries ((PWCHAR)((PUCHAR)RegistryData+RegistryData->DataOffset),
  1214. (PWSTR) ((PUCHAR)RegistryData+RegistryData->DataOffset+RegistryData->DataLength),
  1215. MaxBindings,
  1216. pDevices,
  1217. pNumDevices);
  1218. return STATUS_SUCCESS;
  1219. } /* NbtReadLinkageInformation */
  1220. //----------------------------------------------------------------------------
  1221. ULONG
  1222. NbtReadSingleParameter(
  1223. IN HANDLE ParametersHandle,
  1224. IN PWCHAR ValueName,
  1225. IN ULONG DefaultValue,
  1226. IN ULONG MinimumValue
  1227. )
  1228. /*++
  1229. Routine Description:
  1230. This routine is called by Nbt to read a single parameter
  1231. from the registry. If the parameter is found it is stored
  1232. in Data.
  1233. Arguments:
  1234. ParametersHandle - A pointer to the open registry.
  1235. ValueName - The name of the value to search for.
  1236. DefaultValue - The default value.
  1237. Return Value:
  1238. The value to use; will be the default if the value is not
  1239. found or is not in the correct range.
  1240. --*/
  1241. {
  1242. static ULONG InformationBuffer[60];
  1243. PKEY_VALUE_FULL_INFORMATION Information =
  1244. (PKEY_VALUE_FULL_INFORMATION)InformationBuffer;
  1245. UNICODE_STRING ValueKeyName;
  1246. ULONG InformationLength;
  1247. ULONG ReturnValue=DefaultValue;
  1248. NTSTATUS Status;
  1249. ULONG Count=2;
  1250. PWSTR Dhcp = L"Dhcp";
  1251. BOOLEAN FreeString = FALSE;
  1252. CTEPagedCode();
  1253. RtlInitUnicodeString (&ValueKeyName, ValueName);
  1254. while (Count--)
  1255. {
  1256. Status = ZwQueryValueKey(
  1257. ParametersHandle,
  1258. &ValueKeyName,
  1259. KeyValueFullInformation,
  1260. (PVOID)Information,
  1261. sizeof (InformationBuffer),
  1262. &InformationLength);
  1263. if ((Status == STATUS_SUCCESS) && (Information->DataLength == sizeof(ULONG)))
  1264. {
  1265. RtlMoveMemory(
  1266. (PVOID)&ReturnValue,
  1267. ((PUCHAR)Information) + Information->DataOffset,
  1268. sizeof(ULONG));
  1269. if (ReturnValue < MinimumValue)
  1270. {
  1271. ReturnValue = MinimumValue;
  1272. }
  1273. }
  1274. else
  1275. {
  1276. //
  1277. // try to read the Dhcp key instead if the first read failed.
  1278. //
  1279. Status = STATUS_SUCCESS;
  1280. if (Count)
  1281. {
  1282. Status = NbtAppendString(Dhcp,ValueName,&ValueKeyName);
  1283. }
  1284. if (!NT_SUCCESS(Status))
  1285. {
  1286. Count = 0;
  1287. ReturnValue = DefaultValue;
  1288. }
  1289. else
  1290. FreeString = TRUE;
  1291. }
  1292. } // of while
  1293. // nbt append string allocates memory.
  1294. if (FreeString)
  1295. {
  1296. CTEMemFree(ValueKeyName.Buffer);
  1297. }
  1298. return ReturnValue;
  1299. } /* NbtReadSingleParameter */
  1300. //----------------------------------------------------------------------------
  1301. NTSTATUS
  1302. OpenAndReadElement(
  1303. IN PUNICODE_STRING pucRootPath,
  1304. IN PWSTR pwsValueName,
  1305. OUT PUNICODE_STRING pucString
  1306. )
  1307. /*++
  1308. Routine Description:
  1309. This routine is called by Nbt to read in the Ip address appearing in the
  1310. registry at the path pucRootPath, with a key of pwsKeyName
  1311. Arguments:
  1312. pucRootPath - the registry path to the key to read
  1313. pwsKeyName - the key to open (i.e. Tcpip)
  1314. pwsValueName- the name of the value to read (i.e. IPAddress)
  1315. Return Value:
  1316. pucString - the string returns the string read from the registry
  1317. --*/
  1318. {
  1319. NTSTATUS Status;
  1320. HANDLE hRootKey;
  1321. OBJECT_ATTRIBUTES TmpObjectAttributes;
  1322. CTEPagedCode();
  1323. InitializeObjectAttributes (&TmpObjectAttributes,
  1324. pucRootPath, // name
  1325. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
  1326. NULL, // root
  1327. NULL); // security descriptor
  1328. Status = ZwOpenKey (&hRootKey, KEY_READ, &TmpObjectAttributes);
  1329. if (!NT_SUCCESS(Status))
  1330. {
  1331. return STATUS_UNSUCCESSFUL;
  1332. }
  1333. Status = ReadElement(hRootKey,pwsValueName,pucString);
  1334. ZwClose (hRootKey);
  1335. return(Status);
  1336. }
  1337. //----------------------------------------------------------------------------
  1338. NTSTATUS
  1339. ReadElement(
  1340. IN HANDLE HandleToKey,
  1341. IN PWSTR pwsValueName,
  1342. OUT PUNICODE_STRING pucString
  1343. )
  1344. /*++
  1345. Routine Description:
  1346. This routine is will read a string value given by pwsValueName, under a
  1347. given Key (which must be open) - given by HandleToKey. This routine
  1348. allocates memory for the buffer in the returned pucString, so the caller
  1349. must deallocate that.
  1350. Arguments:
  1351. pwsValueName- the name of the value to read (i.e. IPAddress)
  1352. Return Value:
  1353. pucString - the string returns the string read from the registry
  1354. --*/
  1355. {
  1356. ULONG ReadStorage[150]; // 600 bytes
  1357. ULONG BytesRead;
  1358. NTSTATUS Status;
  1359. PWSTR pwsSrcString;
  1360. PKEY_VALUE_FULL_INFORMATION ReadValue = (PKEY_VALUE_FULL_INFORMATION)ReadStorage;
  1361. CTEPagedCode();
  1362. // now put the name of the value to read into a unicode string
  1363. RtlInitUnicodeString(pucString,pwsValueName);
  1364. // this read the value of IPAddress under the key opened above
  1365. Status = ZwQueryValueKey(
  1366. HandleToKey,
  1367. pucString, // string to retrieve
  1368. KeyValueFullInformation,
  1369. (PVOID)ReadValue, // returned info
  1370. sizeof(ReadStorage),
  1371. &BytesRead // # of bytes returned
  1372. );
  1373. if ( Status == STATUS_BUFFER_OVERFLOW )
  1374. {
  1375. ReadValue = (PKEY_VALUE_FULL_INFORMATION) NbtAllocMem (BytesRead, NBT_TAG2('35'));
  1376. if (ReadValue == NULL)
  1377. {
  1378. IF_DBG(NBT_DEBUG_NTUTIL)
  1379. KdPrint(("ReadElement: failed to allocate %d bytes for element\n",BytesRead));
  1380. Status = STATUS_INSUFFICIENT_RESOURCES;
  1381. goto ReadElement_Return;
  1382. }
  1383. Status = ZwQueryValueKey(
  1384. HandleToKey,
  1385. pucString, // string to retrieve
  1386. KeyValueFullInformation,
  1387. (PVOID)ReadValue, // returned info
  1388. BytesRead,
  1389. &BytesRead // # of bytes returned
  1390. );
  1391. }
  1392. if (!NT_SUCCESS(Status))
  1393. {
  1394. IF_DBG(NBT_DEBUG_NTUTIL)
  1395. KdPrint(("failed to Query Value Status = %X\n",Status));
  1396. goto ReadElement_Return;
  1397. }
  1398. if ( BytesRead == 0 )
  1399. {
  1400. Status = STATUS_ILL_FORMED_SERVICE_ENTRY;
  1401. goto ReadElement_Return;
  1402. }
  1403. else
  1404. if (ReadValue->DataLength == 0)
  1405. {
  1406. Status = STATUS_UNSUCCESSFUL;
  1407. goto ReadElement_Return;
  1408. }
  1409. // create the pucString and copy the data returned to it
  1410. // assumes that the ReadValue string ends in a UNICODE_NULL
  1411. //bStatus = RtlCreateUnicodeString(pucString,pwSrcString);
  1412. pwsSrcString = (PWSTR)NbtAllocMem ((USHORT)ReadValue->DataLength, NBT_TAG2('36'));
  1413. if (!pwsSrcString)
  1414. {
  1415. ASSERTMSG((PVOID)pwsSrcString,
  1416. (PCHAR)"Unable to allocate memory for a Unicode string");
  1417. Status = STATUS_INSUFFICIENT_RESOURCES;
  1418. }
  1419. else
  1420. {
  1421. // move the read in data from the stack to the memory allocated
  1422. // from the nonpaged pool
  1423. RtlMoveMemory(
  1424. (PVOID)pwsSrcString,
  1425. ((PUCHAR)ReadValue) + ReadValue->DataOffset,
  1426. ReadValue->DataLength);
  1427. RtlInitUnicodeString(pucString,pwsSrcString);
  1428. // if there isn't a null on the end of the pwsSrcString, then
  1429. // it will not work correctly. - a null string comes out with a
  1430. // length of 1!! since the null is counted therefore use
  1431. // rtlinitunicode string afterall.
  1432. // pucString->MaximumLength = ReadValue->DataLength;
  1433. // pucString->Length = ReadValue->DataLength;
  1434. // pucString->Buffer = pwsSrcString;
  1435. }
  1436. ReadElement_Return:
  1437. if ((ReadValue != (PKEY_VALUE_FULL_INFORMATION)ReadStorage)
  1438. && (ReadValue != NULL))
  1439. {
  1440. CTEMemFree(ReadValue);
  1441. }
  1442. return(Status);
  1443. }
  1444. //----------------------------------------------------------------------------
  1445. NTSTATUS
  1446. NTGetLmHostPath(
  1447. OUT PUCHAR *ppPath
  1448. )
  1449. /*++
  1450. Routine Description:
  1451. This routine will read the DataBasePath from under
  1452. ...\tcpip\parameters\databasepath
  1453. Arguments:
  1454. pPath - ptr to a buffer containing the path name.
  1455. Return Value:
  1456. --*/
  1457. {
  1458. NTSTATUS status;
  1459. UNICODE_STRING ucDataBase;
  1460. STRING StringPath;
  1461. STRING LmhostsString;
  1462. ULONG StringMax;
  1463. PWSTR LmHosts = L"lmhosts";
  1464. PWSTR TcpIpParams = L"TcpIp\\Parameters";
  1465. PWSTR TcpParams = L"Tcp\\Parameters";
  1466. PWSTR DataBase = L"DataBasePath";
  1467. PCHAR ascLmhosts="\\lmhosts";
  1468. PCHAR pBuffer;
  1469. CTEPagedCode();
  1470. *ppPath = NULL;
  1471. status = ReadStringRelative(&NbtConfig.pRegistry,
  1472. TcpIpParams,
  1473. DataBase,
  1474. &ucDataBase);
  1475. if (!NT_SUCCESS(status))
  1476. {
  1477. // check for the new TCP stack which a slightly different registry
  1478. // key name.
  1479. //
  1480. status = ReadStringRelative(&NbtConfig.pRegistry,
  1481. TcpParams,
  1482. DataBase,
  1483. &ucDataBase);
  1484. if (!NT_SUCCESS(status))
  1485. {
  1486. return STATUS_UNSUCCESSFUL;
  1487. }
  1488. }
  1489. StringMax = ucDataBase.Length/sizeof(WCHAR) + strlen(ascLmhosts) + 1;
  1490. pBuffer = NbtAllocMem (StringMax, NBT_TAG2('37'));
  1491. if (!pBuffer)
  1492. {
  1493. return(STATUS_INSUFFICIENT_RESOURCES);
  1494. }
  1495. StringPath.Buffer = (PCHAR)pBuffer;
  1496. StringPath.MaximumLength = (USHORT)StringMax;
  1497. StringPath.Length = (USHORT)StringMax;
  1498. // convert to ascii from unicode
  1499. status = RtlUnicodeStringToAnsiString(&StringPath, &ucDataBase, FALSE);
  1500. CTEMemFree(ucDataBase.Buffer); // this memory was allocated in OpenAndReadElement
  1501. if (!NT_SUCCESS(status))
  1502. {
  1503. CTEMemFree(StringPath.Buffer);
  1504. return(STATUS_UNSUCCESSFUL);
  1505. }
  1506. // now put the "\lmhosts" name on the end of the string
  1507. //
  1508. RtlInitString(&LmhostsString, ascLmhosts);
  1509. status = RtlAppendStringToString(&StringPath, &LmhostsString);
  1510. if (NT_SUCCESS(status))
  1511. {
  1512. //
  1513. // is the first part of the directory "%SystemRoot%" ?
  1514. //
  1515. // If so, it must be changed to "\\SystemRoot\\".
  1516. //
  1517. // 0123456789 123456789 1
  1518. // %SystemRoot%\somewhere
  1519. //
  1520. //
  1521. if (strncmp(StringPath.Buffer, "%SystemRoot%", 12) == 0)
  1522. {
  1523. StringPath.Buffer[0] = '\\';
  1524. StringPath.Buffer[11] = '\\';
  1525. if (StringPath.Buffer[12] == '\\')
  1526. {
  1527. ASSERT(StringPath.Length >= 13);
  1528. if (StringPath.Length > 13)
  1529. {
  1530. // overlapped copy
  1531. RtlMoveMemory (&(StringPath.Buffer[12]), // Destination
  1532. &(StringPath.Buffer[13]), // Source
  1533. (ULONG) StringPath.Length - 13); // Length
  1534. StringPath.Buffer[StringPath.Length - 1] = (CHAR) NULL;
  1535. }
  1536. StringPath.Length--;
  1537. }
  1538. }
  1539. *ppPath = (PCHAR)StringPath.Buffer;
  1540. }
  1541. else
  1542. {
  1543. CTEMemFree(StringPath.Buffer);
  1544. }
  1545. return(status);
  1546. }
  1547. //----------------------------------------------------------------------------
  1548. NTSTATUS
  1549. ReadStringRelative(
  1550. IN PUNICODE_STRING pRegistryPath,
  1551. IN PWSTR pRelativePath,
  1552. IN PWSTR pValueName,
  1553. OUT PUNICODE_STRING pOutString
  1554. )
  1555. /*++
  1556. Routine Description:
  1557. This routine reads a string from a registry key parallel to the
  1558. Netbt key - such as ..\tcpip\parameters\database
  1559. Arguments:
  1560. pRegistryPath = ptr to the Netbt Registry path
  1561. pRelativePath = path to value relative to same root as nbt.
  1562. pValueName = value to read
  1563. Return Value:
  1564. The length of the path up to and including the last slash and a ptr
  1565. to the first character of the last element of the string.
  1566. --*/
  1567. {
  1568. NTSTATUS status;
  1569. UNICODE_STRING RegistryPath;
  1570. UNICODE_STRING RelativePath;
  1571. ULONG StringMax;
  1572. PVOID pBuffer;
  1573. PWSTR pLastElement;
  1574. ULONG Length;
  1575. CTEPagedCode();
  1576. StringMax = (pRegistryPath->MaximumLength + wcslen(pRelativePath)*sizeof(WCHAR)+2);
  1577. //
  1578. // allocate some memory for the registry path so that it is large enough
  1579. // to append a string on to, for the relative key to be read
  1580. //
  1581. if (!(pBuffer = NbtAllocMem (StringMax, NBT_TAG2('38'))))
  1582. {
  1583. return(STATUS_INSUFFICIENT_RESOURCES);
  1584. }
  1585. RegistryPath.MaximumLength = (USHORT)StringMax;
  1586. RegistryPath.Buffer = pBuffer;
  1587. RtlCopyUnicodeString(&RegistryPath,pRegistryPath);
  1588. //
  1589. // find the last backslash and truncate the string
  1590. NbtFindLastSlash(&RegistryPath,&pLastElement,&Length);
  1591. RegistryPath.Length = (USHORT)Length;
  1592. if (pLastElement)
  1593. {
  1594. *pLastElement = UNICODE_NULL;
  1595. RtlInitUnicodeString(&RelativePath,pRelativePath);
  1596. status = RtlAppendUnicodeStringToString(&RegistryPath,&RelativePath);
  1597. if (NT_SUCCESS(status))
  1598. {
  1599. status = OpenAndReadElement(&RegistryPath,pValueName,pOutString);
  1600. if (NT_SUCCESS(status))
  1601. {
  1602. // free the registry path
  1603. //
  1604. CTEMemFree(pBuffer);
  1605. return(status);
  1606. }
  1607. }
  1608. }
  1609. else
  1610. {
  1611. status = STATUS_UNSUCCESSFUL;
  1612. }
  1613. CTEMemFree(pBuffer);
  1614. return(status);
  1615. }
  1616. //----------------------------------------------------------------------------
  1617. VOID
  1618. NbtFindLastSlash(
  1619. IN PUNICODE_STRING pucRegistryPath,
  1620. OUT PWSTR *ppucLastElement,
  1621. IN int *piLength
  1622. )
  1623. /*++
  1624. Routine Description:
  1625. This routine is called by Nbt to find the last slash in a registry
  1626. path name.
  1627. Arguments:
  1628. Return Value:
  1629. The length of the path up to and including the last slash and a ptr
  1630. to the first character of the last element of the string.
  1631. --*/
  1632. {
  1633. int i;
  1634. PWSTR pwsSlash = L"\\";
  1635. int iStart;
  1636. CTEPagedCode();
  1637. // search starting at the end of the string for the last back slash
  1638. iStart = wcslen(pucRegistryPath->Buffer)-1;
  1639. for(i=iStart;i>=0 ;i-- )
  1640. {
  1641. if (pucRegistryPath->Buffer[i] == *pwsSlash)
  1642. {
  1643. if (i==pucRegistryPath->Length-1)
  1644. {
  1645. // name ends a back slash... this is an error
  1646. break;
  1647. }
  1648. // increase one to allow for the slash
  1649. *piLength = (i+1)*sizeof(WCHAR);
  1650. if (ppucLastElement != NULL)
  1651. {
  1652. // want ptr to point at character after the slash
  1653. *ppucLastElement = &pucRegistryPath->Buffer[i+1];
  1654. }
  1655. return;
  1656. }
  1657. }
  1658. // null the pointer if one is passed in
  1659. if (ppucLastElement != NULL)
  1660. {
  1661. *ppucLastElement = NULL;
  1662. }
  1663. *piLength = 0;
  1664. return;
  1665. }