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.

536 lines
15 KiB

  1. //
  2. // Protocol.cpp
  3. //
  4. // Install, uninstall, and related code for protocols such as TCP/IP.
  5. //
  6. // History:
  7. //
  8. // 2/02/1999 KenSh Created for JetNet
  9. // 9/29/1999 KenSh Repurposed for Home Networking Wizard
  10. //
  11. #include "stdafx.h"
  12. #include "NetConn.h"
  13. #include "nconnwrap.h"
  14. #include "ParseInf.h"
  15. #include "TheApp.h"
  16. #include "HookUI.h"
  17. #include "NetCli.h"
  18. // Local functions
  19. //
  20. VOID RemoveOrphanedProtocol(LPCSTR pszProtocolID);
  21. HRESULT CreateNewProtocolBinding(LPCSTR pszProtocolDeviceID, LPSTR pszBuf, int cchBuf, LPCSTR pszClientBinding, LPCSTR pszServiceBinding);
  22. // IsProtocolInstalled
  23. //
  24. // Returns TRUE if one or more instances of the given protocol
  25. // (e.g. "MSTCP") is bound to a network adapter.
  26. //
  27. BOOL WINAPI IsProtocolInstalled(LPCTSTR pszProtocolDeviceID, BOOL bExhaustive)
  28. {
  29. if (!IsProtocolBoundToAnyAdapter(pszProtocolDeviceID))
  30. return FALSE;
  31. if (bExhaustive)
  32. {
  33. TCHAR szInfSection[50];
  34. wsprintf(szInfSection, "%s.Install", pszProtocolDeviceID);
  35. if (!CheckInfSectionInstallation("nettrans.inf", szInfSection))
  36. return FALSE;
  37. }
  38. return TRUE;
  39. }
  40. // InstallProtocol (public)
  41. //
  42. // Installs the given protocol via NETDI, and binds it to all adapters.
  43. // The standard progress UI is (mostly) suppressed, and instead the given
  44. // callback function is called so a custom progress UI can be implemented.
  45. //
  46. // Returns a NETCONN_xxx result, defined in NetConn.h
  47. //
  48. // Parameters:
  49. //
  50. // hwndParent parent window helpful to use in NETDI call
  51. // pfnProgress function to call with install progress reports
  52. // pvProgressParam user-supplied parameter to pass to pfnProgress
  53. //
  54. // History:
  55. //
  56. // 2/23/1999 KenSh Created
  57. // 3/26/1999 KenSh Check if already installed before reinstalling
  58. //
  59. HRESULT WINAPI InstallProtocol(LPCSTR pszProtocolID, HWND hwndParent, PROGRESS_CALLBACK pfnProgress, LPVOID pvProgressParam)
  60. {
  61. HRESULT hr = NETCONN_SUCCESS;
  62. if (!IsProtocolBoundToAnyAdapter(pszProtocolID))
  63. {
  64. RemoveOrphanedProtocol(pszProtocolID);
  65. BeginSuppressNetdiUI(hwndParent, pfnProgress, pvProgressParam);
  66. DWORD dwResult = CallClassInstaller16(hwndParent, SZ_CLASS_PROTOCOL, pszProtocolID);
  67. EndSuppressNetdiUI();
  68. if (g_bUserAbort)
  69. {
  70. hr = NETCONN_USER_ABORT;
  71. }
  72. else if (SUCCEEDED(HresultFromCCI(dwResult)))
  73. {
  74. hr = NETCONN_NEED_RESTART;
  75. }
  76. // Total hack to work around JetNet bug 1193
  77. // DoDummyDialog(hwndParent);
  78. }
  79. if (SUCCEEDED(hr))
  80. {
  81. // Ensure the protocol is bound exactly once to every NIC
  82. HRESULT hr2 = BindProtocolToAllAdapters(pszProtocolID);
  83. if (hr2 != NETCONN_SUCCESS)
  84. hr = hr2;
  85. }
  86. return hr;
  87. }
  88. // InstallTCPIP (public)
  89. //
  90. // Installs TCP/IP via NETDI. See InstallProtocol for details.
  91. //
  92. HRESULT WINAPI InstallTCPIP(HWND hwndParent, PROGRESS_CALLBACK pfnProgress, LPVOID pvProgressParam)
  93. {
  94. return InstallProtocol(SZ_PROTOCOL_TCPIP, hwndParent, pfnProgress, pvProgressParam);
  95. }
  96. HRESULT WINAPI RemoveProtocol(LPCSTR pszProtocol)
  97. {
  98. HRESULT hr = NETCONN_SUCCESS;
  99. // Remove all pointers to the protocol from net adapters
  100. NETADAPTER* prgAdapters;
  101. int cAdapters = EnumNetAdapters(&prgAdapters);
  102. for (int iAdapter = 0; iAdapter < cAdapters; iAdapter++)
  103. {
  104. NETADAPTER* pAdapter = &prgAdapters[iAdapter];
  105. LPTSTR* prgBindings;
  106. int cBindings = EnumMatchingNetBindings(pAdapter->szEnumKey, pszProtocol, &prgBindings);
  107. if (cBindings > 0)
  108. {
  109. CRegistry regBindings;
  110. if (regBindings.OpenKey(HKEY_LOCAL_MACHINE, pAdapter->szEnumKey) &&
  111. regBindings.OpenSubKey("Bindings"))
  112. {
  113. for (int iBinding = 0; iBinding < cBindings; iBinding++)
  114. {
  115. regBindings.DeleteValue(prgBindings[iBinding]);
  116. hr = NETCONN_NEED_RESTART;
  117. }
  118. }
  119. }
  120. NetConnFree(prgBindings);
  121. }
  122. NetConnFree(prgAdapters);
  123. // Remove the protocol's enum key
  124. CRegistry reg;
  125. if (reg.OpenKey(HKEY_LOCAL_MACHINE, "Enum\\Network"))
  126. {
  127. RegDeleteKeyAndSubKeys(reg.m_hKey, pszProtocol);
  128. }
  129. // Remove the protocol's class key(s)
  130. DeleteClassKeyReferences(SZ_CLASS_PROTOCOL, pszProtocol);
  131. return hr;
  132. }
  133. // IsProtocolBoundToAnyAdapter (public)
  134. //
  135. // Given a protocol ID, such as "MSTCP", returns TRUE if the protocol
  136. // is bound to any adapter, or FALSE if not.
  137. //
  138. // History:
  139. //
  140. // 3/26/1999 KenSh Created
  141. //
  142. BOOL WINAPI IsProtocolBoundToAnyAdapter(LPCSTR pszProtocolID)
  143. {
  144. BOOL bResult = FALSE;
  145. NETADAPTER* prgAdapters;
  146. int cAdapters = EnumNetAdapters(&prgAdapters);
  147. for (int i = 0; i < cAdapters; i++)
  148. {
  149. if (IsProtocolBoundToAdapter(pszProtocolID, &prgAdapters[i]))
  150. {
  151. bResult = TRUE;
  152. goto done;
  153. }
  154. }
  155. done:
  156. NetConnFree(prgAdapters);
  157. return bResult;
  158. }
  159. // Given a protocol ID, such as "MSTCP", and an adapter struct, determines
  160. // whether the protocol is bound to the adapter.
  161. BOOL WINAPI IsProtocolBoundToAdapter(LPCSTR pszProtocolID, const NETADAPTER* pAdapter)
  162. {
  163. LPSTR* prgBindings;
  164. int cBindings = EnumMatchingNetBindings(pAdapter->szEnumKey, pszProtocolID, &prgBindings);
  165. NetConnFree(prgBindings);
  166. return (BOOL)cBindings;
  167. }
  168. // Checks to see whether any instances of this protocol in the Class branch of
  169. // the registry are unreferenced, and deletes them if so.
  170. // pszProtocolID is the generic device ID of the protocol, e.g. "MSTCP"
  171. VOID RemoveOrphanedProtocol(LPCSTR pszProtocolID)
  172. {
  173. // REVIEW: Should we first delete references in Enum that are not in use?
  174. CRegistry reg;
  175. if (reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\Class\\NetTrans", KEY_ALL_ACCESS))
  176. {
  177. //
  178. // Enumerate the various protocols, e.g. "NetTrans\0000"
  179. //
  180. for (DWORD iKey = 0; ; iKey++)
  181. {
  182. CHAR szSubKey[MAX_PATH];
  183. DWORD cbSubKey = _countof(szSubKey);
  184. if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iKey, szSubKey, &cbSubKey, NULL, NULL, NULL, NULL))
  185. break;
  186. //
  187. // Open the "Ndi" subkey so we can see what kind of protocol this is
  188. //
  189. lstrcpy(szSubKey + cbSubKey, "\\Ndi");
  190. CRegistry regNode;
  191. if (regNode.OpenKey(reg.m_hKey, szSubKey, KEY_ALL_ACCESS))
  192. {
  193. CHAR szDeviceID[40];
  194. if (regNode.QueryStringValue("DeviceID", szDeviceID, _countof(szDeviceID)))
  195. {
  196. regNode.CloseKey(); // close the key before we try to delete it
  197. if (0 == lstrcmpi(szDeviceID, pszProtocolID))
  198. {
  199. //
  200. // Found the right protocol, now check if it's referenced
  201. //
  202. if (!IsNetClassKeyReferenced(szSubKey))
  203. {
  204. // Not referenced, so delete it
  205. szSubKey[cbSubKey] = '\0'; // back up to just "NetTrans"
  206. RegDeleteKeyAndSubKeys(reg.m_hKey, szSubKey);
  207. }
  208. }
  209. }
  210. }
  211. }
  212. }
  213. }
  214. // BindProtocolToAdapter
  215. //
  216. // pszProtocolEnumKey is the top-level Enum key for the protocol, e.g. "MSTCP"
  217. //
  218. // pszAdapterEnumKey is the first part of the top-level Enum key for the adapter,
  219. // e.g. "PCI\\VEN_10B7&DEV_9050" or "Root\\Net\\0000" (dial-up adapter)
  220. //
  221. // bEnableSharing determines whether file and printer sharing will be bound
  222. // to the protocol when running through the given adapter.
  223. //
  224. // History:
  225. //
  226. // 3/26/1999 KenSh Created
  227. // 4/09/1999 KenSh Added bEnableSharing flag
  228. //
  229. HRESULT BindProtocolToAdapter(HKEY hkeyAdapterBindings, LPCSTR pszProtocolDeviceID, BOOL bEnableSharing)
  230. {
  231. HRESULT hr;
  232. // NetTrans seems to always clone the Enum key, and also clone the Class key.
  233. // (the new clone of the Enum key points to the new clone of the Class key;
  234. // each new Enum's MasterCopy points to itself)
  235. // NetService and NetClient seem to clone the Enum key, but not the Class key.
  236. CHAR szClient[MAX_PATH];
  237. CHAR szService1[MAX_PATH];
  238. CHAR szService2[MAX_PATH];
  239. CHAR szProtocol[MAX_PATH];
  240. if (bEnableSharing)
  241. {
  242. if (FAILED(hr = CreateNewFilePrintSharing(szService1, _countof(szService1))))
  243. return hr;
  244. if (FAILED(hr = CreateNewFilePrintSharing(szService2, _countof(szService2))))
  245. return hr;
  246. }
  247. else
  248. {
  249. szService1[0] = '\0';
  250. szService2[0] = '\0';
  251. }
  252. if (FAILED(hr = CreateNewClientForMSNet(szClient, _countof(szClient), szService1)))
  253. return hr;
  254. if (FAILED(hr = CreateNewProtocolBinding(pszProtocolDeviceID, szProtocol, _countof(szProtocol), szClient, szService2)))
  255. return hr;
  256. // Bind the new protocol to the adapter
  257. if (ERROR_SUCCESS != RegSetValueEx(hkeyAdapterBindings, szProtocol, 0, REG_SZ, (CONST BYTE*)"", 1))
  258. return NETCONN_UNKNOWN_ERROR;
  259. return NETCONN_NEED_RESTART;
  260. }
  261. HRESULT BindProtocolToAllAdapters_Helper(LPCSTR pszProtocolDeviceID, LPCSTR pszAdapterKey, BOOL bIgnoreVirtualNics)
  262. {
  263. HRESULT hr = NETCONN_SUCCESS;
  264. // Get LowerRange interfaces for protocol
  265. CHAR szProtocolLower[100];
  266. GetDeviceLowerRange(SZ_CLASS_PROTOCOL, pszProtocolDeviceID, szProtocolLower, _countof(szProtocolLower));
  267. // For each adapter, ensure the protocol is bound exactly once
  268. //
  269. NETADAPTER* prgAdapters;
  270. int cAdapters = EnumNetAdapters(&prgAdapters);
  271. // Pass 0: add new bindings
  272. // Pass 1: delete inappropriate bindings
  273. for (int iPass = 0; iPass <= 1; iPass++)
  274. {
  275. for (int iAdapter = 0; iAdapter < cAdapters; iAdapter++)
  276. {
  277. NETADAPTER* pAdapter = &prgAdapters[iAdapter];
  278. CRegistry regAdapter;
  279. // Get UpperRange interfaces for adapter
  280. CHAR szAdapterUpper[100];
  281. GetDeviceUpperRange(SZ_CLASS_ADAPTER, pAdapter->szDeviceID, szAdapterUpper, _countof(szAdapterUpper));
  282. // Check for a match between the protocol and the adapter
  283. BOOL bMatchingInterface = CheckMatchingInterface(szProtocolLower, szAdapterUpper);
  284. CHAR szRegKey[MAX_PATH];
  285. wsprintf(szRegKey, "%s\\Bindings", pAdapter->szEnumKey);
  286. BOOL bCorrectNic = (NULL == pszAdapterKey) || (0 == lstrcmpi(pAdapter->szEnumKey, pszAdapterKey));
  287. if (!lstrcmpi(pszProtocolDeviceID, SZ_PROTOCOL_IPXSPX))
  288. {
  289. // Bind IPX/SPX to all non-broadband NICs by default (usually a max of 1)
  290. if (pszAdapterKey == NULL)
  291. {
  292. if (IsAdapterBroadband(pAdapter))
  293. bCorrectNic = FALSE;
  294. }
  295. // Don't bind IPX/SPX to Dial-Up (or other virtual) adapters (bugs 1163, 1164)
  296. if (pAdapter->bNicType == NIC_VIRTUAL)
  297. bCorrectNic = FALSE;
  298. }
  299. //
  300. // Check the bindings of the current adapter, looking for this protocol
  301. //
  302. if (regAdapter.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, KEY_ALL_ACCESS))
  303. {
  304. TCHAR szValueName[60];
  305. int cFound = 0;
  306. DWORD iValue = 0;
  307. for (;;)
  308. {
  309. DWORD cbValueName = _countof(szValueName);
  310. if (ERROR_SUCCESS != RegEnumValue(regAdapter.m_hKey, iValue, szValueName, &cbValueName, NULL, NULL, NULL, NULL))
  311. break;
  312. LPSTR pchSlash = strchr(szValueName, '\\');
  313. if (pchSlash == NULL)
  314. break;
  315. *pchSlash = '\0';
  316. if (0 == lstrcmpi(szValueName, pszProtocolDeviceID))
  317. {
  318. *pchSlash = '\\';
  319. // If this isn't the right NIC, or if there's not a matching
  320. // interface, or (optionally) if the NIC is virtual, then
  321. // unbind the protocol.
  322. BOOL bUnbindFromNic = !bCorrectNic || !bMatchingInterface;
  323. if (bIgnoreVirtualNics && (pAdapter->bNicType == NIC_VIRTUAL))
  324. bUnbindFromNic = FALSE;
  325. if (bUnbindFromNic || // bound to the wrong adapter!
  326. cFound != 0) // bound more than once to this NIC!
  327. {
  328. if (iPass == 1) // unbind on second pass only
  329. {
  330. // Remove the binding, then restart our search
  331. // for matching protocols
  332. RemoveBindingFromParent(regAdapter.m_hKey, szValueName);
  333. iValue = 0;
  334. cFound = 0;
  335. hr = NETCONN_NEED_RESTART;
  336. continue;
  337. }
  338. }
  339. cFound += 1;
  340. }
  341. iValue += 1;
  342. }
  343. if (bCorrectNic && iPass == 0)
  344. {
  345. if (cFound == 0)
  346. // Protocol is not yet bound to the correct adapter
  347. {
  348. if (bMatchingInterface) // There's an interface in common
  349. {
  350. BOOL bExternalNic = IsAdapterBroadband(pAdapter);
  351. // Enable file/printer sharing if:
  352. // * Adapter is an ethernet or IRDA adapter
  353. // * Adapter is not a broadband NIC
  354. BOOL bEnableSharing = FALSE;
  355. if ((pAdapter->bNetType == NETTYPE_LAN ||
  356. pAdapter->bNetType == NETTYPE_IRDA) &&
  357. !bExternalNic)
  358. {
  359. bEnableSharing = TRUE;
  360. }
  361. HRESULT hr2 = BindProtocolToAdapter(regAdapter.m_hKey, pszProtocolDeviceID, bEnableSharing);
  362. if (hr2 != NETCONN_SUCCESS)
  363. hr = hr2;
  364. }
  365. }
  366. }
  367. }
  368. }
  369. }
  370. NetConnFree(prgAdapters);
  371. return hr;
  372. }
  373. // BindProtocolToOnlyOneAdapter (public)
  374. HRESULT WINAPI BindProtocolToOnlyOneAdapter(LPCSTR pszProtocolDeviceID, LPCSTR pszAdapterKey, BOOL bIgnoreVirtualNics)
  375. {
  376. return BindProtocolToAllAdapters_Helper(pszProtocolDeviceID, pszAdapterKey, bIgnoreVirtualNics);
  377. }
  378. // BindProtocolToAllAdapters (public)
  379. //
  380. // Given the device ID ("MSTCP") of a protocol which is already installed,
  381. // binds that protocol to all adapters, as well as to client for Microsoft
  382. // Networks and File and Printer sharing.
  383. //
  384. // History:
  385. //
  386. // 3/26/1999 KenSh Created
  387. // 4/23/1999 KenSh Enable file sharing only on real NICs
  388. //
  389. HRESULT WINAPI BindProtocolToAllAdapters(LPCSTR pszProtocolDeviceID)
  390. {
  391. return BindProtocolToAllAdapters_Helper(pszProtocolDeviceID, NULL, FALSE);
  392. }
  393. // Given a protocol ID such as "MSTCP", an optional client binding string
  394. // such as "VREDIR\0000", and an optional service binding string such as
  395. // "VSERVER\0000", creates a new protocol binding, and copies the name of
  396. // the new binding into the buffer provided (e.g. "MSTCP\0001").
  397. HRESULT CreateNewProtocolBinding(LPCSTR pszProtocolDeviceID, LPSTR pszBuf, int cchBuf, LPCSTR pszClientBinding, LPCSTR pszServiceBinding)
  398. {
  399. HRESULT hr;
  400. if (FAILED(hr = FindAndCloneNetEnumKey(SZ_CLASS_PROTOCOL, pszProtocolDeviceID, pszBuf, cchBuf)))
  401. {
  402. ASSERT(FALSE);
  403. return hr;
  404. }
  405. // Now pszBuf contains a string of the form "MSTCP\0001"
  406. CHAR szBindings[60];
  407. CRegistry regBindings;
  408. lstrcpy(szBindings, pszBuf); // "MSTCP\0001"
  409. lstrcat(szBindings, "\\Bindings"); // "MSTCP\0001\Bindings"
  410. if (FAILED(hr = OpenNetEnumKey(regBindings, szBindings, KEY_ALL_ACCESS)))
  411. {
  412. ASSERT(FALSE);
  413. return hr;
  414. }
  415. // Delete existing bindings
  416. regBindings.DeleteAllValues();
  417. // Add the client and server bindings
  418. if (pszClientBinding != NULL && *pszClientBinding != '\0')
  419. regBindings.SetStringValue(pszClientBinding, "");
  420. if (pszServiceBinding != NULL && *pszServiceBinding != '\0')
  421. regBindings.SetStringValue(pszServiceBinding, "");
  422. // Change the MasterCopy to point to correct place
  423. CHAR szMasterCopy[MAX_PATH];
  424. wsprintf(szMasterCopy, "Enum\\Network\\%s", pszBuf);
  425. if (regBindings.OpenKey(HKEY_LOCAL_MACHINE, szMasterCopy, KEY_ALL_ACCESS))
  426. {
  427. regBindings.SetStringValue("MasterCopy", szMasterCopy);
  428. }
  429. // Create a clone of the driver (a.k.a. class key)
  430. CHAR szExistingDriver[60];
  431. CHAR szNewDriver[60];
  432. regBindings.QueryStringValue("Driver", szExistingDriver, _countof(szExistingDriver));
  433. CloneNetClassKey(szExistingDriver, szNewDriver, _countof(szNewDriver));
  434. // Change the Driver to point to the new class key
  435. CRegistry regEnumSubKey;
  436. VERIFY(SUCCEEDED(OpenNetEnumKey(regEnumSubKey, pszBuf, KEY_ALL_ACCESS)));
  437. regEnumSubKey.SetStringValue("Driver", szNewDriver);
  438. // If this is a new TCP/IP binding, ensure we don't have a static IP address
  439. if (0 == lstrcmpi(pszProtocolDeviceID, SZ_PROTOCOL_TCPIP))
  440. {
  441. CHAR szFullClassKey[100];
  442. wsprintf(szFullClassKey, "System\\CurrentControlSet\\Services\\Class\\%s", szNewDriver);
  443. CRegistry regClassKey;
  444. VERIFY(regClassKey.OpenKey(HKEY_LOCAL_MACHINE, szFullClassKey));
  445. if (regClassKey.QueryStringValue("IPAddress", szFullClassKey, _countof(szFullClassKey)))
  446. regClassKey.SetStringValue("IPAddress", "0.0.0.0");
  447. if (regClassKey.QueryStringValue("IPMask", szFullClassKey, _countof(szFullClassKey)))
  448. regClassKey.SetStringValue("IPMask", "0.0.0.0");
  449. }
  450. return NETCONN_SUCCESS;
  451. }