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.

1906 lines
61 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: main.cpp
  4. //
  5. // Module: CMDIAL32.DLL
  6. //
  7. // Synopsis: The main module implementing interfaces to external (RAS,
  8. // InetDialHandler and internal modules (CmCustomDialDlg).
  9. //
  10. // Copyright (c) 1996-1999 Microsoft Corporation
  11. //
  12. // Author: Dondu Created 96'
  13. //
  14. // History:
  15. // 5/05/97 Modified byao
  16. // added 'InetDialHandler()' for IE4
  17. // 1/26/98 Modified quintinb
  18. // Added RasCustomDialDlg, RasCustomEntryDlg,
  19. // RasCustomHangUp, and RasCustomDial stubs.
  20. // 02/10/98 Modified Heavily refvised for 1.2 architectural shift
  21. //
  22. //+----------------------------------------------------------------------------
  23. #include <windows.h>
  24. //#ifdef WIN32_LEAN_AND_MEAN
  25. //#include <shellapi.h>
  26. //#endif
  27. #include <ras.h>
  28. #include <raserror.h>
  29. #include <rasdlg.h>
  30. #include "cmmaster.h"
  31. #include <wininet.h>
  32. #include "cmtiming.h"
  33. #include "DynamicLib.h"
  34. #include "shelldll.cpp"
  35. //
  36. // Globals
  37. //
  38. HINSTANCE g_hInst;
  39. const TCHAR* const c_pszCmmgrExe = TEXT("CMMGR32.EXE");
  40. const TCHAR* const c_pszExplorerExe = TEXT("EXPLORER.EXE");
  41. const TCHAR* const c_pszCmstpExe = TEXT("CMSTP.EXE");
  42. const TCHAR* const c_pszRunDll32Exe = TEXT("RUNDLL32.EXE");
  43. const TCHAR* const c_pszRasAutoUExe = TEXT("RASAUTOU.EXE");
  44. const TCHAR* const c_pszConnectMutex = TEXT("Connection Manager Connect - "); // Root only
  45. #define RASDDFLAG_Reserved1 0x10000000
  46. //+---------------------------------------------------------------------------
  47. //
  48. // struct CmRasDialDlg
  49. //
  50. // Description: Append CM reconnect infor mation to the end of RASDIALDLG
  51. //
  52. // History: fengsun Created 11/14/97
  53. //
  54. //----------------------------------------------------------------------------
  55. struct CmRasDialDlg
  56. {
  57. RASDIALDLG RasDialDlgInfo;
  58. struct CmRasDialDlg* pSelf; // point to itself, used to verify CmReConnect
  59. DWORD dwSignature; // verify CmReConnect
  60. CMDIALINFO CmInfo; // Reconnect information
  61. enum {CM_RECONNECT_SIGNATURE = 0xC6687DB5}; // To verify dwSignature
  62. };
  63. //+----------------------------------------------------------------------------
  64. //
  65. // Function: StripTunnelSuffixW
  66. //
  67. // Synopsis: Determines if a connection name string contains a suffix of
  68. // " (for advanced use only)" and removes it if found.
  69. //
  70. // Arguments: LPWSTR pszwConnectionName - The string (connectoid name).
  71. //
  72. // Returns: Nothing
  73. //
  74. // History: nickball created 1/11/00
  75. //
  76. //+----------------------------------------------------------------------------
  77. void StripTunnelSuffixW(LPWSTR pszwConnectionName)
  78. {
  79. MYDBGASSERT(pszwConnectionName);
  80. if (NULL == pszwConnectionName)
  81. {
  82. return;
  83. }
  84. //
  85. // On 9X we have to resolve the tunnel connectoid name to the
  86. // service name by removing " (for advanced use only)" if it.
  87. // exists.
  88. //
  89. if (OS_W9X)
  90. {
  91. LPWSTR pszwSuffix = GetTunnelSuffix();
  92. //
  93. // Search for suffix and truncate as necessary.
  94. // Note: Assumes that the service name does not match our suffix.
  95. //
  96. if (pszwSuffix)
  97. {
  98. LPWSTR pszwTmp = CmStrStrW(pszwConnectionName, pszwSuffix);
  99. if (pszwTmp)
  100. {
  101. CMTRACE1(TEXT("StripTunnelSuffixW - found suffix of %s"), pszwTmp);
  102. *pszwTmp = L'\0';
  103. CMTRACE1(TEXT("StripTunnelSuffixW - long service name is %s"), pszwConnectionName);
  104. }
  105. }
  106. CmFree(pszwSuffix);
  107. }
  108. }
  109. //+----------------------------------------------------------------------------
  110. //
  111. // Function: IsStringWithInBuffer
  112. //
  113. // Synopsis: Verify whether a string go beyond the buffer.
  114. //
  115. //
  116. // Arguments: const TCHAR* pszStr - the string to be tested
  117. // DWORD dwSize - the size of the buffer
  118. //
  119. // Returns: BOOL - TRUE if is
  120. //
  121. // History: fengsun Created Header 5/22/98
  122. //
  123. //+----------------------------------------------------------------------------
  124. BOOL IsStringWithInBuffer(const TCHAR* pszStr, DWORD dwSize)
  125. {
  126. MYDBGASSERT(pszStr);
  127. //
  128. // Can not do strlen here. If the data in pszStr is garbage
  129. // strlen can cause access voilation
  130. //
  131. for (DWORD i =0; i<dwSize; i++)
  132. {
  133. if (pszStr[i] == TEXT('\0'))
  134. {
  135. return TRUE;
  136. }
  137. }
  138. return FALSE;
  139. }
  140. //+----------------------------------------------------------------------------
  141. //
  142. // Function: IsCmReconnectRequest
  143. //
  144. // Synopsis: Check whether CM reconnect information is appended to RASDIALDLG
  145. //
  146. // Arguments: const RASDIALDLG* lpInfo - the structure to check
  147. //
  148. // Returns: BOOL - TRUE if is
  149. //
  150. // History: fengsun Created Header 5/22/98
  151. //
  152. //+----------------------------------------------------------------------------
  153. BOOL IsCmReconnectRequest(const RASDIALDLG* lpInfo)
  154. {
  155. MYDBGASSERT(lpInfo);
  156. if (NULL == lpInfo)
  157. {
  158. return FALSE;
  159. }
  160. CMTRACE1(TEXT("IsCmReconnectRequest - RASDIALDLG.dwFlags is 0x%x"), ((LPRASDIALDLG)lpInfo)->dwFlags);
  161. //
  162. // See its our reconnect case by examining the dwFlags of lpInfo
  163. //
  164. if (((LPRASDIALDLG)lpInfo)->dwFlags & RASDDFLAG_Reserved1)
  165. {
  166. //
  167. // Test whether we can read beyond RASDIALDLG to avoid access violation
  168. //
  169. if (!IsBadReadPtr(lpInfo, sizeof(CmRasDialDlg)) )
  170. {
  171. CmRasDialDlg* const pCmDlgInfo = (CmRasDialDlg* const)lpInfo;
  172. //
  173. // Test whether it has the flag we added
  174. //
  175. if (pCmDlgInfo->pSelf == pCmDlgInfo &&
  176. pCmDlgInfo->dwSignature == CmRasDialDlg::CM_RECONNECT_SIGNATURE)
  177. {
  178. //
  179. // Whether the reconnect information is valid
  180. //
  181. //
  182. // Does password seem ok? Whether the password go beyond CmIndo.szPassword
  183. // We can not do strlen here. If we have some garbage here, strlen can
  184. // cauce access violation.
  185. //
  186. if (IsStringWithInBuffer(pCmDlgInfo->CmInfo.szPassword,
  187. sizeof(pCmDlgInfo->CmInfo.szPassword)) )
  188. {
  189. //
  190. // Inet Password OK?
  191. //
  192. if (IsStringWithInBuffer(pCmDlgInfo->CmInfo.szInetPassword,
  193. sizeof(pCmDlgInfo->CmInfo.szInetPassword)) )
  194. {
  195. //
  196. // skip the dwFlags
  197. // This is a valid reconnect request from CMMON
  198. //
  199. return TRUE;
  200. }
  201. }
  202. }
  203. }
  204. }
  205. return FALSE;
  206. }
  207. //+----------------------------------------------------------------------------
  208. //
  209. // Function: CmReConnect
  210. //
  211. // Synopsis: Used specificly for CMMON to call upon reconnect
  212. // This function is added to fix bug 169128: RasCustomHangup not called
  213. // when hangup reconnected connection.
  214. // In order for RAS to call RasCustomHangup, we have to call RasDialDlg.
  215. // CMMON calls CmReConnect with reconnect information. CmReconnect append
  216. // CM specific information to the RASDIALDLG structure then calls RasDialDlg.
  217. // RasCustomHangup then figures out it is a reconnect request.
  218. //
  219. // Arguments: LPTSTR lpszPhonebook - Ptr to the full path and filename of the phonebook.
  220. // LPTSTR lpszEntry - Ptr to the name of the phone-book entry to dial.
  221. // LPCMDIALINFO lpCmInfo - The reconnect information
  222. //
  223. // Returns: DWORD WINAPI - Return code
  224. //
  225. //+----------------------------------------------------------------------------
  226. extern "C"
  227. BOOL CmReConnect(LPTSTR lpszPhonebook,
  228. LPTSTR lpszEntry,
  229. LPCMDIALINFO lpCmInfo)
  230. {
  231. CMTRACE(TEXT("CmReconnect"));
  232. if (OS_NT5)
  233. {
  234. //
  235. // Call RasDialDlg for NT5
  236. //
  237. CmRasDialDlg CmDlgInfo;
  238. ZeroMemory(&CmDlgInfo, sizeof(CmDlgInfo));
  239. CmDlgInfo.RasDialDlgInfo.dwSize = sizeof(CmDlgInfo.RasDialDlgInfo);
  240. CmDlgInfo.RasDialDlgInfo.dwFlags = RASDDFLAG_Reserved1;
  241. CmDlgInfo.CmInfo = *lpCmInfo;
  242. CmDlgInfo.pSelf = &CmDlgInfo;
  243. CmDlgInfo.dwSignature = (DWORD)CmRasDialDlg::CM_RECONNECT_SIGNATURE;
  244. //
  245. // Load rasdlg.dll
  246. //
  247. CDynamicLibrary libRasDlg(TEXT("rasdlg.dll"));
  248. MYDBGASSERT(libRasDlg.IsLoaded());
  249. typedef BOOL (WINAPI* fnRasDialDlgTYPE)(
  250. LPTSTR lpszPhonebook, LPTSTR lpszEntry, LPTSTR lpszPhoneNumber,
  251. LPRASDIALDLG lpInfo );
  252. #ifndef UNICODE
  253. LPSTR pszRasDialDlgText = {"RasDialDlgA"};
  254. #else
  255. LPSTR pszRasDialDlgText = {"RasDialDlgW"};
  256. #endif
  257. fnRasDialDlgTYPE fnRasDialDlg = (fnRasDialDlgTYPE)libRasDlg.GetProcAddress(pszRasDialDlgText);
  258. if (fnRasDialDlg)
  259. {
  260. //
  261. // We base on the assumption that RasDialDlg passes the same pointer to RasCustomDialDlg.
  262. //
  263. if (lpszPhonebook != NULL && lpszPhonebook[0] == TEXT('\0'))
  264. {
  265. return fnRasDialDlg(NULL, lpszEntry, NULL, (RASDIALDLG*)&CmDlgInfo);
  266. }
  267. return fnRasDialDlg(lpszPhonebook, lpszEntry, NULL, (RASDIALDLG*)&CmDlgInfo);
  268. }
  269. return FALSE;
  270. }
  271. else
  272. {
  273. //
  274. // For non-NT5 platform, call CmCustomDialDlg directly
  275. //
  276. return CmCustomDialDlg(NULL, // hwndParent
  277. RCD_AllUsers, // dwFlags
  278. lpszPhonebook,
  279. lpszEntry,
  280. NULL, // lpszPhoneNumber
  281. NULL, // lpRasDialDlg,
  282. NULL, // lpRasEntryDlg,
  283. lpCmInfo);
  284. }
  285. }
  286. //+----------------------------------------------------------------------------
  287. //
  288. // Function: WhoIsCaller
  289. //
  290. // Synopsis: Helper function to determine if we were called manually from the
  291. // desktop or programmatically.
  292. //
  293. // Arguments: dwCaller - which desktop caller.
  294. //
  295. // Returns: BOOL - TRUE if the caller matches one of those specified in dwCaller.
  296. //
  297. // History: nickball Created Header 3/17/98
  298. //
  299. //+----------------------------------------------------------------------------
  300. BOOL WhoIsCaller(DWORD dwCaller)
  301. {
  302. BOOL bRet = FALSE;
  303. TCHAR szTmp[MAX_PATH + 1];
  304. ZeroMemory(szTmp, sizeof(szTmp));
  305. //
  306. // Get the path of the calling process
  307. //
  308. MYVERIFY(GetModuleFileNameU(GetModuleHandleA(NULL), szTmp, MAX_PATH));
  309. CMTRACE1(TEXT("WhoIsCaller() - Calling process is %s"), szTmp);
  310. //
  311. // Locate the filename part
  312. //
  313. LPTSTR pszName = StripPath(szTmp);
  314. MYDBGASSERT(pszName);
  315. if (pszName)
  316. {
  317. //
  318. // Compare against CM and Shell
  319. //
  320. if (dwCaller & DT_CMMGR)
  321. {
  322. bRet = (lstrcmpiU(pszName, c_pszCmmgrExe) == 0);
  323. }
  324. if (!bRet && dwCaller & DT_CMMON)
  325. {
  326. bRet |= (lstrcmpiU(pszName, c_pszCmMonExeName) == 0);
  327. }
  328. if (!bRet && dwCaller & DT_EXPLORER)
  329. {
  330. bRet |= (lstrcmpiU(pszName, c_pszExplorerExe) == 0);
  331. }
  332. if (!bRet && dwCaller & DT_CMSTP)
  333. {
  334. bRet |= (lstrcmpiU(pszName, c_pszCmstpExe) == 0);
  335. }
  336. if (!bRet && dwCaller & DT_RUNDLL32)
  337. {
  338. bRet |= (lstrcmpiU(pszName, c_pszRunDll32Exe) == 0);
  339. }
  340. if (!bRet && dwCaller & DT_RASAUTOU)
  341. {
  342. bRet |= (lstrcmpiU(pszName, c_pszRasAutoUExe) == 0);
  343. }
  344. CmFree(pszName);
  345. }
  346. return bRet;
  347. }
  348. //+----------------------------------------------------------------------------
  349. //
  350. // Function: HandleCustomConnectRequest
  351. //
  352. // Synopsis: Attempts to resolve a connect request for the specified entry by
  353. // examining the current state if any of that connection.
  354. //
  355. // Arguments: HWND hwndParent - HWND of parent for user notification messages
  356. // CConnectionTable *pConnTable - Ptr to the connection table - assumed open
  357. // LPCTSTR pszEntry - The name of the service entry
  358. // DWORD dwFlags - The application flags FL_...
  359. // LPBOOL pfSuccess - Ptr to flag indicating that the request was
  360. // both 1) resolved and 2) already connected
  361. //
  362. // Returns: BOOL - TRUE if the request was resolved against the existing table data
  363. //
  364. // History: nickball Created 3/18/98
  365. //
  366. //+----------------------------------------------------------------------------
  367. BOOL HandleCustomConnectRequest(
  368. HWND hwndParent,
  369. CConnectionTable *pConnTable,
  370. LPCTSTR pszEntry,
  371. DWORD dwFlags,
  372. LPBOOL pfSuccess)
  373. {
  374. BOOL fResolvedInTable = FALSE;
  375. CM_CONNECTION Connection;
  376. ZeroMemory(&Connection, sizeof(CM_CONNECTION));
  377. //
  378. // Only if there is an existing entry do we have any work here
  379. //
  380. if (SUCCEEDED(pConnTable->GetEntry(pszEntry, &Connection)))
  381. {
  382. *pfSuccess = TRUE; // assume the best
  383. //
  384. // There is a connection entry for this service, examine state.
  385. //
  386. if (CM_RECONNECTPROMPT != Connection.CmState)
  387. {
  388. fResolvedInTable = TRUE; // we can handle it here
  389. //
  390. // The entry is connecting, connected, or disconnecting. If its a manual
  391. // connection just notify the user, otherwise check the exact state.
  392. //
  393. if (dwFlags & FL_DESKTOP) // Set in CMMGR
  394. {
  395. NotifyUserOfExistingConnection(hwndParent, &Connection, FALSE);
  396. }
  397. else
  398. {
  399. //
  400. // Only if we are actually connected can we safely succeed.
  401. //
  402. if (CM_CONNECTED != Connection.CmState)
  403. {
  404. *pfSuccess = FALSE;
  405. }
  406. else
  407. {
  408. MYVERIFY(SUCCEEDED(pConnTable->AddEntry(Connection.szEntry, Connection.fAllUser))); // just bump ref
  409. }
  410. }
  411. }
  412. else
  413. {
  414. //
  415. // We must be in RECONNECT mode, if this connect request is
  416. // from another source, tell CMMON to stop its monitoring.
  417. //
  418. if (!(dwFlags & FL_RECONNECT))
  419. {
  420. //
  421. // Its not a reconnect, so notify CMMON
  422. //
  423. HangupNotifyCmMon(pConnTable, Connection.szEntry);
  424. }
  425. }
  426. }
  427. return fResolvedInTable;
  428. }
  429. //+---------------------------------------------------------------------------
  430. //
  431. // Function: InetDialHandler
  432. //
  433. // Synopsis: Ansi and only form of the AutoDial handler .
  434. //
  435. // Arguments: hwndParent[IN] Handle to parent window. No longer ignored.
  436. // pszConnectoid[IN] Connectoid name
  437. // dwFlags[IN] Custom dial handler execution flags
  438. // Current the following flags are supported
  439. // INTERNET_CUSTOMDIAL_CONNECT
  440. // INTERNET_CUSTOMDIAL_UNATTENDED
  441. // INTERNET_CUSTOMDIAL_DISCONNECT
  442. // These flags will be passed from WININET
  443. // lpdwRasError[OUT] RasError code returned from ICM
  444. //
  445. // Returns: The return type is different than one defined in wininet.h
  446. // TRUE: This handler handled the dial request (connected or not)
  447. // FALSE: This handler didn't handle the dial request
  448. //
  449. // When returning TRUE, lpdwRasError is set to:
  450. // ERROR_SUCCESS: Call completed
  451. // ERROR_USER_DISCONNECTION: User cancelled dial request
  452. // <other ras error> Dial attempt failed.
  453. //
  454. // This is a synchronous call. It should not return until the operation is complete.
  455. //
  456. // Note: We do not provide a wide form of this API as it is stored in
  457. // the szAutoDialfunc member of the RASENTRY downlevel. If the
  458. // wide form were avialable, RASAUTOU.EXE would call the function
  459. // (it appends A or W to the name that it finds in AutoDialFunc),
  460. // which would be inappropriate because the semantics of the
  461. // parameters differ even though the function prototypes match.
  462. //
  463. // History: byao Created - 05/05/97
  464. // quintinb Rewrote to use InetDialHandlerW - 03/09/99
  465. // nickball Removed InetDialHandlerW as it confuses RasAuto on NT4 - 07/28/99
  466. // quintinb Always return true if connect request handled #390890 - 08/19/99
  467. //
  468. //----------------------------------------------------------------------------
  469. extern "C" DWORD WINAPI InetDialHandler(HWND hwndParent,
  470. LPCSTR pszConnectoid,
  471. DWORD dwFlags,
  472. LPDWORD lpdwRasError)
  473. {
  474. MYDBGASSERT(pszConnectoid);
  475. MYDBGASSERT(lpdwRasError);
  476. CMTRACE(TEXT("InetDialHandler"));
  477. TCHAR szProfilePath[MAX_PATH+1];
  478. LPWSTR pszwConnectionName = NULL;
  479. LPTSTR pszRasPhoneBook = NULL;
  480. LPCMDIALINFO lpCmInfo = NULL;
  481. BOOL bRet = TRUE; // Read all comments before modifying this init value.
  482. BOOL bAllUser;
  483. //
  484. // Check whether the parameters are valid
  485. //
  486. if (lpdwRasError)
  487. {
  488. if (! ((INTERNET_CUSTOMDIAL_CONNECT == dwFlags) ||
  489. (INTERNET_CUSTOMDIAL_UNATTENDED == dwFlags) ||
  490. (INTERNET_CUSTOMDIAL_DISCONNECT == dwFlags) ||
  491. (INTERNET_CUSTOMDIAL_SHOWOFFLINE== dwFlags) ))
  492. {
  493. CMASSERTMSG(FALSE, TEXT("InetDialHandler called with invalid flag"));
  494. *lpdwRasError = ERROR_INVALID_PARAMETER;
  495. return FALSE;
  496. }
  497. if (!pszConnectoid || TEXT('\0') == pszConnectoid[0])
  498. {
  499. *lpdwRasError = ERROR_INVALID_PARAMETER;
  500. return FALSE;
  501. }
  502. }
  503. else
  504. {
  505. return FALSE;
  506. }
  507. //
  508. // Make a wide copy of the connectoid name. We also want a copy so
  509. // that we can modify if necessary. On 9x we will resolve tunnel
  510. // entry names down to the base connectoid/service name.
  511. //
  512. pszwConnectionName = SzToWzWithAlloc(pszConnectoid);
  513. MYDBGASSERT(pszwConnectionName);
  514. if (!pszwConnectionName)
  515. {
  516. *lpdwRasError = GetLastError();
  517. bRet = FALSE;
  518. goto InetDialHandlerExit;
  519. }
  520. StripTunnelSuffixW(pszwConnectionName);
  521. //
  522. // Handle the Hangup case
  523. //
  524. if (INTERNET_CUSTOMDIAL_DISCONNECT == dwFlags)
  525. {
  526. *lpdwRasError = CmCustomHangUp(NULL, pszwConnectionName, TRUE, FALSE);
  527. bRet = (ERROR_SUCCESS == *lpdwRasError);
  528. goto InetDialHandlerExit;
  529. }
  530. //
  531. // Its a connect request, setup CmInfo flags and call
  532. //
  533. lpCmInfo = (LPCMDIALINFO) CmMalloc(sizeof(CMDIALINFO));
  534. if (NULL == lpCmInfo)
  535. {
  536. *lpdwRasError = ERROR_NOT_ENOUGH_MEMORY;
  537. bRet = FALSE;
  538. goto InetDialHandlerExit;
  539. }
  540. if (INTERNET_CUSTOMDIAL_UNATTENDED == dwFlags )
  541. {
  542. //
  543. // Unattended dialing mode has been requested
  544. //
  545. lpCmInfo->dwCmFlags |= FL_UNATTENDED;
  546. }
  547. //
  548. // Note: Treat INTERNET_CUSTOMDIAL_SHOWOFFLINE the same as INTERNET_CUSTOMDIAL_CONNECT
  549. //
  550. bAllUser = ReadMapping(pszwConnectionName, szProfilePath, (sizeof(szProfilePath)/sizeof(TCHAR)), TRUE, TRUE); // TRUE == fAllUser, TRUE == bExpandEnvStrings
  551. if (FALSE == bAllUser)
  552. {
  553. if (FALSE == ReadMapping(pszwConnectionName, szProfilePath, (sizeof(szProfilePath)/sizeof(TCHAR)), FALSE, TRUE)) // FALSE == fAllUser, TRUE == bExpandEnvStrings
  554. {
  555. //
  556. // No mapping, no connection
  557. //
  558. *lpdwRasError = ERROR_INVALID_PARAMETER;
  559. bRet = FALSE;
  560. goto InetDialHandlerExit;
  561. }
  562. //
  563. // We have a single user profile path. If this is NT5, build a phonebook path
  564. //
  565. MYDBGASSERT(OS_NT5);
  566. if (OS_NT5)
  567. {
  568. pszRasPhoneBook = GetRasPbkFromNT5ProfilePath(szProfilePath);
  569. MYDBGASSERT(pszRasPhoneBook);
  570. }
  571. }
  572. //
  573. // InetDialHandler is usually an auto-dial case.
  574. // Exceptions are:
  575. // 1) When called from WinLogon.exe on NT4. NT #370311
  576. // 2) When called from Rundll32.exe.on any platform. 9x #127217
  577. //
  578. if ((FALSE == IsLogonAsSystem()) && (FALSE == WhoIsCaller(DT_RUNDLL32)))
  579. {
  580. lpCmInfo->dwCmFlags |= FL_AUTODIAL;
  581. }
  582. //
  583. // We set the error code based on whether or not we connected. However,
  584. // we should always return TRUE to indicate to WININET, etc. that we
  585. // handled the connection request (if we did actually handle it).
  586. // Otherwise the caller (eg.IE) will try to dial its own dialer. #390890
  587. //
  588. if (CmCustomDialDlg(hwndParent,
  589. bAllUser ? RCD_AllUsers : RCD_SingleUser,
  590. pszRasPhoneBook,
  591. pszwConnectionName,
  592. NULL,
  593. NULL,
  594. NULL,
  595. lpCmInfo))
  596. {
  597. *lpdwRasError = ERROR_SUCCESS;
  598. }
  599. else
  600. {
  601. *lpdwRasError = ERROR_USER_DISCONNECTION;
  602. }
  603. InetDialHandlerExit:
  604. CmFree(pszRasPhoneBook);
  605. CmFree(lpCmInfo);
  606. CmFree(pszwConnectionName);
  607. CMTRACE2(TEXT("InetDialHandler returns %u with *lpdwRasError %u"), bRet, *lpdwRasError);
  608. return bRet;
  609. }
  610. //+----------------------------------------------------------------------------
  611. //
  612. // Function: AutoDialFunc
  613. //
  614. // Synopsis: The original AutoDial callback function, provided for backward
  615. // compatibility.
  616. //
  617. // Arguments: HWND hwndParent - The hwnd of the caller.
  618. // LPCTSTR pszEntry - The name of the connection to be dialed
  619. // DWORD dwFlags - Specific behaviour for the dial session.
  620. // LPDWORD pdwRetCode - Buffer for return code.
  621. //
  622. // Returns: BOOL WINAPI - TRUE on success
  623. //
  624. // History: nickball Created Header 2/5/98
  625. //
  626. // Note: This is used by RAS on NT4 SP6
  627. //
  628. //+----------------------------------------------------------------------------
  629. extern "C" BOOL WINAPI AutoDialFunc(HWND hwndParent,
  630. LPCSTR pszEntry,
  631. DWORD dwFlags,
  632. LPDWORD pdwRetCode)
  633. {
  634. CMTRACE(TEXT("AutoDialFunc()"));
  635. MYDBGASSERT(OS_NT4);
  636. //
  637. // InetDialHandler always returns TRUE, thus we must determine success or
  638. // failure from the pdwRetCode. If this is ERROR_SUCCESS then we should
  639. // return TRUE, otherwise FALSE.
  640. //
  641. InetDialHandler(hwndParent, pszEntry, dwFlags, pdwRetCode);
  642. BOOL bRet = (ERROR_SUCCESS == *pdwRetCode);
  643. //
  644. // Always override pdwRetCode to ERROR_SUCCESS or RAS will throw an
  645. // unpleasant error. RAS is only interested in success or failure.
  646. //
  647. *pdwRetCode = ERROR_SUCCESS;
  648. CMTRACE2(TEXT("AutoDialFunc returns %u with *pdwRetCode %u"), bRet, *pdwRetCode);
  649. return bRet;
  650. }
  651. //+----------------------------------------------------------------------------
  652. //
  653. // Function: CopyRasInput
  654. //
  655. // Synopsis: Simple wrapper function to make copies of the parameters we
  656. // receive from RAS.
  657. //
  658. // Arguments: LPTSTR* ppszOurCopy - pointer to the string pointer to hold the return string
  659. // LPWSTR pszwStringFromRas - String from RAS
  660. //
  661. // Returns: BOOL - returns TRUE on Success, FALSE otherwise
  662. //
  663. // History: quintinb Created 4/13/99
  664. //
  665. //+----------------------------------------------------------------------------
  666. BOOL CopyRasInput(LPTSTR* ppszOurCopy, LPWSTR pszwStringFromRas)
  667. {
  668. if (pszwStringFromRas)
  669. {
  670. #ifndef _UNICODE
  671. *ppszOurCopy = WzToSzWithAlloc(pszwStringFromRas);
  672. #else
  673. *ppszOurCopy = CmStrCpyAllocW (pszwStringFromRas);
  674. #endif
  675. return (NULL != *ppszOurCopy);
  676. }
  677. return TRUE;
  678. }
  679. //+----------------------------------------------------------------------------
  680. //
  681. // Function: RasCustomDialDlg
  682. //
  683. // Synopsis: Our implementation of RasCustomDialDlg extension, analogous to
  684. // RasDialDlg, but providing custom functionality.
  685. //
  686. // Arguments: HINSTANCE hInstDll - The HINSTANCE of the caller.
  687. // DWORD dwFlags - Dial flags
  688. // LPTSTR lpszPhonebook - Ptr to the full path and filename of the phonebook.
  689. // LPTSTR lpszEntry - Ptr to the name of the phone-book entry to dial.
  690. // LPTSTR lpszPhoneNumber - Ptr toi replacement phone number
  691. // LPRASDIALDLG lpInfo - Ptr to structure for additional parameters
  692. //
  693. // Returns: BOOL WINAPI - TRUE on success
  694. //
  695. // History: nickball Created Header 2/5/98
  696. //
  697. //+----------------------------------------------------------------------------
  698. extern "C" BOOL WINAPI RasCustomDialDlg(HINSTANCE hInstDll,
  699. DWORD dwFlags,
  700. LPWSTR lpszwPhonebook,
  701. LPWSTR lpszwEntry,
  702. LPWSTR lpszwPhoneNumber,
  703. LPRASDIALDLG lpInfo,
  704. PVOID pVoid)
  705. {
  706. MYDBGASSERT(lpszwEntry);
  707. MYDBGASSERT(lpszwEntry[0]);
  708. MYDBGASSERT(lpInfo);
  709. CMTRACE1(TEXT("RasCustomDialDlg() - dwFlags = 0x%x"), dwFlags);
  710. CMTRACE1(TEXT("RasCustomDialDlg() - (RASDIALDLG)lpInfo->dwFlags = 0x%x"), lpInfo->dwFlags);
  711. if (NULL == lpszwEntry || 0 == lpszwEntry[0])
  712. {
  713. return FALSE;
  714. }
  715. //
  716. // We have the minimum requirement of an entry name, get to work
  717. //
  718. BOOL fSuccess = TRUE;
  719. LPTSTR pszEntry = NULL;
  720. LPTSTR pszPhonebook = NULL;
  721. //
  722. // If we have a Phonebook name make a copy
  723. //
  724. fSuccess = CopyRasInput(&pszPhonebook, lpszwPhonebook);
  725. if (fSuccess)
  726. {
  727. //
  728. // If we have an entry name (always do), make a copy to work with
  729. //
  730. fSuccess = CopyRasInput(&pszEntry, lpszwEntry);
  731. if (fSuccess)
  732. {
  733. //
  734. // Its always a simple connect request, no flags, no caller ids
  735. //
  736. CMDIALINFO CmInfo;
  737. ZeroMemory(&CmInfo, sizeof(CMDIALINFO));
  738. //
  739. // If this is a reconnect request from CMMON, copy the information
  740. //
  741. if (lpInfo && IsCmReconnectRequest(lpInfo))
  742. {
  743. CmInfo = ((CmRasDialDlg* )lpInfo)->CmInfo;
  744. }
  745. else
  746. {
  747. //
  748. // If running under the system account its never an autodial
  749. //
  750. if (FALSE == IsLogonAsSystem())
  751. {
  752. //
  753. // See where the call originated. If not a desktop scenario
  754. // then set the AUTODIAL flag so that we do the right thing
  755. // down the line. This is ugly, but we have no other way of
  756. // making the determination. Note: That this entry point
  757. // only exists on NT5 and is only called by RAS so the perf
  758. // hit is contained and CMMGR is not a valid desktop scenario
  759. // so we don't have to check for it.
  760. //
  761. // DT_RASAUTOU - When ICS is enabled, rasauto starts the
  762. // rasautou.exe process to dial a connection. CM used to add
  763. // rasautou in the process watch list. The issue was that
  764. // it goes away after connecting, so cmmon32 thought it needed
  765. // to disconnected. Now, RASAUTOU is not a watched process
  766. // and cmmon32 does not disconnect.
  767. //
  768. if (FALSE == WhoIsCaller(DT_EXPLORER | DT_CMSTP | DT_RASAUTOU))
  769. {
  770. CmInfo.dwCmFlags |= FL_AUTODIAL;
  771. }
  772. }
  773. //
  774. // Note that we want to set the Unattended flag if RASDDFLAG_NoPrompt is set, unless
  775. // the RASDDFLAG_LinkFailure is also set. We only use the RAS redial on link failure
  776. // when we are logging on through WinLogon where we no longer user cmmon32.exe. Elsewhere,
  777. // redial is handled by Cmmon32.exe. However, in this one case we don't want to be in
  778. // unattended mode because the user won't have a saved password (they logged on from WinLogon)
  779. // and unattended mode will just exit silently if it doesn't have all the needed info to dial.
  780. //
  781. if ((lpInfo->dwFlags & RASDDFLAG_NoPrompt) && !(lpInfo->dwFlags & RASDDFLAG_LinkFailure))
  782. {
  783. CmInfo.dwCmFlags |= FL_UNATTENDED;
  784. CMTRACE(TEXT("RasCustomDialDlg - Setting CmInfo.dwCmFlags |= FL_UNATTENDED"));
  785. }
  786. }
  787. //
  788. // If we have a RASNOUSER struct, make sure to encode the password
  789. //
  790. LPRASNOUSER lpRasNoUser = NULL;
  791. if (NULL != pVoid)
  792. {
  793. if (0 == (dwFlags & RCD_Eap))
  794. {
  795. lpRasNoUser = (LPRASNOUSER) pVoid;
  796. CmEncodePassword(lpRasNoUser->szPassword);
  797. }
  798. }
  799. fSuccess = CmCustomDialDlg(lpInfo ? lpInfo->hwndOwner : NULL,
  800. dwFlags,
  801. pszPhonebook,
  802. pszEntry,
  803. NULL,
  804. lpInfo,
  805. NULL,
  806. &CmInfo,
  807. pVoid);
  808. //
  809. // If we have a RASNOUSER struct, decode the password to make it plain text again
  810. //
  811. if (NULL != lpRasNoUser)
  812. {
  813. CmDecodePassword(lpRasNoUser->szPassword);
  814. }
  815. }
  816. }
  817. //
  818. // Cleanup and go home
  819. //
  820. CmFree(pszPhonebook);
  821. CmFree(pszEntry);
  822. CMTRACE1(TEXT("RasCustomDialDlg returning %d"), fSuccess);
  823. return fSuccess;
  824. }
  825. //+----------------------------------------------------------------------------
  826. //
  827. // Function: RasCustomEntryDlg
  828. //
  829. // Synopsis: Our implementation of RasCustomEntryDlg extension, analogous to
  830. // RasEntryDlg, but providing custom functionality.
  831. //
  832. // Arguments: HINSTANCE hInstDll - The HINSTANCE of the caller.
  833. // LPTSTR lpszPhonebook - Ptr to the full path and name of the phonebook to be edited.
  834. // LPTSTR lpszEntry - Ptr to the name of the entry to be edited.
  835. // LPRASENTRYDLG lpInfo - Ptr to structure containing additional parameters.
  836. //
  837. // Returns: BOOL WINAPI - TRUE on success
  838. //
  839. // History: nickball 2/5/98 Created Header
  840. // nickball 1/11/00 Now used on 9x, added use of function
  841. // StripTunnelSuffixW() to resolve 9x tunnel
  842. // connectoid names.
  843. //
  844. //+----------------------------------------------------------------------------
  845. extern "C" BOOL WINAPI RasCustomEntryDlg(HINSTANCE hInstDll,
  846. LPWSTR lpszwPhonebook,
  847. LPWSTR lpszwEntry,
  848. LPRASENTRYDLG lpInfo,
  849. DWORD dwFlags)
  850. {
  851. MYDBGASSERT(lpszwEntry);
  852. MYDBGASSERT(lpszwEntry[0]);
  853. CMTRACE1(TEXT("RasCustomEntryDlg() - dwFlags = 0x%x"), dwFlags);
  854. if (NULL == lpszwEntry || 0 == lpszwEntry[0])
  855. {
  856. return FALSE;
  857. }
  858. //
  859. // We have the minimum requirement of an entry name, get to work
  860. //
  861. BOOL fSuccess = TRUE;
  862. LPTSTR pszEntry = NULL;
  863. LPTSTR pszPhonebook = NULL;
  864. //
  865. // If we have a Phonebook name, make a copy to work with
  866. //
  867. fSuccess = CopyRasInput(&pszPhonebook, lpszwPhonebook);
  868. if (fSuccess)
  869. {
  870. //
  871. // If we have an entry name (always do), make a copy to work with
  872. //
  873. fSuccess = CopyRasInput(&pszEntry, lpszwEntry);
  874. if (fSuccess)
  875. {
  876. StripTunnelSuffixW(pszEntry); // Assumes we'll always compile Unicode
  877. //
  878. // Its always a properties request, set the flag and dial
  879. //
  880. LPCMDIALINFO lpCmInfo = (LPCMDIALINFO) CmMalloc(sizeof(CMDIALINFO));
  881. if (lpCmInfo)
  882. {
  883. lpCmInfo->dwCmFlags |= FL_PROPERTIES;
  884. fSuccess = CmCustomDialDlg(lpInfo ? lpInfo->hwndOwner : NULL,
  885. dwFlags,
  886. pszPhonebook,
  887. pszEntry,
  888. NULL,
  889. NULL,
  890. lpInfo,
  891. lpCmInfo);
  892. }
  893. else
  894. {
  895. fSuccess = FALSE;
  896. }
  897. CmFree(lpCmInfo);
  898. }
  899. }
  900. //
  901. // Cleanup and go home
  902. //
  903. CmFree(pszPhonebook);
  904. CmFree(pszEntry);
  905. return fSuccess;
  906. }
  907. //+----------------------------------------------------------------------------
  908. //
  909. // Function: RasCustomHangUp
  910. //
  911. // Synopsis: Our implementation of the RasCustomHangUp extension, analogous to
  912. // RasHangup, but providing custom functionality. This function is
  913. // only called on NT5
  914. //
  915. // Arguments: HRASCONN hRasConn - The handle of the connection to be terminated.
  916. //
  917. // Returns: DWORD WINAPI - Return code
  918. //
  919. // History: nickball Created Header 2/5/98
  920. //
  921. //+----------------------------------------------------------------------------
  922. extern "C" DWORD WINAPI RasCustomHangUp(HRASCONN hRasConn)
  923. {
  924. //
  925. // If someone is calling this function on a system other then NT5, assert.
  926. //
  927. MYDBGASSERT(OS_NT5);
  928. MYDBGASSERT(hRasConn);
  929. CMTRACE(TEXT("RasCustomHangup()"));
  930. DWORD dwRes = ERROR_SUCCESS;
  931. //
  932. // First try to open the table, if none found then succeed.
  933. //
  934. CConnectionTable ConnTable;
  935. if (FAILED(ConnTable.Open()))
  936. {
  937. return dwRes;
  938. }
  939. //
  940. // If we have an entry, do the Disconnect
  941. //
  942. CM_CONNECTION Connection;
  943. ZeroMemory(&Connection, sizeof(CM_CONNECTION));
  944. if (SUCCEEDED(ConnTable.GetEntry(hRasConn, &Connection)))
  945. {
  946. MYDBGASSERT(hRasConn == Connection.hDial || hRasConn == Connection.hTunnel);
  947. //
  948. // Check connect state of entry.
  949. // If we are already in the DISCONNECTING state, perform a simple hangup.
  950. //
  951. if (CM_DISCONNECTING == Connection.CmState)
  952. {
  953. //
  954. // Set up RAS linkage
  955. //
  956. RasLinkageStruct rlsRasLink;
  957. ZeroMemory(&rlsRasLink, sizeof(RasLinkageStruct));
  958. if (TRUE == LinkToRas(&rlsRasLink) && rlsRasLink.pfnHangUp)
  959. {
  960. //
  961. // Linkage is good, make the hangup call
  962. //
  963. dwRes = DoRasHangup(&rlsRasLink, hRasConn);
  964. }
  965. else
  966. {
  967. MYDBGASSERT(FALSE);
  968. dwRes = ERROR_NOT_READY;
  969. }
  970. //
  971. // Cleanup
  972. //
  973. UnlinkFromRas(&rlsRasLink);
  974. }
  975. else
  976. {
  977. //
  978. // If we're still here then we are not in the middle of an existing
  979. // disconnect, handle disconnect as we otherwise would.
  980. //
  981. dwRes = Disconnect(&ConnTable, &Connection, FALSE, FALSE);
  982. }
  983. }
  984. else
  985. {
  986. dwRes = ERROR_NOT_FOUND;
  987. }
  988. //
  989. // We are done with the table, close it now.
  990. //
  991. MYVERIFY(SUCCEEDED(ConnTable.Close()));
  992. return dwRes;
  993. }
  994. //+----------------------------------------------------------------------------
  995. //
  996. // Function: RasCustomDial
  997. //
  998. // Synopsis: Our implementation of RasCustomDial which we don't support.
  999. // Provided so that we can return E_NOTIMPL to indicate our lack of
  1000. // support for this extension.
  1001. //
  1002. // Arguments: N/A
  1003. //
  1004. // Returns: DWORD WINAPI - E_NOTIMPL
  1005. //
  1006. // History: nickball Created Header 2/5/98
  1007. //
  1008. //+----------------------------------------------------------------------------
  1009. extern "C" DWORD WINAPI RasCustomDial(
  1010. HINSTANCE hInstDll,
  1011. LPRASDIALEXTENSIONS lpRasDialExtensions,
  1012. LPWSTR lpszPhonebook,
  1013. LPRASDIALPARAMSW lpRasDialParams,
  1014. DWORD dwNotifierType,
  1015. LPVOID lpvNotifier,
  1016. LPHRASCONN lphRasConn,
  1017. DWORD dwFlags)
  1018. {
  1019. return E_NOTIMPL;
  1020. }
  1021. //+----------------------------------------------------------------------------
  1022. //
  1023. // Function: RasCustomDeleteEntryNotify
  1024. //
  1025. // Synopsis: Our implementation of RasCustomDeleteEntry.
  1026. //
  1027. // Arguments:
  1028. //
  1029. // Returns: DWORD WINAPI -
  1030. //
  1031. // History: quintinb Created Header 2/5/98
  1032. //
  1033. //+----------------------------------------------------------------------------
  1034. extern "C" DWORD WINAPI RasCustomDeleteEntryNotify(LPWSTR pszPhonebook, LPWSTR pszEntry, DWORD dwFlags)
  1035. {
  1036. CDynamicLibrary UserEnv(L"userenv.dll");
  1037. CDynamicLibrary Advapi32(L"advapi32.dll");
  1038. DWORD dwReturn = ERROR_INVALID_PARAMETER;
  1039. HANDLE hImpersonationToken = NULL; // The token of the thread
  1040. HANDLE hPrimaryToken = NULL; // The primary token for the new process
  1041. LPWSTR pszShortServiceName = NULL;
  1042. LPWSTR pszCmDirpath = NULL;
  1043. PROCESS_INFORMATION ProcessInfo = {0};
  1044. STARTUPINFO StartupInfo = {0};
  1045. WCHAR szCmpPath[MAX_PATH+1] = {0};
  1046. WCHAR szInfPath[MAX_PATH+1];
  1047. WCHAR szParams[2*MAX_PATH+1];
  1048. typedef BOOL (WINAPI* pfnCreateEnvironmentBlockSpec)(LPVOID*, HANDLE, BOOL);
  1049. typedef BOOL (WINAPI* pfnDestroyEnvironmentBlockSpec)(LPVOID);
  1050. typedef BOOL (WINAPI* pfnDuplicateTokenExSpec)(HANDLE, DWORD, LPSECURITY_ATTRIBUTES, SECURITY_IMPERSONATION_LEVEL, TOKEN_TYPE, PHANDLE);
  1051. pfnCreateEnvironmentBlockSpec pfnCreateEnvironmentBlock = NULL;
  1052. pfnDestroyEnvironmentBlockSpec pfnDestroyEnvironmentBlock = NULL;
  1053. pfnDuplicateTokenExSpec pfnDuplicateTokenEx = NULL;
  1054. //
  1055. // Are we deleting an All User or a Single User Connection
  1056. //
  1057. BOOL bAllUser = (RCD_AllUsers & dwFlags);
  1058. //
  1059. // Assume we are impersonating until we know otherwise. Profiles deleted from the
  1060. // IE Connections Tab will not be impersonating, whereas delete requests from the
  1061. // folder go through Netman.dll in svchost.exe and are thus impersonating.
  1062. //
  1063. BOOL bImpersonatingProfile = TRUE;
  1064. //
  1065. // Check the params, note that pszPhoneBook could be NULL
  1066. //
  1067. if ((NULL == pszEntry) || (L'\0' == pszEntry[0]) ||
  1068. ((NULL != pszPhonebook) && (L'\0' == pszPhonebook[0])))
  1069. {
  1070. goto exit;
  1071. }
  1072. //
  1073. // Next lets setup the impersonation Token
  1074. //
  1075. if (OpenThreadToken(GetCurrentThread(),
  1076. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
  1077. TRUE, &hImpersonationToken))
  1078. {
  1079. //
  1080. // Okay, we have an impersonation token. Lets get it, duplicate it and then
  1081. // we can use it to call CreateProcessAsUser
  1082. //
  1083. pfnDuplicateTokenEx = (pfnDuplicateTokenExSpec)Advapi32.GetProcAddress("DuplicateTokenEx");
  1084. if (NULL == pfnDuplicateTokenEx)
  1085. {
  1086. dwReturn = GetLastError();
  1087. CMTRACE1(TEXT("RasCustomDeleteEntry -- Unable get proc address for DuplicateTokenEx, GLE %d"), GetLastError());
  1088. goto exit;
  1089. }
  1090. if (!pfnDuplicateTokenEx(hImpersonationToken,
  1091. TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE,
  1092. NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken))
  1093. {
  1094. dwReturn = GetLastError();
  1095. CMTRACE1(TEXT("RasCustomDeleteEntry -- DuplicateTokenEx Failed, GLE %d"), GetLastError());
  1096. goto exit;
  1097. }
  1098. }
  1099. else
  1100. {
  1101. bImpersonatingProfile = FALSE;
  1102. }
  1103. //
  1104. // First let's read the Mappings Key, note that we don't expand the environment strings
  1105. // if it is an impersonating profile. ExpandEnvironmentStrings doesn't have the correct
  1106. // environment loaded sometimes when we are impersonating. We are launching cmstp.exe
  1107. // with a full environment block via CreateProcessAsUser, this will take care of the
  1108. // expansion so there is no need.
  1109. //
  1110. if (FALSE == ReadMapping(pszEntry, szCmpPath, MAX_PATH, bAllUser, !bImpersonatingProfile)) // !bImpersonatingProfile == bExpandEnvStrings
  1111. {
  1112. //
  1113. // No mappings key, return failure
  1114. //
  1115. CMASSERTMSG(FALSE, TEXT("RasCustomDeleteEntry -- ReadMapping returned FALSE, unable to find the profile."));
  1116. dwReturn = ERROR_FILE_NOT_FOUND;
  1117. goto exit;
  1118. }
  1119. //
  1120. // At this point we should have a mappings value. We need to convert that into the INF
  1121. // path. CM 1.0/1.1 profiles stored their INF files in the system(32) dir.
  1122. // CM 1.2 Profiles store this file in the Profile directory. Since
  1123. // a user could install an old profile we must try the Legacy location
  1124. // if the current location fails.
  1125. //
  1126. pszShortServiceName = CmStripPathAndExt(szCmpPath);
  1127. pszCmDirpath = CmStripFileName(szCmpPath, TRUE); // bKeepSlash == TRUE
  1128. if (pszShortServiceName && pszCmDirpath)
  1129. {
  1130. //
  1131. // Build the new inf location
  1132. //
  1133. wsprintfW(szInfPath, L"%s%s\\%s.inf", pszCmDirpath, pszShortServiceName, pszShortServiceName);
  1134. if (!FileExists(szInfPath) && bAllUser) // if the doesn't file exists and we are all user then try the sys dir
  1135. {
  1136. //
  1137. // Looks like this is an old style profile with the inf in the system directory.
  1138. // Now build the old style path and see if it exists. Note that 1.0 profiles were All User only
  1139. //
  1140. if (0 != GetSystemDirectoryU(szInfPath, MAX_PATH))
  1141. {
  1142. lstrcatU(szInfPath, L"\\");
  1143. lstrcatU(szInfPath, pszShortServiceName);
  1144. lstrcatU(szInfPath, L".inf");
  1145. if (!FileExists(szInfPath))
  1146. {
  1147. CMASSERTMSG(FALSE, TEXT("RasCustomDeleteEntry -- Unable to locate profile inf."));
  1148. dwReturn = ERROR_FILE_NOT_FOUND;
  1149. goto exit;
  1150. }
  1151. }
  1152. else
  1153. {
  1154. dwReturn = GetLastError();
  1155. goto exit;
  1156. }
  1157. }
  1158. }
  1159. else
  1160. {
  1161. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1162. goto exit;
  1163. }
  1164. lstrcpyU(szParams, L"cmstp.exe /u /s \"");
  1165. lstrcatU(szParams, szInfPath);
  1166. lstrcatU(szParams, L"\"");
  1167. if (bImpersonatingProfile)
  1168. {
  1169. //
  1170. // Fill in the environment block
  1171. //
  1172. WCHAR* pszEnvBlock;
  1173. pfnCreateEnvironmentBlock = (pfnCreateEnvironmentBlockSpec)UserEnv.GetProcAddress("CreateEnvironmentBlock");
  1174. pfnDestroyEnvironmentBlock = (pfnDestroyEnvironmentBlockSpec)UserEnv.GetProcAddress("DestroyEnvironmentBlock");
  1175. if ((NULL == pfnCreateEnvironmentBlock) || (NULL == pfnDestroyEnvironmentBlock))
  1176. {
  1177. dwReturn = ERROR_PROC_NOT_FOUND;
  1178. CMTRACE(TEXT("RasCustomDeleteEntry -- Unable to load pfnCreateEnvironmentBlock Or pfnDestroyEnvironmentBlock."));
  1179. goto exit;
  1180. }
  1181. if (pfnCreateEnvironmentBlock((void**)&pszEnvBlock, hPrimaryToken, TRUE))
  1182. {
  1183. if (CreateProcessAsUser(hPrimaryToken,
  1184. NULL, // lpApplicationName
  1185. szParams, // lpCommandLine
  1186. NULL, // pProcessAttributes
  1187. NULL, // lpThreadAttributes
  1188. FALSE, // bInheritHandles
  1189. CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
  1190. pszEnvBlock, // lpEnvironment
  1191. NULL, // lpCurrentDirectory
  1192. &StartupInfo,
  1193. &ProcessInfo))
  1194. {
  1195. CloseHandle(ProcessInfo.hProcess);
  1196. CloseHandle(ProcessInfo.hThread);
  1197. dwReturn = ERROR_SUCCESS;
  1198. }
  1199. else
  1200. {
  1201. dwReturn = GetLastError();
  1202. CMTRACE1(TEXT("RasCustomDeleteEntry -- CreateProcessAsUser Failed, GLE %d"), GetLastError());
  1203. }
  1204. pfnDestroyEnvironmentBlock(pszEnvBlock);
  1205. }
  1206. else
  1207. {
  1208. CMTRACE1(L"Unable to Create the Environment block, GLE %d", GetLastError());
  1209. }
  1210. }
  1211. else
  1212. {
  1213. //
  1214. // We aren't impersonating just use regular CreateProcess
  1215. //
  1216. if (CreateProcess(NULL, // lpApplicationName
  1217. szParams, // lpCommandLine
  1218. NULL, // pProcessAttributes
  1219. NULL, // lpThreadAttributes
  1220. FALSE, // bInheritHandles
  1221. CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
  1222. NULL, // lpEnvironment
  1223. NULL, // lpCurrentDirectory
  1224. &StartupInfo,
  1225. &ProcessInfo))
  1226. {
  1227. CloseHandle(ProcessInfo.hProcess);
  1228. CloseHandle(ProcessInfo.hThread);
  1229. dwReturn = ERROR_SUCCESS;
  1230. }
  1231. else
  1232. {
  1233. dwReturn = GetLastError();
  1234. CMTRACE1(TEXT("RasCustomDeleteEntry -- CreateProcessAsUser Failed, GLE %d"), GetLastError());
  1235. }
  1236. }
  1237. exit:
  1238. if (hImpersonationToken)
  1239. {
  1240. CloseHandle(hImpersonationToken);
  1241. }
  1242. if (hPrimaryToken)
  1243. {
  1244. CloseHandle(hPrimaryToken);
  1245. }
  1246. CmFree(pszCmDirpath);
  1247. CmFree(pszShortServiceName);
  1248. return dwReturn;
  1249. }
  1250. //+----------------------------------------------------------------------------
  1251. //
  1252. // Function: DllMain
  1253. //
  1254. // Synopsis: Main entry point into the DLL.
  1255. //
  1256. // Arguments: HINSTANCE hinstDLL - Our HINSTANCE
  1257. // DWORD fdwReason - The reason we are being called.
  1258. // LPVOID lpvReserved - Reserved
  1259. //
  1260. // Returns: BOOL WINAPI - TRUE - always
  1261. //
  1262. // History: nickball Created Header 2/5/98
  1263. //
  1264. //+----------------------------------------------------------------------------
  1265. extern "C" BOOL WINAPI DllMain(HINSTANCE hInstDLL,
  1266. DWORD fdwReason,
  1267. LPVOID lpvReserved)
  1268. {
  1269. switch (fdwReason)
  1270. {
  1271. case DLL_PROCESS_ATTACH:
  1272. if (!InitUnicodeAPI())
  1273. {
  1274. //
  1275. // Without our U api's we are going no where. Bail.
  1276. //
  1277. MessageBox(NULL, TEXT("Cmdial32.dll Initialization Error: Unable to initialize Unicode to ANSI conversion layer, exiting."),
  1278. TEXT("Connection Manager"), MB_OK | MB_ICONERROR);
  1279. return FALSE;
  1280. }
  1281. /*
  1282. if (S_OK != CmLogInitialize(hInstDLL))
  1283. {
  1284. MessageBox(NULL, TEXT("Cmdial32.dll initialization error: Unable to initialize logging, exiting."),
  1285. TEXT("Connection Manager"), MB_OK | MB_ICONERROR);
  1286. // not fatal
  1287. }
  1288. */
  1289. CMTRACE(TEXT("====================================================="));
  1290. CMTRACE1(TEXT(" CMDIAL32.DLL - LOADING - Process ID is 0x%x "), GetCurrentProcessId());
  1291. CMTRACE(TEXT("====================================================="));
  1292. #ifdef DEBUG
  1293. TCHAR szTmp[MAX_PATH];
  1294. MYVERIFY(GetModuleFileNameU (GetModuleHandleA(NULL), szTmp, MAX_PATH));
  1295. CMTRACE1(TEXT("Calling process is %s"), szTmp);
  1296. #endif
  1297. //
  1298. // Setup global instance data
  1299. //
  1300. g_hInst = hInstDLL;
  1301. //
  1302. // Disable thread attach notification
  1303. //
  1304. MYVERIFY(DisableThreadLibraryCalls(hInstDLL));
  1305. break;
  1306. case DLL_PROCESS_DETACH:
  1307. CMTRACE(TEXT("====================================================="));
  1308. CMTRACE1(TEXT(" CMDIAL32.DLL - UNLOADING - Process ID is 0x%x "), GetCurrentProcessId());
  1309. CMTRACE(TEXT("====================================================="));
  1310. if (!UnInitUnicodeAPI())
  1311. {
  1312. CMASSERTMSG(FALSE, TEXT("cmdial32 dllmain UnInitUnicodeAPI failed - we are probably leaking a handle"));
  1313. }
  1314. //
  1315. // Unlike Windows 95, on Windows NT, Windows classes
  1316. // that a DLL registers are NOT unregistered when the DLL is unloaded.
  1317. // Bug 168251:First launch of profile from connections UI causes access violation,
  1318. // after copy new CM bits
  1319. //
  1320. if (OS_NT)
  1321. {
  1322. //
  1323. // Unregister the bitmap class. The new CM bits will re-register the class with
  1324. // correct wnd proc address.
  1325. //
  1326. UnregisterClassU(ICONNMGR_BMP_CLASS, g_hInst);
  1327. UnRegisterWindowClass(g_hInst);
  1328. }
  1329. break;
  1330. }
  1331. return TRUE;
  1332. }
  1333. //+----------------------------------------------------------------------------
  1334. //
  1335. // Function: CmCustomDialDlg
  1336. //
  1337. // Synopsis: Our CM specific variation on RasCustomDialDlg.
  1338. //
  1339. // Arguments: HWND hwndParent - The HWND of the parent if deemed necessary by the caller
  1340. // DWORD dwFlags - Dial flags
  1341. // LPTSTR lpszPhonebook - Ptr to the full path and filename of the phonebook.
  1342. // NULL = RAS system phone book
  1343. // "something" = user-defined RAS phonebook
  1344. // "" = has not been determined yet
  1345. // LPTSTR lpszEntry - Ptr to the name of the phone-book entry to dial.
  1346. // LPTSTR lpszPhoneNumber - Ptr to replacement phone number [IGNORED]
  1347. // LPRASDIALDLG lpRasDialDlg - Ptr to RASDIALDLG struct
  1348. // LPRASENTRYDLG lpRasEntryDlg - Ptr to RASENTRYDLG struct
  1349. // LPCMDIALINFO lpCmInfo - Ptr to CMDIALINFO struct containing CM dial info such as flags.
  1350. //
  1351. // Returns: BOOL WINAPI - TRUE on success
  1352. //
  1353. // History: nickball Created Header 2/5/98
  1354. //
  1355. //+----------------------------------------------------------------------------
  1356. extern "C" BOOL WINAPI CmCustomDialDlg(HWND hwndParent,
  1357. DWORD dwFlags,
  1358. LPTSTR lpszPhonebook,
  1359. LPCTSTR lpszEntry,
  1360. LPTSTR, // lpszPhoneNumber
  1361. LPRASDIALDLG lpRasDialDlg,
  1362. LPRASENTRYDLG lpRasEntryDlg,
  1363. LPCMDIALINFO lpCmInfo,
  1364. PVOID pvLogonBlob)
  1365. {
  1366. MYDBGASSERT(lpCmInfo);
  1367. MYDBGASSERT(lpszEntry);
  1368. MYDBGASSERT(lpszEntry[0]);
  1369. //DebugBreak();
  1370. CMTRACE1(TEXT("CmCustomDialDlg() - dwFlags = 0x%x"), dwFlags);
  1371. CMTRACE1(TEXT("CmCustomDialDlg() - lpszPhonebook = %s"), MYDBGSTR(lpszPhonebook));
  1372. CMTRACE1(TEXT("CmCustomDialDlg() - lpszEntry = %s"), MYDBGSTR(lpszEntry));
  1373. //
  1374. // lpszPhonebook can be NULL, because we are called by our own modules, CMMGR, CMMON, etc.
  1375. //
  1376. if (NULL == lpszEntry || NULL == lpszEntry[0] || NULL == lpCmInfo)
  1377. {
  1378. return FALSE;
  1379. }
  1380. CM_SET_TIMING_INTERVAL("CmCustomDialDlg - Begin");
  1381. CNamedMutex ConnectMutex;
  1382. CConnectionTable ConnTable;
  1383. BOOL fConnTableExists = FALSE;
  1384. BOOL fMultiInst = FALSE;
  1385. if (!(lpCmInfo->dwCmFlags & FL_PROPERTIES))
  1386. {
  1387. //
  1388. // Try to acquire connect mutex
  1389. //
  1390. LPTSTR pszTmp = CmStrCpyAlloc(c_pszConnectMutex);
  1391. pszTmp = CmStrCatAlloc(&pszTmp, lpszEntry);
  1392. if (FALSE == ConnectMutex.Lock(pszTmp, FALSE))
  1393. {
  1394. if (FALSE == IsLogonAsSystem())
  1395. {
  1396. //
  1397. // Another connect instance exists, try to front it
  1398. //
  1399. FrontExistingUI(NULL, lpszEntry, TRUE);
  1400. //
  1401. // Now wait for Mutex to be released.
  1402. //
  1403. ConnectMutex.Lock(pszTmp, TRUE, INFINITE, TRUE);
  1404. //
  1405. // Mutex was released by the other instance, we'll handle the connect
  1406. // request in the main path. If there is no table, we know that the
  1407. // instance which previously owned the mutex terminated without
  1408. // connecting and we follow suit by returning failure. Otherwise, we
  1409. // have to take a closer look.
  1410. //
  1411. fMultiInst = TRUE;
  1412. }
  1413. else
  1414. {
  1415. //
  1416. // No one is logged on and we don't need to be waiting for the mutex.
  1417. //
  1418. CmFree(pszTmp);
  1419. return FALSE;
  1420. }
  1421. }
  1422. CmFree(pszTmp);
  1423. }
  1424. CMTRACE(TEXT("CmCustomDialDlg - Connect mutex acquired. Examining connection table."));
  1425. fConnTableExists = SUCCEEDED(ConnTable.Open());
  1426. if ((!fConnTableExists) && fMultiInst)
  1427. {
  1428. //
  1429. // If we're a secondary thread that was released from the mutex and
  1430. // there is no connection table, then the user canceled, so bail.
  1431. //
  1432. CMTRACE(TEXT("CmCustomDialDlg - returning connect failure post mutex wait"));
  1433. return FALSE;
  1434. }
  1435. //
  1436. // If this is a connect request, see if connection exists.
  1437. //
  1438. if (!(lpCmInfo->dwCmFlags & FL_PROPERTIES))
  1439. {
  1440. if (fConnTableExists)
  1441. {
  1442. //
  1443. // Examine the connection table and try to resolve the connect request
  1444. //
  1445. BOOL fSuccess = FALSE;
  1446. BOOL fDone = HandleCustomConnectRequest(NULL,
  1447. &ConnTable,
  1448. lpszEntry,
  1449. lpCmInfo->dwCmFlags,
  1450. &fSuccess);
  1451. //
  1452. // If we resolved the request, or we're in fMultiInst mode
  1453. // then we can we can bail with the given success code. If
  1454. // fMultInst, we know we can bail because there is no entry
  1455. // in the table, from which we infer that the previous owner
  1456. // of the mutex failed and we return this out to our caller.
  1457. //
  1458. // NOTE: There is a theoretical corner case here in the multi-inst
  1459. // request case. If a succesful connection was established by the
  1460. // first thread, there is a window between the moment that the mutex
  1461. // lock is cleared above (releasing the waiting thread), and when
  1462. // the newly release thread reaches here. The logic is fouled if,
  1463. // and only if, the connection were dropped and entered the
  1464. // reconnect prompt state during this window. This is because the
  1465. // second thread would dismiss the CMMON reconnect prompt UI during
  1466. // the call to HandleCustomConnectRequest, but would then return
  1467. // despite fDone being FALSE. The correct behavior would be to
  1468. // continue, and honor the connect request. This state could be
  1469. // identified by an fDone of FALSE coupled with an fSuccess of TRUE.
  1470. //
  1471. if (fDone || fMultiInst)
  1472. {
  1473. MYVERIFY(SUCCEEDED(ConnTable.Close()));
  1474. return fSuccess;
  1475. }
  1476. }
  1477. }
  1478. else
  1479. {
  1480. //
  1481. // Its a properties request, front any UI that might exist
  1482. //
  1483. if (TRUE == FrontExistingUI(fConnTableExists? &ConnTable : NULL, lpszEntry, FALSE))
  1484. {
  1485. if (fConnTableExists)
  1486. {
  1487. MYVERIFY(SUCCEEDED(ConnTable.Close()));
  1488. }
  1489. return TRUE;
  1490. }
  1491. }
  1492. if (fConnTableExists)
  1493. {
  1494. MYVERIFY(SUCCEEDED(ConnTable.Close()));
  1495. }
  1496. //
  1497. // Make a connection attempt
  1498. //
  1499. HRESULT hrRes = Connect(hwndParent,
  1500. lpszEntry,
  1501. lpszPhonebook,
  1502. lpRasDialDlg,
  1503. lpRasEntryDlg,
  1504. lpCmInfo,
  1505. OS_NT5 ? dwFlags : RCD_AllUsers, // Always AllUser downlevel
  1506. pvLogonBlob);
  1507. //
  1508. // Make sure we push error codes back out
  1509. //
  1510. BOOL bReturn = SUCCEEDED(hrRes);
  1511. DWORD dwError = 0;
  1512. if (lpRasDialDlg)
  1513. {
  1514. if (ERROR_CANCELLED == HRESULT_CODE(hrRes))
  1515. {
  1516. //
  1517. // If the user canceled then RasDialDlg returns a false to indicate failure
  1518. // but sets the dwError value to 0. In order to match the way RAS does
  1519. // things we need to do this too.
  1520. //
  1521. lpRasDialDlg->dwError = 0;
  1522. }
  1523. else
  1524. {
  1525. //
  1526. // If the user entered the wrong PIN, we pass the error up to RAS unchanged
  1527. // so that RAS knows to take down its 'choose connectoid' dialog and drop
  1528. // the user back to winlogon
  1529. //
  1530. lpRasDialDlg->dwError = (BAD_SCARD_PIN(hrRes) ? hrRes : HRESULT_CODE(hrRes));
  1531. }
  1532. dwError = lpRasDialDlg->dwError;
  1533. }
  1534. if (lpRasEntryDlg)
  1535. {
  1536. if (ERROR_CANCELLED == HRESULT_CODE(hrRes))
  1537. {
  1538. //
  1539. // If the user canceled then RasEntryDlg returns a false to indicate failure
  1540. // but sets the dwError value to 0. In order to match the way RAS does
  1541. // things we need to do this too.
  1542. //
  1543. lpRasEntryDlg->dwError = 0;
  1544. }
  1545. else
  1546. {
  1547. lpRasEntryDlg->dwError = HRESULT_CODE(hrRes);
  1548. }
  1549. dwError = lpRasEntryDlg->dwError;
  1550. }
  1551. //
  1552. // Let go of the connect mutex and go home to papa.
  1553. //
  1554. CMTRACE(TEXT("CmCustomDialDlg - Releasing mutex"));
  1555. ConnectMutex.Unlock();
  1556. CMTRACE2(TEXT("CmCustomDialDlg() returning with bReturn = %d, dwError = 0x%x"), bReturn, dwError);
  1557. return bReturn;
  1558. }
  1559. //+----------------------------------------------------------------------------
  1560. //
  1561. // Function: CmCustomHangUp
  1562. //
  1563. // Synopsis: Our CM specific variation on RasCustomHangUp. Optionally, the entry
  1564. // name may be given instead of the RAS handle.
  1565. //
  1566. // Arguments: HRASCONN hRasConn - The handle of the connection to be terminated.
  1567. // LPCTSTR pszEntry - Ptr to the name of the entry to be terminated.
  1568. // BOLL fPersist - Preserve the entry and its usage count.
  1569. //
  1570. // Returns: DWORD WINAPI - Return code
  1571. //
  1572. //+----------------------------------------------------------------------------
  1573. extern "C" DWORD WINAPI CmCustomHangUp(HRASCONN hRasConn,
  1574. LPCTSTR pszEntry,
  1575. BOOL fIgnoreRefCount,
  1576. BOOL fPersist)
  1577. {
  1578. CMTRACE(TEXT("CmCustomHangUp"));
  1579. MYDBGASSERT(hRasConn || (pszEntry && pszEntry[0]));
  1580. DWORD dwRes = ERROR_SUCCESS;
  1581. //
  1582. // Must have a handle or an entry name
  1583. //
  1584. if (NULL == hRasConn && (NULL == pszEntry || 0 == pszEntry[0]))
  1585. {
  1586. return ERROR_INVALID_PARAMETER;
  1587. }
  1588. //
  1589. // First try to open the table, if none found then succeed.
  1590. //
  1591. CConnectionTable ConnTable;
  1592. if (FAILED(ConnTable.Open()))
  1593. {
  1594. return ERROR_NOT_FOUND;
  1595. }
  1596. //
  1597. // Look up the specified entry
  1598. //
  1599. HRESULT hrRes;
  1600. CM_CONNECTION Connection;
  1601. ZeroMemory(&Connection, sizeof(CM_CONNECTION));
  1602. if (hRasConn)
  1603. {
  1604. hrRes = ConnTable.GetEntry(hRasConn, &Connection);
  1605. }
  1606. else
  1607. {
  1608. hrRes = ConnTable.GetEntry(pszEntry, &Connection);
  1609. }
  1610. //
  1611. // We have an entry, do the Disconnect
  1612. //
  1613. if (SUCCEEDED(hrRes))
  1614. {
  1615. if (CM_CONNECTING == Connection.CmState)
  1616. {
  1617. dwRes = ERROR_NOT_FOUND;
  1618. }
  1619. else
  1620. {
  1621. //
  1622. // If the persist flag is not set and the caller is from the desktop
  1623. // then ignore the ref count and do a complete hangup.
  1624. //
  1625. // BOOL fIgnoreRefCount = ((!fPersist) && WhoIsCaller(DT_CMMON | DT_EXPLORER));
  1626. dwRes = Disconnect(&ConnTable, &Connection, fIgnoreRefCount, fPersist);
  1627. }
  1628. }
  1629. MYVERIFY(SUCCEEDED(ConnTable.Close()));
  1630. return dwRes;
  1631. }