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.

586 lines
17 KiB

  1. //
  2. // ICSInst.cpp
  3. //
  4. // ICS (Internet Connection Sharing) installation functions and thunk
  5. // layer.
  6. //
  7. // History:
  8. //
  9. // 9/27/1999 RayRicha Created
  10. // 11/01/1999 KenSh Store function ptrs in array rather than globals
  11. // 12/09/1999 KenSh Check for 3rd party NATs
  12. //
  13. #include "stdafx.h"
  14. #include "ICSInst.h"
  15. #include "TheApp.h"
  16. #include "Config.h"
  17. #include "DefConn.h"
  18. #include "NetConn.h"
  19. #include "Util.h"
  20. #include "netapi.h"
  21. extern "C" {
  22. #include "icsapi.h"
  23. }
  24. // these are the Command Line parameters to CreateProcess for running a first time install and a reconfig
  25. static const TCHAR c_szUpdateDriverBindings[] = _T("rundll.exe ISSETUP.DLL,UpdateDriverBindings");
  26. static const TCHAR c_szInstallICS[] = _T("rundll.exe ISSETUP.DLL,InstallOptionalComponent ICS");
  27. static const TCHAR c_szUninstall[] = _T("rundll.exe ISSETUP.DLL,ExtUninstall");
  28. static const TCHAR c_szICSSettingsKey[] = _T("System\\CurrentControlSet\\Services\\ICSharing\\Settings\\General");
  29. static const TCHAR c_szICSInt[] = _T("System\\CurrentControlSet\\Services\\ICSharing\\Settings\\General\\InternalAdapters");
  30. static const TCHAR c_szInternalAdapters[] = _T("InternalAdapters");
  31. static const TCHAR c_szRunServices[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices");
  32. #define c_szIcsRegVal_ShowTrayIcon _T("ShowTrayIcon")
  33. #define SZ_UNINSTALL_KEY _T("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
  34. static void (PASCAL FAR * g_pfInstallOptionalComponent)(HWND, HINSTANCE, LPSTR, int);
  35. HHOOK g_hSupressRebootHook = NULL;
  36. //////////////////////////////////////////////////////////////////////////////
  37. // Helper functions
  38. BOOL RunNetworkInstall(BOOL* pfRebootRequired)
  39. {
  40. PROCESS_INFORMATION ProcessInfo;
  41. STARTUPINFO si;
  42. DWORD dwExitCode = 0xffffffffL;
  43. BOOL fSuccess;
  44. memset((char *)&si, 0, sizeof(si));
  45. si.cb = sizeof(si);
  46. si.wShowWindow = SW_SHOW;
  47. fSuccess = CreateProcess(NULL, (LPTSTR)c_szUpdateDriverBindings, NULL, NULL, FALSE,
  48. 0, NULL, NULL, &si, &ProcessInfo);
  49. if (fSuccess)
  50. {
  51. HANDLE hProcess = ProcessInfo.hProcess;
  52. CloseHandle(ProcessInfo.hThread);
  53. //
  54. // wait for update driver bindings to complete
  55. //
  56. WaitForSingleObject(hProcess, INFINITE);
  57. GetExitCodeProcess(hProcess, &dwExitCode);
  58. CloseHandle(hProcess);
  59. *pfRebootRequired = TRUE;
  60. return TRUE;
  61. }
  62. return FALSE;
  63. }
  64. // check for 3rd party NATs - returns TRUE if any are installed
  65. BOOL IsOtherNATAlreadyInstalled(LPTSTR pszOtherNatDescription, int cchOtherNatDescription)
  66. {
  67. BOOL bRet = FALSE;
  68. CRegistry reg;
  69. LPCTSTR pszUninstallKey = NULL;
  70. if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szRunServices, KEY_READ))
  71. {
  72. if (0 != reg.GetValueSize(_T("SyGateService")))
  73. {
  74. bRet = TRUE;
  75. pszUninstallKey = _T("SyGate");
  76. }
  77. else if (0 != reg.GetValueSize(_T("WinGate Service")))
  78. {
  79. bRet = TRUE;
  80. pszUninstallKey = _T("WinGate");
  81. }
  82. else if (0 != reg.GetValueSize(_T("ENSApServer"))) // Intel AnyPoint
  83. {
  84. bRet = TRUE;
  85. pszUninstallKey = _T("Intel AnyPoint Network Software");
  86. }
  87. else if (0 != reg.GetValueSize(_T("WinNATService"))) // Diamond HomeFree
  88. {
  89. bRet = TRUE;
  90. pszUninstallKey = _T("WinNAT");
  91. }
  92. }
  93. // WinProxy has to be launched manually, and requires a static IP. Just check
  94. // to see if it's installed - the user might not even be running it.
  95. //
  96. if (reg.OpenKey(HKEY_LOCAL_MACHINE, SZ_UNINSTALL_KEY _T("\\WinProxy"), KEY_READ))
  97. {
  98. bRet = TRUE;
  99. pszUninstallKey = _T("WinProxy");
  100. }
  101. if (pszOtherNatDescription != NULL)
  102. {
  103. *pszOtherNatDescription = _T('\0');
  104. if (bRet) // Get the friendly name of the conflicting service from uninstall key
  105. {
  106. if (reg.OpenKey(HKEY_LOCAL_MACHINE, SZ_UNINSTALL_KEY, KEY_READ))
  107. {
  108. if (reg.OpenSubKey(pszUninstallKey, KEY_READ))
  109. {
  110. reg.QueryStringValue(_T("DisplayName"), pszOtherNatDescription, cchOtherNatDescription);
  111. }
  112. }
  113. }
  114. }
  115. return bRet;
  116. }
  117. //////////////////////////////////////////////////////////////////////////////
  118. // CICSInst
  119. CICSInst::CICSInst()
  120. {
  121. m_option = ICS_NOACTION;
  122. m_pszHostName = theApp.LoadStringAlloc(IDS_ICS_HOST);
  123. m_bInstalledElsewhere = FALSE;
  124. m_bShowTrayIcon = TRUE;
  125. CRegistry reg;
  126. if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey, KEY_READ))
  127. {
  128. TCHAR szTrayIcon[10];
  129. if (reg.QueryStringValue(c_szIcsRegVal_ShowTrayIcon, szTrayIcon, _countof(szTrayIcon)))
  130. {
  131. if (!StrCmp(szTrayIcon, _T("0")))
  132. {
  133. m_bShowTrayIcon = FALSE;
  134. }
  135. }
  136. }
  137. }
  138. CICSInst::~CICSInst()
  139. {
  140. free(m_pszHostName);
  141. }
  142. BOOL
  143. CICSInst::InitICSAPI()
  144. {
  145. return TRUE;
  146. }
  147. // UpdateIcsTrayIcon
  148. //
  149. // Updates the registry values that affect the ICS tray icon, and
  150. // immediately updates the icon to reflect the new values.
  151. //
  152. // 2/04/2000 KenSh Created
  153. //
  154. void CICSInst::UpdateIcsTrayIcon()
  155. {
  156. CRegistry reg;
  157. if (reg.CreateKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey))
  158. {
  159. // Update the tray icon setting in the registry
  160. TCHAR szVal[2];
  161. szVal[0] = m_bShowTrayIcon ? _T('1') : _T('0');
  162. szVal[1] = _T('\0');
  163. reg.SetStringValue(c_szIcsRegVal_ShowTrayIcon, szVal);
  164. }
  165. // Show or hide the icon immediately
  166. HWND hwndTray = ::FindWindow(_T("ICSTrayWnd"), NULL);
  167. if (hwndTray != NULL)
  168. {
  169. // Post a custom message to the ICS manager window (icshare\util\icsmgr\trayicon.c)
  170. //
  171. // This message shows or hides the tray icon according to the value in
  172. // the registry.
  173. //
  174. // wParam: enable/disable accordint to value in registry
  175. // lParam: unused
  176. //
  177. UINT uUpdateMsg = RegisterWindowMessage(_T("ICSTaskbarUpdate"));
  178. PostMessage(hwndTray, uUpdateMsg, FALSE, 0L);
  179. }
  180. }
  181. void CICSInst::DoInstallOption(BOOL* pfRebootRequired, UINT ipaInternal)
  182. {
  183. BOOL bIcsInstalled = ::IsIcsInstalled();
  184. // Force uninstall if internal or external NIC is not valid
  185. if ((m_option == ICS_UNINSTALL && TRUE == bIcsInstalled)||
  186. (bIcsInstalled && m_option == ICS_NOACTION && !this->IsInstalled()))
  187. {
  188. Uninstall(pfRebootRequired);
  189. bIcsInstalled = FALSE;
  190. }
  191. // Force tray icon to show up, if ICS is currently installed
  192. m_bShowTrayIcon = TRUE;
  193. UpdateIcsTrayIcon();
  194. switch (m_option)
  195. {
  196. case ICS_INSTALL:
  197. if(FALSE == IsInstalled())
  198. {
  199. Install(pfRebootRequired, ipaInternal);
  200. }
  201. break;
  202. case ICS_UPDATEBINDINGS:
  203. UpdateBindings(pfRebootRequired, ipaInternal);
  204. break;
  205. case ICS_UNINSTALL:
  206. // Already handled above
  207. break;
  208. case ICS_ENABLE:
  209. Enable();
  210. break;
  211. case ICS_DISABLE:
  212. Disable();
  213. break;
  214. case ICS_CLIENTSETUP:
  215. SetupClient();
  216. break;
  217. case ICS_NOACTION:
  218. break;
  219. }
  220. }
  221. // Similar steps from here as Win98SE ConfigureICS (without UI)
  222. void CICSInst::UpdateBindings(BOOL* pfRebootRequired, UINT ipaInternal)
  223. {
  224. CConfig rghConfig;
  225. // TODO: remove hardcoded values!
  226. StrCpy(rghConfig.m_HangupTimer, _T("300"));
  227. SetInternetConnection();
  228. SetHomeConnection(ipaInternal);
  229. // REVIEW: is there a case where these values should be set differently?
  230. rghConfig.m_EnableICS = TRUE;
  231. rghConfig.m_EnableDialOnDemand = TRUE;
  232. rghConfig.m_EnableDHCP = TRUE;
  233. rghConfig.m_ShowTrayIcon = m_bShowTrayIcon;
  234. rghConfig.InitWizardResult();
  235. // Set to TRUE until we see a need to differentiate between new install and update
  236. rghConfig.WriteWizardCode(TRUE);
  237. int iSaveStatus = rghConfig.SaveConfig();
  238. // TODO: determine if we need to check for binding changes
  239. //if ( iSaveStatus == BINDINGS_NEEDED )
  240. //{
  241. RunNetworkInstall(pfRebootRequired);
  242. //}
  243. }
  244. void CICSInst::Install(BOOL* pfRebootRequired, UINT ipaInternal)
  245. {
  246. PROCESS_INFORMATION ProcessInfo;
  247. STARTUPINFO si;
  248. BOOL fSuccess;
  249. // Check for conflicting 3rd party NAT
  250. {
  251. TCHAR szConflictingNAT[260];
  252. if (IsOtherNATAlreadyInstalled(szConflictingNAT, _countof(szConflictingNAT)))
  253. {
  254. if (szConflictingNAT[0] == _T('\0'))
  255. {
  256. LPTSTR pszDefault1 = theApp.LoadStringAlloc(IDS_OTHERNAT_GENERIC);
  257. LPTSTR pszDefault2 = theApp.LoadStringAlloc(IDS_OTHERNAT_GENERIC_THE);
  258. if (pszDefault1 && pszDefault2)
  259. theApp.MessageBoxFormat(MB_ICONEXCLAMATION | MB_OK, IDS_ERR_OTHERNAT, pszDefault1, pszDefault2);
  260. free(pszDefault2);
  261. free(pszDefault1);
  262. }
  263. else
  264. {
  265. theApp.MessageBoxFormat(MB_ICONEXCLAMATION | MB_OK, IDS_ERR_OTHERNAT, szConflictingNAT, szConflictingNAT);
  266. }
  267. return; // block ICS installation
  268. }
  269. }
  270. ZeroMemory(&si, sizeof(si));
  271. si.cb = sizeof(si);
  272. si.wShowWindow = SW_SHOW;
  273. fSuccess = CreateProcess(NULL, (LPTSTR)c_szInstallICS, NULL, NULL, FALSE,
  274. 0, NULL, NULL, &si, &ProcessInfo);
  275. if (fSuccess)
  276. {
  277. HANDLE hProcess = ProcessInfo.hProcess;
  278. CloseHandle(ProcessInfo.hThread);
  279. //
  280. // wait for update driver bindings to complete
  281. //
  282. WaitForSingleObject(hProcess, INFINITE);
  283. CloseHandle(hProcess);
  284. UpdateBindings(pfRebootRequired, ipaInternal);
  285. // Need to reboot
  286. *pfRebootRequired = TRUE;
  287. }
  288. }
  289. LRESULT CALLBACK SupressRebootDialog(int nCode, WPARAM wParam, LPARAM lParam)
  290. {
  291. LRESULT lResult = 0;
  292. if (nCode == HCBT_CREATEWND)
  293. {
  294. HWND hwnd = (HWND)wParam;
  295. CBT_CREATEWND* pCW = (CBT_CREATEWND*)lParam;
  296. LPCREATESTRUCT pCreateStruct = pCW->lpcs;
  297. lResult = 1; // prevent window creation
  298. }
  299. else
  300. {
  301. lResult = CallNextHookEx(g_hSupressRebootHook, nCode, wParam, lParam);
  302. }
  303. return lResult;
  304. }
  305. void CICSInst::Uninstall(BOOL* pfRebootRequired)
  306. {
  307. g_hSupressRebootHook = SetWindowsHookEx(WH_CBT, SupressRebootDialog, NULL, GetCurrentThreadId()); // not thread safe, should be OK
  308. IcsUninstall();
  309. if(NULL != g_hSupressRebootHook)
  310. {
  311. UnhookWindowsHookEx(g_hSupressRebootHook );
  312. }
  313. *pfRebootRequired = TRUE;
  314. return;
  315. }
  316. BOOL CICSInst::IsInstalled()
  317. {
  318. // Make sure ICS is installed correctly by checking Internet and Home connection.
  319. return (IsIcsInstalled() && GetICSConnections(NULL, NULL) && IsHomeConnectionValid());
  320. }
  321. BOOL CICSInst::IsEnabled()
  322. {
  323. return IsIcsEnabled();
  324. }
  325. BOOL CICSInst::IsInstalledElsewhere()
  326. {
  327. if (m_bInstalledElsewhere || IsIcsAvailable())
  328. {
  329. //MessageBox(theApp.m_hWndMain, "IsIcsAvailable returned TRUE", "Test", MB_OK);
  330. // Note: if we knew the name of the ICS host, here's where we'd set m_pszHostName.
  331. return TRUE;
  332. }
  333. else
  334. {
  335. //MessageBox(theApp.m_hWndMain, "IsIcsAvailable returned FALSE", "Test", MB_OK);
  336. return FALSE;
  337. }
  338. }
  339. void CICSInst::SetInternetConnection()
  340. {
  341. /*
  342. if (-1 != theApp.m_uExternalAdapter)
  343. {
  344. TCHAR szClassKey[MAX_KEY_SIZE];
  345. StrCpy(szClassKey, FindFileTitle(theApp.m_pCachedNetAdapters[theApp.m_uExternalAdapter].szClassKey));
  346. CRegistry reg;
  347. reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey);
  348. reg.SetStringValue(_T("ExternalAdapter"), szClassKey);
  349. reg.SetStringValue(_T("ExternalAdapterReg"), szClassKey);
  350. }
  351. */
  352. }
  353. BOOL CICSInst::GetICSConnections(LPTSTR szExternalConnection, LPTSTR szInternalConnection)
  354. {
  355. CRegistry reg;
  356. TCHAR szEntry[10];
  357. if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey, KEY_READ))
  358. {
  359. if (reg.QueryStringValue(_T("ExternalAdapterReg"), szEntry, _countof(szEntry)) &&
  360. lstrlen(szEntry))
  361. {
  362. if (szExternalConnection)
  363. {
  364. StrCpy(szExternalConnection, szEntry);
  365. }
  366. if (reg.QueryStringValue(_T("InternalAdapterReg"), szEntry, _countof(szEntry)) &&
  367. lstrlen(szEntry))
  368. {
  369. if (szInternalConnection)
  370. {
  371. StrCpy(szInternalConnection, szEntry);
  372. }
  373. return TRUE;
  374. }
  375. }
  376. }
  377. return FALSE;
  378. }
  379. void CICSInst::SetHomeConnection(UINT ipaInternal)
  380. {
  381. int cInternalAdapter = 0; // hack for one adapter
  382. TCHAR szNumber[5];
  383. wnsprintf(szNumber, ARRAYSIZE(szNumber), TEXT("%04d"), cInternalAdapter);
  384. const NETADAPTER* pAdapterArray;
  385. EnumCachedNetAdapters(&pAdapterArray);
  386. const NETADAPTER* pAdapter = &pAdapterArray[ipaInternal];
  387. TCHAR szClassKey[MAX_KEY_SIZE];
  388. StrCpy(szClassKey, FindFileTitle((LPCTSTR)pAdapter->szClassKey));
  389. LPTSTR* prgBindings;
  390. int cBindings = EnumMatchingNetBindings(pAdapter->szEnumKey, SZ_PROTOCOL_TCPIP, (LPWSTR**)&prgBindings);
  391. CRegistry reg2(HKEY_LOCAL_MACHINE, c_szICSInt);
  392. reg2.CreateSubKey(szNumber);
  393. reg2.SetStringValue(_T("InternalAdapterReg"), szClassKey);
  394. reg2.SetStringValue(_T("InternalAdapter"), szClassKey);
  395. // Assume that adapter is only bound to one TCP/IP instance
  396. reg2.SetStringValue(_T("InternalBinding"), prgBindings[0]);
  397. TCHAR szIPAddress[30];
  398. wnsprintf(szIPAddress, ARRAYSIZE(szIPAddress), TEXT("192.168.%d.1,255.255.255.0"), cInternalAdapter);
  399. reg2.SetStringValue(_T("IntranetInfo"), szIPAddress);
  400. // TODO: remove
  401. // Put the first adapter in the "old location" to support legacy config
  402. CRegistry reg;
  403. reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey);
  404. reg.DeleteSubKey(c_szInternalAdapters);
  405. reg.CreateSubKey(c_szInternalAdapters);
  406. reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey);
  407. reg.SetStringValue(_T("InternalAdapterReg"), szClassKey);
  408. reg.SetStringValue(_T("InternalAdapter"), szClassKey);
  409. // Assume that adapter is only bound to one TCP/IP instance
  410. reg.SetStringValue(_T("InternalBinding"), prgBindings[0]);
  411. reg.SetStringValue(_T("IntranetInfo"), szIPAddress);
  412. }
  413. // TODO: expand with support for multiple adapters
  414. BOOL CICSInst::IsHomeConnectionValid()
  415. {
  416. CRegistry reg;
  417. TCHAR szEntry[10];
  418. if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey, KEY_READ))
  419. {
  420. if (reg.QueryStringValue(_T("InternalAdapterReg"), szEntry, _countof(szEntry)) &&
  421. lstrlen(szEntry))
  422. {
  423. return TRUE;
  424. }
  425. else
  426. {
  427. // Check for valid multiple-adapter scenario
  428. if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSInt) &&
  429. reg.OpenSubKey(_T("0000")) &&
  430. reg.QueryStringValue(_T("InternalAdapterReg"), szEntry, _countof(szEntry)) &&
  431. lstrlen(szEntry))
  432. {
  433. return TRUE;
  434. }
  435. }
  436. }
  437. return FALSE;
  438. }
  439. BOOL CICSInst::Enable()
  440. {
  441. if (InitICSAPI())
  442. {
  443. IcsEnable(0);
  444. return TRUE;
  445. }
  446. else
  447. {
  448. return FALSE;
  449. }
  450. // return (!IcsEnable(0));
  451. }
  452. BOOL CICSInst::Disable()
  453. {
  454. if (InitICSAPI())
  455. {
  456. IcsDisable(0);
  457. return TRUE;
  458. }
  459. else
  460. {
  461. return FALSE;
  462. }
  463. // return (!IcsDisable(0));
  464. }
  465. void CICSInst::SetupClient()
  466. {
  467. // Move this functionality to WizPages.cpp and Install.cpp for now
  468. //::SetDefaultDialupConnection(NULL);
  469. }
  470. BOOLEAN APIENTRY IsIcsInstalled(VOID) // API not available on Win98 so implement it here
  471. {
  472. BOOLEAN fIcsInstalled = FALSE;
  473. HKEY hKey;
  474. DWORD dwRet = RegOpenKeyEx (HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, (DWORD)0, KEY_READ, &hKey);
  475. if (ERROR_SUCCESS == dwRet)
  476. {
  477. DWORD dwType;
  478. char szValue[128];
  479. DWORD dwSize = sizeof(szValue) / sizeof(char);
  480. dwRet = RegQueryValueExA(hKey, "ICSMGR", NULL, &dwType, reinterpret_cast<LPBYTE>(szValue), &dwSize);
  481. if ((ERROR_SUCCESS == dwRet) && (dwType == REG_SZ))
  482. {
  483. fIcsInstalled = 0 == lstrcmpA(szValue, "ICSMGR.EXE");
  484. }
  485. RegCloseKey ( hKey );
  486. }
  487. return (fIcsInstalled);
  488. }