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.

2032 lines
56 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: cmroute.cpp
  4. //
  5. // Module: CMROUTE.DLL
  6. //
  7. // Synopsis: Route Plumbing implementation for CM, as a post-connect action
  8. //
  9. // Copyright (c) 1998-2000 Microsoft Corporation
  10. //
  11. // Author: 12-Mar-2000 SumitC Created
  12. //
  13. // Note:
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include "pch.h"
  17. #include "iphlpapi.h"
  18. #include "cmdebug.h"
  19. //
  20. // Include the shared source code for SuppressInetAutoDial and SetInetStateConnected
  21. //
  22. #include "inetopt.cpp"
  23. //
  24. // Include the locale-safe replacement for lstrcmpi
  25. //
  26. #include "CompareString.cpp"
  27. //
  28. // Function declarations
  29. //
  30. HRESULT ParseArgs(LPSTR pszArgList,
  31. BOOL * pfUseFile,
  32. LPSTR pszRoutesFile,
  33. BOOL * pfUseURL,
  34. LPSTR pszRoutesURL,
  35. BOOL * pfProfile,
  36. LPSTR pszProfile,
  37. BOOL * pfURLNotFoundIgnorable,
  38. BOOL * pfStayAliveOnAccessDenied,
  39. BOOL * pfKeepTempFiles);
  40. #if 0
  41. // see note below
  42. HRESULT CheckIPForwarding();
  43. #endif
  44. HRESULT Initialize(PMIB_IPFORWARDTABLE * pRouteTable, PMIB_IPFORWARDROW * pGateway);
  45. HRESULT GetRoutesFromFile(LPSTR pszFileName,
  46. LPSTR pszProfile,
  47. LPSTR * ppszRouteInfo,
  48. DWORD * pcbRouteInfo);
  49. HRESULT GetRoutesFromURL(LPSTR pszURL,
  50. BOOL fKeepTempFiles,
  51. LPSTR * ppszRouteInfo,
  52. DWORD * pcbRouteInfo);
  53. HRESULT ProcessRouteInfo(const LPSTR pszNewRouteInfo,
  54. DWORD cbNewRouteInfo,
  55. PMIB_IPFORWARDTABLE pmibRouteTable,
  56. PMIB_IPFORWARDROW pGateway,
  57. BOOL * pfDeleteDefaultGateway);
  58. HRESULT DeleteDefaultGateway(PMIB_IPFORWARDROW pGateway);
  59. //
  60. // Route Table functions
  61. //
  62. HRESULT GetRouteTable(PMIB_IPFORWARDTABLE * pTable);
  63. DWORD GetIf(const MIB_IPFORWARDROW& route, const MIB_IPFORWARDTABLE& RouteTable);
  64. PMIB_IPFORWARDROW GetDefaultGateway(PMIB_IPFORWARDTABLE pRouteTable);
  65. //
  66. // Helper functions
  67. //
  68. BOOL ConvertSzToIP(LPSTR sz, DWORD& dwIP);
  69. LPTSTR IPtoTsz(DWORD dw);
  70. LPSTR IPtosz(DWORD dwIP, char *psz);
  71. LPSTR StrCpyWithoutQuotes(LPSTR pszDest, LPCSTR pszSrc);
  72. BOOL VerifyProfileAndGetServiceDir(LPSTR pszProfile);
  73. //
  74. // IP Helper function prototypes
  75. //
  76. typedef DWORD (WINAPI *pfnCreateIpForwardEntrySpec)(PMIB_IPFORWARDROW);
  77. typedef DWORD (WINAPI *pfnDeleteIpForwardEntrySpec)(PMIB_IPFORWARDROW);
  78. typedef DWORD (WINAPI *pfnGetIpForwardTableSpec)(PMIB_IPFORWARDTABLE, PULONG, BOOL);
  79. pfnCreateIpForwardEntrySpec g_pfnCreateIpForwardEntry = NULL;
  80. pfnDeleteIpForwardEntrySpec g_pfnDeleteIpForwardEntry = NULL;
  81. pfnGetIpForwardTableSpec g_pfnGetIpForwardTable = NULL;
  82. HMODULE g_hIpHlpApi = NULL;
  83. #if DBG
  84. void PrintRouteTable();
  85. #endif
  86. //+----------------------------------------------------------------------------
  87. //
  88. // Func: FreeIpHlpApis
  89. //
  90. // Desc: This function frees the instance of iphlpapi.dll loaded through
  91. // LoadIpHelpApis. Note that it also sets the module handle and all
  92. // of the function pointers loaded from this module to NULL.
  93. //
  94. // Args: None
  95. //
  96. // Return: Nothing
  97. //
  98. // Notes:
  99. //
  100. // History: 14-Dec-2000 quintinb Created
  101. //
  102. //-----------------------------------------------------------------------------
  103. void FreeIpHlpApis(void)
  104. {
  105. if (g_hIpHlpApi)
  106. {
  107. FreeLibrary(g_hIpHlpApi);
  108. g_hIpHlpApi = NULL;
  109. g_pfnCreateIpForwardEntry = NULL;
  110. g_pfnDeleteIpForwardEntry = NULL;
  111. g_pfnGetIpForwardTable = NULL;
  112. }
  113. }
  114. //+----------------------------------------------------------------------------
  115. //
  116. // Func: LoadIpHelpApis
  117. //
  118. // Desc: This functions loads a copy of the iphlpapi.dll and then retrieves
  119. // function pointers for CreateIpForwardEntry, DeleteIpForwardEntry,
  120. // and GetIpForwardTable. The module handle and the function pointers
  121. // are stored in globals vars.
  122. //
  123. // Args: None
  124. //
  125. // Return: HRESULT - S_OK on success, S_FALSE on failure. This prevents cmroute
  126. // from returning an error value (which would stop the connection)
  127. // but allows cmroute to exit cleanly.
  128. //
  129. // Notes:
  130. //
  131. // History: 14-Dec-2000 quintinb Created
  132. //
  133. //-----------------------------------------------------------------------------
  134. HRESULT LoadIpHelpApis(void)
  135. {
  136. HRESULT hr = S_FALSE; // we want the connection to continue but cmroute to not do anything...
  137. g_hIpHlpApi = LoadLibrary(TEXT("IPHLPAPI.DLL"));
  138. if (g_hIpHlpApi)
  139. {
  140. g_pfnCreateIpForwardEntry = (pfnCreateIpForwardEntrySpec)GetProcAddress(g_hIpHlpApi, "CreateIpForwardEntry");
  141. g_pfnDeleteIpForwardEntry = (pfnDeleteIpForwardEntrySpec)GetProcAddress(g_hIpHlpApi, "DeleteIpForwardEntry");
  142. g_pfnGetIpForwardTable = (pfnGetIpForwardTableSpec)GetProcAddress(g_hIpHlpApi, "GetIpForwardTable");
  143. if (g_pfnCreateIpForwardEntry && g_pfnDeleteIpForwardEntry && g_pfnGetIpForwardTable)
  144. {
  145. hr = S_OK;
  146. }
  147. else
  148. {
  149. FreeIpHlpApis();
  150. }
  151. }
  152. CMTRACEHR("LoadIpHelpApis", hr);
  153. return hr;
  154. }
  155. //+----------------------------------------------------------------------------
  156. //
  157. // Func: SetRoutes
  158. //
  159. // Desc: The entry point for handling route munging for VPN connections.
  160. // This is a Connection Manager connect action and uses the CM connect
  161. // action format (see CMAK docs for more info). Thus the parameters
  162. // to the dll are passed via a string which contains parameters (see the
  163. // cmproxy spec for a list of the parameter values).
  164. //
  165. // Args: [hWnd] - window handle of caller
  166. // [hInst] - instance handle of caller
  167. // [pszArgs] - argument string for connect action
  168. // [nShow] - unused
  169. //
  170. // Return: HRESULT
  171. //
  172. // Notes:
  173. //
  174. // History: 12-Mar-2000 SumitC Created
  175. //
  176. //-----------------------------------------------------------------------------
  177. HRESULT WINAPI SetRoutes(HWND hWnd, HINSTANCE hInst, LPSTR pszArgs, int nShow)
  178. {
  179. HRESULT hr = S_OK;
  180. PMIB_IPFORWARDTABLE pRouteTable = NULL;
  181. PMIB_IPFORWARDROW pGateway = NULL;
  182. LPSTR pszRoutesFromFile = NULL;
  183. DWORD cbRoutesFromFile = 0;
  184. LPSTR pszRoutesFromURL = NULL;
  185. DWORD cbRoutesFromURL = 0;
  186. // results of parsing the commandline
  187. BOOL fUseFile = FALSE;
  188. BOOL fUseURL = FALSE;
  189. BOOL fProfile = FALSE;
  190. BOOL fURLNotFoundIsNotFatal = FALSE;
  191. BOOL fStayAliveOnAccessDenied = FALSE;
  192. BOOL fDeleteDefaultGatewayViaFile = FALSE;
  193. BOOL fDeleteDefaultGatewayViaURL = FALSE;
  194. BOOL fKeepTempFiles = FALSE;
  195. char szRoutesFile[MAX_PATH + 1];
  196. char szRoutesURL[MAX_PATH + 1];
  197. char szProfile[MAX_PATH + 1];
  198. #if 0
  199. /*
  200. // start security check to block unauthorized users
  201. // REVIEW: remove before shipping!
  202. //
  203. // Quick and dirty security test. See if we can open hard-coded file first.
  204. // If file is not available, then bail out completely.
  205. //
  206. lstrcpy(szRoutesFile, "\\\\sherpa\\route-plumb\\msroutes.txt");
  207. HANDLE hFile = CreateFile(szRoutesFile,
  208. GENERIC_READ,
  209. FILE_SHARE_READ,
  210. NULL,
  211. OPEN_EXISTING,
  212. FILE_ATTRIBUTE_NORMAL,
  213. NULL);
  214. if (INVALID_HANDLE_VALUE == hFile)
  215. {
  216. CMTRACE1("Unable to access file %s\n", szRoutesFile);
  217. MessageBox(NULL, "You are not authorized to use this tool.",
  218. "CMROUTE.DLL Custom Action", MB_OK);
  219. CloseHandle(hFile);
  220. return E_ACCESSDENIED;
  221. }
  222. CloseHandle(hFile);
  223. // end security check
  224. */
  225. #endif
  226. //
  227. // See if we can get the function pointers we need in IP helper?
  228. //
  229. hr = LoadIpHelpApis();
  230. if (S_OK != hr)
  231. {
  232. goto Cleanup;
  233. }
  234. //
  235. // parse args
  236. //
  237. hr = ParseArgs(pszArgs,
  238. &fUseFile,
  239. szRoutesFile,
  240. &fUseURL,
  241. szRoutesURL,
  242. &fProfile,
  243. szProfile,
  244. &fURLNotFoundIsNotFatal,
  245. &fStayAliveOnAccessDenied,
  246. &fKeepTempFiles);
  247. if (S_OK != hr)
  248. {
  249. goto Cleanup;
  250. }
  251. #if 0
  252. // see note below
  253. hr = CheckIPForwarding();
  254. if (S_FALSE == hr)
  255. {
  256. CMTRACE("SetRoutes: IP forwarding is enabled - cmroute won't do anything");
  257. hr = S_OK;
  258. goto Cleanup;
  259. }
  260. if (S_OK != hr)
  261. {
  262. goto Cleanup;
  263. }
  264. #endif
  265. #if DBG
  266. PrintRouteTable();
  267. #endif
  268. //
  269. // Get the routetable and default gateway
  270. //
  271. hr = Initialize(&pRouteTable, &pGateway);
  272. if (S_OK != hr)
  273. {
  274. goto Cleanup;
  275. }
  276. //
  277. // Get the routes out of the file if asked
  278. //
  279. if (fUseFile)
  280. {
  281. hr = GetRoutesFromFile(szRoutesFile,
  282. (fProfile ? szProfile : NULL),
  283. &pszRoutesFromFile,
  284. &cbRoutesFromFile);
  285. if (S_OK != hr)
  286. {
  287. goto Cleanup;
  288. }
  289. #if DBG
  290. OutputDebugString(pszRoutesFromFile);
  291. #endif
  292. }
  293. //
  294. // Get the routes out of the URL if asked
  295. //
  296. if (fUseURL)
  297. {
  298. hr = GetRoutesFromURL(szRoutesURL,
  299. fKeepTempFiles,
  300. &pszRoutesFromURL,
  301. &cbRoutesFromURL);
  302. if (S_OK != hr)
  303. {
  304. //
  305. // It might have been worth adding a clause below to restrict this
  306. // to "failures to access the URL", but this list of errorcodes is
  307. // likely to be large (and if the system is really hosed, we'll find
  308. // out soon enough). So, bypass *all* errors if /DONT_REQUIRE_URL
  309. // is set.
  310. //
  311. if (fURLNotFoundIsNotFatal)
  312. {
  313. //
  314. // If URL_Access_Failure_Not_Fatal is set, don't return an error.
  315. // However, we unset the flag so that we stop processing the URL.
  316. //
  317. CMTRACE("SetRoutes: dont_require_url is set, bypassing error");
  318. fUseURL = FALSE;
  319. hr = S_OK;
  320. }
  321. else
  322. {
  323. goto Cleanup;
  324. }
  325. }
  326. #if DBG
  327. OutputDebugString(pszRoutesFromURL);
  328. #endif
  329. }
  330. //
  331. // Now set the routes
  332. //
  333. MYDBGASSERT(S_OK == hr);
  334. if (fUseFile)
  335. {
  336. hr = ProcessRouteInfo(pszRoutesFromFile, cbRoutesFromFile, pRouteTable, pGateway, &fDeleteDefaultGatewayViaFile);
  337. if (S_OK != hr)
  338. {
  339. CMTRACE1("SetRoutes: adding routes from FILE failed with %x", hr);
  340. goto Cleanup;
  341. }
  342. }
  343. MYDBGASSERT(S_OK == hr);
  344. if (fUseURL)
  345. {
  346. hr = ProcessRouteInfo(pszRoutesFromURL, cbRoutesFromURL, pRouteTable, pGateway, &fDeleteDefaultGatewayViaURL);
  347. if (S_OK != hr)
  348. {
  349. if ((E_UNEXPECTED == hr) && fURLNotFoundIsNotFatal)
  350. {
  351. // we use E_UNEXPECTED to indicate that the URL points to a .htm file
  352. // instead of the file containing just routes which is what we're
  353. // expecting. In this case, we ignore this error.
  354. //
  355. CMTRACE("html string found error ignored because Dont_Require_URL is set");
  356. hr = S_OK;
  357. }
  358. else
  359. {
  360. CMTRACE1("SetRoutes: adding routes from URL failed with %x", hr);
  361. goto Cleanup;
  362. }
  363. }
  364. }
  365. //
  366. // Delete default gateway
  367. //
  368. MYDBGASSERT(S_OK == hr);
  369. if (fDeleteDefaultGatewayViaFile || fDeleteDefaultGatewayViaURL)
  370. {
  371. hr = DeleteDefaultGateway(pGateway);
  372. }
  373. Cleanup:
  374. //
  375. // cleanup and leave
  376. //
  377. if (pRouteTable)
  378. {
  379. VirtualFree(pRouteTable, 0, MEM_RELEASE);
  380. }
  381. FreeIpHlpApis();
  382. //
  383. // If we failed because of an access denied error from iphlpapi, but the admin
  384. // has set the flag to keep the connection alive anyway, mask the error.
  385. //
  386. if ((HRESULT_FROM_WIN32(ERROR_NETWORK_ACCESS_DENIED) == hr) &&
  387. fStayAliveOnAccessDenied)
  388. {
  389. CMTRACE("SetRoutes: masking ERROR_NETWORK_ACCESS_DENIED because of StayAlive flag");
  390. hr = S_FALSE;
  391. }
  392. CMTRACEHR("SetRoutes", hr);
  393. return hr;
  394. }
  395. //+----------------------------------------------------------------------------
  396. //
  397. // Func: GetNextToken
  398. //
  399. // Desc: utility function for parsing the argument string. Goes past leading
  400. // whitespace and extracts a string
  401. //
  402. // Args: [pszStart] - IN the argument string
  403. // [ppszEnd] - OUT where parsing for this arg ended
  404. // [pszOut] - INOUT array of size MAX_PATH to hold arg if found
  405. //
  406. // Return: BOOL, TRUE if another arg found, FALSE if not
  407. //
  408. // Notes:
  409. //
  410. // History: 12-Mar-2000 SumitC Created
  411. //
  412. //-----------------------------------------------------------------------------
  413. BOOL
  414. GetNextToken(LPSTR pszStart, LPSTR * ppszEnd, LPSTR pszOut)
  415. {
  416. MYDBGASSERT(pszStart);
  417. MYDBGASSERT(ppszEnd);
  418. LPSTR pszEnd = NULL;
  419. // clear leading white space
  420. while (isspace(*pszStart))
  421. {
  422. pszStart++;
  423. }
  424. if (NULL == *pszStart)
  425. {
  426. // just white space, no arg
  427. return FALSE;
  428. }
  429. //
  430. // If this character is ", this is probably a quoted string, containing spaces.
  431. // In this case, the termination character is another ". Otherwise, assume
  432. // it is a regular string terminated by a space.
  433. //
  434. if ('"' == *pszStart)
  435. {
  436. // may be a string containing spaces.
  437. pszEnd = strchr(pszStart + 1, '"');
  438. }
  439. if (NULL == pszEnd)
  440. {
  441. //
  442. // Either it's a regular string, or we couldn't find a terminating " char
  443. // so we fall back on space-delimited handling.
  444. //
  445. pszEnd = pszStart + 1;
  446. while (*pszEnd && !isspace(*pszEnd))
  447. {
  448. pszEnd++;
  449. }
  450. pszEnd--;
  451. }
  452. UINT cLen = (UINT)(pszEnd - pszStart + 1);
  453. if (cLen + 1 > MAX_PATH)
  454. {
  455. return FALSE;
  456. }
  457. else
  458. {
  459. lstrcpyn(pszOut, pszStart, cLen + 1);
  460. *ppszEnd = ++pszEnd;
  461. return TRUE;
  462. }
  463. }
  464. //+----------------------------------------------------------------------------
  465. //
  466. // Func: Initialize
  467. //
  468. // Desc: Initialization function, gets the route table and default gateway
  469. //
  470. // Args: [ppmibRouteTable] - return location for route table
  471. // [ppGateway] - return location for default gateway
  472. //
  473. // Return: HRESULT
  474. //
  475. // Notes:
  476. //
  477. // History: 12-Mar-2000 SumitC Created
  478. //
  479. //-----------------------------------------------------------------------------
  480. HRESULT
  481. Initialize(
  482. OUT PMIB_IPFORWARDTABLE * ppmibRouteTable,
  483. OUT PMIB_IPFORWARDROW * ppGateway)
  484. {
  485. HRESULT hr = S_OK;
  486. MYDBGASSERT(ppmibRouteTable);
  487. MYDBGASSERT(ppGateway);
  488. if (NULL == ppmibRouteTable || NULL == ppGateway)
  489. {
  490. return E_INVALIDARG;
  491. }
  492. hr = GetRouteTable(ppmibRouteTable);
  493. if (S_OK == hr)
  494. {
  495. MYDBGASSERT(*ppmibRouteTable);
  496. *ppGateway = GetDefaultGateway(*ppmibRouteTable);
  497. }
  498. CMTRACEHR("Initialize", hr);
  499. return hr;
  500. }
  501. //+----------------------------------------------------------------------------
  502. //
  503. // Func: ParseArgs
  504. //
  505. // Desc: convert the argument list into flags for our use.
  506. //
  507. // Args: [pszArgList] - IN, the argument list
  508. // [the rest] - OUT, all the arg values returned
  509. //
  510. // Return: HRESULT
  511. //
  512. // Notes:
  513. //
  514. // History: 12-Mar-2000 SumitC Created
  515. //
  516. //-----------------------------------------------------------------------------
  517. HRESULT
  518. ParseArgs(
  519. LPSTR pszArgList,
  520. BOOL * pfUseFile,
  521. LPSTR pszRoutesFile,
  522. BOOL * pfUseURL,
  523. LPSTR pszRoutesURL,
  524. BOOL * pfProfile,
  525. LPSTR pszProfile,
  526. BOOL * pfURLNotFoundIgnorable,
  527. BOOL * pfStayAliveOnAccessDenied,
  528. BOOL * pfKeepTempFiles)
  529. {
  530. HRESULT hr = S_OK;
  531. char szArg[MAX_PATH];
  532. //
  533. // verify arguments
  534. //
  535. if (NULL == pszArgList || 0 == lstrlen(pszArgList) ||
  536. !pfUseFile || !pszRoutesFile || !pfUseURL || !pszRoutesURL ||
  537. !pfProfile || !pszProfile ||
  538. !pfURLNotFoundIgnorable ||
  539. !pfKeepTempFiles)
  540. {
  541. return E_INVALIDARG;
  542. }
  543. CMTRACE1("ParseArgs: arg list is %s", pszArgList);
  544. //
  545. // set the defaults
  546. //
  547. *pfUseFile = *pfUseURL = *pfProfile = *pfURLNotFoundIgnorable = FALSE;
  548. //
  549. // process the Arglist
  550. //
  551. while (GetNextToken(pszArgList, &pszArgList, szArg))
  552. {
  553. if (0 == SafeCompareString("/Static_File_Name", szArg))
  554. {
  555. *pfUseFile = TRUE;
  556. if (!GetNextToken(pszArgList, &pszArgList, szArg))
  557. {
  558. return E_INVALIDARG;
  559. }
  560. if (lstrlen(szArg) > MAX_PATH)
  561. {
  562. CMTRACE("ParseArgs: file name is bigger than MAX_PATH!!");
  563. return E_INVALIDARG;
  564. }
  565. StrCpyWithoutQuotes(pszRoutesFile, szArg);
  566. }
  567. else if (0 == SafeCompareString("/Dont_Require_URL", szArg))
  568. {
  569. *pfURLNotFoundIgnorable = TRUE;
  570. }
  571. else if (0 == SafeCompareString("/URL_Update_Path", szArg))
  572. {
  573. *pfUseURL = TRUE;
  574. if (!GetNextToken(pszArgList, &pszArgList, szArg))
  575. {
  576. return E_INVALIDARG;
  577. }
  578. if (lstrlen(szArg) > MAX_PATH)
  579. {
  580. CMTRACE("ParseArgs: URL name is bigger than MAX_PATH!!");
  581. return E_INVALIDARG;
  582. }
  583. lstrcpy(pszRoutesURL, szArg);
  584. }
  585. else if (0 == SafeCompareString("/Profile", szArg))
  586. {
  587. *pfProfile = TRUE;
  588. if (!GetNextToken(pszArgList, &pszArgList, szArg))
  589. {
  590. return E_INVALIDARG;
  591. }
  592. if (lstrlen(szArg) > MAX_PATH)
  593. {
  594. CMTRACE("ParseArgs: Profile filename is bigger than MAX_PATH!!");
  595. return E_INVALIDARG;
  596. }
  597. StrCpyWithoutQuotes(pszProfile, szArg);
  598. }
  599. else if (0 == SafeCompareString("/IPHlpApi_Access_Denied_OK", szArg))
  600. {
  601. *pfStayAliveOnAccessDenied = TRUE;
  602. }
  603. else if (0 == SafeCompareString("/No_Delete", szArg))
  604. {
  605. *pfKeepTempFiles = TRUE;
  606. }
  607. else
  608. {
  609. CMTRACE1("Cmroute: unrecognized parameter - %s", szArg);
  610. MYDBGASSERT("Cmroute - unrecognized parameter!!");
  611. }
  612. }
  613. CMTRACEHR("ParseArgs", hr);
  614. return hr;
  615. }
  616. #if 0
  617. // 2000/11/28 SumitC
  618. // It wasn't clear what the required action should be when IP forwarding was
  619. // detected (should the connection be dropped or not) and it is a little late
  620. // to add UI to Whistler. The 'Check IP forwarding' feature is thus removed.
  621. //
  622. // see Windows Db bug # 216558 for more details.
  623. //+----------------------------------------------------------------------------
  624. //
  625. // Func: CheckIPForwarding
  626. //
  627. // Desc: checks to see if anything is enabled on the client machine that would
  628. // make us want to have cmroute not do anything
  629. //
  630. // Args: none
  631. //
  632. // Return: HRESULT
  633. //
  634. // Notes:
  635. //
  636. // History: 01-Nov-2000 SumitC Created
  637. //
  638. //-----------------------------------------------------------------------------
  639. HRESULT
  640. CheckIPForwarding()
  641. {
  642. HRESULT hr = S_OK;
  643. MIB_IPSTATS stats;
  644. if (NO_ERROR != GetIpStatistics(&stats))
  645. {
  646. hr = HRESULT_FROM_WIN32(GetLastError());
  647. }
  648. else
  649. {
  650. if (stats.dwForwarding)
  651. {
  652. hr = S_FALSE;
  653. }
  654. }
  655. CMTRACEHR("CheckIPForwarding", hr);
  656. return hr;
  657. }
  658. #endif
  659. //+----------------------------------------------------------------------------
  660. //
  661. // Func: GetRoutesFromFile
  662. //
  663. // Desc: extracts the contents of the given file
  664. //
  665. // Args: [pszFileName] - IN, filename
  666. // [pszProfile] - IN, profile if available
  667. // [ppszRouteInfo] - OUT, the route table bytes
  668. // [pcbRouteInfo] - OUT, the route table size
  669. //
  670. // Return: HRESULT
  671. //
  672. // Notes:
  673. //
  674. // History: 12-Mar-2000 SumitC Created
  675. //
  676. //-----------------------------------------------------------------------------
  677. HRESULT
  678. GetRoutesFromFile(
  679. LPSTR pszFileName,
  680. LPSTR pszProfile,
  681. LPSTR * ppszRouteInfo,
  682. DWORD * pcbRouteInfo)
  683. {
  684. HRESULT hr = S_OK;
  685. HANDLE hFile = NULL;
  686. LPSTR psz = NULL;
  687. DWORD cb = 0;
  688. BOOL fRet;
  689. BY_HANDLE_FILE_INFORMATION info;
  690. MYDBGASSERT(pszFileName);
  691. MYDBGASSERT(ppszRouteInfo);
  692. MYDBGASSERT(pcbRouteInfo);
  693. if (NULL == pszFileName || NULL == ppszRouteInfo || NULL == pcbRouteInfo)
  694. {
  695. hr = E_INVALIDARG;
  696. goto Cleanup;
  697. }
  698. CMTRACE1("GetRoutesFromFile: filename is %s", pszFileName);
  699. //
  700. // open the file, and read its contents into a buffer
  701. //
  702. hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  703. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  704. if (INVALID_HANDLE_VALUE == hFile)
  705. {
  706. //
  707. // perhaps the full pathname for the routes file wasn't specified. If
  708. // a Profile was passed in, we extract the ServiceDir and try again,
  709. // using the ServiceDir as the path.
  710. //
  711. if (VerifyProfileAndGetServiceDir(pszProfile))
  712. {
  713. char sz[2 * MAX_PATH + 1];
  714. lstrcpy(sz, pszProfile);
  715. lstrcat(sz, pszFileName);
  716. CMTRACE1("GetRoutesFromFile: retrying with %s", sz);
  717. hFile = CreateFile(sz, GENERIC_READ, FILE_SHARE_READ, NULL,
  718. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  719. }
  720. if (INVALID_HANDLE_VALUE == hFile)
  721. {
  722. hr = HRESULT_FROM_WIN32(GetLastError());
  723. goto Cleanup;
  724. }
  725. }
  726. if (FALSE == GetFileInformationByHandle(hFile, &info))
  727. {
  728. hr = E_FAIL;
  729. goto Cleanup;
  730. }
  731. if (0 == info.nFileSizeLow)
  732. {
  733. CMTRACE("Routes file is EMPTY!!");
  734. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  735. goto Cleanup;
  736. }
  737. psz = (LPSTR) VirtualAlloc(NULL, info.nFileSizeLow, MEM_COMMIT, PAGE_READWRITE);
  738. if (NULL == psz)
  739. {
  740. hr = E_OUTOFMEMORY;
  741. goto Cleanup;
  742. }
  743. fRet = ReadFile(hFile, psz, info.nFileSizeLow, &cb, NULL);
  744. if (FALSE == fRet)
  745. {
  746. hr = E_FAIL;
  747. goto Cleanup;
  748. }
  749. // success
  750. *ppszRouteInfo = psz;
  751. *pcbRouteInfo = cb;
  752. Cleanup:
  753. if (hFile)
  754. {
  755. CloseHandle(hFile);
  756. }
  757. if (S_OK != hr)
  758. {
  759. VirtualFree(psz, 0, MEM_RELEASE);
  760. }
  761. CMTRACEHR("GetRoutesFromFile", hr);
  762. return hr;
  763. }
  764. //+----------------------------------------------------------------------------
  765. //
  766. // Func: GetRoutesFromURL
  767. //
  768. // Desc: extracts the contents of the given URL
  769. //
  770. // Args: [pszURL] - IN, the URL
  771. // [fKeepTempFiles] - IN, do not delete temp buffer file(s)
  772. // [ppszRouteInfo] - OUT, the route table bytes
  773. // [pcbRouteInfo] - OUT, the route table size
  774. //
  775. // Return: HRESULT
  776. //
  777. // Notes:
  778. //
  779. // History: 12-Mar-2000 SumitC Created
  780. //
  781. //-----------------------------------------------------------------------------
  782. HRESULT
  783. GetRoutesFromURL(
  784. LPSTR pszURL,
  785. BOOL fKeepTempFiles,
  786. LPSTR * ppszRouteInfo,
  787. DWORD * pcbRouteInfo)
  788. {
  789. HRESULT hr = S_OK;
  790. HINTERNET hInternet = NULL;
  791. HINTERNET hPage = NULL;
  792. LPBYTE pb = NULL;
  793. DWORD cb = 0;
  794. TCHAR szLocalBufferFile[MAX_PATH + 1];
  795. DWORD cchLocalBuffer = 0;
  796. LPTSTR pszLocalBuffer = NULL;
  797. FILE * fp = NULL;
  798. BYTE Buffer[1024];
  799. DWORD dwRead;
  800. MYDBGASSERT(pszURL);
  801. MYDBGASSERT(ppszRouteInfo);
  802. MYDBGASSERT(pcbRouteInfo);
  803. if (NULL == pszURL || NULL == ppszRouteInfo || NULL == pcbRouteInfo)
  804. {
  805. hr = E_INVALIDARG;
  806. goto Cleanup;
  807. }
  808. CMTRACE1("GetRoutesFromURL: URL is %s", pszURL);
  809. //
  810. // Get the path to the temp dir, if there is one.
  811. //
  812. cchLocalBuffer = GetTempPath(0, NULL);
  813. if (0 == cchLocalBuffer)
  814. {
  815. DWORD dwErr = GetLastError();
  816. CMTRACE1(TEXT("GetTempPath failed, using current dir, GLE=%d"), dwErr);
  817. }
  818. else
  819. {
  820. cchLocalBuffer += (lstrlen(TEXT("\\")) + lstrlen(szLocalBufferFile) + 1);
  821. pszLocalBuffer = (LPTSTR) VirtualAlloc(NULL,
  822. cchLocalBuffer * sizeof(TCHAR),
  823. MEM_COMMIT,
  824. PAGE_READWRITE);
  825. if (NULL == pszLocalBuffer)
  826. {
  827. hr = E_OUTOFMEMORY;
  828. CMTRACE(TEXT("GetRoutesFromURL - VirtualAlloc failed"));
  829. goto Cleanup;
  830. }
  831. if (0 == GetTempPath(cchLocalBuffer, pszLocalBuffer))
  832. {
  833. DWORD dwErr = GetLastError();
  834. CMTRACE1(TEXT("GetTempPath 2nd call failed, GLE=%d"), GetLastError());
  835. hr = HRESULT_FROM_WIN32(dwErr);
  836. goto Cleanup;
  837. }
  838. }
  839. //
  840. // Get a name for the temp file (using the temp path if there is one)
  841. //
  842. if (0 == GetTempFileName(pszLocalBuffer ? pszLocalBuffer : TEXT("."),
  843. TEXT("CMR"),
  844. 0,
  845. szLocalBufferFile))
  846. {
  847. DWORD dwErr = GetLastError();
  848. CMTRACE1(TEXT("GetTempFileName failed, GLE=%d"), dwErr);
  849. hr = HRESULT_FROM_WIN32(dwErr);
  850. goto Cleanup;
  851. }
  852. //
  853. // Open the temp file, and proceed.
  854. //
  855. fp = fopen(szLocalBufferFile, "w+b");
  856. if (NULL == fp)
  857. {
  858. CMTRACE1(TEXT("fopen failed(%s)"), szLocalBufferFile);
  859. hr = E_FAIL;
  860. goto Cleanup;
  861. }
  862. //
  863. // Initialize WININET
  864. //
  865. hInternet = InternetOpen(TEXT("RouteMan"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
  866. if (NULL == hInternet)
  867. {
  868. hr = HRESULT_FROM_WIN32(GetLastError());
  869. CMTRACE1(TEXT("InternetOpen failed with 0x%x"), hr);
  870. goto Cleanup;
  871. }
  872. //
  873. // Supress auto-dial calls to CM from WININET now that we have a handle
  874. //
  875. SuppressInetAutoDial(hInternet);
  876. //
  877. // Make sure that WinInet isn't in offline mode
  878. //
  879. (VOID)SetInetStateConnected(hInternet);
  880. //
  881. // Open the URL
  882. //
  883. hPage = InternetOpenUrl(hInternet, pszURL, NULL, 0, 0, 0);
  884. if (NULL == hPage)
  885. {
  886. hr = HRESULT_FROM_WIN32(GetLastError());
  887. CMTRACE1(TEXT("InternetOpenUrl failed with 0x%x"), hr);
  888. goto Cleanup;
  889. }
  890. //
  891. // Read the entire URL contents into the tempfile
  892. //
  893. do
  894. {
  895. if (!InternetReadFile(hPage, Buffer, sizeof(Buffer), &dwRead))
  896. {
  897. hr = HRESULT_FROM_WIN32(GetLastError());
  898. CMTRACE1(TEXT("InternetReadFile failed with 0x%x"), hr);
  899. goto Cleanup;
  900. }
  901. if (fwrite(Buffer, sizeof(BYTE), dwRead, fp) != dwRead)
  902. {
  903. CMTRACE1(TEXT("write failed to %s"), pszLocalBuffer);
  904. hr = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  905. goto Cleanup;
  906. }
  907. cb += dwRead;
  908. #if 0
  909. // ISSUE-2000/07/21-SumitC Code seems strange but might need it later
  910. //
  911. // Vijay/Andrew's original code has this, but is this correct?
  912. // The doc for InternetReadFile says this is just an EOF, if we
  913. // are to handle this case at all, we should just break;
  914. if (!dwRead)
  915. goto Cleanup;
  916. #endif
  917. }
  918. while (dwRead == 1024);
  919. hr = S_OK;
  920. if (fseek(fp, SEEK_SET, 0) != 0)
  921. {
  922. hr = E_FAIL;
  923. goto Cleanup;
  924. }
  925. pb = (LPBYTE) VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_READWRITE);
  926. if (NULL == pb)
  927. {
  928. hr = E_OUTOFMEMORY;
  929. goto Cleanup;
  930. }
  931. if (fread(pb, sizeof(BYTE), cb, fp) != cb)
  932. {
  933. hr = E_FAIL;
  934. goto Cleanup;
  935. }
  936. // success
  937. *ppszRouteInfo = (LPSTR) pb;
  938. *pcbRouteInfo = cb;
  939. Cleanup:
  940. if (fp)
  941. {
  942. fclose(fp);
  943. }
  944. if (FALSE == fKeepTempFiles)
  945. {
  946. remove(szLocalBufferFile);
  947. }
  948. if (pszLocalBuffer && cchLocalBuffer)
  949. {
  950. VirtualFree(pszLocalBuffer, 0, MEM_RELEASE);
  951. }
  952. if (hPage)
  953. {
  954. InternetCloseHandle(hPage);
  955. }
  956. if (hInternet)
  957. {
  958. InternetCloseHandle(hInternet);
  959. }
  960. if (S_OK != hr)
  961. {
  962. VirtualFree(pb, 0, MEM_RELEASE);
  963. }
  964. CMTRACEHR("GetRoutesFromURL", hr);
  965. return hr;
  966. }
  967. //+----------------------------------------------------------------------------
  968. //
  969. // Func: ProcessRouteInfo
  970. //
  971. // Desc: Parses the given route table and modifies the real routetable accordingly
  972. //
  973. // Args: [pszNewRouteInfo] - IN, bytes of route table to parse and add to the real one
  974. // [cbNewRouteInfo] - IN, size of routetable
  975. // [pmibRouteTable] - IN, real route table
  976. // [pGateway] - IN, default gateway
  977. // [pfDeleteGateway] - OUT, does the route file say to delete default gateway?
  978. //
  979. // Return: HRESULT (E_INVALIDARG, E_UNEXPECTED - for html file, etc)
  980. //
  981. // Notes:
  982. //
  983. // History: 12-Mar-2000 SumitC Created
  984. //
  985. //-----------------------------------------------------------------------------
  986. HRESULT
  987. ProcessRouteInfo(
  988. const LPSTR pszNewRouteInfo,
  989. DWORD cbNewRouteInfo,
  990. PMIB_IPFORWARDTABLE pmibRouteTable,
  991. PMIB_IPFORWARDROW pGateway,
  992. BOOL * pfDeleteDefaultGateway)
  993. {
  994. HRESULT hr = S_OK;
  995. DWORD cLines = 0;
  996. char szBuf[MAX_PATH];
  997. LPSTR pszNextLineToProcess;
  998. MYDBGASSERT(pszNewRouteInfo);
  999. MYDBGASSERT(cbNewRouteInfo);
  1000. MYDBGASSERT(pmibRouteTable);
  1001. MYDBGASSERT(pGateway);
  1002. MYDBGASSERT(pfDeleteDefaultGateway);
  1003. if (!pszNewRouteInfo || !cbNewRouteInfo || !pmibRouteTable || !pGateway || !pfDeleteDefaultGateway)
  1004. {
  1005. return E_INVALIDARG;
  1006. }
  1007. if ((NULL == g_pfnCreateIpForwardEntry) || (NULL == g_pfnDeleteIpForwardEntry))
  1008. {
  1009. return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
  1010. }
  1011. *pfDeleteDefaultGateway = FALSE;
  1012. // Make sure WININET zero terminates this....
  1013. pszNewRouteInfo[cbNewRouteInfo] = '\0';
  1014. //
  1015. // Convert string to lower
  1016. //
  1017. CharLowerA(pszNewRouteInfo);
  1018. //
  1019. // sanity checks (in the URL case, if the route file isn't found the server
  1020. // is likely to return an HTML file to indicate 404 - file not found.)
  1021. //
  1022. if (strstr(pszNewRouteInfo, "<html"))
  1023. {
  1024. CMTRACE("html string found - invalid route file\n");
  1025. hr = E_UNEXPECTED;
  1026. goto Cleanup;
  1027. }
  1028. //
  1029. // for each line
  1030. //
  1031. for (;;)
  1032. {
  1033. DWORD ipDest, ipMask, ipGateway, ipMetric;
  1034. DWORD dwIf = -1;
  1035. DWORD dwParam;
  1036. LPSTR psz; // temp var to hold each line as we process it
  1037. MIB_IPFORWARDROW route;
  1038. enum { VERB_ADD, VERB_DELETE } eVerb;
  1039. //
  1040. // Per strtok syntax, use pszNewRouteInfo the first time, and NULL thereafter
  1041. //
  1042. psz = strtok(((0 == cLines) ? pszNewRouteInfo : NULL), "\n\0");
  1043. if (NULL == psz)
  1044. break;
  1045. ++cLines;
  1046. //
  1047. // All errors within the for statement are due to bad data within the file
  1048. //
  1049. hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
  1050. //
  1051. // PART 1 : add/delete, followed by the IP address, or remove_gateway
  1052. //
  1053. if (FALSE == GetNextToken(psz, &psz, szBuf))
  1054. {
  1055. CMTRACE1("ProcessRouteInfo [%d] didn't find add/delete which is required", cLines);
  1056. goto Cleanup;
  1057. }
  1058. if (0 == SafeCompareString(szBuf, "add"))
  1059. {
  1060. eVerb = VERB_ADD;
  1061. }
  1062. else if (0 == SafeCompareString(szBuf, "delete"))
  1063. {
  1064. eVerb = VERB_DELETE;
  1065. }
  1066. else if (0 == SafeCompareString(szBuf, "remove_gateway"))
  1067. {
  1068. *pfDeleteDefaultGateway = TRUE;
  1069. hr = S_OK;
  1070. // ignore the rest of the line
  1071. continue;
  1072. }
  1073. else
  1074. {
  1075. CMTRACE2("ProcessRouteInfo [%d] found unexpected string %s instead of add/delete/remove_gateway", cLines, szBuf);
  1076. goto Cleanup;
  1077. }
  1078. if (FALSE == GetNextToken(psz, &psz, szBuf))
  1079. {
  1080. CMTRACE1("ProcessRouteInfo [%d] dest ip required for add/delete, and is missing", cLines);
  1081. goto Cleanup;
  1082. }
  1083. if (FALSE == ConvertSzToIP(szBuf, ipDest))
  1084. {
  1085. CMTRACE2("ProcessRouteInfo [%d] required ip address/mask %s has bad format", cLines, szBuf);
  1086. goto Cleanup;
  1087. }
  1088. //
  1089. // PART 2 : mask, followed by the IP address (NOT REQUIRED)
  1090. //
  1091. if (FALSE == GetNextToken(psz, &psz, szBuf))
  1092. {
  1093. CMTRACE1("ProcessRouteInfo [%d] ends too early after add/delete", cLines);
  1094. goto Cleanup;
  1095. }
  1096. if (0 == SafeCompareString(szBuf, "mask"))
  1097. {
  1098. if (FALSE == GetNextToken(psz, &psz, szBuf))
  1099. {
  1100. CMTRACE1("ProcessRouteInfo [%d] ip required for mask, and is missing", cLines);
  1101. goto Cleanup;
  1102. }
  1103. if (FALSE == ConvertSzToIP(szBuf, ipMask))
  1104. {
  1105. CMTRACE2("ProcessRouteInfo [%d] required ip address/mask %s has bad format", cLines, szBuf);
  1106. goto Cleanup;
  1107. }
  1108. if (FALSE == GetNextToken(psz, &psz, szBuf))
  1109. {
  1110. CMTRACE1("ProcessRouteInfo [%d] ends too early after mask", cLines);
  1111. goto Cleanup;
  1112. }
  1113. }
  1114. else
  1115. {
  1116. CMTRACE1("ProcessRouteInfo [%d] didn't find \"mask\", that's ok, continuing", cLines);
  1117. ipMask = (DWORD)-1;
  1118. }
  1119. //
  1120. // PART 3 : gateway (or "default")
  1121. //
  1122. if (0 == SafeCompareString(szBuf, "default"))
  1123. {
  1124. ipGateway = pGateway->dwForwardNextHop;
  1125. }
  1126. else
  1127. {
  1128. if (FALSE == ConvertSzToIP(szBuf, ipGateway))
  1129. {
  1130. CMTRACE2("ProcessRouteInfo [%d] bad format for gateway %s", cLines, szBuf);
  1131. goto Cleanup;
  1132. }
  1133. }
  1134. //
  1135. // PART 4 : metric, followed by a number (REQUIRED)
  1136. //
  1137. if (FALSE == GetNextToken(psz, &psz, szBuf))
  1138. {
  1139. CMTRACE1("ProcessRouteInfo [%d] didn't find \"metric\" which is required", cLines);
  1140. goto Cleanup;
  1141. }
  1142. if (0 == SafeCompareString(szBuf, "metric"))
  1143. {
  1144. if (FALSE == GetNextToken(psz, &psz, szBuf))
  1145. {
  1146. CMTRACE1("ProcessRouteInfo [%d] number value after \"metric\" missing", cLines);
  1147. goto Cleanup;
  1148. }
  1149. if (0 == SafeCompareString(szBuf, "default"))
  1150. {
  1151. ipMetric = pGateway->dwForwardMetric1;
  1152. }
  1153. else
  1154. {
  1155. if (FALSE == ConvertSzToIP(szBuf, ipMetric))
  1156. {
  1157. CMTRACE2("ProcessRouteInfo [%d] required ip metric %s has bad format", cLines, szBuf);
  1158. goto Cleanup;
  1159. }
  1160. /*
  1161. #if 0
  1162. dwParam = sscanf(szBuf, "%d", &ipMetric);
  1163. if (0 == dwParam)
  1164. {
  1165. CMTRACE2("ProcessRouteInfo [%d] bad format for metric value - %s", cLines, szBuf);
  1166. goto Cleanup;
  1167. }
  1168. #endif
  1169. */
  1170. }
  1171. }
  1172. else
  1173. {
  1174. CMTRACE2("ProcessRouteInfo [%d] found unexpected string %s instead of \"metric\"", cLines, szBuf);
  1175. goto Cleanup;
  1176. }
  1177. //
  1178. // PART 5 : if (the interface), followed by a number (REQUIRED)
  1179. //
  1180. if (FALSE == GetNextToken(psz, &psz, szBuf))
  1181. {
  1182. CMTRACE1("ProcessRouteInfo [%d] didn't find \"if\" which is required", cLines);
  1183. goto Cleanup;
  1184. }
  1185. if (0 == SafeCompareString(szBuf, "if"))
  1186. {
  1187. if (FALSE == GetNextToken(psz, &psz, szBuf))
  1188. {
  1189. CMTRACE1("ProcessRouteInfo [%d] number value after \"if\" missing", cLines);
  1190. goto Cleanup;
  1191. }
  1192. if (0 == SafeCompareString(szBuf, "default"))
  1193. {
  1194. dwIf = pGateway->dwForwardIfIndex;
  1195. }
  1196. else
  1197. {
  1198. dwParam = sscanf(szBuf, "%d", &dwIf);
  1199. if (0 == dwParam)
  1200. {
  1201. CMTRACE2("ProcessRouteInfo [%d] bad format for if value - %s", cLines, szBuf);
  1202. goto Cleanup;
  1203. }
  1204. }
  1205. }
  1206. else
  1207. {
  1208. CMTRACE2("ProcessRouteInfo [%d] found unexpected string %s instead of \"if\"", cLines, szBuf);
  1209. goto Cleanup;
  1210. }
  1211. //
  1212. // Run the verb (add or delete)
  1213. //
  1214. ZeroMemory(&route, sizeof(route));
  1215. route.dwForwardDest = ipDest;
  1216. route.dwForwardIfIndex = dwIf;
  1217. route.dwForwardMask = ipMask;
  1218. route.dwForwardMetric1 = ipMetric;
  1219. route.dwForwardNextHop = ipGateway;
  1220. route.dwForwardPolicy = 0;
  1221. route.dwForwardNextHopAS = 0;
  1222. route.dwForwardType = 3;
  1223. route.dwForwardProto = 3;
  1224. route.dwForwardAge = INFINITE;
  1225. route.dwForwardMetric2 = 0xFFFFFFFF;
  1226. route.dwForwardMetric3 = 0xFFFFFFFF;
  1227. route.dwForwardMetric4 = 0xFFFFFFFF;
  1228. route.dwForwardMetric5 = 0xFFFFFFFF;
  1229. // ISSUE-2000/07/21-SumitC Can we ever really get here in the code with dwIf == -1 ?
  1230. //
  1231. // Check that the interface was specified
  1232. if (-1 == dwIf)
  1233. {
  1234. // Nope, lets go pick one
  1235. dwIf = GetIf(route, *pmibRouteTable);
  1236. }
  1237. DWORD dwRet = 0;
  1238. switch (eVerb)
  1239. {
  1240. case VERB_ADD:
  1241. dwRet = g_pfnCreateIpForwardEntry(&route);
  1242. if (ERROR_SUCCESS != dwRet)
  1243. {
  1244. // NETWORK_ACCESS_DENIED (0x41=65) is special-cased at the end of SetRoutes
  1245. CMTRACE2("ProcessRouteInfo [%d] CreateIpForwardEntry failed with %d", cLines, dwRet);
  1246. hr = HRESULT_FROM_WIN32(dwRet);
  1247. goto Cleanup;
  1248. }
  1249. hr = S_OK;
  1250. break;
  1251. case VERB_DELETE:
  1252. dwRet = g_pfnDeleteIpForwardEntry(&route);
  1253. if (ERROR_SUCCESS != dwRet)
  1254. {
  1255. // NETWORK_ACCESS_DENIED (0x41=65) is special-cased at the end of SetRoutes
  1256. CMTRACE2("ProcessRouteInfo [%d] DeleteIpForwardEntry failed with %d", cLines, dwRet);
  1257. hr = HRESULT_FROM_WIN32(dwRet);
  1258. goto Cleanup;
  1259. }
  1260. hr = S_OK;
  1261. break;
  1262. default:
  1263. CMTRACE("ProcessRouteInfo [%d] Unsupported route command, add or delete only");
  1264. MYDBGASSERT(0);
  1265. hr = E_FAIL;
  1266. break;
  1267. }
  1268. }
  1269. Cleanup:
  1270. CMTRACEHR("ProcessRouteInfo", hr);
  1271. return hr;
  1272. }
  1273. //+----------------------------------------------------------------------------
  1274. //
  1275. // Func: DeleteDefaultGateway
  1276. //
  1277. // Desc: Deletes the default routing gateway for this system
  1278. //
  1279. // Args: [pGateway] - the gateway
  1280. //
  1281. // Return: HRESULT
  1282. //
  1283. // Notes: This should be the last function called within CMroute, and is called
  1284. // only if all other processing succeeded.
  1285. //
  1286. // History: 12-Mar-2000 SumitC Created
  1287. //
  1288. //-----------------------------------------------------------------------------
  1289. HRESULT
  1290. DeleteDefaultGateway(PMIB_IPFORWARDROW pGateway)
  1291. {
  1292. CMTRACE("DeleteDefaultGateway: entering");
  1293. HRESULT hr = S_OK;
  1294. DWORD dwErr = 0;
  1295. if (NULL == g_pfnDeleteIpForwardEntry)
  1296. {
  1297. hr = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
  1298. goto Cleanup;
  1299. }
  1300. dwErr = g_pfnDeleteIpForwardEntry(pGateway);
  1301. if (NO_ERROR != dwErr)
  1302. {
  1303. hr = HRESULT_FROM_WIN32(dwErr);
  1304. CMTRACE1("DeleteDefaultGateway failed with error %x", dwErr);
  1305. }
  1306. Cleanup:
  1307. CMTRACEHR("DeleteDefaultGateway", hr);
  1308. return hr;
  1309. }
  1310. //+----------------------------------------------------------------------------
  1311. //
  1312. // Func: IsValidIPAddress
  1313. //
  1314. // Desc: Checks to see if given string can be a valid IP address
  1315. //
  1316. // Args: [sz] - IN, the string
  1317. //
  1318. // Return: BOOL, FALSE means invalid chars were found
  1319. //
  1320. // History: 20-Mar-2000 SumitC Created
  1321. //
  1322. //-----------------------------------------------------------------------------
  1323. BOOL
  1324. IsValidIPAddress(LPSTR sz)
  1325. {
  1326. MYDBGASSERT(sz);
  1327. while ((*sz) && (!isspace(*sz)))
  1328. {
  1329. if ((*sz >= '0') && (*sz <= '9'))
  1330. ;
  1331. else if ((*sz == '.') || (*sz == '*') || (*sz == '?'))
  1332. ;
  1333. else
  1334. {
  1335. CMTRACE1(TEXT("IsValidIPAddress failed on %s\n"), sz);
  1336. MYDBGASSERT("IsValidIPAddress");
  1337. return FALSE;
  1338. }
  1339. ++sz;
  1340. }
  1341. return TRUE;
  1342. }
  1343. //+----------------------------------------------------------------------------
  1344. //
  1345. // Func: ConvertSzToIP
  1346. //
  1347. // Desc: Converts the given string into a DWORD representing an IP address
  1348. //
  1349. // Args: [sz] - IN, string to convert
  1350. // [dwIP] - OUT BYREF, dword for IP address
  1351. //
  1352. // Return: BOOL, FALSE if conversion failed (usually means bad format)
  1353. //
  1354. // History: 12-Mar-2000 SumitC Created
  1355. //
  1356. //-----------------------------------------------------------------------------
  1357. BOOL
  1358. ConvertSzToIP(LPSTR sz, DWORD& dwIP)
  1359. {
  1360. DWORD dwParams, d1, d2, d3, d4;
  1361. if (FALSE == IsValidIPAddress(sz))
  1362. {
  1363. return FALSE;
  1364. }
  1365. dwParams = sscanf(sz, "%d.%d.%d.%d", &d1, &d2, &d3, &d4);
  1366. if (0 == dwParams)
  1367. {
  1368. MYDBGASSERT("ConvertSzToIP - bad format for IP address");
  1369. return FALSE;
  1370. }
  1371. else if (1 == dwParams)
  1372. {
  1373. dwIP = d1 | 0xffffff00;
  1374. }
  1375. else if (2 == dwParams)
  1376. {
  1377. dwIP = d1 | (d2 << 8) | 0xffff0000;
  1378. }
  1379. else if (3 == dwParams)
  1380. {
  1381. dwIP = d1 | (d2 << 8) | (d3 << 16) | 0xff000000;
  1382. }
  1383. else
  1384. {
  1385. dwIP = d1 | (d2 << 8) | (d3 << 16) | (d4 << 24);
  1386. }
  1387. return TRUE;
  1388. }
  1389. //+----------------------------------------------------------------------------
  1390. //
  1391. // Func: GetRouteTable
  1392. //
  1393. // Desc: Same as GetIpForwardTable but alloc's the table for you.
  1394. // VirtualFree() the buffer returned.
  1395. //
  1396. // Args: [ppTable] - OUT, returned route table
  1397. //
  1398. // Return: HRESULT
  1399. //
  1400. // Notes: ppTable should be VirtualFree'd by caller.
  1401. //
  1402. // History: 24-Feb-1999 AnBrad Created
  1403. // 22-Mar-2000 SumitC Rewrote
  1404. //
  1405. //-----------------------------------------------------------------------------
  1406. HRESULT
  1407. GetRouteTable(PMIB_IPFORWARDTABLE * ppTable)
  1408. {
  1409. DWORD dwErr = NO_ERROR;
  1410. DWORD cbbuf = 0;
  1411. PMIB_IPFORWARDTABLE p = NULL;
  1412. HRESULT hr = S_OK;
  1413. MYDBGASSERT(ppTable);
  1414. //
  1415. // Make sure we have a function pointer for GetIpForwardTable
  1416. //
  1417. if (NULL == g_pfnGetIpForwardTable)
  1418. {
  1419. hr = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
  1420. goto Cleanup;
  1421. }
  1422. //
  1423. // Get the route table
  1424. //
  1425. dwErr = g_pfnGetIpForwardTable(NULL, &cbbuf, FALSE);
  1426. if (ERROR_INSUFFICIENT_BUFFER != dwErr)
  1427. {
  1428. // hmm, a real error
  1429. hr = HRESULT_FROM_WIN32(ERROR_UNEXP_NET_ERR);
  1430. goto Cleanup;
  1431. }
  1432. else
  1433. {
  1434. p = (PMIB_IPFORWARDTABLE) VirtualAlloc(NULL, cbbuf, MEM_COMMIT, PAGE_READWRITE);
  1435. if (!p)
  1436. {
  1437. hr = E_OUTOFMEMORY;
  1438. goto Cleanup;
  1439. }
  1440. if (g_pfnGetIpForwardTable(p, &cbbuf, TRUE))
  1441. {
  1442. hr = E_FAIL;
  1443. goto Cleanup;
  1444. }
  1445. *ppTable = p;
  1446. }
  1447. Cleanup:
  1448. if (S_OK != hr)
  1449. {
  1450. if (p)
  1451. {
  1452. VirtualFree(p, 0, MEM_RELEASE);
  1453. }
  1454. }
  1455. CMTRACEHR("GetRouteTable", hr);
  1456. return hr;
  1457. }
  1458. //+----------------------------------------------------------------------------
  1459. //
  1460. // Func: GetIf
  1461. //
  1462. // Desc: Find the interface for a route
  1463. //
  1464. // Args: [route] - IN, route for which we need the Interface
  1465. // [RouteTable] - IN, route table
  1466. //
  1467. // Return: DWORD which is the IF
  1468. //
  1469. // Notes: Logic stolen from \nt\private\net\sockets\strmtcp\route
  1470. //
  1471. // History: 24-Feb-1999 AnBrad Created
  1472. // 22-Mar-2000 SumitC Cleaned up
  1473. //
  1474. //-----------------------------------------------------------------------------
  1475. DWORD
  1476. GetIf(const MIB_IPFORWARDROW& route, const MIB_IPFORWARDTABLE& RouteTable)
  1477. {
  1478. for(DWORD dwIndex = 0; dwIndex < RouteTable.dwNumEntries; dwIndex++)
  1479. {
  1480. const MIB_IPFORWARDROW& Row = RouteTable.table[dwIndex];
  1481. if (Row.dwForwardMask &&
  1482. (Row.dwForwardDest & Row.dwForwardMask) ==
  1483. (route.dwForwardNextHop & Row.dwForwardMask))
  1484. {
  1485. return Row.dwForwardIfIndex;
  1486. }
  1487. }
  1488. return 0;
  1489. }
  1490. //+----------------------------------------------------------------------------
  1491. //
  1492. // Func: GetDefaultGateway
  1493. //
  1494. // Desc: Find the default gateway
  1495. //
  1496. // Args: [pRouteTable] - IN, the route table (IP forward table)
  1497. //
  1498. // Return: PMIB_IPFORWARDROW the row of the gateway (a ptr within pRouteTable)
  1499. //
  1500. // Notes: Do not free returned value
  1501. //
  1502. // History: 24-Feb-1999 AnBrad Created
  1503. // 22-Mar-2000 SumitC Cleaned up
  1504. //
  1505. //-----------------------------------------------------------------------------
  1506. PMIB_IPFORWARDROW
  1507. GetDefaultGateway(PMIB_IPFORWARDTABLE pRouteTable)
  1508. {
  1509. PMIB_IPFORWARDROW pRow, pDefGateway;
  1510. // Cycle thru the entire table & find the gateway with the least metric
  1511. pDefGateway = NULL;
  1512. for(pRow = pRouteTable->table; pRow != pRouteTable->table + pRouteTable->dwNumEntries; ++pRow)
  1513. {
  1514. if (pRow->dwForwardDest == 0)
  1515. {
  1516. if (pDefGateway == NULL)
  1517. {
  1518. pDefGateway = pRow;
  1519. }
  1520. else
  1521. {
  1522. if (pRow->dwForwardMetric1 == pDefGateway->dwForwardMetric1 &&
  1523. pRow->dwForwardAge >= pDefGateway->dwForwardAge)
  1524. {
  1525. pDefGateway = pRow;
  1526. }
  1527. if (pRow->dwForwardMetric1 < pDefGateway->dwForwardMetric1)
  1528. {
  1529. pDefGateway = pRow;
  1530. }
  1531. }
  1532. }
  1533. }
  1534. return pDefGateway;
  1535. }
  1536. //+----------------------------------------------------------------------------
  1537. //
  1538. // Func: StrCpyWithoutQuotes
  1539. //
  1540. // Desc: Wrapper for lstrcpy, which removes surrounding double quotes if necessary
  1541. //
  1542. // Args: [pszDest] - OUT, destination for the copy
  1543. // [pszSrc] - OUT, source for the copy
  1544. //
  1545. // Return: a ptr to pszDest, or NULL if failure.
  1546. //
  1547. // Notes:
  1548. //
  1549. // History: 12-Apr-1999 SumitC Created
  1550. //
  1551. //-----------------------------------------------------------------------------
  1552. LPSTR
  1553. StrCpyWithoutQuotes(LPSTR pszDest, LPCSTR pszSrc)
  1554. {
  1555. MYDBGASSERT(pszDest);
  1556. MYDBGASSERT(pszSrc);
  1557. int len = lstrlen(pszSrc);
  1558. if ((len > 2) && ('"' == pszSrc[0]) && ('"' == pszSrc[len - 1]))
  1559. {
  1560. return lstrcpyn(pszDest, &pszSrc[1], len - 1);
  1561. }
  1562. else
  1563. {
  1564. return lstrcpy(pszDest, pszSrc);
  1565. }
  1566. }
  1567. //+----------------------------------------------------------------------------
  1568. //
  1569. // Func: VerifyProfileAndGetServiceDir
  1570. //
  1571. // Desc: Checks the given profile, and modifies it to produce the ServiceDir
  1572. //
  1573. // Args: [pszProfile] - IN OUT, profile name, modified IN PLACE
  1574. //
  1575. // Return: TRUE if modified pszProfile is now the ServiceDir, or FALSE if failure.
  1576. //
  1577. // Notes: pszProfile is MODIFIED IN PLACE.
  1578. //
  1579. // History: 12-Apr-1999 SumitC Created
  1580. //
  1581. //-----------------------------------------------------------------------------
  1582. BOOL
  1583. VerifyProfileAndGetServiceDir(IN OUT LPSTR pszProfile)
  1584. {
  1585. HANDLE hFile = NULL;
  1586. MYDBGASSERT(pszProfile);
  1587. MYDBGASSERT(lstrlen(pszProfile));
  1588. if ((NULL == pszProfile) || (lstrlen(pszProfile) < 4))
  1589. {
  1590. return FALSE;
  1591. }
  1592. //
  1593. // The profile string may be surrounded by double-quotes, if so remove them.
  1594. //
  1595. //
  1596. // First check to see if the profile really exists. This also serves as
  1597. // verification for the existence of the directory.
  1598. //
  1599. hFile = CreateFile(pszProfile, GENERIC_READ, FILE_SHARE_READ, NULL,
  1600. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1601. if (INVALID_HANDLE_VALUE == hFile)
  1602. {
  1603. return FALSE;
  1604. }
  1605. else
  1606. {
  1607. CloseHandle(hFile);
  1608. }
  1609. //
  1610. // Now check to see that the file does indeed end in .CMP
  1611. //
  1612. LPSTR psz = pszProfile + lstrlen(pszProfile) - lstrlen(".CMP");
  1613. if (0 != SafeCompareString(psz, ".CMP"))
  1614. {
  1615. return FALSE;
  1616. }
  1617. //
  1618. // The profile name is the same as the ServiceDir name, so we just terminate
  1619. // the string at the '.' and append a '\'
  1620. //
  1621. *psz = '\\';
  1622. psz++;
  1623. *psz = '\0';
  1624. return TRUE;
  1625. }
  1626. #if DBG
  1627. LPTSTR aszMapType[] = {TEXT("Other"),
  1628. TEXT("Invalid"),
  1629. TEXT("Direct"),
  1630. TEXT("Indirect")};
  1631. LPTSTR aszMapProto[] = {TEXT("Other"), // MIB_IPPROTO_OTHER 1
  1632. TEXT("Local"), // MIB_IPPROTO_LOCAL 2
  1633. TEXT("SNMP"), // MIB_IPPROTO_NETMGMT 3
  1634. TEXT("ICMP"), // MIB_IPPROTO_ICMP 4
  1635. TEXT("Exterior Gateway Protocol"), // MIB_IPPROTO_EGP 5
  1636. TEXT("GGP"), // MIB_IPPROTO_GGP 6
  1637. TEXT("Hello"), // MIB_IPPROTO_HELLO 7
  1638. TEXT("Routing Information Protocol"), // MIB_IPPROTO_RIP 8
  1639. TEXT("IS IS"), // MIB_IPPROTO_IS_IS 9
  1640. TEXT("ES IS"), // MIB_IPPROTO_ES_IS 10
  1641. TEXT("Cicso"), // MIB_IPPROTO_CISCO 11
  1642. TEXT("BBN"), // MIB_IPPROTO_BBN 12
  1643. TEXT("Open Shortest Path First"), // MIB_IPPROTO_OSPF 13
  1644. TEXT("Border Gateway Protocol")}; // MIB_IPPROTO_BGP 14
  1645. //+----------------------------------------------------------------------
  1646. //
  1647. // Function: PrintRoute
  1648. //
  1649. // Purpose: Prints out a route from the IP forward table
  1650. //
  1651. // Arguments:
  1652. // pRow [in] the route
  1653. //
  1654. // Returns: zip
  1655. //
  1656. // Author: anbrad 24 Feb 1999
  1657. //
  1658. // Notes:
  1659. //
  1660. //-----------------------------------------------------------------------
  1661. void PrintRoute(PMIB_IPFORWARDROW pRow)
  1662. {
  1663. TCHAR sz[MAX_PATH];
  1664. wsprintf(sz, "dwDest = %s\n", IPtoTsz(pRow->dwForwardDest)); // IP addr of destination
  1665. OutputDebugString(sz);
  1666. wsprintf(sz, "dwMask = %s\n", IPtoTsz(pRow->dwForwardMask)); // subnetwork mask of destination
  1667. OutputDebugString(sz);
  1668. wsprintf(sz, "dwPolicy = %d\n"
  1669. "dwNextHop = %s\n"
  1670. "dwIfIndex = %d\n"
  1671. "dwType = %s\n"
  1672. "dwProto = %s\n"
  1673. "dwAge = %d\n"
  1674. "dwNextHopAS = %d\n",
  1675. pRow->dwForwardPolicy, // conditions for multi-path route
  1676. IPtoTsz(pRow->dwForwardNextHop), // IP address of next hop
  1677. pRow->dwForwardIfIndex, // index of interface
  1678. aszMapType[pRow->dwForwardType-1], // route type
  1679. aszMapProto[pRow->dwForwardProto-1],// protocol that generated route
  1680. pRow->dwForwardAge, // age of route
  1681. pRow->dwForwardNextHopAS); // autonomous system number
  1682. // of next hop
  1683. OutputDebugString(sz);
  1684. if (MIB_IPROUTE_METRIC_UNUSED != pRow->dwForwardMetric1)
  1685. {
  1686. wsprintf(sz, "dwMetric1 = %d\n", pRow->dwForwardMetric1);
  1687. OutputDebugString(sz);
  1688. }
  1689. if (MIB_IPROUTE_METRIC_UNUSED != pRow->dwForwardMetric2)
  1690. {
  1691. wsprintf(sz, "dwMetric2 = %d\n", pRow->dwForwardMetric2);
  1692. OutputDebugString(sz);
  1693. }
  1694. if (MIB_IPROUTE_METRIC_UNUSED != pRow->dwForwardMetric3)
  1695. {
  1696. wsprintf(sz, "dwMetric3 = %d\n", pRow->dwForwardMetric3);
  1697. OutputDebugString(sz);
  1698. }
  1699. if (MIB_IPROUTE_METRIC_UNUSED != pRow->dwForwardMetric4)
  1700. {
  1701. wsprintf(sz, "dwMetric4 = %d\n", pRow->dwForwardMetric4);
  1702. OutputDebugString(sz);
  1703. }
  1704. if (MIB_IPROUTE_METRIC_UNUSED != pRow->dwForwardMetric5)
  1705. {
  1706. wsprintf(sz, "dwMetric5 = %d\n", pRow->dwForwardMetric5);
  1707. OutputDebugString(sz);
  1708. }
  1709. wsprintf(sz, "\n");
  1710. OutputDebugString(sz);
  1711. }
  1712. #if DBG
  1713. //+----------------------------------------------------------------------
  1714. //
  1715. // Function: PrintRouteTable
  1716. //
  1717. // Purpose: Does a "ROUTE PRINT" using the iphlpapi's
  1718. //
  1719. // Arguments: none
  1720. //
  1721. // Returns: zip
  1722. //
  1723. // Author: anbrad 24 Feb 1999
  1724. //
  1725. // Notes:
  1726. //
  1727. //-----------------------------------------------------------------------
  1728. void PrintRouteTable()
  1729. {
  1730. #define PAGE 4096
  1731. BYTE buf[PAGE];
  1732. DWORD cbbuf = sizeof(buf);
  1733. TCHAR sz[MAX_PATH];
  1734. if (g_pfnGetIpForwardTable)
  1735. {
  1736. PMIB_IPFORWARDTABLE table = (PMIB_IPFORWARDTABLE)buf;
  1737. if (g_pfnGetIpForwardTable(table, &cbbuf, TRUE))
  1738. return;
  1739. wsprintf(sz, "\n\nFound %d routes\n", table->dwNumEntries);
  1740. OutputDebugString(sz);
  1741. for (DWORD d=0; d < table->dwNumEntries; ++d)
  1742. {
  1743. PrintRoute(table->table+d);
  1744. }
  1745. }
  1746. }
  1747. #endif
  1748. //+----------------------------------------------------------------------
  1749. //
  1750. // Function: IPtoTsz
  1751. //
  1752. // Purpose: Changes a dword to a "dotted string" notation
  1753. //
  1754. // Arguments:
  1755. // dw [in] IP address
  1756. //
  1757. // Returns: LPTSTR which is a static string
  1758. //
  1759. // Author: anbrad 24 Feb 1999
  1760. //
  1761. // Notes: Global makes this NOT thread safe, and it is not needed
  1762. // for cmroute.exe
  1763. //
  1764. //-----------------------------------------------------------------------
  1765. TCHAR tsz[20];
  1766. LPTSTR IPtoTsz(DWORD dw)
  1767. {
  1768. wsprintf(tsz, TEXT("%03d.%03d.%03d.%03d"),
  1769. (DWORD)LOBYTE(LOWORD(dw)),
  1770. (DWORD)HIBYTE(LOWORD(dw)),
  1771. (DWORD)LOBYTE(HIWORD(dw)),
  1772. (DWORD)HIBYTE(HIWORD(dw)));
  1773. return tsz;
  1774. }
  1775. LPSTR IPtosz(DWORD dwIP, char *psz)
  1776. {
  1777. wsprintfA(psz, ("%d.%d.%d.%d"),
  1778. (DWORD)LOBYTE(LOWORD(dwIP)),
  1779. (DWORD)HIBYTE(LOWORD(dwIP)),
  1780. (DWORD)LOBYTE(HIWORD(dwIP)),
  1781. (DWORD)HIBYTE(HIWORD(dwIP)));
  1782. return psz;
  1783. }
  1784. #endif // DBG