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.

540 lines
15 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: disconn.cpp
  4. //
  5. // Module: CMDIAL32.DLL
  6. //
  7. // Synopsis: The main code path for terminating a connection.
  8. //
  9. // Copyright (c) 1998-1999 Microsoft Corporation
  10. //
  11. // Author: nickball Created 2/10/98
  12. //
  13. //+----------------------------------------------------------------------------
  14. #include "cmmaster.h"
  15. #include "actlist.h"
  16. #include "tunl_str.h"
  17. #include "conact_str.h"
  18. // The following block is copied from wtsapi32.h (we compile with
  19. // _WIN32_WINNT set to less than 5.01, so we can't get these values via a #include)
  20. //
  21. #include "WtsApi32.h"
  22. #define WTS_CONSOLE_CONNECT 0x1
  23. #define WTS_CONSOLE_DISCONNECT 0x2
  24. #define WTS_REMOTE_CONNECT 0x3
  25. #define WTS_REMOTE_DISCONNECT 0x4
  26. #define WTS_SESSION_LOGON 0x5
  27. #define WTS_SESSION_LOGOFF 0x6
  28. #define WTS_SESSION_LOCK 0x7
  29. #define WTS_SESSION_UNLOCK 0x8
  30. //+----------------------------------------------------------------------------
  31. //
  32. // Function: InFastUserSwitch
  33. //
  34. // Synopsis: Are we in a Fast User switch
  35. //
  36. // Argsuments: None
  37. //
  38. // Return: BOOL (TRUE if yes, FALSE if not)
  39. //
  40. // History: 18-Jul-2001 SumitC Created
  41. //
  42. //-----------------------------------------------------------------------------
  43. BOOL
  44. InFastUserSwitch()
  45. {
  46. BOOL fReturn = FALSE;
  47. if (OS_NT51)
  48. {
  49. HINSTANCE hInstLib = LoadLibraryExU(TEXT("WTSAPI32.DLL"), NULL, 0);
  50. if (hInstLib)
  51. {
  52. typedef BOOL (WINAPI *pfnWTSQuerySessionInformationW_TYPE) (HANDLE, DWORD, WTS_INFO_CLASS, LPWSTR*, DWORD*);
  53. typedef VOID (WINAPI *pfnWTSFreeMemory_TYPE) (PVOID);
  54. pfnWTSQuerySessionInformationW_TYPE pfnWTSQuerySessionInformationW;
  55. pfnWTSFreeMemory_TYPE pfnWTSFreeMemory;
  56. pfnWTSQuerySessionInformationW = (pfnWTSQuerySessionInformationW_TYPE) GetProcAddress(hInstLib, "WTSQuerySessionInformationW");
  57. pfnWTSFreeMemory = (pfnWTSFreeMemory_TYPE) GetProcAddress(hInstLib, "WTSFreeMemory");
  58. if (pfnWTSQuerySessionInformationW && pfnWTSFreeMemory)
  59. {
  60. DWORD cb;
  61. WTS_CONNECTSTATE_CLASS * pConnectState = NULL;
  62. CMTRACE(TEXT("Querying to see if we're in a FUS"));
  63. if (pfnWTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE,
  64. WTS_CURRENT_SESSION,
  65. WTSConnectState,
  66. (LPTSTR *)&pConnectState,
  67. &cb))
  68. {
  69. CMTRACE1(TEXT("Querying to see if we're in a FUS - succeeded, connstate is %d"), *pConnectState);
  70. if (WTSDisconnected == *pConnectState)
  71. {
  72. fReturn = TRUE;
  73. CMTRACE(TEXT("Querying to see if we're in a FUS - yes we are."));
  74. }
  75. pfnWTSFreeMemory(pConnectState);
  76. }
  77. }
  78. FreeLibrary(hInstLib);
  79. }
  80. }
  81. return fReturn;
  82. }
  83. //+----------------------------------------------------------------------------
  84. //
  85. // Function: CleanupDisconnect
  86. //
  87. // Synopsis: Helper function encapsulating release of resource allocated duri
  88. // ng disconnect.
  89. //
  90. // Arguments: ArgsStruct *pArgs - Ptr to global Args struct
  91. //
  92. // Returns: Nothing
  93. //
  94. // History: nickball Created 8/14/98
  95. //
  96. //+----------------------------------------------------------------------------
  97. void CleanupDisconnect(ArgsStruct *pArgs)
  98. {
  99. MYDBGASSERT(pArgs);
  100. if (NULL == pArgs)
  101. {
  102. return;
  103. }
  104. UnlinkFromRas(&pArgs->rlsRasLink);
  105. ReleaseIniObjects(pArgs);
  106. if (pArgs->pszRasPbk)
  107. {
  108. CmFree(pArgs->pszRasPbk);
  109. pArgs->pszRasPbk = NULL;
  110. }
  111. if (pArgs->pszCurrentAccessPoint)
  112. {
  113. CmFree(pArgs->pszCurrentAccessPoint);
  114. pArgs->pszCurrentAccessPoint = NULL;
  115. }
  116. if (pArgs->pszRasHiddenPbk)
  117. {
  118. CmFree(pArgs->pszRasHiddenPbk);
  119. pArgs->pszRasHiddenPbk = NULL;
  120. }
  121. if (pArgs->pszVpnFile)
  122. {
  123. CmFree(pArgs->pszVpnFile);
  124. pArgs->pszVpnFile = NULL;
  125. }
  126. CmFree(pArgs);
  127. }
  128. //+----------------------------------------------------------------------------
  129. //
  130. // Function: HangupNotifyCmMon
  131. //
  132. // Synopsis: Sends a hangup message to CmMon via WM_COPYDATA
  133. //
  134. // Arguments: CConnectionTable *pConnTable - Ptr to the Connection table.
  135. // LPCTSTR pszEntry - The name of the entry.
  136. //
  137. // Returns: DWORD - Failure code
  138. //
  139. // History: nickball Created 2/11/98
  140. //
  141. //+----------------------------------------------------------------------------
  142. DWORD HangupNotifyCmMon(CConnectionTable *pConnTable,
  143. LPCTSTR pszEntry)
  144. {
  145. MYDBGASSERT(pConnTable);
  146. MYDBGASSERT(pszEntry);
  147. if (NULL == pConnTable || NULL == pszEntry || 0 == pszEntry[0])
  148. {
  149. return ERROR_INVALID_PARAMETER;
  150. }
  151. //
  152. // Update CMMON if present
  153. //
  154. HWND hwndMon;
  155. if (SUCCEEDED(pConnTable->GetMonitorWnd(&hwndMon)) && IsWindow(hwndMon))
  156. {
  157. CMTRACE1(TEXT("HangupNotifyCmMon() - Notifying CMMON that we are disconnecting %s"), pszEntry);
  158. //
  159. // Stash the entry name in HangupInfo
  160. //
  161. CM_HANGUP_INFO HangupInfo;
  162. lstrcpyU(HangupInfo.szEntryName, pszEntry);
  163. //
  164. // Send Hangup info to CMMON via COPYDATA
  165. //
  166. COPYDATASTRUCT CopyData;
  167. CopyData.dwData = CMMON_HANGUP_INFO;
  168. CopyData.cbData = sizeof(CM_HANGUP_INFO);
  169. CopyData.lpData = (PVOID) &HangupInfo;
  170. SendMessageU(hwndMon, WM_COPYDATA, NULL, (LPARAM) &CopyData);
  171. }
  172. #ifdef DEBUG
  173. if (!hwndMon)
  174. {
  175. CMTRACE(TEXT("HangupNotifyCmMon() - CMMON hwnd is NULL"));
  176. }
  177. #endif
  178. return ERROR_SUCCESS;
  179. }
  180. //+----------------------------------------------------------------------------
  181. //
  182. // Function: DoDisconnect
  183. //
  184. // Synopsis: Encapulates initialization of pArgs with profile, service, etc.
  185. // Runs disconnect actions and terminates the connection.
  186. //
  187. // Arguments: LPCM_CONNECTION pConnection - Ptr to a CM_CONNECTION struct containing
  188. // connection info such as entry name and RAS handles.
  189. // BOOL fActions - Flag indicating that disconnect actions should be run
  190. //
  191. // Returns: DWORD - Failure code
  192. //
  193. // History: nickball Created Header 2/12/98
  194. //
  195. //+----------------------------------------------------------------------------
  196. DWORD DoDisconnect(LPCM_CONNECTION pConnection, BOOL fActions)
  197. {
  198. MYDBGASSERT(pConnection);
  199. if (NULL == pConnection)
  200. {
  201. return ERROR_INVALID_PARAMETER;
  202. }
  203. //
  204. // Allocate and initialize pArgs
  205. //
  206. ArgsStruct* pArgs = (ArgsStruct*) CmMalloc(sizeof(ArgsStruct));
  207. if (NULL == pArgs)
  208. {
  209. return ERROR_ALLOCATING_MEMORY;
  210. }
  211. //
  212. // Clear and init global args struct
  213. //
  214. HRESULT hrRet = InitArgsForDisconnect(pArgs, pConnection->fAllUser);
  215. if (FAILED(hrRet))
  216. {
  217. return HRESULT_CODE(hrRet);
  218. }
  219. //
  220. // Initialize the profile
  221. //
  222. hrRet = InitProfile(pArgs, pConnection->szEntry);
  223. if (FAILED(hrRet))
  224. {
  225. return HRESULT_CODE(hrRet);
  226. }
  227. //
  228. // Do we want tunneling? If this was a tunnel connection, then the connection table
  229. // will have a non-NULL value for the hTunnel field of that connection entry.
  230. //
  231. pArgs->fTunnelPrimary = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryTunnelPrimary);
  232. pArgs->fTunnelReferences = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryTunnelReferences);
  233. pArgs->fUseTunneling = pConnection->hTunnel ? TRUE : FALSE;
  234. //
  235. // Determine our connect type
  236. //
  237. GetConnectType(pArgs);
  238. //
  239. // Initialize the path to the phonebook if this is NT5 so that disconnect
  240. // actions can use it if they want to. Note that the temporary phonebook
  241. // has already been deleted at this point so we will return NULL so that
  242. // it doesn't confuse the disconnect actions.
  243. //
  244. if (OS_NT5)
  245. {
  246. pArgs->pszRasPbk = GetRasPbkFromNT5ProfilePath(pArgs->piniProfile->GetFile());
  247. }
  248. //
  249. // Initialize logging and log the disconnect event.
  250. //
  251. (VOID) InitLogging(pArgs, pConnection->szEntry, FALSE); // FALSE => no banner
  252. // ignore return value
  253. TCHAR szTmp[MAX_PATH];
  254. MYVERIFY(GetModuleFileNameU(NULL, szTmp, MAX_PATH));
  255. pArgs->Log.Log(DISCONNECT_EVENT, szTmp);
  256. //
  257. // If we are in a Fast User Switch, set the flag so that we can skip customactions
  258. // that might block the disconnect (by bringing up UI etc)
  259. //
  260. pArgs->fInFastUserSwitch = InFastUserSwitch();
  261. //
  262. // If we are connected, run Disconnect Actions before we actually terminate
  263. //
  264. if (fActions)
  265. {
  266. CActionList DisconnectActList;
  267. DisconnectActList.Append(pArgs->piniService, c_pszCmSectionOnDisconnect);
  268. DisconnectActList.RunAccordType(NULL, pArgs, FALSE);
  269. }
  270. //
  271. // Initialize Data and links for Hangup
  272. //
  273. if (FALSE == LinkToRas(&pArgs->rlsRasLink))
  274. {
  275. MYDBGASSERT(FALSE);
  276. return ERROR_NOT_READY;
  277. }
  278. //
  279. // Linkage is good, hangup
  280. //
  281. if (pArgs->rlsRasLink.pfnHangUp)
  282. {
  283. //
  284. // Test the connection status of each connection handle. If not
  285. // connected, then there is no reason for us to call Hangup
  286. //
  287. RASCONNSTATUS rcs;
  288. if (pConnection->hTunnel)
  289. {
  290. ZeroMemory(&rcs,sizeof(rcs));
  291. rcs.dwSize = sizeof(rcs);
  292. if (ERROR_SUCCESS == pArgs->rlsRasLink.pfnGetConnectStatus(pConnection->hTunnel,&rcs) &&
  293. rcs.rasconnstate == RASCS_Connected)
  294. {
  295. if (IsLogonAsSystem())
  296. {
  297. //
  298. // Don't want to bring up any UI
  299. //
  300. DoRasHangup(&pArgs->rlsRasLink, pConnection->hTunnel);
  301. }
  302. else
  303. {
  304. MYVERIFY(ERROR_SUCCESS == DoRasHangup(&pArgs->rlsRasLink, pConnection->hTunnel));
  305. }
  306. }
  307. }
  308. if (pConnection->hDial)
  309. {
  310. ZeroMemory(&rcs,sizeof(rcs));
  311. rcs.dwSize = sizeof(rcs);
  312. if (ERROR_SUCCESS == pArgs->rlsRasLink.pfnGetConnectStatus(pConnection->hDial,&rcs) &&
  313. rcs.rasconnstate == RASCS_Connected)
  314. {
  315. if (IsLogonAsSystem())
  316. {
  317. //
  318. // Don't want to bring up any UI
  319. //
  320. DoRasHangup(&pArgs->rlsRasLink, pConnection->hDial);
  321. }
  322. else
  323. {
  324. DWORD dwRet = DoRasHangup(&pArgs->rlsRasLink, pConnection->hDial);
  325. if (ERROR_SUCCESS != dwRet)
  326. {
  327. CMTRACE1(TEXT("DoDisconnect: DoRasHangup failed with error code with %d"), dwRet);
  328. }
  329. }
  330. }
  331. }
  332. }
  333. //
  334. // Un-initialize logging
  335. //
  336. (VOID) pArgs->Log.DeInit();
  337. // ignore return value
  338. //
  339. // Cleanup linkage and memory
  340. //
  341. CleanupDisconnect(pArgs);
  342. return ERROR_SUCCESS;
  343. }
  344. //+----------------------------------------------------------------------------
  345. //
  346. // Function: Disconnect
  347. //
  348. // Synopsis: Disconnects the connection with the name pszEntry.
  349. //
  350. // Arguments: CConnectionTable *pConnTable - Ptr to connection table
  351. // LPCM_CONNECTION pConnection - The current table data for the entry.
  352. // BOOL fIgnoreRefCount - Flag to override ref count
  353. // BOOL fPersist - Flag indicating that entry should be persistent
  354. //
  355. // Returns: DWORD - Failure code
  356. //
  357. // History: nickball Created 2/11/98
  358. //
  359. //+----------------------------------------------------------------------------
  360. DWORD Disconnect(CConnectionTable *pConnTable, LPCM_CONNECTION pConnection, BOOL fIgnoreRefCount, BOOL fPersist)
  361. {
  362. MYDBGASSERT(pConnection);
  363. MYDBGASSERT(pConnTable);
  364. CMTRACE(TEXT("Disconnect()"));
  365. #ifdef DEBUG
  366. IsLogonAsSystem(); // Traces user name
  367. #endif
  368. if (NULL == pConnection || NULL == pConnTable)
  369. {
  370. return ERROR_INVALID_PARAMETER;
  371. }
  372. // MYDBGASSERT(!(fIgnoreRefCount && fPersist)); // mutually exclusive flags
  373. MYDBGASSERT(CM_CONNECTING != pConnection->CmState);
  374. if (!fIgnoreRefCount)
  375. {
  376. //
  377. // The hangup is not forced, check usage
  378. //
  379. if (pConnection->dwUsage > 1)
  380. {
  381. //
  382. // As long as fPersist is false, adjust the usage count
  383. //
  384. if (!fPersist)
  385. {
  386. pConnTable->RemoveEntry(pConnection->szEntry);
  387. }
  388. return ERROR_SUCCESS;
  389. }
  390. else
  391. {
  392. //
  393. // If we are already disconnecting, just succeed
  394. //
  395. if (CM_DISCONNECTING == pConnection->CmState)
  396. {
  397. return ERROR_SUCCESS;
  398. }
  399. }
  400. }
  401. //
  402. // Looks like we are comitted to getting to a usage of zero, tell CMMON
  403. // to stop monitoring this connection unless we are in persist state.
  404. //
  405. if (!fPersist)
  406. {
  407. HangupNotifyCmMon(pConnTable, pConnection->szEntry);
  408. }
  409. LRESULT lRes = ERROR_SUCCESS;
  410. //
  411. // Usage is down <= 1, or being ignored. If we are in reconnect prompt
  412. // state, then there is nothing to disconnect so don't call hangup.
  413. //
  414. if (CM_RECONNECTPROMPT != pConnection->CmState)
  415. {
  416. //
  417. // We are committed to a real disconnect, so set the entry
  418. // to the disconnecting state while we hangup.
  419. //
  420. BOOL fActions = (CM_CONNECTED == pConnection->CmState);
  421. pConnTable->SetDisconnecting(pConnection->szEntry);
  422. lRes = DoDisconnect(pConnection, fActions);
  423. //
  424. // If persisting, just set the state to reconnect prompt
  425. //
  426. if (fPersist)
  427. {
  428. //
  429. // Set entry to limbo state of reconnect prompt
  430. //
  431. pConnTable->SetPrompting(pConnection->szEntry);
  432. return (DWORD)lRes;
  433. }
  434. }
  435. //
  436. // If forced connect, removed entry completely
  437. //
  438. if (fIgnoreRefCount)
  439. {
  440. pConnTable->ClearEntry(pConnection->szEntry);
  441. }
  442. else
  443. {
  444. pConnTable->RemoveEntry(pConnection->szEntry);
  445. }
  446. return (DWORD)lRes;
  447. }