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.

472 lines
11 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000
  6. //
  7. // File: ausessions.cpp
  8. //
  9. // History: 10/19/2001 annah
  10. // transformed struct in class, added constructors
  11. // destructors, and also proctected write operations
  12. // with a critical session (on win2k the code can
  13. // have race conditions). Also moved some functions
  14. // from service.cpp to the class.
  15. //
  16. //--------------------------------------------------------------------------
  17. #include "pch.h"
  18. #include "tscompat.h"
  19. #include "service.h"
  20. #pragma hdrstop
  21. //SESSION_STATUS Functions
  22. SESSION_STATUS::SESSION_STATUS (void)
  23. {
  24. m_fInitCS = FALSE;
  25. }
  26. SESSION_STATUS::~SESSION_STATUS()
  27. {
  28. if (m_fInitCS)
  29. {
  30. DeleteCriticalSection(&m_csWrite);
  31. }
  32. }
  33. BOOL SESSION_STATUS::Initialize(BOOL fUseCriticalSection, BOOL fAllActiveUsers)
  34. {
  35. m_fAllActiveUsers = fAllActiveUsers;
  36. m_pSessionStateInfo = NULL;
  37. m_iLastSession = -1;
  38. m_cAllocBufSessions = 0;
  39. m_iCurSession = CDWNO_SESSION;
  40. //
  41. // The code will only execute concurrent paths on win2K
  42. // It won't be expensive to use th critical session
  43. // for all platforms, however
  44. //
  45. if (fUseCriticalSection)
  46. {
  47. if (!m_fInitCS)
  48. {
  49. m_fInitCS = SafeInitializeCriticalSection(&m_csWrite);
  50. }
  51. }
  52. else
  53. {
  54. AUASSERT(!m_fInitCS);
  55. }
  56. return (m_fInitCS == fUseCriticalSection);
  57. }
  58. void SESSION_STATUS::Clear(void)
  59. {
  60. if (NULL != m_pSessionStateInfo)
  61. {
  62. free(m_pSessionStateInfo);
  63. }
  64. }
  65. // Method used when we want to rebuild the array from scratch
  66. void SESSION_STATUS::m_EraseAll()
  67. {
  68. if (m_fInitCS)
  69. {
  70. EnterCriticalSection(&m_csWrite);
  71. }
  72. Clear();
  73. BOOL fRet = Initialize(m_fInitCS, m_fAllActiveUsers);
  74. AUASSERT(fRet);
  75. if (m_fInitCS)
  76. {
  77. LeaveCriticalSection(&m_csWrite);
  78. }
  79. }
  80. void SESSION_STATUS::RebuildSessionCache()
  81. {
  82. if (m_fInitCS)
  83. {
  84. EnterCriticalSection(&m_csWrite);
  85. }
  86. m_EraseAll();
  87. CacheExistingSessions();
  88. if (m_fInitCS)
  89. {
  90. LeaveCriticalSection(&m_csWrite);
  91. }
  92. }
  93. BOOL SESSION_STATUS::m_FAddSession(DWORD dwSessionId, SESSION_STATE *pSesState)
  94. {
  95. BOOL fRet = TRUE;
  96. if (m_fInitCS)
  97. {
  98. EnterCriticalSection(&m_csWrite);
  99. }
  100. //
  101. // Fix for bug 498256 -- annah
  102. // It can happen that a user logs in right when the service is starting, so
  103. // we would add the session though the TS enumeration code AND
  104. // then possibly again through the code that receives SCM logon notifications.
  105. // The fix will be to test if the session is already stored, and skip
  106. // adding entries that for session ids that are already there.
  107. //
  108. if (m_iFindSession(dwSessionId) != CDWNO_SESSION)
  109. {
  110. // do nothing -- don't add duplicate entries if the session id
  111. // is already there.
  112. fRet = FALSE;
  113. goto Done;
  114. }
  115. if (NULL == m_pSessionStateInfo || m_iLastSession >= m_cAllocBufSessions - 1)
  116. {
  117. int cSessions;
  118. if (m_cAllocBufSessions == 0)
  119. {
  120. cSessions = CMIN_SESSIONS;
  121. m_iCurSession = 0;
  122. }
  123. else
  124. {
  125. cSessions = m_cAllocBufSessions * 2;
  126. }
  127. if (!m_FChangeBufSession(cSessions))
  128. {
  129. fRet = FALSE;
  130. goto Done;
  131. }
  132. }
  133. m_iLastSession++;
  134. m_pSessionStateInfo[m_iLastSession].dwSessionId = dwSessionId;
  135. m_pSessionStateInfo[m_iLastSession].SessionState = *pSesState;
  136. Done:
  137. if (m_fInitCS)
  138. {
  139. LeaveCriticalSection(&m_csWrite);
  140. }
  141. #ifdef DBG
  142. DEBUGMSG("After AddSession");
  143. m_DumpSessions();
  144. #endif
  145. return fRet;
  146. }
  147. //determine whether or not session dwSessionId is a cached AU session
  148. BOOL SESSION_STATUS::m_FGetSessionState(DWORD dwSessionId, SESSION_STATE **pSesState )
  149. {
  150. int iSession = m_iFindSession(dwSessionId);
  151. BOOL fRet = (CDWNO_SESSION != iSession);
  152. if (fRet && (NULL != pSesState))
  153. {
  154. *pSesState = &m_pSessionStateInfo[iSession].SessionState;
  155. }
  156. return fRet;
  157. }
  158. BOOL SESSION_STATUS::m_FDeleteSession(DWORD dwSessionId)
  159. {
  160. BOOL fRet= FALSE;
  161. if (m_fInitCS)
  162. {
  163. EnterCriticalSection(&m_csWrite);
  164. }
  165. int iSession = m_iFindSession(dwSessionId);
  166. if (CDWNO_SESSION == iSession)
  167. {
  168. goto Done;
  169. }
  170. if (iSession != m_iLastSession)
  171. {
  172. memmove(m_pSessionStateInfo + iSession,
  173. m_pSessionStateInfo + iSession + 1,
  174. sizeof(SESSION_STATE_INFO) * (m_iLastSession - iSession));
  175. }
  176. if (m_iCurSession > iSession)
  177. {
  178. m_iCurSession--;
  179. }
  180. //fixcode m_iCurSession should point to the previous session
  181. if (m_iCurSession == m_iLastSession)
  182. {
  183. m_iCurSession = 0;
  184. }
  185. m_iLastSession--;
  186. fRet = TRUE;
  187. Done:
  188. if (m_fInitCS)
  189. {
  190. LeaveCriticalSection(&m_csWrite);
  191. }
  192. #ifdef DBG
  193. DEBUGMSG("After DeleteSession");
  194. m_DumpSessions();
  195. #endif
  196. return fRet;
  197. }
  198. BOOL SESSION_STATUS::m_FGetCurrentSession(DWORD *pdwSessionId)
  199. {
  200. if (0 == CSessions())
  201. {
  202. return FALSE;
  203. }
  204. *pdwSessionId = m_pSessionStateInfo[m_iCurSession].dwSessionId;
  205. return TRUE;
  206. }
  207. BOOL SESSION_STATUS::m_FGetNextSession(DWORD *pdwSessionId)
  208. {
  209. if (0 == CSessions())
  210. {
  211. return FALSE;
  212. }
  213. m_iCurSession = (m_iCurSession + 1 ) % CSessions();
  214. *pdwSessionId = m_pSessionStateInfo[m_iCurSession].dwSessionId;
  215. return TRUE;
  216. }
  217. int SESSION_STATUS::m_iFindSession(DWORD dwSessionId)
  218. {
  219. for (int iSession = 0; iSession < CSessions(); iSession++)
  220. {
  221. if (dwSessionId == m_pSessionStateInfo[iSession].dwSessionId)
  222. {
  223. return iSession;
  224. }
  225. }
  226. return CDWNO_SESSION;
  227. }
  228. // this functions lets someone traverse the content of
  229. // the array sequencially.
  230. int SESSION_STATUS::m_iGetSessionIdAtIndex(int iIndex)
  231. {
  232. if (iIndex < 0 || iIndex >= CSessions())
  233. {
  234. // Out of bound!!
  235. return -1;
  236. }
  237. return m_pSessionStateInfo[iIndex].dwSessionId;
  238. }
  239. BOOL SESSION_STATUS::m_FChangeBufSession(int cSessions)
  240. {
  241. BOOL fRet = FALSE;
  242. SESSION_STATE_INFO *pSessionStateInfo = (SESSION_STATE_INFO *)realloc(m_pSessionStateInfo, sizeof(SESSION_STATE_INFO) * cSessions);
  243. if (NULL != pSessionStateInfo)
  244. {
  245. m_pSessionStateInfo = pSessionStateInfo;
  246. }
  247. else
  248. {
  249. goto Done;
  250. }
  251. m_cAllocBufSessions = cSessions;
  252. fRet = TRUE;
  253. Done:
  254. return fRet;
  255. }
  256. // Function for debugging
  257. VOID SESSION_STATUS::m_DumpSessions()
  258. {
  259. DEBUGMSG(">>>>>>> DUMPING cached sessions content ");
  260. for (int iSession = 0; iSession < CSessions(); iSession++)
  261. {
  262. DEBUGMSG(">>> position %d: %lu", iSession, m_pSessionStateInfo[iSession].dwSessionId);
  263. }
  264. DEBUGMSG(">>>>>>> END DUMPING cached sessions content ");
  265. }
  266. /**
  267. CacheExistingSessions()
  268. Enumerates existent sessions and persists the admin sessions for future reference
  269. **/
  270. VOID SESSION_STATUS::CacheExistingSessions()
  271. {
  272. PWTS_SESSION_INFO pSessionInfo = NULL;
  273. DWORD dwCount = 0;
  274. //
  275. // Check if TS is enabled and try to enumerate existing
  276. // sessions. If TS is not running, query only session 0.
  277. //
  278. if (_IsTerminalServiceRunning())
  279. {
  280. if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount))
  281. {
  282. DEBUGMSG("WUAUENG WTSEnumerateSessions dwCount= %lu",dwCount);
  283. for (DWORD dwSession = 0; dwSession < dwCount; dwSession++)
  284. {
  285. WTS_SESSION_INFO SessionInfo = pSessionInfo[dwSession];
  286. DEBUGMSG("WUAUENG CacheExistingSessions, enumerating SessionId =%lu, State =%d",SessionInfo.SessionId, SessionInfo.State);
  287. if (m_fAllActiveUsers)
  288. {
  289. if (WTSActive != SessionInfo.State)
  290. {
  291. continue;
  292. }
  293. HANDLE hImpersonationToken;
  294. if (AUGetUserToken(SessionInfo.SessionId, &hImpersonationToken))
  295. {
  296. SESSION_STATE SessionState;
  297. SessionState.fFoundEnumerating = TRUE;
  298. m_FAddSession(SessionInfo.SessionId, &SessionState);
  299. CloseHandle(hImpersonationToken);
  300. }
  301. }
  302. else
  303. {
  304. if ((WTSActive != SessionInfo.State) && ( WTSConnected != SessionInfo.State) ||
  305. (m_iFindSession(SessionInfo.SessionId) != CDWNO_SESSION))
  306. {
  307. //We only care about Active and Connected sessions that existed before
  308. //the service was registered, this means that if fAdminSessionLoggedOn is turned on
  309. //the logon notification was received already and we must no check anything
  310. continue;
  311. }
  312. if (CacheSessionIfAUEnabledAdmin(SessionInfo.SessionId, TRUE))
  313. {
  314. DEBUGMSG("WUAUENG Existent Admin Session = %lu",SessionInfo.SessionId);
  315. }
  316. }
  317. }
  318. WTSFreeMemory(pSessionInfo);
  319. }
  320. else
  321. {
  322. DWORD dwRet = GetLastError();
  323. DEBUGMSG("WUAUENG WTSEnumerateSessions failed dwRet = %lu", dwRet);
  324. }
  325. }
  326. else
  327. {
  328. if (m_fAllActiveUsers)
  329. {
  330. HANDLE hImpersonationToken;
  331. if (AUGetUserToken(0, &hImpersonationToken))
  332. {
  333. SESSION_STATE SessionState;
  334. SessionState.fFoundEnumerating = TRUE;
  335. m_FAddSession(0, &SessionState);
  336. CloseHandle(hImpersonationToken);
  337. }
  338. }
  339. else
  340. {
  341. if (CacheSessionIfAUEnabledAdmin(0, TRUE)) //Check Session 0 because Terminal Services are disabled
  342. {
  343. DEBUGMSG("WUAUENG Existent Admin Session = %d",0);
  344. }
  345. }
  346. }
  347. #ifdef DBG
  348. DEBUGMSG("After CacheExistingSessions");
  349. m_DumpSessions();
  350. #endif
  351. }
  352. /**
  353. CacheSessionIfAUEnabledAdmin
  354. Cache session in internal data structure if session has administrator logged on and
  355. has AU group policy allowing update
  356. Also store this admin session's origin (logon notification or via Enumeration)
  357. **/
  358. BOOL SESSION_STATUS::CacheSessionIfAUEnabledAdmin(DWORD dwSessionId, BOOL fFoundEnumerating)
  359. {
  360. BOOL fRet = TRUE;
  361. if (IsUserAUEnabledAdmin(dwSessionId))
  362. {
  363. SESSION_STATE SessionState;
  364. SessionState.fFoundEnumerating = fFoundEnumerating;
  365. fRet = m_FAddSession(dwSessionId, &SessionState);
  366. }
  367. else
  368. {
  369. fRet = FALSE;
  370. }
  371. return fRet;
  372. }
  373. void SESSION_STATUS::ValidateCachedSessions()
  374. {
  375. DWORD *rgMarkedForDelete = NULL;
  376. int cSession = 0;
  377. int cMarkedForDelete = 0;
  378. //m_DumpSessions();
  379. cSession = CSessions();
  380. rgMarkedForDelete = new DWORD[cSession];
  381. if (!rgMarkedForDelete)
  382. {
  383. goto cleanup;
  384. }
  385. if (m_fInitCS)
  386. {
  387. EnterCriticalSection(&m_csWrite);
  388. }
  389. for (int i = 0; i < cSession; i++)
  390. {
  391. DWORD dwAdminSession = m_iGetSessionIdAtIndex(i);
  392. if (!IsAUValidSession(dwAdminSession))
  393. {
  394. // store the sessions id to be deleted and deleted after we exit the loop
  395. rgMarkedForDelete[cMarkedForDelete] = dwAdminSession;
  396. cMarkedForDelete++;
  397. }
  398. }
  399. // delete the pending sessions that are now invalid
  400. for (int i=0; i < cMarkedForDelete; i++)
  401. {
  402. DEBUGMSG("WUAUENG Found cached admin session that is not valid anymore. Deleting entry for session %lu", rgMarkedForDelete[i]);
  403. m_FDeleteSession(rgMarkedForDelete[i]);
  404. }
  405. if (m_fInitCS)
  406. {
  407. LeaveCriticalSection(&m_csWrite);
  408. }
  409. //m_DumpSessions();
  410. cleanup:
  411. if (rgMarkedForDelete)
  412. {
  413. delete [] rgMarkedForDelete;
  414. }
  415. }