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.

372 lines
8.9 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: termserv.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #pragma hdrstop
  12. #include <winsta.h> // WinStationGetTermSrvCountersValue
  13. #include <allproc.h> // TS_COUNTER
  14. #include "termserv.h"
  15. #include "strings.h"
  16. HRESULT TS_AppServer(void);
  17. HRESULT TS_MultipleUsersAllowed(void);
  18. HRESULT TS_ConnectionsAllowed(void);
  19. HRESULT TS_ActiveSessionCount(DWORD *pcSessions);
  20. HRESULT TS_MultipleSessions(void);
  21. //
  22. // Returns:
  23. // S_OK == Yes, is App Server.
  24. // S_FALSE == No, is not app server.
  25. //
  26. HRESULT
  27. TS_AppServer(
  28. void
  29. )
  30. {
  31. HRESULT hr = S_FALSE;
  32. OSVERSIONINFOEX osVersion;
  33. ZeroMemory(&osVersion, sizeof(OSVERSIONINFOEX));
  34. osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  35. if (GetVersionEx((LPOSVERSIONINFO)&osVersion))
  36. {
  37. if ((osVersion.wSuiteMask & VER_SUITE_TERMINAL) &&
  38. !(osVersion.wSuiteMask & VER_SUITE_SINGLEUSERTS))
  39. {
  40. hr = S_OK;
  41. }
  42. }
  43. return hr;
  44. }
  45. //
  46. // Returns:
  47. // S_OK == Yes, multiple users allowed.
  48. // S_FALSE == No, multiple users not allowed.
  49. // other == Failure.
  50. //
  51. HRESULT
  52. TS_MultipleUsersAllowed(
  53. void
  54. )
  55. {
  56. return(IsOS(OS_FASTUSERSWITCHING) ? S_OK : S_FALSE);
  57. }
  58. //
  59. // Returns:
  60. // S_OK == Yes, terminal server connections are allowed.
  61. // S_FALSE == Now, TS connections are not allowed.
  62. // other == Failure.
  63. //
  64. HRESULT
  65. TS_ConnectionsAllowed(
  66. void
  67. )
  68. {
  69. HRESULT hr = E_FAIL;
  70. HMODULE hmodRegAPI = LoadLibrary(TEXT("RegApi.dll"));
  71. if (NULL != hmodRegAPI)
  72. {
  73. typedef BOOLEAN (*PFDenyConnectionPolicy)(void);
  74. PFDenyConnectionPolicy pfnDenyConnectionPolicy;
  75. pfnDenyConnectionPolicy = (PFDenyConnectionPolicy) GetProcAddress(hmodRegAPI, "RegDenyTSConnectionsPolicy");
  76. if (NULL != pfnDenyConnectionPolicy)
  77. {
  78. //
  79. // This function returns FALSE if connections are allowed.
  80. //
  81. if (!(*pfnDenyConnectionPolicy)())
  82. {
  83. hr = S_OK;
  84. }
  85. else
  86. {
  87. hr = S_FALSE;
  88. }
  89. }
  90. FreeLibrary(hmodRegAPI);
  91. }
  92. return hr;
  93. }
  94. //
  95. // Returns:
  96. // E_FAIL on failure of WTS APIs.
  97. // S_OK otherwise.
  98. //
  99. HRESULT
  100. TS_ActiveSessionCount(
  101. DWORD *pcSessions
  102. )
  103. {
  104. HRESULT hr = E_FAIL;
  105. DWORD dwActiveSessionCount = 0;
  106. // Open a connection to terminal services and get the number of sessions.
  107. HANDLE hServer = WinStationOpenServerW(reinterpret_cast<WCHAR*>(SERVERNAME_CURRENT));
  108. if (hServer != NULL)
  109. {
  110. TS_COUNTER tsCounters[2] = {0};
  111. tsCounters[0].counterHead.dwCounterID = TERMSRV_CURRENT_DISC_SESSIONS;
  112. tsCounters[1].counterHead.dwCounterID = TERMSRV_CURRENT_ACTIVE_SESSIONS;
  113. if (WinStationGetTermSrvCountersValue(hServer, ARRAYSIZE(tsCounters), tsCounters))
  114. {
  115. int i;
  116. hr = S_OK;
  117. for (i = 0; i < ARRAYSIZE(tsCounters); i++)
  118. {
  119. if (tsCounters[i].counterHead.bResult)
  120. {
  121. dwActiveSessionCount += tsCounters[i].dwValue;
  122. }
  123. }
  124. }
  125. WinStationCloseServer(hServer);
  126. }
  127. if (NULL != pcSessions)
  128. {
  129. *pcSessions = dwActiveSessionCount;
  130. }
  131. return hr;
  132. }
  133. //
  134. // Returns:
  135. // S_OK == Yes, there are 2+ active sessions.
  136. // S_FALSE == No, there are 1 or less active sessions.
  137. // other == Failure.
  138. //
  139. HRESULT
  140. TS_MultipleSessions(
  141. void
  142. )
  143. {
  144. DWORD cSessions;
  145. HRESULT hr = TS_ActiveSessionCount(&cSessions);
  146. if (SUCCEEDED(hr))
  147. {
  148. hr = (1 < cSessions) ? S_OK : S_FALSE;
  149. }
  150. return hr;
  151. }
  152. //
  153. // Request ownership of the global "configuring Terminal Server" mutex.
  154. // This is a well-known mutex defined by the terminal server group.
  155. // There are currently 3 scenarios that claim ownership of the mutex.
  156. //
  157. // 1. Terminal Server configuration UI.
  158. // 2. The TS_IsTerminalServerCompatibleWithCSC API (below).
  159. // 3. The Offline Files property page when the user has hit 'Apply'
  160. // and the user is enabling CSC.
  161. //
  162. // If the function succeeds, the caller is responsible for closing the
  163. // mutex handle returned in *phMutex.
  164. //
  165. HRESULT
  166. TS_RequestConfigMutex(
  167. HANDLE *phMutex,
  168. DWORD dwTimeoutMs
  169. )
  170. {
  171. HANDLE hMutex = CreateMutex(NULL, TRUE, c_szTSConfigMutex);
  172. if (NULL != hMutex)
  173. {
  174. if (ERROR_ALREADY_EXISTS == GetLastError())
  175. {
  176. if (WAIT_OBJECT_0 != WaitForSingleObject(hMutex, dwTimeoutMs))
  177. {
  178. CloseHandle(hMutex);
  179. hMutex = NULL;
  180. }
  181. }
  182. *phMutex = hMutex;
  183. }
  184. return NULL != hMutex ? S_OK : E_FAIL;
  185. }
  186. //
  187. // Returns a text string associated with a particular TS mode explaining
  188. // that mode and why CSC is incompatible with it.
  189. // The caller is responsible for freeing the returned buffer with
  190. // LocalFree().
  191. //
  192. HRESULT
  193. TS_GetIncompatibilityReasonText(
  194. DWORD dwTsMode,
  195. LPTSTR *ppszText
  196. )
  197. {
  198. TraceAssert(CSCTSF_COUNT > dwTsMode);
  199. TraceAssert(NULL != ppszText);
  200. HRESULT hr = S_OK;
  201. UINT idsText = IDS_TS_UNKNOWN;
  202. *ppszText = NULL;
  203. //
  204. // Map of TS mode to string resource ID.
  205. //
  206. static const struct
  207. {
  208. DWORD dwTsMode;
  209. UINT idsText;
  210. } rgMap[] = {
  211. { CSCTSF_UNKNOWN, IDS_TS_UNKNOWN },
  212. { CSCTSF_APP_SERVER, IDS_TS_APP_SERVER },
  213. { CSCTSF_MULTI_CNX, IDS_TS_MULTI_CNX },
  214. { CSCTSF_REMOTE_CNX, IDS_TS_REMOTE_CNX },
  215. { CSCTSF_FUS_ENABLED, IDS_TS_FUS_ENABLED }
  216. };
  217. for (int iMode = 0; iMode < ARRAYSIZE(rgMap); iMode++)
  218. {
  219. if (rgMap[iMode].dwTsMode == dwTsMode)
  220. {
  221. idsText = rgMap[iMode].idsText;
  222. break;
  223. }
  224. }
  225. //
  226. // Load and display the text explaining what the user needs
  227. // to do to enable CSC.
  228. //
  229. LPTSTR pszText;
  230. if (0 == LoadStringAlloc(ppszText, g_hInstance, idsText))
  231. {
  232. const DWORD dwErr = GetLastError();
  233. hr = HRESULT_FROM_WIN32(dwErr);
  234. }
  235. return hr;
  236. }
  237. //
  238. // Returns:
  239. // S_OK == OK to display CSC UI.
  240. // S_FALSE == Not OK to display CSC UI. Inspect *pdwTsMode for reason.
  241. // other == Failure. *pdwTsMode contains CSCTSF_UNKNOWN.
  242. //
  243. HRESULT
  244. CSCUIIsTerminalServerCompatibleWithCSC(
  245. DWORD *pdwTsMode
  246. )
  247. {
  248. TraceAssert(NULL != pdwTsMode);
  249. if (IsOS(OS_FRIENDLYLOGONUI) && IsOS(OS_FASTUSERSWITCHING))
  250. {
  251. *pdwTsMode = CSCTSF_FUS_ENABLED;
  252. return S_FALSE;
  253. }
  254. HANDLE hMutex;
  255. HRESULT hr = TS_RequestConfigMutex(&hMutex, 5000);
  256. if (SUCCEEDED(hr))
  257. {
  258. *pdwTsMode = CSCTSF_APP_SERVER;
  259. if (S_FALSE == (hr = TS_AppServer()))
  260. {
  261. //
  262. // Not app server.
  263. //
  264. if ((S_OK == (hr = TS_ConnectionsAllowed())))
  265. {
  266. //
  267. // Connections are allowed.
  268. // Check if multiple connections are allowed (like on TS servers)
  269. //
  270. if (S_OK == (hr = TS_MultipleUsersAllowed()))
  271. {
  272. //
  273. // There can be multiple users or TS connections.
  274. //
  275. *pdwTsMode = CSCTSF_MULTI_CNX;
  276. }
  277. else
  278. {
  279. //
  280. // Personal Terminal Server (only 1 active connection can be allowed)
  281. // OK to display CSC UI.
  282. //
  283. *pdwTsMode = CSCTSF_CSC_OK;
  284. CloseHandle(hMutex);
  285. return S_OK;
  286. }
  287. }
  288. else
  289. {
  290. //
  291. // TS connections are not allowed, but there could be existing active connecitons,
  292. // check if any exists.
  293. //
  294. if (S_OK == (hr = TS_MultipleSessions()))
  295. {
  296. *pdwTsMode = CSCTSF_REMOTE_CNX;
  297. }
  298. else
  299. {
  300. //
  301. // No active remote sessions,
  302. // OK to display CSC UI.
  303. //
  304. *pdwTsMode = CSCTSF_CSC_OK;
  305. CloseHandle(hMutex);
  306. return S_OK;
  307. }
  308. }
  309. }
  310. CloseHandle(hMutex);
  311. }
  312. if (FAILED(hr))
  313. {
  314. //
  315. // Something failed. We can't report any particular TS mode
  316. // with any confidence.
  317. //
  318. *pdwTsMode = CSCTSF_UNKNOWN;
  319. }
  320. //
  321. // Any S_OK return value was returned inline above.
  322. // At this point we want to return either S_FALSE or an error code.
  323. //
  324. return SUCCEEDED(hr) ? S_FALSE : hr;
  325. }