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.

754 lines
19 KiB

  1. /*
  2. File enumlan.c
  3. Implementation of functions to enumerate lan interfaces
  4. on a given machine. This implementation actually bypasses
  5. netman and gets the information using setup api's.
  6. Paul Mayfield, 5/13/98
  7. */
  8. #include <nt.h>
  9. #include <ntrtl.h>
  10. #include <nturtl.h>
  11. #include <windows.h>
  12. #include <winerror.h>
  13. #include <netcfgx.h>
  14. #include <netcon.h>
  15. #include <setupapi.h>
  16. #include <devguid.h>
  17. #include <cfgmgr32.h>
  18. #include <mprapi.h>
  19. #include "rtcfg.h"
  20. #include "enumlan.h"
  21. #define EL_MAP_GROW_FACTOR 25
  22. //
  23. // Determines whether a given machine is nt40
  24. //
  25. DWORD
  26. IsNt40Machine (
  27. IN HKEY hkeyMachine,
  28. OUT PBOOL pbIsNt40);
  29. //
  30. // Structure represents a growable array of name map nodes.
  31. //
  32. typedef struct _EL_NAMEMAP
  33. {
  34. DWORD dwNumNodes;
  35. EL_ADAPTER_INFO *pNodes;
  36. } EL_NAMEMAP;
  37. //
  38. // Structure contains data manipulated by ElIsNetcfgDevice
  39. //
  40. typedef struct _EL_ISNETCFGDEV_INFO
  41. {
  42. EL_ADAPTER_INFO* pAdapter; // IN OUT
  43. WCHAR pszPnpInstance[MAX_PATH]; // OUT
  44. } EL_ISNETCFGDEV_INFO;
  45. //
  46. // Structure contains data manipulated by ElGetAdapterStatus
  47. //
  48. typedef struct _EL_ADAPTER_STATUS_INFO
  49. {
  50. EL_ADAPTER_INFO* pAdapter; // IN OUT
  51. HANDLE hkCmMachine; // IN
  52. PWCHAR pszPnpInstance; // IN
  53. } EL_ADAPTER_STATUS_INFO;
  54. //
  55. // Defines a filter function (used by lan adapter enumeration)
  56. //
  57. typedef
  58. DWORD
  59. (*DevFilterFuncPtr)(
  60. HKEY,
  61. HKEY,
  62. HANDLE,
  63. PBOOL);
  64. //
  65. // Stolen from netcfg project
  66. //
  67. #define IA_INSTALLED 1
  68. const WCHAR c_szRegKeyInterfacesFromInstance[] = L"Ndi\\Interfaces";
  69. const WCHAR c_szRegValueUpperRange[] = L"UpperRange";
  70. const WCHAR c_szBiNdis4[] = L"ndis4";
  71. const WCHAR c_szBiNdis5[] = L"ndis5";
  72. const WCHAR c_szBiNdisAtm[] = L"ndisatm";
  73. const WCHAR c_szBiNdis1394[] = L"ndis1394";
  74. const WCHAR c_szCharacteristics[] = L"Characteristics";
  75. const WCHAR c_szRegValueNetCfgInstanceId[] = L"NetCfgInstanceID";
  76. const WCHAR c_szRegValueInstallerAction[] = L"InstallerAction";
  77. const WCHAR c_szRegKeyConnection[] = L"Connection";
  78. const WCHAR c_szRegValueConName[] = L"Name";
  79. const WCHAR c_szRegValuePnpInstanceId[] = L"PnpInstanceID";
  80. const WCHAR c_szRegKeyComponentClasses[] =
  81. L"SYSTEM\\CurrentControlSet\\Control\\Network";
  82. //
  83. // Maps a CM_PROB_* value to a EL_STATUS_* value
  84. //
  85. DWORD
  86. ElMapCmStatusToElStatus(
  87. IN DWORD dwCmStatus,
  88. OUT LPDWORD lpdwElStatus)
  89. {
  90. return NO_ERROR;
  91. }
  92. //
  93. // Adapted version of HrIsLanCapableAdapterFromHkey determines
  94. // whether an adapter is lan capable based on its registry key.
  95. //
  96. DWORD
  97. ElIsLanAdapter(
  98. IN HKEY hkMachine,
  99. IN HKEY hkey,
  100. OUT HANDLE hData,
  101. OUT PBOOL pbIsLan)
  102. {
  103. HKEY hkeyInterfaces;
  104. WCHAR pszBuf[256], *pszCur, *pszEnd;
  105. DWORD dwErr, dwType = REG_SZ, dwSize = sizeof(pszBuf);
  106. *pbIsLan = FALSE;
  107. // Open the interfaces key
  108. dwErr = RegOpenKeyEx( hkey,
  109. c_szRegKeyInterfacesFromInstance,
  110. 0,
  111. KEY_READ,
  112. &hkeyInterfaces);
  113. if (dwErr != ERROR_SUCCESS)
  114. return dwErr;
  115. // Read in the upper range
  116. dwErr = RegQueryValueExW (hkeyInterfaces,
  117. c_szRegValueUpperRange,
  118. NULL,
  119. &dwType,
  120. (LPBYTE)pszBuf,
  121. &dwSize);
  122. if (dwErr != ERROR_SUCCESS)
  123. return NO_ERROR;
  124. // See if this buffer has the magic strings in it
  125. pszCur = pszBuf;
  126. while (TRUE) {
  127. pszEnd = wcsstr(pszCur, L",");
  128. if (pszEnd != NULL)
  129. *pszEnd = (WCHAR)0;
  130. if ((lstrcmpi (pszCur, c_szBiNdis4) == 0) ||
  131. (lstrcmpi (pszCur, c_szBiNdis5) == 0) ||
  132. (lstrcmpi (pszCur, c_szBiNdis1394) == 0) ||
  133. (lstrcmpi (pszCur, c_szBiNdisAtm) == 0))
  134. {
  135. *pbIsLan = TRUE;
  136. break;
  137. }
  138. if (pszEnd == NULL)
  139. break;
  140. else
  141. pszCur = pszEnd + 1;
  142. }
  143. RegCloseKey(hkeyInterfaces);
  144. return NO_ERROR;
  145. }
  146. //
  147. // Filters netcfg devices. If a device passes this filter
  148. // it will have its guid and freindly name returned through
  149. // the hData parameter (option user defined data).
  150. //
  151. DWORD
  152. ElIsNetcfgDevice(
  153. IN HKEY hkMachine,
  154. IN HKEY hkDev,
  155. OUT HANDLE hData,
  156. OUT PBOOL pbOk)
  157. {
  158. EL_ISNETCFGDEV_INFO* pInfo = (EL_ISNETCFGDEV_INFO*)hData;
  159. EL_ADAPTER_INFO *pNode = pInfo->pAdapter;
  160. GUID Guid = GUID_DEVCLASS_NET;
  161. WCHAR pszBuf[1024], pszPath[256], pszClassGuid[256];
  162. DWORD dwErr = NO_ERROR, dwType = REG_SZ, dwSize = sizeof(pszBuf), dwAction;
  163. HKEY hkeyNetCfg = NULL;
  164. *pbOk = FALSE;
  165. // Read in the netcfg instance
  166. dwErr = RegQueryValueExW (
  167. hkDev,
  168. c_szRegValueNetCfgInstanceId,
  169. NULL,
  170. &dwType,
  171. (LPBYTE)pszBuf,
  172. &dwSize);
  173. if (dwErr != NO_ERROR)
  174. {
  175. return dwErr;
  176. }
  177. // Generate path in registry for lookup
  178. StringFromGUID2(
  179. &Guid,
  180. pszClassGuid,
  181. sizeof(pszClassGuid)/sizeof(pszClassGuid[0]));
  182. wsprintf(
  183. pszPath,
  184. L"%s\\%s\\%s\\%s",
  185. c_szRegKeyComponentClasses,
  186. pszClassGuid,
  187. pszBuf,
  188. c_szRegKeyConnection);
  189. do
  190. {
  191. // Open the key
  192. dwErr = RegOpenKeyEx(
  193. hkMachine,
  194. pszPath,
  195. 0,
  196. KEY_READ,
  197. &hkeyNetCfg);
  198. if (dwErr != ERROR_SUCCESS)
  199. {
  200. break;
  201. }
  202. // Pass the filter
  203. *pbOk = TRUE;
  204. // Store the guid
  205. pszBuf[wcslen(pszBuf) - 1] = (WCHAR)0;
  206. if (UuidFromString(pszBuf + 1, &(pNode->guid)) != RPC_S_OK)
  207. return ERROR_NOT_ENOUGH_MEMORY;
  208. // Read in the adapter name
  209. //
  210. dwType = REG_SZ;
  211. dwSize = sizeof(pszBuf);
  212. dwErr = RegQueryValueEx(
  213. hkeyNetCfg,
  214. c_szRegValueConName,
  215. NULL,
  216. &dwType,
  217. (LPBYTE)pszBuf,
  218. &dwSize);
  219. if (dwErr == ERROR_SUCCESS)
  220. {
  221. pNode->pszName = SysAllocString(pszBuf);
  222. if (pNode->pszName == NULL)
  223. {
  224. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  225. break;
  226. }
  227. }
  228. // Read in the adapter pnp instance id
  229. //
  230. dwType = REG_SZ;
  231. dwSize = sizeof(pInfo->pszPnpInstance);
  232. dwErr = RegQueryValueEx(
  233. hkeyNetCfg,
  234. c_szRegValuePnpInstanceId,
  235. NULL,
  236. &dwType,
  237. (LPBYTE)(pInfo->pszPnpInstance),
  238. &dwSize);
  239. if (dwErr != ERROR_SUCCESS)
  240. {
  241. break;
  242. }
  243. } while (FALSE);
  244. // Cleanup
  245. {
  246. if (hkeyNetCfg)
  247. {
  248. RegCloseKey(hkeyNetCfg);
  249. }
  250. }
  251. return dwErr;
  252. }
  253. //
  254. // Filters hidden devices
  255. //
  256. DWORD
  257. ElIsNotHiddenDevice (
  258. IN HKEY hkMachine,
  259. IN HKEY hkDev,
  260. OUT HANDLE hData,
  261. OUT PBOOL pbOk)
  262. {
  263. DWORD dwErr, dwType = REG_DWORD,
  264. dwSize = sizeof(DWORD), dwChars;
  265. dwErr = RegQueryValueEx ( hkDev,
  266. c_szCharacteristics,
  267. NULL,
  268. &dwType,
  269. (LPBYTE)&dwChars,
  270. &dwSize);
  271. if (dwErr != ERROR_SUCCESS)
  272. return dwErr;
  273. *pbOk = !(dwChars & NCF_HIDDEN);
  274. return NO_ERROR;
  275. }
  276. //
  277. // Filter that simply loads the adapter status
  278. //
  279. DWORD
  280. ElGetAdapterStatus(
  281. IN HKEY hkMachine,
  282. IN HKEY hkDev,
  283. OUT HANDLE hData,
  284. OUT PBOOL pbOk)
  285. {
  286. EL_ADAPTER_STATUS_INFO* pInfo = (EL_ADAPTER_STATUS_INFO*)hData;
  287. DEVINST DevInst;
  288. CONFIGRET cr = CR_SUCCESS;
  289. ULONG ulStatus = 0, ulProblem = 0;
  290. // Validate parameters
  291. //
  292. if (pInfo == NULL)
  293. {
  294. return ERROR_INVALID_PARAMETER;
  295. }
  296. // Find the device
  297. //
  298. cr = CM_Locate_DevNode_ExW(
  299. &DevInst,
  300. pInfo->pszPnpInstance,
  301. CM_LOCATE_DEVNODE_NORMAL,
  302. pInfo->hkCmMachine);
  303. if (cr != CR_SUCCESS)
  304. {
  305. return ERROR_CAN_NOT_COMPLETE;
  306. }
  307. // Get the device status
  308. //
  309. cr = CM_Get_DevNode_Status_Ex(
  310. &ulStatus,
  311. &ulProblem,
  312. DevInst,
  313. 0,
  314. pInfo->hkCmMachine);
  315. if (cr != CR_SUCCESS)
  316. {
  317. return ERROR_CAN_NOT_COMPLETE;
  318. }
  319. // Map CM's status to our own
  320. //
  321. switch (ulProblem)
  322. {
  323. // No problem, we're connected
  324. case 0:
  325. pInfo->pAdapter->dwStatus = EL_STATUS_OK;
  326. break;
  327. // Device not present
  328. case CM_PROB_DEVICE_NOT_THERE:
  329. case CM_PROB_MOVED:
  330. pInfo->pAdapter->dwStatus = EL_STATUS_NOT_THERE;
  331. break;
  332. // Device was disabled via Device Manager
  333. case CM_PROB_HARDWARE_DISABLED:
  334. pInfo->pAdapter->dwStatus = EL_STATUS_HWDISABLED;
  335. break;
  336. // Device was disconnected
  337. case CM_PROB_DISABLED:
  338. pInfo->pAdapter->dwStatus = EL_STATUS_DISABLED;
  339. break;
  340. // All other problems
  341. default:
  342. pInfo->pAdapter->dwStatus = EL_STATUS_OTHER;
  343. break;
  344. }
  345. // Make sure this device passes the filter
  346. //
  347. *pbOk = TRUE;
  348. return NO_ERROR;
  349. }
  350. //
  351. // Returns TRUE if the given device passes the filter.
  352. // Returns FALSE otherwise.
  353. //
  354. BOOL
  355. ElDevicePassesFilter (
  356. IN HKEY hkMachine,
  357. IN HKEY hkDev,
  358. IN HANDLE hData,
  359. IN DevFilterFuncPtr pFilter)
  360. {
  361. BOOL bOk = TRUE;
  362. DWORD dwErr;
  363. dwErr = (*pFilter)(hkMachine, hkDev, hData, &bOk);
  364. if ((dwErr == NO_ERROR) && (bOk == TRUE))
  365. return TRUE;
  366. return FALSE;
  367. }
  368. //
  369. // Allocates additional space in a EL_NAMEMAP
  370. //
  371. DWORD
  372. ElEnlargeMap (
  373. IN OUT EL_NAMEMAP * pMap,
  374. DWORD dwAmount)
  375. {
  376. EL_ADAPTER_INFO * pNewNodes;
  377. DWORD dwNewSize, i;
  378. // Figure out the new size
  379. dwNewSize = pMap->dwNumNodes + dwAmount;
  380. // Resize the array
  381. pNewNodes = (EL_ADAPTER_INFO *) Malloc (dwNewSize * sizeof(EL_ADAPTER_INFO));
  382. if (!pNewNodes)
  383. return ERROR_NOT_ENOUGH_MEMORY;
  384. ZeroMemory(pNewNodes, dwNewSize * sizeof(EL_ADAPTER_INFO));
  385. // Initialize the arrays.
  386. CopyMemory(pNewNodes, pMap->pNodes, pMap->dwNumNodes * sizeof(EL_ADAPTER_INFO));
  387. // Free old data if needed
  388. if (pMap->dwNumNodes)
  389. Free (pMap->pNodes);
  390. // Assign the new arrays
  391. pMap->pNodes = pNewNodes;
  392. pMap->dwNumNodes = dwNewSize;
  393. return NO_ERROR;
  394. }
  395. //
  396. // Find out if given server is NT 4
  397. //
  398. DWORD
  399. ElIsNt40Machine (
  400. IN PWCHAR pszMachine,
  401. OUT PBOOL pbNt40,
  402. OUT HKEY* phkMachine)
  403. {
  404. DWORD dwErr;
  405. dwErr = RegConnectRegistry (
  406. pszMachine,
  407. HKEY_LOCAL_MACHINE,
  408. phkMachine);
  409. if ((dwErr != ERROR_SUCCESS) || (phkMachine == NULL))
  410. return dwErr;
  411. return IsNt40Machine (*phkMachine, pbNt40);
  412. }
  413. //
  414. // Obtains the map of connection names to guids on the given server
  415. // from its netman service.
  416. //
  417. // Parameters:
  418. // pszServer: Server on which to obtain map (NULL = local)
  419. // ppMap: Returns array of EL_ADAPTER_INFO's
  420. // lpdwCount Returns number of elements read into ppMap
  421. // pbNt40: Returns whether server is nt4 installation
  422. //
  423. DWORD
  424. ElEnumLanAdapters (
  425. IN PWCHAR pszServer,
  426. OUT EL_ADAPTER_INFO ** ppMap,
  427. OUT LPDWORD lpdwNumNodes,
  428. OUT PBOOL pbNt40 )
  429. {
  430. GUID DevGuid = GUID_DEVCLASS_NET;
  431. SP_DEVINFO_DATA Device;
  432. HDEVINFO hDevInfo = NULL;
  433. HKEY hkDev = NULL, hkMachine = NULL;
  434. DWORD dwErr = NO_ERROR, dwIndex, dwTotal, dwSize;
  435. EL_NAMEMAP Map;
  436. WCHAR pszMachine[512], pszTemp[512];
  437. HANDLE hkCmMachine = NULL;
  438. EL_ADAPTER_STATUS_INFO AdapterStatusInfo;
  439. EL_ISNETCFGDEV_INFO IsNetCfgDevInfo;
  440. CONFIGRET cr = CR_SUCCESS;
  441. #ifdef KSL_IPINIP
  442. PMPR_IPINIP_INTERFACE_0 pIpIpTable;
  443. DWORD dwIpIpCount;
  444. #endif
  445. // Validate parameters
  446. if (!ppMap || !lpdwNumNodes || !pbNt40)
  447. {
  448. return ERROR_INVALID_PARAMETER;
  449. }
  450. *pbNt40 = FALSE;
  451. // Initialize
  452. //
  453. ZeroMemory(&Map, sizeof(EL_NAMEMAP));
  454. do
  455. {
  456. // Prepare the name of the computer
  457. wcscpy(pszMachine, L"\\\\");
  458. if (pszServer)
  459. {
  460. if (*pszServer == L'\\')
  461. {
  462. wcscpy(pszMachine, pszServer);
  463. }
  464. else
  465. {
  466. wcscat(pszMachine, pszServer);
  467. }
  468. }
  469. else
  470. {
  471. dwSize = sizeof(pszTemp) / sizeof(WCHAR);
  472. if (GetComputerName(pszTemp, &dwSize))
  473. {
  474. wcscat(pszMachine, pszTemp);
  475. }
  476. else
  477. {
  478. dwErr = ERROR_CAN_NOT_COMPLETE;
  479. break;
  480. }
  481. }
  482. // Find out if we're talking about an nt40 machine
  483. dwErr = ElIsNt40Machine(pszMachine, pbNt40, &hkMachine);
  484. if (dwErr != NO_ERROR)
  485. {
  486. break;
  487. }
  488. // If it is, we're done -- no mapping
  489. if (*pbNt40)
  490. {
  491. *ppMap = NULL;
  492. *lpdwNumNodes = 0;
  493. dwErr = NO_ERROR;
  494. break;
  495. }
  496. // Connect to the connection manager rpc instance
  497. //
  498. if (pszMachine)
  499. {
  500. cr = CM_Connect_MachineW(
  501. pszMachine,
  502. &hkCmMachine);
  503. if (cr != CR_SUCCESS)
  504. {
  505. dwErr = cr;
  506. break;
  507. }
  508. }
  509. // Otherwise, read 'em in...
  510. hDevInfo = SetupDiGetClassDevsExW(
  511. &DevGuid,
  512. NULL,
  513. NULL,
  514. DIGCF_PRESENT | DIGCF_PROFILE,
  515. NULL,
  516. pszMachine,
  517. NULL);
  518. if (hDevInfo == INVALID_HANDLE_VALUE)
  519. {
  520. *ppMap = NULL;
  521. *lpdwNumNodes = 0;
  522. dwErr = GetLastError();
  523. break;
  524. }
  525. // Enumerate the devices
  526. dwTotal = 0;
  527. for (dwIndex = 0; ; dwIndex++)
  528. {
  529. // Get the next device
  530. Device.cbSize = sizeof(SP_DEVINFO_DATA);
  531. if (! SetupDiEnumDeviceInfo(hDevInfo, dwIndex, &Device))
  532. {
  533. break;
  534. }
  535. // Get its registry key
  536. hkDev = SetupDiOpenDevRegKey(
  537. hDevInfo,
  538. &Device,
  539. DICS_FLAG_GLOBAL,
  540. 0,
  541. DIREG_DRV,
  542. KEY_READ);
  543. if ((hkDev == NULL) || (hkDev == INVALID_HANDLE_VALUE))
  544. {
  545. continue;
  546. }
  547. if (Map.dwNumNodes <= dwTotal + 1)
  548. {
  549. ElEnlargeMap (&Map, EL_MAP_GROW_FACTOR);
  550. }
  551. // Set up the data to be used by the filters
  552. //
  553. ZeroMemory(&IsNetCfgDevInfo, sizeof(IsNetCfgDevInfo));
  554. ZeroMemory(&AdapterStatusInfo, sizeof(AdapterStatusInfo));
  555. IsNetCfgDevInfo.pAdapter = &(Map.pNodes[dwTotal]);
  556. AdapterStatusInfo.pAdapter = IsNetCfgDevInfo.pAdapter;
  557. AdapterStatusInfo.hkCmMachine = hkCmMachine;
  558. AdapterStatusInfo.pszPnpInstance = (PWCHAR)
  559. IsNetCfgDevInfo.pszPnpInstance;
  560. // Filter out the devices we aren't interested
  561. // in.
  562. if ((ElDevicePassesFilter (hkMachine,
  563. hkDev,
  564. 0,
  565. ElIsLanAdapter)) &&
  566. (ElDevicePassesFilter (hkMachine,
  567. hkDev,
  568. (HANDLE)&IsNetCfgDevInfo,
  569. ElIsNetcfgDevice)) &&
  570. (ElDevicePassesFilter (hkMachine,
  571. hkDev,
  572. 0,
  573. ElIsNotHiddenDevice)) &&
  574. (ElDevicePassesFilter (hkMachine,
  575. hkDev,
  576. (HANDLE)&AdapterStatusInfo,
  577. ElGetAdapterStatus))
  578. )
  579. {
  580. dwTotal++;
  581. }
  582. RegCloseKey(hkDev);
  583. }
  584. #ifdef KSL_IPINIP
  585. //
  586. // Now read out the ip in ip interfaces
  587. //
  588. if(MprSetupIpInIpInterfaceFriendlyNameEnum(pszMachine,
  589. (BYTE **)&pIpIpTable,
  590. &dwIpIpCount) == NO_ERROR)
  591. {
  592. DWORD i;
  593. //
  594. // Grow the map
  595. //
  596. ElEnlargeMap (&Map, dwIpIpCount);
  597. //
  598. // Copy out the interface info
  599. //
  600. for(i = 0; i < dwIpIpCount; i++)
  601. {
  602. Map.pNodes[dwTotal].pszName = SysAllocString(pIpIpTable[i].wszFriendlyName);
  603. Map.pNodes[dwTotal].guid = pIpIpTable[i].Guid;
  604. Map.pNodes[dwTotal].dwStatus = EL_STATUS_OK;
  605. dwTotal++;
  606. }
  607. }
  608. #endif
  609. // Assign the return values
  610. *lpdwNumNodes = dwTotal;
  611. if (dwTotal)
  612. {
  613. *ppMap = Map.pNodes;
  614. }
  615. else
  616. {
  617. ElCleanup(Map.pNodes, 0);
  618. *ppMap = NULL;
  619. }
  620. } while (FALSE);
  621. // Cleanup
  622. {
  623. if (hkMachine)
  624. {
  625. RegCloseKey(hkMachine);
  626. }
  627. if (hDevInfo)
  628. {
  629. SetupDiDestroyDeviceInfoList(hDevInfo);
  630. }
  631. if (hkCmMachine)
  632. {
  633. CM_Disconnect_Machine(hkCmMachine);
  634. }
  635. }
  636. return dwErr;
  637. }
  638. //
  639. // Cleans up the buffer returned from ElEnumLanAdapters
  640. //
  641. DWORD
  642. ElCleanup (
  643. IN EL_ADAPTER_INFO * pMap,
  644. IN DWORD dwCount)
  645. {
  646. DWORD i;
  647. for (i = 0; i < dwCount; i++) {
  648. if (pMap[i].pszName)
  649. SysFreeString(pMap[i].pszName);
  650. }
  651. Free (pMap);
  652. return NO_ERROR;
  653. }