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.

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