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.

453 lines
14 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: LogonMutex.cpp
  3. //
  4. // Copyright (c) 2001, Microsoft Corporation
  5. //
  6. // File that implements a class that manages a single global logon mutex.
  7. //
  8. // History: 2001-04-06 vtan created
  9. // --------------------------------------------------------------------------
  10. #include "StandardHeader.h"
  11. #include "LogonMutex.h"
  12. #include <msginaexports.h>
  13. #include "Access.h"
  14. #include "SystemSettings.h"
  15. DWORD CLogonMutex::s_dwThreadID = 0;
  16. LONG CLogonMutex::s_lAcquireCount = 0;
  17. HANDLE CLogonMutex::s_hMutex = NULL;
  18. HANDLE CLogonMutex::s_hMutexRequest = NULL;
  19. HANDLE CLogonMutex::s_hEvent = NULL;
  20. const TCHAR CLogonMutex::s_szLogonMutexName[] = SZ_INTERACTIVE_LOGON_MUTEX_NAME;
  21. const TCHAR CLogonMutex::s_szLogonRequestMutexName[] = SZ_INTERACTIVE_LOGON_REQUEST_MUTEX_NAME;
  22. const TCHAR CLogonMutex::s_szLogonReplyEventName[] = SZ_INTERACTIVE_LOGON_REPLY_EVENT_NAME;
  23. const TCHAR CLogonMutex::s_szShutdownEventName[] = SZ_SHUT_DOWN_EVENT_NAME;
  24. SID_IDENTIFIER_AUTHORITY CLogonMutex::s_SecurityNTAuthority = SECURITY_NT_AUTHORITY;
  25. SID_IDENTIFIER_AUTHORITY CLogonMutex::s_SecurityWorldSID = SECURITY_WORLD_SID_AUTHORITY;
  26. // --------------------------------------------------------------------------
  27. // CLogonMutex::Acquire
  28. //
  29. // Arguments: <none>
  30. //
  31. // Returns: <none>
  32. //
  33. // Purpose: Acquires the mutex. Ensures that the mutex is only acquired
  34. // on the main thread of winlogon by an assert. The mutex should
  35. // never be abandoned within normal execution. However, a
  36. // process termination can cause this to happen.
  37. //
  38. // History: 2001-04-06 vtan created
  39. // --------------------------------------------------------------------------
  40. void CLogonMutex::Acquire (void)
  41. {
  42. DWORD dwWaitResult;
  43. ASSERTMSG((s_dwThreadID == 0) || (s_dwThreadID == GetCurrentThreadId()), "Must acquire mutex on initializing thread in CLogonMutex::Acquire");
  44. if ((s_hMutex != NULL) && (WAIT_TIMEOUT == WaitForSingleObject(s_hEvent, 0)))
  45. {
  46. ASSERTMSG(s_lAcquireCount == 0, "Mutex already owned in CLogonMutex::Acquire");
  47. dwWaitResult = WaitForSingleObject(s_hMutex, INFINITE);
  48. ++s_lAcquireCount;
  49. }
  50. }
  51. // --------------------------------------------------------------------------
  52. // CLogonMutex::Release
  53. //
  54. // Arguments: <none>
  55. //
  56. // Returns: <none>
  57. //
  58. // Purpose: Releases the mutex. Again makes sure the caller is the main
  59. // thread of winlogon. The acquisitions and releases are
  60. // reference counted to allow unbalanced release calls to be
  61. // made.
  62. //
  63. // History: 2001-04-06 vtan created
  64. // --------------------------------------------------------------------------
  65. void CLogonMutex::Release (void)
  66. {
  67. ASSERTMSG((s_dwThreadID == 0) || (s_dwThreadID == GetCurrentThreadId()), "Must acquire mutex on initializing thread in CLogonMutex::Release");
  68. if ((s_hMutex != NULL) && (s_lAcquireCount > 0))
  69. {
  70. TBOOL(ReleaseMutex(s_hMutex));
  71. --s_lAcquireCount;
  72. }
  73. }
  74. // --------------------------------------------------------------------------
  75. // CLogonMutex::SignalReply
  76. //
  77. // Arguments: <none>
  78. //
  79. // Returns: <none>
  80. //
  81. // Purpose: Open the global logon reply event and signal it.
  82. //
  83. // History: 2001-04-06 vtan created
  84. // --------------------------------------------------------------------------
  85. void CLogonMutex::SignalReply (void)
  86. {
  87. HANDLE hEvent;
  88. hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, s_szLogonReplyEventName);
  89. if (hEvent != NULL)
  90. {
  91. TBOOL(SetEvent(hEvent));
  92. TBOOL(CloseHandle(hEvent));
  93. }
  94. }
  95. // --------------------------------------------------------------------------
  96. // CLogonMutex::SignalShutdown
  97. //
  98. // Arguments: <none>
  99. //
  100. // Returns: <none>
  101. //
  102. // Purpose: Signal the global shut down event. This will prevent further
  103. // interactive requests from being processed.
  104. //
  105. // History: 2001-04-06 vtan created
  106. // --------------------------------------------------------------------------
  107. void CLogonMutex::SignalShutdown (void)
  108. {
  109. if (s_hEvent != NULL)
  110. {
  111. TBOOL(SetEvent(s_hEvent));
  112. }
  113. }
  114. // --------------------------------------------------------------------------
  115. // CLogonMutex::StaticInitialize
  116. //
  117. // Arguments: <none>
  118. //
  119. // Returns: <none>
  120. //
  121. // Purpose: Initializes the logon mutex objects based on whether this is
  122. // session 0 or higher and or what the product type is. Because
  123. // the initialization for session is done only the once this
  124. // requires a machine restart for the objects to be created.
  125. //
  126. // History: 2001-04-06 vtan created
  127. // --------------------------------------------------------------------------
  128. void CLogonMutex::StaticInitialize (void)
  129. {
  130. // Check the machine settings. Must be friendly UI and PER/PRO (FUS).
  131. if (CSystemSettings::IsFriendlyUIActive() && CSystemSettings::IsMultipleUsersEnabled() && CSystemSettings::IsWorkStationProduct())
  132. {
  133. DWORD dwErrorCode;
  134. s_dwThreadID = GetCurrentThreadId();
  135. s_lAcquireCount = 0;
  136. // On session 0 create the objects and ACL them.
  137. if (NtCurrentPeb()->SessionId == 0)
  138. {
  139. s_hEvent = CreateShutdownEvent();
  140. if (s_hEvent != NULL)
  141. {
  142. s_hMutex = CreateLogonMutex();
  143. if (s_hMutex != NULL)
  144. {
  145. s_hMutexRequest = CreateLogonRequestMutex();
  146. if (s_hMutexRequest != NULL)
  147. {
  148. Acquire();
  149. dwErrorCode = ERROR_SUCCESS;
  150. }
  151. else
  152. {
  153. dwErrorCode = GetLastError();
  154. }
  155. }
  156. else
  157. {
  158. dwErrorCode = GetLastError();
  159. }
  160. }
  161. else
  162. {
  163. dwErrorCode = GetLastError();
  164. }
  165. }
  166. else
  167. {
  168. // For sessions other than 0 open the objects.
  169. s_hEvent = OpenShutdownEvent();
  170. if (s_hEvent != NULL)
  171. {
  172. if (WAIT_TIMEOUT == WaitForSingleObject(s_hEvent, 0))
  173. {
  174. s_hMutex = OpenLogonMutex();
  175. if (s_hMutex != NULL)
  176. {
  177. Acquire();
  178. dwErrorCode = ERROR_SUCCESS;
  179. }
  180. else
  181. {
  182. dwErrorCode = GetLastError();
  183. }
  184. }
  185. else
  186. {
  187. dwErrorCode = ERROR_SHUTDOWN_IN_PROGRESS;
  188. }
  189. }
  190. else
  191. {
  192. dwErrorCode = GetLastError();
  193. }
  194. }
  195. if (ERROR_SUCCESS == dwErrorCode)
  196. {
  197. ASSERTMSG(s_hMutex != NULL, "NULL s_hMutex in CLogonMutex::StaticInitialize");
  198. ASSERTMSG(s_hEvent != NULL, "NULL s_hEvent in CLogonMutex::StaticInitialize");
  199. }
  200. else
  201. {
  202. ReleaseHandle(s_hEvent);
  203. ReleaseHandle(s_hMutex);
  204. s_dwThreadID = 0;
  205. }
  206. }
  207. else
  208. {
  209. s_dwThreadID = 0;
  210. s_lAcquireCount = 0;
  211. s_hMutex = NULL;
  212. s_hEvent = NULL;
  213. }
  214. }
  215. // --------------------------------------------------------------------------
  216. // CLogonMutex::StaticTerminate
  217. //
  218. // Arguments: <none>
  219. //
  220. // Returns: <none>
  221. //
  222. // Purpose: Releases the mutex if held and closes the object handle.
  223. //
  224. // History: 2001-04-06 vtan created
  225. // --------------------------------------------------------------------------
  226. void CLogonMutex::StaticTerminate (void)
  227. {
  228. Release();
  229. ASSERTMSG(s_lAcquireCount == 0, "Mutex not released in CLogonMutex::StaticTerminate");
  230. ReleaseHandle(s_hMutex);
  231. }
  232. // --------------------------------------------------------------------------
  233. // CLogonMutex::CreateShutdownEvent
  234. //
  235. // Arguments: <none>
  236. //
  237. // Returns: HANDLE
  238. //
  239. // Purpose: Creates the global shut down event. ACL'd so that anybody can
  240. // synchronize against it and therefore listen but only SYSTEM
  241. // can set it to indicate machine shut down has begun.
  242. //
  243. // History: 2001-04-06 vtan created
  244. // --------------------------------------------------------------------------
  245. HANDLE CLogonMutex::CreateShutdownEvent (void)
  246. {
  247. HANDLE hEvent;
  248. SECURITY_ATTRIBUTES securityAttributes;
  249. // Build a security descriptor for the event that allows:
  250. // S-1-5-18 NT AUTHORITY\SYSTEM EVENT_ALL_ACCESS
  251. // S-1-5-32-544 <local administrators> READ_CONTROL | SYNCHRONIZE
  252. // S-1-1-0 <everybody> SYNCHRONIZE
  253. static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
  254. {
  255. {
  256. &s_SecurityNTAuthority,
  257. 1,
  258. SECURITY_LOCAL_SYSTEM_RID,
  259. 0, 0, 0, 0, 0, 0, 0,
  260. EVENT_ALL_ACCESS
  261. },
  262. {
  263. &s_SecurityNTAuthority,
  264. 2,
  265. SECURITY_BUILTIN_DOMAIN_RID,
  266. DOMAIN_ALIAS_RID_ADMINS,
  267. 0, 0, 0, 0, 0, 0,
  268. READ_CONTROL | SYNCHRONIZE
  269. },
  270. {
  271. &s_SecurityWorldSID,
  272. 1,
  273. SECURITY_WORLD_RID,
  274. 0, 0, 0, 0, 0, 0, 0,
  275. SYNCHRONIZE
  276. }
  277. };
  278. securityAttributes.nLength = sizeof(securityAttributes);
  279. securityAttributes.lpSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
  280. securityAttributes.bInheritHandle = FALSE;
  281. hEvent = CreateEvent(&securityAttributes, TRUE, FALSE, s_szShutdownEventName);
  282. if (securityAttributes.lpSecurityDescriptor != NULL)
  283. {
  284. (HLOCAL)LocalFree(securityAttributes.lpSecurityDescriptor);
  285. }
  286. return(hEvent);
  287. }
  288. // --------------------------------------------------------------------------
  289. // CLogonMutex::CreateLogonMutex
  290. //
  291. // Arguments: <none>
  292. //
  293. // Returns: HANDLE
  294. //
  295. // Purpose: Creates the global logon mutex. ACL'd so that only SYSTEM can
  296. // acquire and release the mutex. This is not for user
  297. // consumption.
  298. //
  299. // History: 2001-04-06 vtan created
  300. // --------------------------------------------------------------------------
  301. HANDLE CLogonMutex::CreateLogonMutex (void)
  302. {
  303. HANDLE hMutex;
  304. SECURITY_ATTRIBUTES securityAttributes;
  305. // Build a security descriptor for the mutex that allows:
  306. // S-1-5-18 NT AUTHORITY\SYSTEM MUTEX_ALL_ACCESS
  307. static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
  308. {
  309. {
  310. &s_SecurityNTAuthority,
  311. 1,
  312. SECURITY_LOCAL_SYSTEM_RID,
  313. 0, 0, 0, 0, 0, 0, 0,
  314. MUTEX_ALL_ACCESS
  315. }
  316. };
  317. securityAttributes.nLength = sizeof(securityAttributes);
  318. securityAttributes.lpSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
  319. securityAttributes.bInheritHandle = FALSE;
  320. hMutex = CreateMutex(&securityAttributes, FALSE, s_szLogonMutexName);
  321. if (securityAttributes.lpSecurityDescriptor != NULL)
  322. {
  323. (HLOCAL)LocalFree(securityAttributes.lpSecurityDescriptor);
  324. }
  325. return(hMutex);
  326. }
  327. // --------------------------------------------------------------------------
  328. // CLogonMutex::CreateLogonRequestMutex
  329. //
  330. // Arguments: <none>
  331. //
  332. // Returns: HANDLE
  333. //
  334. // Purpose: Creates the logon request mutex for interactive logon
  335. // requests. For a service to make this request it must acquire
  336. // the mutex and therefore only a single request can be made at
  337. // any one time. This is ACL'd so that only SYSTEM can gain
  338. // access to this object.
  339. //
  340. // History: 2001-04-06 vtan created
  341. // --------------------------------------------------------------------------
  342. HANDLE CLogonMutex::CreateLogonRequestMutex (void)
  343. {
  344. HANDLE hMutex;
  345. SECURITY_ATTRIBUTES securityAttributes;
  346. // Build a security descriptor for the mutex that allows:
  347. // S-1-5-18 NT AUTHORITY\SYSTEM MUTEX_ALL_ACCESS
  348. static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
  349. {
  350. {
  351. &s_SecurityNTAuthority,
  352. 1,
  353. SECURITY_LOCAL_SYSTEM_RID,
  354. 0, 0, 0, 0, 0, 0, 0,
  355. MUTEX_ALL_ACCESS
  356. }
  357. };
  358. securityAttributes.nLength = sizeof(securityAttributes);
  359. securityAttributes.lpSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
  360. securityAttributes.bInheritHandle = FALSE;
  361. hMutex = CreateMutex(&securityAttributes, FALSE, s_szLogonRequestMutexName);
  362. if (securityAttributes.lpSecurityDescriptor != NULL)
  363. {
  364. (HLOCAL)LocalFree(securityAttributes.lpSecurityDescriptor);
  365. }
  366. return(hMutex);
  367. }
  368. // --------------------------------------------------------------------------
  369. // CLogonMutex::OpenShutdownEvent
  370. //
  371. // Arguments: <none>
  372. //
  373. // Returns: HANDLE
  374. //
  375. // Purpose: Opens a handle to the global shut down event.
  376. //
  377. // History: 2001-04-06 vtan created
  378. // --------------------------------------------------------------------------
  379. HANDLE CLogonMutex::OpenShutdownEvent (void)
  380. {
  381. return(OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, s_szShutdownEventName));
  382. }
  383. // --------------------------------------------------------------------------
  384. // CLogonMutex::OpenLogonMutex
  385. //
  386. // Arguments: <none>
  387. //
  388. // Returns: HANDLE
  389. //
  390. // Purpose: Opens a handle to the global logon mutex.
  391. //
  392. // History: 2001-04-06 vtan created
  393. // --------------------------------------------------------------------------
  394. HANDLE CLogonMutex::OpenLogonMutex (void)
  395. {
  396. return(OpenMutex(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, s_szLogonMutexName));
  397. }