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.

667 lines
15 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. autodial.cxx
  5. Abstract:
  6. Contains the implementation of autodial
  7. Contents:
  8. Author:
  9. Darren Mitchell (darrenmi) 22-Apr-1997
  10. Environment:
  11. Win32(s) user-mode DLL
  12. Revision History:
  13. 14-Jan-2002 ssulzer
  14. Ported small subset to WinHttp
  15. 22-Apr-1997 darrenmi
  16. Created
  17. --*/
  18. #include "wininetp.h"
  19. #include "autodial.h"
  20. #include "rashelp.h"
  21. #include <winsvc.h>
  22. #include <iphlpapi.h>
  23. // Globals.
  24. DWORD g_dwLastTickCount = 0;
  25. // serialize access to RAS
  26. HANDLE g_hRasMutex = INVALID_HANDLE_VALUE;
  27. // don't check RNA state more than once every 10 seconds
  28. #define MIN_RNA_BUSY_CHECK_INTERVAL 10000
  29. //
  30. // Current ras connections - used so we don't poll ras every time we're
  31. // interested - only poll every 10 seconds (const. above)
  32. //
  33. RasEnumConnHelp * g_RasCon;
  34. DWORD g_dwConnections = 0;
  35. BOOL g_fRasInstalled = FALSE;
  36. DWORD g_dwLastDialupTicks = 0;
  37. //
  38. // Control of autodial initialization
  39. //
  40. BOOL g_fAutodialInitialized = FALSE;
  41. ///////////////////////////////////////////////////////////////////////////
  42. ///////////////////////////////////////////////////////////////////////////
  43. //
  44. // RAS dynaload code
  45. //
  46. ///////////////////////////////////////////////////////////////////////////
  47. ///////////////////////////////////////////////////////////////////////////
  48. static HINSTANCE g_hRasLib = NULL;
  49. static _RASENUMENTRIESW pfnRasEnumEntriesW = NULL;
  50. static _RASGETCONNECTSTATUSW pfnRasGetConnectStatusW = NULL;
  51. static _RASENUMCONNECTIONSW pfnRasEnumConnectionsW = NULL;
  52. static _RASGETENTRYPROPERTIESW pfnRasGetEntryPropertiesW = NULL;
  53. typedef struct _tagAPIMAPENTRY {
  54. FARPROC* pfn;
  55. LPSTR pszProc;
  56. } APIMAPENTRY;
  57. APIMAPENTRY rgRasApiMapW[] = {
  58. { (FARPROC*) &pfnRasEnumEntriesW, "RasEnumEntriesW" },
  59. { (FARPROC*) &pfnRasGetConnectStatusW, "RasGetConnectStatusW" },
  60. { (FARPROC*) &pfnRasEnumConnectionsW, "RasEnumConnectionsW" },
  61. { (FARPROC*) &pfnRasGetEntryPropertiesW, "RasGetEntryPropertiesW"},
  62. { NULL, NULL },
  63. };
  64. #define RASFCN(_fn, _part, _par, _dbge, _dbgl) \
  65. DWORD _##_fn _part \
  66. { \
  67. DEBUG_ENTER(_dbge); \
  68. \
  69. DWORD dwRet; \
  70. if(NULL == pfn##_fn) \
  71. { \
  72. _dbgl(ERROR_INVALID_FUNCTION); \
  73. return ERROR_INVALID_FUNCTION; \
  74. } \
  75. \
  76. dwRet = (* pfn##_fn) _par; \
  77. \
  78. _dbgl(dwRet); \
  79. return dwRet; \
  80. }
  81. RASFCN(RasEnumEntriesW,
  82. (LPWSTR lpszReserved, LPWSTR lpszPhonebook, LPRASENTRYNAMEW lprasentryname,
  83. LPDWORD lpcb, LPDWORD lpcEntries),
  84. (lpszReserved, lpszPhonebook, lprasentryname, lpcb, lpcEntries),
  85. (DBG_DIALUP, Dword, "RasEnumEntriesW", "%#x (%Q), %#x (%Q), %#x, %#x %#x", lpszReserved, lpszReserved, lpszPhonebook, lpszPhonebook, lprasentryname, lpcb, lpcEntries),
  86. DEBUG_LEAVE
  87. );
  88. RASFCN(RasGetConnectStatusW,
  89. (HRASCONN hrasconn, LPRASCONNSTATUSW lprasconnstatus),
  90. (hrasconn, lprasconnstatus),
  91. (DBG_DIALUP, Dword, "RasGetConnectStatusW", "%#x, %#x", hrasconn, lprasconnstatus),
  92. DEBUG_LEAVE
  93. );
  94. RASFCN(RasGetEntryPropertiesW,
  95. (LPWSTR lpszPhonebook, LPWSTR lpszEntry, LPRASENTRYW lpRasEntry, LPDWORD lpdwEntryInfoSize, LPBYTE lpbDeviceInfo, LPDWORD lpdwDeviceInfoSize),
  96. (lpszPhonebook, lpszEntry, lpRasEntry, lpdwEntryInfoSize, lpbDeviceInfo, lpdwDeviceInfoSize),
  97. (DBG_DIALUP, Dword, "RasGetEntryPropertiesW", "%#x (%Q), %#x (%Q), %#x, %#x, %#x %#x", lpszPhonebook, lpszPhonebook, lpszEntry, lpszEntry, lpRasEntry, lpdwEntryInfoSize, lpbDeviceInfo, lpdwDeviceInfoSize),
  98. DEBUG_LEAVE
  99. );
  100. RASFCN(RasEnumConnectionsW,
  101. (LPRASCONNW lpRasConn, LPDWORD lpdwSize, LPDWORD lpdwConn),
  102. (lpRasConn, lpdwSize, lpdwConn),
  103. (DBG_DIALUP, Dword, "RasEnumConnectionsW", "%#x, %#x, %#x", lpRasConn, lpdwSize, lpdwConn),
  104. DEBUG_LEAVE
  105. );
  106. ///////////////////////////////////////////////////////////////////////////
  107. ///////////////////////////////////////////////////////////////////////////
  108. BOOL
  109. EnsureRasLoaded(
  110. VOID
  111. )
  112. /*++
  113. Routine Description:
  114. Dynaload ras apis
  115. Arguments:
  116. pfInstalled - return installed state of ras
  117. Return Value:
  118. BOOL
  119. TRUE - Ras loaded
  120. FALSE - Ras not loaded
  121. --*/
  122. {
  123. DEBUG_ENTER((DBG_DIALUP,
  124. Bool,
  125. "EnsureRasLoaded",
  126. NULL
  127. ));
  128. //
  129. // Looks like RAS is installed - try and load it up!
  130. //
  131. if(NULL == g_hRasLib)
  132. {
  133. g_hRasLib = LoadLibrary("RASAPI32.DLL");
  134. if(NULL == g_hRasLib)
  135. {
  136. DEBUG_LEAVE(FALSE);
  137. return FALSE;
  138. }
  139. APIMAPENTRY *prgRasApiMap = rgRasApiMapW;
  140. int nIndex = 0;
  141. while ((prgRasApiMap+nIndex)->pszProc != NULL)
  142. {
  143. // Some functions are only present on some platforms. Don't
  144. // assume this succeeds for all functions.
  145. *(prgRasApiMap+nIndex)->pfn =
  146. GetProcAddress(g_hRasLib, (prgRasApiMap+nIndex)->pszProc);
  147. nIndex++;
  148. }
  149. }
  150. if(g_hRasLib)
  151. {
  152. DEBUG_LEAVE(TRUE);
  153. return TRUE;
  154. }
  155. DEBUG_LEAVE(FALSE);
  156. return FALSE;
  157. }
  158. BOOL
  159. IsRasInstalled(
  160. VOID
  161. )
  162. /*++
  163. Routine Description:
  164. Determines whether ras is installed on this machine
  165. Arguments:
  166. none
  167. Return Value:
  168. BOOL
  169. TRUE - Ras is installed
  170. FALSE - Ras is not installed
  171. --*/
  172. {
  173. DEBUG_ENTER_API((DBG_DIALUP,
  174. Bool,
  175. "IsRasInstalled",
  176. NULL
  177. ));
  178. static fChecked = FALSE;
  179. //
  180. // If RAS is already loaded, don't bother doing any work.
  181. //
  182. if(g_hRasLib)
  183. {
  184. DEBUG_LEAVE_API(TRUE);
  185. return TRUE;
  186. }
  187. //
  188. // if we've already done the check, don't do it again
  189. //
  190. if(fChecked)
  191. {
  192. DEBUG_LEAVE_API(g_fRasInstalled);
  193. return g_fRasInstalled;
  194. }
  195. OSVERSIONINFO osvi;
  196. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  197. GetVersionEx(&osvi);
  198. if (osvi.dwMajorVersion < 5)
  199. {
  200. // WinHttp does not support the use of RAS on NT4
  201. g_fRasInstalled = FALSE;
  202. }
  203. else
  204. {
  205. // NT5 and presumably beyond, ras is always installed
  206. g_fRasInstalled = TRUE;
  207. }
  208. fChecked = TRUE;
  209. DEBUG_LEAVE_API(g_fRasInstalled);
  210. return g_fRasInstalled;
  211. }
  212. BOOL
  213. DoConnectoidsExist(
  214. VOID
  215. )
  216. /*++
  217. Routine Description:
  218. Determines whether any ras connectoids exist
  219. Arguments:
  220. none
  221. Return Value:
  222. BOOL
  223. TRUE - Connectoids exist
  224. FALSE - No connectoids exist
  225. --*/
  226. {
  227. DEBUG_ENTER_API((DBG_DIALUP,
  228. Bool,
  229. "DoConnectoidsExist",
  230. NULL
  231. ));
  232. static BOOL fExist = FALSE;
  233. //
  234. // If we found connectoids before, don't bother looking again
  235. //
  236. if(fExist)
  237. {
  238. DEBUG_LEAVE_API(TRUE);
  239. return TRUE;
  240. }
  241. //
  242. // If RAS is already loaded, ask it
  243. //
  244. if(g_hRasLib)
  245. {
  246. DWORD dwRet, dwEntries;
  247. RasEnumHelp *pRasEnum = new RasEnumHelp;
  248. if (pRasEnum)
  249. {
  250. dwRet = pRasEnum->GetError();
  251. dwEntries = pRasEnum->GetEntryCount();
  252. delete pRasEnum;
  253. }
  254. else
  255. {
  256. dwRet = ERROR_NOT_ENOUGH_MEMORY;
  257. dwEntries = 0;
  258. }
  259. // If ras tells us there are none, return none
  260. if(ERROR_SUCCESS == dwRet && 0 == dwEntries)
  261. {
  262. DEBUG_LEAVE_API(FALSE);
  263. return FALSE;
  264. }
  265. // couldn't determine that there aren't any so assume there are.
  266. fExist = TRUE;
  267. DEBUG_LEAVE_API(TRUE);
  268. return TRUE;
  269. }
  270. //
  271. // if ras isn't installed, say no connectoids
  272. //
  273. if(FALSE == IsRasInstalled())
  274. {
  275. DEBUG_LEAVE_API(FALSE);
  276. return FALSE;
  277. }
  278. OSVERSIONINFO osvi;
  279. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  280. GetVersionEx(&osvi);
  281. // assume connectoids exist
  282. fExist = TRUE;
  283. if (osvi.dwMajorVersion < 5)
  284. {
  285. fExist = FALSE;
  286. }
  287. DEBUG_LEAVE_API(fExist);
  288. return fExist;
  289. }
  290. ///////////////////////////////////////////////////////////////////////////
  291. ///////////////////////////////////////////////////////////////////////////
  292. //
  293. // Initialization
  294. //
  295. ///////////////////////////////////////////////////////////////////////////
  296. ///////////////////////////////////////////////////////////////////////////
  297. BOOL
  298. InitAutodialModule()
  299. /*++
  300. Routine Description:
  301. Initialize autodial code
  302. Arguments:
  303. None.
  304. Return Value:
  305. None.
  306. --*/
  307. {
  308. DEBUG_ENTER((DBG_DIALUP,
  309. Bool,
  310. "InitAutodialModule",
  311. NULL
  312. ));
  313. // Assert that WinHttp's global data has already been initialized
  314. INET_ASSERT(GlobalDataInitialized);
  315. // only do this once...
  316. if(g_fAutodialInitialized)
  317. {
  318. DEBUG_LEAVE(g_fAutodialInitialized);
  319. return g_fAutodialInitialized;
  320. }
  321. if (GlobalDataInitCritSec.Lock())
  322. {
  323. if (!g_fAutodialInitialized)
  324. {
  325. // create mutex to serialize access to RAS (per process)
  326. g_hRasMutex = CreateMutex(NULL, FALSE, NULL);
  327. if (g_hRasMutex != INVALID_HANDLE_VALUE)
  328. {
  329. g_RasCon = new RasEnumConnHelp();
  330. if (g_RasCon != NULL)
  331. {
  332. g_fAutodialInitialized = TRUE;
  333. }
  334. else
  335. {
  336. CloseHandle(g_hRasMutex);
  337. g_hRasMutex = INVALID_HANDLE_VALUE;
  338. }
  339. }
  340. }
  341. GlobalDataInitCritSec.Unlock();
  342. }
  343. DEBUG_LEAVE(g_fAutodialInitialized);
  344. return g_fAutodialInitialized;
  345. }
  346. VOID
  347. ExitAutodialModule(
  348. VOID
  349. )
  350. /*++
  351. Routine Description:
  352. Clean up autodial code
  353. Arguments:
  354. None.
  355. Return Value:
  356. None.
  357. --*/
  358. {
  359. DEBUG_ENTER((DBG_DIALUP,
  360. None,
  361. "ExitAutodialModule",
  362. NULL
  363. ));
  364. // don't do anything if not initialized
  365. if(FALSE == g_fAutodialInitialized)
  366. {
  367. DEBUG_LEAVE(0);
  368. return;
  369. }
  370. if (g_RasCon)
  371. {
  372. delete g_RasCon;
  373. g_RasCon = NULL;
  374. }
  375. if(INVALID_HANDLE_VALUE != g_hRasMutex)
  376. {
  377. CloseHandle(g_hRasMutex);
  378. g_hRasMutex = INVALID_HANDLE_VALUE;
  379. }
  380. if (g_hRasLib)
  381. {
  382. FreeLibrary(g_hRasLib);
  383. g_hRasLib = NULL;
  384. }
  385. g_fAutodialInitialized = FALSE;
  386. DEBUG_LEAVE(0);
  387. }
  388. ///////////////////////////////////////////////////////////////////////////
  389. ///////////////////////////////////////////////////////////////////////////
  390. //
  391. // Connection management code
  392. //
  393. ///////////////////////////////////////////////////////////////////////////
  394. ///////////////////////////////////////////////////////////////////////////
  395. LPSTR
  396. GetActiveConnectionName()
  397. /*++
  398. Routine Description:
  399. Figure out the current connection and fix proxy settings for it.
  400. Basically a cheap, return-no-info version of GetConnectedStateEx used
  401. by the winsock callback.
  402. Arguments:
  403. none
  404. Return Value:
  405. BOOL
  406. TRUE - connected
  407. FALSE - not connected
  408. --*/
  409. {
  410. DEBUG_ENTER((DBG_DIALUP,
  411. String,
  412. "GetActiveConnectionName",
  413. NULL
  414. ));
  415. static BOOL fRasLoaded = FALSE;
  416. DWORD dwNewTickCount, dwElapsed;
  417. DWORD dwConnection = 0;
  418. LPSTR lpstrConnection = NULL;
  419. //
  420. // Make sure everything's initialized
  421. //
  422. if (!InitAutodialModule())
  423. goto quit;
  424. //
  425. // serialize
  426. //
  427. WaitForSingleObject(g_hRasMutex, INFINITE);
  428. //
  429. // Check out how recently we polled ras
  430. //
  431. dwNewTickCount = GetTickCountWrap();
  432. dwElapsed = dwNewTickCount - g_dwLastDialupTicks;
  433. //
  434. // Only refresh if more than MIN... ticks has passed
  435. //
  436. if(dwElapsed >= MIN_RNA_BUSY_CHECK_INTERVAL)
  437. {
  438. g_dwLastDialupTicks = dwNewTickCount;
  439. if(DoConnectoidsExist())
  440. {
  441. if(FALSE == fRasLoaded)
  442. fRasLoaded = EnsureRasLoaded();
  443. if(fRasLoaded)
  444. {
  445. g_RasCon->Enum();
  446. if(g_RasCon->GetError() == 0)
  447. g_dwConnections = g_RasCon->GetConnectionsCount();
  448. else
  449. g_dwConnections = 0;
  450. }
  451. }
  452. else
  453. {
  454. g_dwConnections = 0;
  455. }
  456. }
  457. DEBUG_PRINT(DIALUP, INFO, ("Found %d connections\n", g_dwConnections));
  458. if(g_dwConnections > 1)
  459. {
  460. //
  461. // We have more than one connection and caller wants to know which one
  462. // is the interesting one. Try to find a VPN connectoid.
  463. //
  464. RasEntryPropHelp *pRasProp = new RasEntryPropHelp;
  465. if (pRasProp)
  466. {
  467. for(DWORD dwConNum = 0; dwConNum < g_dwConnections; dwConNum++)
  468. {
  469. if(0 == pRasProp->GetW(g_RasCon->GetEntryW(dwConNum)))
  470. {
  471. if(0 == lstrcmpiA(pRasProp->GetDeviceTypeA(), RASDT_Vpn))
  472. {
  473. DEBUG_PRINT(DIALUP, INFO, ("Found VPN entry: %ws\n",
  474. g_RasCon->GetEntryW(dwConNum)));
  475. dwConnection = dwConNum;
  476. break;
  477. }
  478. }
  479. }
  480. delete pRasProp;
  481. }
  482. }
  483. //
  484. // verify status of connection we're interested in is RASCS_Connected.
  485. //
  486. if(g_dwConnections != 0)
  487. {
  488. RasGetConnectStatusHelp RasGetConnectStatus(g_RasCon->GetHandle(dwConnection));
  489. DWORD dwRes = RasGetConnectStatus.GetError();
  490. if (!dwRes && (RasGetConnectStatus.ConnState() == RASCS_Connected))
  491. {
  492. WideCharToAscii_UsingGlobalAlloc(g_RasCon->GetEntryW(dwConnection),
  493. &lpstrConnection);
  494. }
  495. DEBUG_PRINT(DIALUP, INFO, ("Connect Status: dwRet=%x, connstate=%x\n", dwRes, RasGetConnectStatus.ConnState()));
  496. }
  497. ReleaseMutex(g_hRasMutex);
  498. quit:
  499. DEBUG_LEAVE(lpstrConnection);
  500. return lpstrConnection;
  501. }