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.

369 lines
9.1 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. return(IsOS(OS_TERMINALSERVER) ? S_OK : S_FALSE);
  32. }
  33. //
  34. // Returns:
  35. // S_OK == Yes, multiple users allowed.
  36. // S_FALSE == No, multiple users not allowed.
  37. // other == Failure.
  38. //
  39. HRESULT
  40. TS_MultipleUsersAllowed(
  41. void
  42. )
  43. {
  44. HRESULT hr = S_FALSE;
  45. if (IsOS(OS_ANYSERVER))
  46. {
  47. //
  48. // Assume "multiple users allowed" on all server SKUs.
  49. // This is per the Terminal Server team (MakarP).
  50. //
  51. hr = S_OK;
  52. }
  53. else if (IsOS(OS_FASTUSERSWITCHING))
  54. {
  55. hr = S_OK;
  56. }
  57. return hr;
  58. }
  59. //
  60. // Returns:
  61. // S_OK == Yes, terminal server connections are allowed.
  62. // S_FALSE == Now, TS connections are not allowed.
  63. // other == Failure.
  64. //
  65. HRESULT
  66. TS_ConnectionsAllowed(
  67. void
  68. )
  69. {
  70. HRESULT hr = E_FAIL;
  71. HMODULE hmodRegAPI = LoadLibrary(TEXT("RegApi.dll"));
  72. if (NULL != hmodRegAPI)
  73. {
  74. typedef BOOLEAN (*PFDenyConnectionPolicy)(void);
  75. PFDenyConnectionPolicy pfnDenyConnectionPolicy;
  76. pfnDenyConnectionPolicy = (PFDenyConnectionPolicy) GetProcAddress(hmodRegAPI, "RegDenyTSConnectionsPolicy");
  77. if (NULL != pfnDenyConnectionPolicy)
  78. {
  79. //
  80. // This function returns FALSE if connections are allowed.
  81. //
  82. if (!(*pfnDenyConnectionPolicy)())
  83. {
  84. hr = S_OK;
  85. }
  86. else
  87. {
  88. hr = S_FALSE;
  89. }
  90. }
  91. FreeLibrary(hmodRegAPI);
  92. }
  93. return hr;
  94. }
  95. //
  96. // Returns:
  97. // E_FAIL on failure of WTS APIs.
  98. // S_OK otherwise.
  99. //
  100. HRESULT
  101. TS_ActiveSessionCount(
  102. DWORD *pcSessions
  103. )
  104. {
  105. HRESULT hr = E_FAIL;
  106. DWORD dwActiveSessionCount = 0;
  107. // Open a connection to terminal services and get the number of sessions.
  108. HANDLE hServer = WinStationOpenServerW(reinterpret_cast<WCHAR*>(SERVERNAME_CURRENT));
  109. if (hServer != NULL)
  110. {
  111. TS_COUNTER tsCounters[2] = {0};
  112. tsCounters[0].counterHead.dwCounterID = TERMSRV_CURRENT_DISC_SESSIONS;
  113. tsCounters[1].counterHead.dwCounterID = TERMSRV_CURRENT_ACTIVE_SESSIONS;
  114. if (WinStationGetTermSrvCountersValue(hServer, ARRAYSIZE(tsCounters), tsCounters))
  115. {
  116. int i;
  117. hr = S_OK;
  118. for (i = 0; i < ARRAYSIZE(tsCounters); i++)
  119. {
  120. if (tsCounters[i].counterHead.bResult)
  121. {
  122. dwActiveSessionCount += tsCounters[i].dwValue;
  123. }
  124. }
  125. }
  126. WinStationCloseServer(hServer);
  127. }
  128. if (NULL != pcSessions)
  129. {
  130. *pcSessions = dwActiveSessionCount;
  131. }
  132. return hr;
  133. }
  134. //
  135. // Returns:
  136. // S_OK == Yes, there are 2+ active sessions.
  137. // S_FALSE == No, there are 1 or less active sessions.
  138. // other == Failure.
  139. //
  140. HRESULT
  141. TS_MultipleSessions(
  142. void
  143. )
  144. {
  145. DWORD cSessions;
  146. HRESULT hr = TS_ActiveSessionCount(&cSessions);
  147. if (SUCCEEDED(hr))
  148. {
  149. hr = (1 < cSessions) ? S_OK : S_FALSE;
  150. }
  151. return hr;
  152. }
  153. //
  154. // Request ownership of the global "configuring Terminal Server" mutex.
  155. // This is a well-known mutex defined by the terminal server group.
  156. // There are currently 3 scenarios that claim ownership of the mutex.
  157. //
  158. // 1. Terminal Server configuration UI.
  159. // 2. The TS_IsTerminalServerCompatibleWithCSC API (below).
  160. // 3. The Offline Files property page when the user has hit 'Apply'
  161. // and the user is enabling CSC.
  162. //
  163. // If the function succeeds, the caller is responsible for closing the
  164. // mutex handle returned in *phMutex.
  165. //
  166. HRESULT
  167. TS_RequestConfigMutex(
  168. HANDLE *phMutex,
  169. DWORD dwTimeoutMs
  170. )
  171. {
  172. HANDLE hMutex = CreateMutex(NULL, TRUE, c_szTSConfigMutex);
  173. if (NULL != hMutex)
  174. {
  175. if (ERROR_ALREADY_EXISTS == GetLastError())
  176. {
  177. if (WAIT_OBJECT_0 != WaitForSingleObject(hMutex, dwTimeoutMs))
  178. {
  179. CloseHandle(hMutex);
  180. hMutex = NULL;
  181. }
  182. }
  183. *phMutex = hMutex;
  184. }
  185. return NULL != hMutex ? S_OK : E_FAIL;
  186. }
  187. //
  188. // Returns a text string associated with a particular TS mode explaining
  189. // that mode and why CSC is incompatible with it.
  190. // The caller is responsible for freeing the returned buffer with
  191. // LocalFree().
  192. //
  193. HRESULT
  194. TS_GetIncompatibilityReasonText(
  195. DWORD dwTsMode,
  196. LPTSTR *ppszText
  197. )
  198. {
  199. TraceAssert(CSCTSF_COUNT > dwTsMode);
  200. TraceAssert(NULL != ppszText);
  201. HRESULT hr = S_OK;
  202. UINT idsText = IDS_TS_UNKNOWN;
  203. *ppszText = NULL;
  204. //
  205. // Map of TS mode to string resource ID.
  206. //
  207. static const struct
  208. {
  209. DWORD dwTsMode;
  210. UINT idsText;
  211. } rgMap[] = {
  212. { CSCTSF_UNKNOWN, IDS_TS_UNKNOWN },
  213. { CSCTSF_APP_SERVER, IDS_TS_APP_SERVER },
  214. { CSCTSF_MULTI_CNX, IDS_TS_MULTI_CNX },
  215. { CSCTSF_REMOTE_CNX, IDS_TS_REMOTE_CNX },
  216. { CSCTSF_FUS_ENABLED, IDS_TS_FUS_ENABLED }
  217. };
  218. for (int iMode = 0; iMode < ARRAYSIZE(rgMap); iMode++)
  219. {
  220. if (rgMap[iMode].dwTsMode == dwTsMode)
  221. {
  222. idsText = rgMap[iMode].idsText;
  223. break;
  224. }
  225. }
  226. //
  227. // Load and display the text explaining what the user needs
  228. // to do to enable CSC.
  229. //
  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. }