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

1470 lines
39 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. sockreg.cxx
  5. Abstract:
  6. Contains the registry/ini-file specific functions from gethost.c
  7. Taken from Win95 Winsock 1.1 project
  8. Contents:
  9. SockGetSingleValue
  10. (CheckRegistryForParameter)
  11. (GetDnsServerListFromDhcp)
  12. (GetDomainNameFromDhcp)
  13. (GetDhcpHardwareInfo)
  14. (OpenDhcpVxdHandle)
  15. (DhcpVxdRequest)
  16. Author:
  17. Richard L Firth (rfirth) 10-Feb-1994
  18. Environment:
  19. Win32 user-mode DLL
  20. Revision History:
  21. 10-Feb-1994 (rfirth)
  22. Created
  23. --*/
  24. //
  25. // includes
  26. //
  27. #include <wininetp.h>
  28. #include "aproxp.h"
  29. //
  30. // manifests
  31. //
  32. #define PLATFORM_TYPE_UNKNOWN ((DWORD)(-1))
  33. #define PLATFORM_TYPE_WIN95 ((DWORD)(0))
  34. #define PLATFORM_TYPE_WINNT ((DWORD)(1))
  35. #define PLATFORM_SUPPORTS_UNICODE 0x00000001
  36. #define DEVICE_PREFIX "\\Device\\"
  37. //
  38. // manifests
  39. //
  40. //
  41. // macros
  42. //
  43. #define FSTRLEN(p) lstrlen((LPSTR)(p))
  44. #define FSTRCPY(p1, p2) lstrcpy((LPSTR)(p1), (LPSTR)(p2))
  45. #define FSTRCAT(p1, p2) lstrcat((LPSTR)(p1), (LPSTR)(p2))
  46. //
  47. // MAP_PARAMETER_ID - returns a string corresponding to the database parameter
  48. //
  49. // N.B. id MUST start at 1
  50. //
  51. #define MAP_PARAMETER_ID(id) ParameterNames[(id) - 1]
  52. //
  53. // globally available registry keys
  54. //
  55. extern HKEY ServicesKey; // = INVALID_HANDLE_VALUE;
  56. //
  57. // private prototypes
  58. //
  59. PRIVATE
  60. UINT
  61. CheckRegistryForParameter(
  62. IN UINT ParameterId,
  63. OUT LPBYTE Data,
  64. IN UINT DataLength
  65. );
  66. PRIVATE
  67. UINT
  68. GetDnsServerListFromDhcp(
  69. LPBYTE Data,
  70. UINT DataLength
  71. );
  72. PRIVATE
  73. UINT
  74. GetDomainNameFromDhcp(
  75. LPBYTE Data,
  76. UINT DataLength
  77. );
  78. PRIVATE
  79. LPDHCP_QUERYINFO
  80. GetDhcpHardwareInfo(
  81. VOID
  82. );
  83. PRIVATE
  84. DWORD_PTR
  85. OpenDhcpVxdHandle(
  86. VOID
  87. );
  88. PRIVATE
  89. WORD
  90. DhcpVxdRequest(
  91. IN DWORD_PTR Handle,
  92. IN WORD Request,
  93. IN WORD BufferLength,
  94. OUT LPVOID Buffer
  95. );
  96. PRIVATE
  97. DWORD_PTR
  98. OsOpenVxdHandle(
  99. CHAR * VxdName,
  100. WORD VxdId
  101. );
  102. PRIVATE
  103. VOID
  104. OsCloseVxdHandle(
  105. DWORD_PTR VxdHandle
  106. );
  107. PRIVATE
  108. INT
  109. OsSubmitVxdRequest(
  110. DWORD_PTR VxdHandle,
  111. INT OpCode,
  112. LPVOID Param,
  113. INT ParamLength
  114. );
  115. //
  116. // private data
  117. //
  118. //
  119. // ParameterNames - the names of the registry values corresponding to the
  120. // variables retrieved by SockGetSingleValue.
  121. //
  122. // N.B. These MUST be in order of the CONFIG_ manifests in sockreg.h
  123. //
  124. PRIVATE const LPCSTR ParameterNames[] = {
  125. "HostName",
  126. "Domain",
  127. "SearchList",
  128. "NameServer"
  129. };
  130. //
  131. // functions
  132. //
  133. /*******************************************************************************
  134. *
  135. * GetBoundAdapterList
  136. *
  137. * Gets a list of names of all adapters bound to a protocol (TCP/IP). Returns
  138. * a pointer to an array of pointers to strings - basically an argv list. The
  139. * memory for the strings is concatenated to the array and the array is NULL
  140. * terminated. If Elnkii1 and IbmTok2 are bound to TCP/IP then this function
  141. * will return:
  142. *
  143. * ---> addr of string1 \
  144. * addr of string2 \
  145. * NULL > allocated as one block
  146. * &string1: "Elnkii1" /
  147. * &string2: "IbmTok2" /
  148. *
  149. * ENTRY BindingsSectionKey
  150. * - Open registry handle to a linkage key (e.g. Tcpip\Linkage)
  151. *
  152. * EXIT
  153. *
  154. * RETURNS pointer to argv[] style array, or NULL
  155. *
  156. * ASSUMES
  157. *
  158. ******************************************************************************/
  159. LPSTR* GetBoundAdapterList(HKEY BindingsSectionKey)
  160. {
  161. LPSTR* resultBuffer;
  162. LONG err;
  163. DWORD valueType;
  164. PBYTE valueBuffer = NULL;
  165. DWORD valueLength;
  166. LPSTR* nextResult;
  167. int len;
  168. DWORD resultLength;
  169. LPSTR nextValue;
  170. LPSTR variableData;
  171. DWORD numberOfBindings;
  172. //
  173. // get required size of value buffer
  174. //
  175. valueLength = 0;
  176. resultBuffer = NULL;
  177. err = RegQueryValueEx(BindingsSectionKey,
  178. "Bind",
  179. NULL, // reserved
  180. &valueType,
  181. NULL,
  182. &valueLength
  183. );
  184. if (err != ERROR_SUCCESS) {
  185. goto quit;
  186. }
  187. if (valueType != REG_MULTI_SZ) {
  188. goto quit;
  189. }
  190. if (!valueLength) {
  191. goto quit;
  192. }
  193. valueBuffer = (PBYTE)ALLOCATE_MEMORY(LPTR, valueLength);
  194. if ( valueBuffer == NULL ) {
  195. goto quit;
  196. }
  197. err = RegQueryValueEx(BindingsSectionKey,
  198. "Bind",
  199. NULL, // reserved
  200. &valueType,
  201. valueBuffer,
  202. &valueLength
  203. );
  204. if (err != ERROR_SUCCESS) {
  205. goto quit;
  206. }
  207. resultLength = sizeof(LPSTR); // the NULL at the end of the list
  208. numberOfBindings = 0;
  209. nextValue = (LPSTR)valueBuffer;
  210. while (len = strlen(nextValue)) {
  211. resultLength += sizeof(LPSTR) + len + 1;
  212. if (!_strnicmp(nextValue, DEVICE_PREFIX, sizeof(DEVICE_PREFIX) - 1)) {
  213. resultLength -= sizeof(DEVICE_PREFIX) - 1;
  214. }
  215. nextValue += len + 1;
  216. ++numberOfBindings;
  217. }
  218. resultBuffer = (LPSTR*)ALLOCATE_MEMORY(LPTR, resultLength);
  219. if ( resultBuffer == NULL ) {
  220. goto quit;
  221. }
  222. nextValue = (LPSTR)valueBuffer;
  223. nextResult = resultBuffer;
  224. variableData = (LPSTR)(((LPSTR*)resultBuffer) + numberOfBindings + 1);
  225. while (numberOfBindings--) {
  226. LPSTR adapterName;
  227. adapterName = nextValue;
  228. if (!_strnicmp(adapterName, DEVICE_PREFIX, sizeof(DEVICE_PREFIX) - 1)) {
  229. adapterName += sizeof(DEVICE_PREFIX) - 1;
  230. }
  231. *nextResult++ = variableData;
  232. strcpy(variableData, adapterName);
  233. while (*variableData) {
  234. ++variableData;
  235. }
  236. ++variableData;
  237. while (*nextValue) {
  238. ++nextValue;
  239. }
  240. ++nextValue;
  241. }
  242. *nextResult = NULL;
  243. quit:
  244. if ( valueBuffer != NULL )
  245. {
  246. FREE_MEMORY(valueBuffer);
  247. }
  248. return resultBuffer;
  249. }
  250. /*******************************************************************************
  251. *
  252. * OpenAdapterKey
  253. *
  254. * Opens one of the 2 per-adapter registry keys: <Adapter>\Parameters\Tcpip, or
  255. * NetBT\Adapters\<Adapter>
  256. *
  257. * ENTRY KeyType - KEY_TCP or KEY_NBT
  258. * Name - pointer to adapter name to use
  259. * Key - pointer to returned key
  260. *
  261. * EXIT Key updated
  262. *
  263. * RETURNS TRUE if success
  264. *
  265. * ASSUMES
  266. *
  267. ******************************************************************************/
  268. BOOL OpenAdapterKey(DWORD KeyType, LPSTR Name, PHKEY Key)
  269. {
  270. LONG err;
  271. CHAR keyName[MAX_ADAPTER_NAME_LENGTH + sizeof("\\Parameters\\Tcpip")];
  272. if ((lstrlen(Name)+sizeof("\\Parameters\\Tcpip")) < ARRAY_ELEMENTS(keyName))
  273. {
  274. if (KeyType == KEY_TCP) {
  275. //
  276. // open the handle to this adapter's TCPIP parameter key
  277. //
  278. strcpy(keyName, Name);
  279. strcat(keyName, "\\Parameters\\Tcpip");
  280. } else if (KeyType == KEY_NBT) {
  281. //
  282. // open the handle to the NetBT\Adapters\<Adapter> handle
  283. //
  284. strcpy(keyName, "NetBT\\Adapters\\");
  285. strcat(keyName, Name);
  286. }
  287. }
  288. else
  289. {
  290. INET_ASSERT((lstrlen(Name)+sizeof("\\Parameters\\Tcpip")) < ARRAY_ELEMENTS(keyName));
  291. return FALSE;
  292. }
  293. err = REGOPENKEY(ServicesKey,
  294. keyName,
  295. Key
  296. );
  297. DEBUG_PRINT( SOCKETS,
  298. INFO,
  299. ("RegOpenKey %s %s %s %d\n",
  300. SERVICES_KEY_NAME, keyName,
  301. (err != ERROR_SUCCESS )? "failed":"success",
  302. GetLastError() ));
  303. return (err == ERROR_SUCCESS);
  304. }
  305. /*******************************************************************************
  306. *
  307. * ReadRegistryDword
  308. *
  309. * Reads a registry value that is stored as a DWORD
  310. *
  311. * ENTRY Key - open registry key where value resides
  312. * ParameterName - name of value to read from registry
  313. * Value - pointer to returned value
  314. *
  315. * EXIT *Value = value read
  316. *
  317. * RETURNS TRUE if success
  318. *
  319. * ASSUMES
  320. *
  321. ******************************************************************************/
  322. BOOL ReadRegistryDword(HKEY Key, LPSTR ParameterName, LPDWORD Value)
  323. {
  324. LONG err;
  325. DWORD valueLength;
  326. DWORD valueType;
  327. valueLength = sizeof(*Value);
  328. err = RegQueryValueEx(Key,
  329. ParameterName,
  330. NULL, // reserved
  331. &valueType,
  332. (LPBYTE)Value,
  333. &valueLength
  334. );
  335. if( (err == ERROR_SUCCESS )
  336. && (valueType == REG_DWORD )
  337. && (valueLength == sizeof(DWORD))) {
  338. return 1;
  339. } else {
  340. DEBUG_PRINT(SOCKETS, INFO,
  341. ("ReadRegistryDword(%s): err=%d\n", ParameterName, err ));
  342. return 0;
  343. }
  344. }
  345. /*******************************************************************************
  346. *
  347. * ReadRegistryString
  348. *
  349. * Reads a registry value that is stored as a string
  350. *
  351. * ENTRY Key - open registry key
  352. * ParameterName - name of value to read from registry
  353. * String - pointer to returned string
  354. * Length - IN: length of String buffer. OUT: length of returned string
  355. *
  356. * EXIT String contains string read
  357. *
  358. * RETURNS TRUE if success
  359. *
  360. * ASSUMES
  361. *
  362. ******************************************************************************/
  363. BOOL
  364. ReadRegistryString(HKEY Key, LPSTR ParameterName, LPSTR String, LPDWORD Length)
  365. {
  366. LONG err;
  367. DWORD valueType;
  368. *String = '\0';
  369. err = RegQueryValueEx(Key,
  370. ParameterName,
  371. NULL, // reserved
  372. &valueType,
  373. (LPBYTE)String,
  374. Length
  375. );
  376. if (err == ERROR_SUCCESS) {
  377. DLL_ASSERT(valueType == REG_SZ || valueType == REG_MULTI_SZ);
  378. return (*Length) > sizeof(char);
  379. } else {
  380. DEBUG_PRINT(SOCKETS,
  381. INFO,
  382. ("ReadRegistryString(%s): err=%d\n", ParameterName, err ));
  383. return 0;
  384. }
  385. }
  386. UINT
  387. SockGetSingleValue(
  388. IN UINT ParameterId,
  389. OUT LPBYTE Data,
  390. IN UINT DataLength
  391. )
  392. /*++
  393. Routine Description:
  394. Retrieve parameter from Registry/DHCP/TCPIP
  395. This is what we look for and where:
  396. HostName: 1. HKLM\Services\CurrentControlSet\System\Vxd\MSTCP\HostName (Win95)
  397. HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\Hostname (NT)
  398. 2. (SYSTEM.INI:DNS.HostName)* (N/A)
  399. 3. GetComputerName()
  400. DomainName: 1. HKLM\Services\CurrentControlSet\System\Vxd\MSTCP\Domain (Win95)
  401. HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\DhcpDomain (NT)
  402. HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\Domain (NT)
  403. 2. (SYSTEM.INI:DNS.DomainName)* (N/A)
  404. 3. DHCP (Win95)
  405. SearchList: 1. HKLM\Services\CurrentControlSet\System\Vxd\MSTCP\SearchList (Win95)
  406. HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\SearchList (NT)
  407. 2. (SYSTEM.INI:DNS.DNSDomains)* (N/A)
  408. NameServer: 1. HKLM\Services\CurrentControlSet\System\Vxd\MSTCP\NameServer (Win95)
  409. HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\DhcpNameServer (NT)
  410. HKLM\Services\CurrentControlSet\System\Tcpip\Parameters\NameServer (NT)
  411. 2. (SYSTEM.INI:DNS.DNSServers)* (N/A)
  412. 3. DHCP (Win95)
  413. * Entries marked thus are registry backups from SYSTEM.INI until all
  414. keys are moved into registry or if platform is WFW 3.11 (in which
  415. case there is no registry)
  416. ASSUMES 1. Data is big enough to hold the default value (single byte for
  417. strings, dword for dwords)
  418. 2. Registry is accessible from 16-bit code too
  419. Arguments:
  420. ParameterId - identifier of parameter to retrieve
  421. Data - pointer to untyped storage space for parameter
  422. DataLength - length of data returned (in bytes)
  423. Return Value:
  424. UINT
  425. Success - ERROR_SUCCESS
  426. Failure - ERROR_PATH_NOT_FOUND
  427. can't locate required parameter in registry/ini/etc.
  428. --*/
  429. {
  430. UINT error = CheckRegistryForParameter(ParameterId, Data, DataLength);
  431. //
  432. // if the value was not in the registry then we must attempt to get it from
  433. // another place, specific to the particular variable requested
  434. //
  435. if (error != ERROR_SUCCESS) {
  436. if (ParameterId == CONFIG_HOSTNAME) {
  437. //
  438. // on Win32 platform we can call GetComputerName() to provide the
  439. // computer name, which is the default host name, if none is
  440. // specified elsewhere
  441. //
  442. DWORD length;
  443. length = DataLength;
  444. if (!GetComputerName((LPSTR)Data, &length)) {
  445. error = GetLastError();
  446. }
  447. } else if (ParameterId == CONFIG_DOMAIN) {
  448. if (GlobalPlatformType == PLATFORM_TYPE_WIN95) {
  449. error = GetDomainNameFromDhcp(Data, DataLength);
  450. }
  451. } else if (ParameterId == CONFIG_NAME_SERVER) {
  452. if (GlobalPlatformType == PLATFORM_TYPE_WIN95) {
  453. error = GetDnsServerListFromDhcp(Data, DataLength);
  454. }
  455. } else {
  456. //
  457. // the caller is requesting the domain list (or an invalid config
  458. // parameter value?!?). We have nowhere else to get this value -
  459. // return an error
  460. //
  461. error = ERROR_PATH_NOT_FOUND;
  462. }
  463. }
  464. IF_DEBUG(REGISTRY) {
  465. if (error != ERROR_SUCCESS) {
  466. DLL_PRINT(("SockGetSingleValue(%s) returns %d\r",
  467. MAP_PARAMETER_ID(ParameterId),
  468. error
  469. ));
  470. } else {
  471. DLL_PRINT(("SockGetSingleValue(%s) returns \"%s\"\n",
  472. MAP_PARAMETER_ID(ParameterId),
  473. Data
  474. ));
  475. }
  476. }
  477. return error;
  478. }
  479. PRIVATE
  480. UINT
  481. CheckRegistryForParameter(
  482. IN UINT ParameterId,
  483. OUT LPBYTE Data,
  484. IN UINT DataLength
  485. )
  486. /*++
  487. Routine Description:
  488. Retrieve parameter from registry
  489. ASSUMES 1. Data is big enough to hold the default value (single byte for
  490. strings, dword for dwords)
  491. Arguments:
  492. ParameterId - identifier of parameter to retrieve
  493. Data - pointer to untyped storage space for parameter
  494. DataLength - length of data returned (in bytes)
  495. Return Value:
  496. UINT
  497. Success - ERROR_SUCCESS
  498. Failure - ERROR_PATH_NOT_FOUND
  499. ERROR_INSUFFICIENT_BUFFER
  500. --*/
  501. {
  502. HKEY key;
  503. LONG error = REGOPENKEY(HKEY_LOCAL_MACHINE,
  504. (GlobalPlatformType == PLATFORM_TYPE_WINNT)
  505. ? "System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
  506. : "System\\CurrentControlSet\\Services\\VxD\\MSTCP",
  507. &key
  508. );
  509. if (error == ERROR_SUCCESS) {
  510. char dhcpBuffer[128]; // arbitrary
  511. LPSTR p;
  512. DWORD length;
  513. DWORD type;
  514. BOOL tryDhcp;
  515. if (GlobalPlatformType == PLATFORM_TYPE_WINNT) {
  516. FSTRCPY(dhcpBuffer, "Dhcp");
  517. p = &dhcpBuffer[sizeof("Dhcp") - 1];
  518. tryDhcp = TRUE;
  519. } else {
  520. p = dhcpBuffer;
  521. tryDhcp = FALSE;
  522. }
  523. FSTRCPY(p, MAP_PARAMETER_ID(ParameterId));
  524. //
  525. // on NT, we look first for the manually-entered variables e.g. "Domain"
  526. // and if not found, we look a second time for the DHCP-configured
  527. // variant, e.g. "DhcpDomain"
  528. //
  529. for (int i = 0; i < 2; ++i) {
  530. //
  531. // if NT, first we try the transient key which is written to the
  532. // registry when we have a dial-up connection
  533. //
  534. if ((i == 0) && (GlobalPlatformType == PLATFORM_TYPE_WINNT)) {
  535. HKEY transientKey;
  536. error = REGOPENKEY(key, "Transient", &transientKey);
  537. if (error == ERROR_SUCCESS) {
  538. length = DataLength;
  539. error = RegQueryValueEx(transientKey,
  540. p,
  541. NULL, // reserved
  542. &type,
  543. Data,
  544. &length
  545. );
  546. REGCLOSEKEY(transientKey);
  547. //
  548. // if we succeeded in retrieving a non-empty string then
  549. // we're done.
  550. //
  551. // We test for > 1 because the registry returns the length
  552. // including the zero-terminator
  553. //
  554. if ((error == ERROR_SUCCESS) && (length > 1)) {
  555. break;
  556. }
  557. }
  558. }
  559. length = DataLength;
  560. error = RegQueryValueEx(key,
  561. p,
  562. NULL, // reserved
  563. &type,
  564. Data,
  565. &length
  566. );
  567. //
  568. // if the key exists, but there is no value then return an error OR
  569. // if we didn't find the key (or value) AND NT then try for the DHCP
  570. // version (Note: We try for DhcpSearchList even though it doesn't
  571. // exist)
  572. //
  573. if ((error != ERROR_SUCCESS)
  574. || (length == 0)
  575. || ((length == 1) && (Data[0] == '\0'))) {
  576. if (tryDhcp) {
  577. p = dhcpBuffer;
  578. tryDhcp = FALSE;
  579. continue;
  580. } else {
  581. error = ERROR_PATH_NOT_FOUND;
  582. break;
  583. }
  584. } else if ((UINT)length > DataLength) {
  585. error = ERROR_INSUFFICIENT_BUFFER;
  586. break;
  587. }
  588. }
  589. REGCLOSEKEY(key);
  590. }
  591. IF_DEBUG(REGISTRY) {
  592. DLL_PRINT(("CheckRegistryForParameter(%s): returning %d\n",
  593. MAP_PARAMETER_ID(ParameterId),
  594. error
  595. ));
  596. }
  597. return (UINT)error;
  598. }
  599. UINT
  600. GetDhcpServerFromDhcp(
  601. IN OUT CAdapterInterface * paiInterface
  602. )
  603. /*******************************************************************************
  604. *
  605. * GetDhcpServerFromDhcp
  606. *
  607. * Updates an CAdapterInterface with the DHCP server from the DHCP info
  608. *
  609. * ENTRY paiInterface - pointer to CAdapterInterface to update
  610. *
  611. * EXIT paiInterface - DhcpServer may be updated
  612. *
  613. * RETURNS TRUE if AdapterInfo->DhcpServer updated
  614. *
  615. * ASSUMES 1. AdapterInfo->Address is valid
  616. *
  617. ******************************************************************************/
  618. {
  619. LPDHCP_QUERYINFO pDhcpInfoPtr;
  620. if ( GlobalPlatformType == PLATFORM_TYPE_WINNT )
  621. {
  622. HKEY key;
  623. if (paiInterface->GetAdapterName() &&
  624. OpenAdapterKey(KEY_TCP, paiInterface->GetAdapterName(), &key))
  625. {
  626. char dhcpServerAddress[4 * 4];
  627. DWORD addressLength;
  628. DWORD fDhcpEnabled = FALSE;
  629. ReadRegistryDword(key,
  630. "EnableDHCP",
  631. &fDhcpEnabled
  632. );
  633. if ( fDhcpEnabled )
  634. {
  635. addressLength = sizeof(dhcpServerAddress);
  636. if (ReadRegistryString(key,
  637. "DhcpServer",
  638. dhcpServerAddress,
  639. &addressLength
  640. ))
  641. {
  642. DWORD ipAddress = _I_inet_addr(dhcpServerAddress);
  643. if ( IS_VALID_NON_LOOPBACK_IP_ADDRESS(ipAddress) )
  644. {
  645. paiInterface->AddDhcpServer(ipAddress);
  646. paiInterface->SetDhcp();
  647. }
  648. }
  649. }
  650. //ReadRegistryDword(key,
  651. // "LeaseObtainedTime",
  652. // &AdapterInfo->LeaseObtained
  653. // );
  654. //ReadRegistryDword(key,
  655. // "LeaseTerminatesTime",
  656. // &AdapterInfo->LeaseExpires
  657. // );
  658. REGCLOSEKEY(key);
  659. return fDhcpEnabled;
  660. }
  661. }
  662. else
  663. {
  664. if (pDhcpInfoPtr = GetDhcpHardwareInfo()) {
  665. DWORD i;
  666. for (i = 0; i < pDhcpInfoPtr->NumNICs; ++i)
  667. {
  668. LPDHCP_NIC_INFO info;
  669. register BOOL match;
  670. info = &pDhcpInfoPtr->NicInfo[i];
  671. match = paiInterface->IsHardwareAddress( ((LPBYTE)pDhcpInfoPtr + info->OffsetHardwareAddress) );
  672. if (match && info->DhcpServerAddress) {
  673. paiInterface->AddDhcpServer(info->DhcpServerAddress);
  674. //
  675. // side-effect: this adapter is DHCP enabled
  676. //
  677. paiInterface->SetDhcp();
  678. DEBUG_PRINT(SOCKETS,
  679. INFO,
  680. ( "GetDhcpServerFromDhcp %s\n",
  681. "bugbug"/*inet_ntoa((int)info->DhcpServerAddress)*/ ));
  682. return TRUE;
  683. }
  684. }
  685. } else {
  686. DEBUG_PRINT(SOCKETS,
  687. INFO,
  688. ("GetDhcpServerFromDhcp: DhcpInfoPtr is 0\n"));
  689. }
  690. }
  691. return FALSE;
  692. }
  693. PRIVATE
  694. UINT
  695. GetDnsServerListFromDhcp(
  696. LPBYTE Data,
  697. UINT DataLength
  698. )
  699. /*++
  700. Routine Description:
  701. Attempts to retrieve a list of DNS servers from DHCP if DHCP is active and
  702. the DNS servers option was specified at the DHCP server
  703. Arguments:
  704. Data - pointer to place to return the list
  705. DataLength - length of Data
  706. Return Value:
  707. UINT
  708. Success - ERROR_SUCCESS
  709. Failure - ERROR_PATH_NOT_FOUND
  710. --*/
  711. {
  712. LPDHCP_QUERYINFO pInfo;
  713. LPBYTE originalData;
  714. originalData = Data;
  715. *Data = 0;
  716. if (pInfo = GetDhcpHardwareInfo()) {
  717. UINT n = (UINT)pInfo->NumNICs;
  718. LPDHCP_NIC_INFO pNicInfo = &pInfo->NicInfo[0];
  719. UINT first = TRUE;
  720. DWORD smallCache[16];
  721. UINT cacheIndex = 0;
  722. IF_DEBUG(REGISTRY) {
  723. DLL_PRINT(("GetDnsServerListFromDhcp(): DHCP has %d adapters\n",
  724. pInfo->NumNICs
  725. ));
  726. }
  727. while (n-- && DataLength) {
  728. UINT i;
  729. LPDWORD pServers = (LPDWORD)((LPBYTE)pInfo + pNicInfo->OffsetDNSServers);
  730. IF_DEBUG(REGISTRY) {
  731. DLL_PRINT(("GetDnsServerListFromDhcp(): NIC %x has %d DNS addresses\n",
  732. pNicInfo,
  733. pNicInfo->DNSServersLen / 4
  734. ));
  735. }
  736. for (i = 0; i < pNicInfo->DNSServersLen; i += 4) {
  737. IN_ADDR inaddr;
  738. char* p;
  739. //
  740. // copy the next DNS address from the DHCP list
  741. //
  742. memcpy(&inaddr, pServers++, sizeof(DWORD));
  743. //
  744. // inet_ntoa will validate the address: if it returns NULL, the
  745. // address is no good, so we skip it
  746. //
  747. p = _I_inet_ntoa(inaddr);
  748. if ((p != NULL) && *p) {
  749. BOOL found;
  750. UINT cachePos;
  751. //
  752. // now check if we've already seen this address. If we have
  753. // then we skip it: no sense in adding redundant DNS addresses.
  754. // This can happen when we have multiple cards, all configured
  755. // with the same DNS info
  756. //
  757. found = FALSE;
  758. for (cachePos = 0; cachePos < cacheIndex; ++cachePos) {
  759. if (smallCache[cachePos] == (DWORD)inaddr.s_addr) {
  760. found = TRUE;
  761. break;
  762. }
  763. }
  764. if (!found) {
  765. UINT len;
  766. //
  767. // new one: add it
  768. //
  769. if (cacheIndex < (sizeof(smallCache)/sizeof(smallCache[0])) - 1) {
  770. IF_DEBUG(REGISTRY) {
  771. DLL_PRINT(("GetDnsServerListFromDhcp(): adding %s to smallCache[%d]\n",
  772. p,
  773. cacheIndex
  774. ));
  775. }
  776. smallCache[cacheIndex] = (DWORD)inaddr.s_addr;
  777. //
  778. // increment the cache index; don't let it go past
  779. // the last element
  780. //
  781. if (cacheIndex < (sizeof(smallCache)/sizeof(smallCache[0])) - 1) {
  782. ++cacheIndex;
  783. }
  784. } else {
  785. IF_DEBUG(REGISTRY) {
  786. DLL_PRINT(("GetDnsServerListFromDhcp(): smallCache full (!)\n"));
  787. }
  788. }
  789. len = FSTRLEN(p);
  790. //
  791. // this assumes that we have more buffer than just
  792. // enough for one string: if there is only one address
  793. // and we have been supplied with DataLength == length
  794. // of the address plus 1 for the zero terminator, then
  795. // we will fail to copy it since we check for space
  796. // enough for the string, zero terminator, plus an extra
  797. // byte for the space separator. But this is being
  798. // overly pedantic. Casuistry even
  799. //
  800. if (DataLength > len + 1) {
  801. if (!first) {
  802. *Data++ = ' ';
  803. --DataLength;
  804. }
  805. IF_DEBUG(REGISTRY) {
  806. DLL_PRINT(("GetDnsServerListFromDhcp() found \"%s\"\n",
  807. p
  808. ));
  809. }
  810. FSTRCPY(Data, p);
  811. DataLength -= len;
  812. Data += len;
  813. first = FALSE;
  814. } else {
  815. IF_DEBUG(REGISTRY) {
  816. DLL_PRINT(("GetDnsServerListFromDhcp(): out of buffer space (need=%d, left=%d)\n",
  817. len + 1,
  818. DataLength
  819. ));
  820. }
  821. }
  822. } else {
  823. IF_DEBUG(REGISTRY) {
  824. DLL_PRINT(("GetDnsServerListFromDhcp(): already seen address %s\n",
  825. p
  826. ));
  827. }
  828. }
  829. }
  830. }
  831. ++pNicInfo;
  832. }
  833. DllFreeMem((void*)pInfo);
  834. //
  835. // if we didn't find any DNS addresses or couldn't fit them in the
  836. // supplied buffer then return an error
  837. //
  838. return (UINT)((*originalData != 0) ? ERROR_SUCCESS : ERROR_PATH_NOT_FOUND);
  839. } else {
  840. IF_DEBUG(REGISTRY) {
  841. DLL_PRINT(("GetDnsServerListFromDhcp() returning %d\n",
  842. ERROR_PATH_NOT_FOUND
  843. ));
  844. }
  845. return ERROR_PATH_NOT_FOUND;
  846. }
  847. }
  848. PRIVATE
  849. UINT
  850. GetDomainNameFromDhcp(
  851. LPBYTE Data,
  852. UINT DataLength
  853. )
  854. /*++
  855. Routine Description:
  856. Attempts to retrieve the domain from DHCP. In this case, the DHCP server
  857. gave out the domain name we are supposed to use
  858. Arguments:
  859. Data - pointer to place to return the list
  860. DataLength - length of Data
  861. Return Value:
  862. UINT
  863. --*/
  864. {
  865. LPDHCP_QUERYINFO pInfo;
  866. pInfo = GetDhcpHardwareInfo();
  867. if (pInfo) {
  868. UINT n;
  869. LPDHCP_NIC_INFO pNicInfo;
  870. //
  871. // search for the first domain name in the NIC list
  872. //
  873. n = (UINT)pInfo->NumNICs;
  874. pNicInfo = &pInfo->NicInfo[0];
  875. //
  876. // BUGBUG - is this correct for multi-homed hosts?
  877. //
  878. while (n--) {
  879. DWORD dnLen;
  880. dnLen = pNicInfo->DomainNameLen;
  881. if (dnLen && (DataLength >= dnLen)) {
  882. IF_DEBUG(REGISTRY) {
  883. DLL_PRINT(("GetDomainNameFromDhcp() found \"%s\"\n",
  884. (LPBYTE)pInfo + pNicInfo->OffsetDomainName
  885. ));
  886. }
  887. memcpy(Data,
  888. (LPBYTE)pInfo + pNicInfo->OffsetDomainName,
  889. (size_t)dnLen
  890. );
  891. //
  892. // we've got our one and only domain name (that we're interested
  893. // in, anyway), so exit
  894. //
  895. break;
  896. }
  897. }
  898. DllFreeMem((void*)pInfo);
  899. return ERROR_SUCCESS;
  900. } else {
  901. IF_DEBUG(REGISTRY) {
  902. DLL_PRINT(("GetDomainNameFromDhcp() returning %d\n",
  903. ERROR_PATH_NOT_FOUND
  904. ));
  905. }
  906. return ERROR_PATH_NOT_FOUND;
  907. }
  908. }
  909. /*******************************************************************************
  910. *
  911. * GetDhcpHardwareInfo
  912. *
  913. * Retrieves all the hardware-specific information for all adapters from the
  914. * DHCP VxD
  915. *
  916. * ENTRY nothing
  917. *
  918. * EXIT nothing
  919. *
  920. * RETURNS Success - pointer to allocated buffer containing all hardware info
  921. * Failure - NULL
  922. *
  923. * ASSUMES
  924. *
  925. ******************************************************************************/
  926. PRIVATE
  927. LPDHCP_QUERYINFO
  928. GetDhcpHardwareInfo(
  929. VOID
  930. )
  931. {
  932. LPDHCP_QUERYINFO info = NULL;
  933. DWORD_PTR handle = OpenDhcpVxdHandle();
  934. if (handle) {
  935. WORD result;
  936. DWORD sizeRequired;
  937. result = DhcpVxdRequest(handle,
  938. DHCP_QUERY_INFO,
  939. sizeof(sizeRequired),
  940. &sizeRequired
  941. );
  942. //
  943. // ERROR_BUFFER_OVERFLOW tells us exactly how many bytes we need. If we
  944. // don't get this error back, then its an unexpected (i.e. error)
  945. // situation
  946. //
  947. if (result == ERROR_BUFFER_OVERFLOW) {
  948. info = (LPDHCP_QUERYINFO)DllAllocMem((size_t)sizeRequired);
  949. if (info) {
  950. result = DhcpVxdRequest(handle,
  951. DHCP_QUERY_INFO,
  952. (WORD)sizeRequired,
  953. info
  954. );
  955. if (result != ERROR_SUCCESS) {
  956. DllFreeMem((void*)info);
  957. }
  958. }
  959. }
  960. }
  961. if (handle) {
  962. OsCloseVxdHandle(handle);
  963. }
  964. return info;
  965. }
  966. /*******************************************************************************
  967. *
  968. * OpenDhcpVxdHandle
  969. *
  970. * On Snowball, just retrieves the (real-mode) entry point address to the VxD
  971. *
  972. * ENTRY nothing
  973. *
  974. * EXIT DhcpVxdEntryPoint set
  975. *
  976. * RETURNS DhcpVxdEntryPoint
  977. *
  978. * ASSUMES 1. We are running in V86 mode
  979. *
  980. ******************************************************************************/
  981. PRIVATE
  982. DWORD_PTR
  983. OpenDhcpVxdHandle(
  984. VOID
  985. )
  986. {
  987. return OsOpenVxdHandle("VDHCP", VDHCP_Device_ID);
  988. }
  989. /*******************************************************************************
  990. *
  991. * DhcpVxdRequest
  992. *
  993. * Makes a DHCP VxD request - passes a function code, parameter buffer and
  994. * length to the (real-mode/V86) VxD entry-point
  995. *
  996. * ENTRY Handle - handle for Win32 call
  997. * Request - DHCP VxD request
  998. * BufferLength - length of Buffer
  999. * Buffer - pointer to request-specific parameters
  1000. *
  1001. * EXIT depends on request
  1002. *
  1003. * RETURNS Success - 0
  1004. * Failure - ERROR_PATH_NOT_FOUND
  1005. * Returned if a specified adapter address could not be
  1006. * found
  1007. *
  1008. * ERROR_BUFFER_OVERFLOW
  1009. * Returned if the supplied buffer is too small to contain
  1010. * the requested information
  1011. *
  1012. * ASSUMES
  1013. *
  1014. ******************************************************************************/
  1015. PRIVATE
  1016. WORD
  1017. DhcpVxdRequest(
  1018. IN DWORD_PTR Handle,
  1019. IN WORD Request,
  1020. IN WORD BufferLength,
  1021. OUT LPVOID Buffer
  1022. )
  1023. {
  1024. return (WORD) OsSubmitVxdRequest(Handle,
  1025. (INT)Request,
  1026. (LPVOID)Buffer,
  1027. (INT)BufferLength
  1028. );
  1029. }
  1030. PRIVATE
  1031. DWORD_PTR
  1032. OsOpenVxdHandle(
  1033. CHAR * VxdName,
  1034. WORD VxdId
  1035. )
  1036. {
  1037. HANDLE VxdHandle;
  1038. CHAR VxdPath[MAX_PATH];
  1039. //
  1040. // Sanity check.
  1041. //
  1042. DLL_ASSERT( VxdName != NULL );
  1043. DLL_ASSERT( VxdId != 0 );
  1044. IF_DEBUG( VXD_IO )
  1045. {
  1046. DLL_PRINT(( "OsOpenVxdHandle: id = %04X, name = %s\n",
  1047. VxdId,
  1048. VxdName ));
  1049. }
  1050. //
  1051. // Build the VxD path.
  1052. //
  1053. FSTRCPY( VxdPath, "\\\\.\\");
  1054. if(FSTRLEN(VxdPath) + FSTRLEN(VxdName) >= sizeof(VxdPath) / sizeof(VxdPath[0]))
  1055. {
  1056. DLL_ASSERT(FALSE);
  1057. return 0;
  1058. }
  1059. FSTRCAT( VxdPath, VxdName);
  1060. //
  1061. // Open the device.
  1062. //
  1063. // First try the name without the .VXD extension. This will
  1064. // cause CreateFile to connect with the VxD if it is already
  1065. // loaded (CreateFile will not load the VxD in this case).
  1066. //
  1067. VxdHandle = CreateFile( VxdPath,
  1068. GENERIC_READ | GENERIC_WRITE,
  1069. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1070. NULL,
  1071. OPEN_EXISTING,
  1072. FILE_FLAG_DELETE_ON_CLOSE,
  1073. NULL );
  1074. if( VxdHandle == INVALID_HANDLE_VALUE )
  1075. {
  1076. //
  1077. // Not found. Append the .VXD extension and try again.
  1078. // This will cause CreateFile to load the VxD.
  1079. //
  1080. FSTRCAT( VxdPath, ".VXD" );
  1081. VxdHandle = CreateFile( VxdPath,
  1082. GENERIC_READ | GENERIC_WRITE,
  1083. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1084. NULL,
  1085. OPEN_EXISTING,
  1086. FILE_FLAG_DELETE_ON_CLOSE,
  1087. NULL );
  1088. }
  1089. if( VxdHandle != INVALID_HANDLE_VALUE )
  1090. {
  1091. IF_DEBUG( VXD_IO )
  1092. {
  1093. DLL_PRINT(( "OsOpenVxdHandle: returning handle %08lX\n",
  1094. VxdHandle ));
  1095. }
  1096. return (DWORD_PTR)VxdHandle;
  1097. }
  1098. IF_DEBUG( VXD_IO )
  1099. {
  1100. DLL_PRINT(( "OsOpenVxdHandle: cannot open %s (%04X), error %d\n",
  1101. VxdPath,
  1102. VxdId,
  1103. GetLastError() ));
  1104. }
  1105. return 0;
  1106. } // OsOpenVxdHandle
  1107. PRIVATE
  1108. VOID
  1109. OsCloseVxdHandle(
  1110. DWORD_PTR VxdHandle
  1111. )
  1112. {
  1113. //
  1114. // Sanity check.
  1115. //
  1116. DLL_ASSERT( VxdHandle != 0 );
  1117. IF_DEBUG( VXD_IO )
  1118. {
  1119. DLL_PRINT(( "OsCloseVxdHandle: handle %08X\n",
  1120. VxdHandle ));
  1121. }
  1122. if( !CloseHandle( (HANDLE)VxdHandle ) )
  1123. {
  1124. DLL_PRINT(( "OsCloseVxdHandle: cannot close handle %08X, error %d\n",
  1125. VxdHandle,
  1126. GetLastError() ));
  1127. }
  1128. } // OsCloseVxdHandle
  1129. PRIVATE
  1130. INT
  1131. OsSubmitVxdRequest(
  1132. DWORD_PTR VxdHandle,
  1133. INT OpCode,
  1134. LPVOID Param,
  1135. INT ParamLength
  1136. )
  1137. {
  1138. DWORD BytesRead;
  1139. INT Result = 0;
  1140. //
  1141. // Sanity check.
  1142. //
  1143. DLL_ASSERT( VxdHandle != 0 );
  1144. DLL_ASSERT( ( Param != NULL ) || ( ParamLength == 0 ) );
  1145. IF_DEBUG( VXD_IO )
  1146. {
  1147. DLL_PRINT(( "OsSubmitVxdRequest: opcode %04X, param %08lX, length %d\n",
  1148. OpCode,
  1149. Param,
  1150. ParamLength ));
  1151. }
  1152. if( !DeviceIoControl( (HANDLE)VxdHandle,
  1153. OpCode,
  1154. Param,
  1155. ParamLength,
  1156. Param,
  1157. ParamLength,
  1158. &BytesRead,
  1159. NULL ) )
  1160. {
  1161. Result = GetLastError();
  1162. }
  1163. IF_DEBUG( VXD_IO )
  1164. {
  1165. DLL_PRINT(( "OsSubmitVxdRequest: returning %d\n",
  1166. Result ));
  1167. }
  1168. return Result;
  1169. } // OsSubmitVxdRequest