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.

316 lines
8.1 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1999.
  5. //
  6. // File: W R L O C K . C P P
  7. //
  8. // Contents: Defines the interface to the netcfg write lock used to
  9. // protect the network configuration information from being
  10. // modified by more than one writer at a time.
  11. //
  12. // Notes:
  13. //
  14. // Author: shaunco 15 Jan 1999
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <pch.h>
  18. #pragma hdrstop
  19. #include "nccom.h"
  20. #include "ncreg.h"
  21. #include "util.h"
  22. #include "wrlock.h"
  23. #define MUTEX_NAME L"Global\\NetCfgWriteLock"
  24. #define LOCK_HOLDER_SUBKEY L"NetCfgLockHolder"
  25. CWriteLock::~CWriteLock ()
  26. {
  27. // If we have the mutex created, release it if we own it
  28. // and close its handle.
  29. //
  30. if (m_hMutex)
  31. {
  32. ReleaseIfOwned ();
  33. CloseHandle (m_hMutex);
  34. }
  35. }
  36. HRESULT
  37. CWriteLock::HrEnsureMutexCreated ()
  38. {
  39. if (m_hMutex)
  40. {
  41. return S_OK;
  42. }
  43. // Ensure the mutex has been created. It is important to create it
  44. // with a security descriptor that allows access to the world because
  45. // we may be running under the localsystem account and someone else
  46. // may be running under a user account. If we didn't give the world
  47. // explicit access, the user account clients would get access denied
  48. // because the mutex would have inherited the security level of our
  49. // process.
  50. //
  51. HRESULT hr;
  52. Assert (!m_hMutex);
  53. Assert (!m_fOwned);
  54. hr = HrCreateMutexWithWorldAccess (
  55. MUTEX_NAME,
  56. FALSE, // not initially owned,
  57. NULL,
  58. &m_hMutex);
  59. TraceHr (ttidError, FAL, hr, FALSE, "CWriteLock::HrEnsureMutexCreated");
  60. return hr;
  61. }
  62. BOOL
  63. CWriteLock::WaitToAcquire (
  64. IN DWORD dwMilliseconds,
  65. IN PCWSTR pszNewOwnerDesc,
  66. OUT PWSTR* ppszCurrentOwnerDesc OPTIONAL)
  67. {
  68. HRESULT hr;
  69. BOOL fAcquired = FALSE;
  70. hr = HrEnsureMutexCreated ();
  71. if (S_OK == hr)
  72. {
  73. // Now wait for the mutext to become available. (Pump messages while
  74. // waiting so we don't hang the clients UI.)
  75. //
  76. while (1)
  77. {
  78. DWORD dwWait;
  79. dwWait = MsgWaitForMultipleObjects (
  80. 1, &m_hMutex, FALSE,
  81. dwMilliseconds, QS_ALLINPUT);
  82. if ((WAIT_OBJECT_0 + 1) == dwWait)
  83. {
  84. // We have messages to pump.
  85. //
  86. MSG msg;
  87. while (PeekMessage (&msg, NULL, NULL, NULL, PM_REMOVE))
  88. {
  89. DispatchMessage (&msg);
  90. }
  91. }
  92. else
  93. {
  94. if (WAIT_OBJECT_0 == dwWait)
  95. {
  96. fAcquired = TRUE;
  97. }
  98. else if (WAIT_ABANDONED_0 == dwWait)
  99. {
  100. fAcquired = TRUE;
  101. TraceTag (ttidError, "NetCfg write lock was abandoned!");
  102. }
  103. else if (WAIT_TIMEOUT == dwWait)
  104. {
  105. hr = HRESULT_FROM_WIN32 (ERROR_TIMEOUT);
  106. }
  107. else
  108. {
  109. hr = HrFromLastWin32Error ();
  110. TraceHr (ttidError, FAL, hr, FALSE,
  111. "MsgWaitForMultipleObjects");
  112. }
  113. // If we acquired the mutex, set the new owner.
  114. //
  115. if (fAcquired)
  116. {
  117. m_fOwned = TRUE;
  118. SetOrQueryLockHolder (TRUE,
  119. pszNewOwnerDesc, ppszCurrentOwnerDesc);
  120. }
  121. else if (ppszCurrentOwnerDesc)
  122. {
  123. // Query the lock holder description.
  124. //
  125. SetOrQueryLockHolder (FALSE,
  126. NULL, ppszCurrentOwnerDesc);
  127. }
  128. break;
  129. }
  130. }
  131. }
  132. return fAcquired;
  133. }
  134. BOOL
  135. CWriteLock::FIsLockedByAnyone (
  136. OUT PWSTR* ppszCurrentOwnerDesc OPTIONAL)
  137. {
  138. // It's locked if we own it.
  139. //
  140. BOOL fLocked = m_fOwned;
  141. // If we don't own it, check to see if some other process does.
  142. //
  143. if (!fLocked)
  144. {
  145. HRESULT hr;
  146. hr = HrEnsureMutexCreated ();
  147. if (S_OK == hr)
  148. {
  149. DWORD dw;
  150. // Wait for the mutex, but with a zero timeout. This is
  151. // equivalent to a quick check. (But we still need to release
  152. // it if we acquire ownership. If we timeout, it means that
  153. // someone else owns it.
  154. //
  155. dw = WaitForSingleObject (m_hMutex, 0);
  156. if (WAIT_OBJECT_0 == dw)
  157. {
  158. ReleaseMutex (m_hMutex);
  159. }
  160. else if (WAIT_TIMEOUT == dw)
  161. {
  162. // Someone else owns it.
  163. //
  164. fLocked = TRUE;
  165. }
  166. }
  167. }
  168. if (fLocked)
  169. {
  170. // Query the lock holder description.
  171. //
  172. SetOrQueryLockHolder (FALSE, NULL, ppszCurrentOwnerDesc);
  173. }
  174. return fLocked;
  175. }
  176. VOID
  177. CWriteLock::ReleaseIfOwned ()
  178. {
  179. if (m_fOwned)
  180. {
  181. Assert (m_hMutex);
  182. // Clear the lock holder now that no one is about to own it.
  183. //
  184. SetOrQueryLockHolder (TRUE, NULL, NULL);
  185. ReleaseMutex (m_hMutex);
  186. m_fOwned = FALSE;
  187. }
  188. }
  189. VOID
  190. CWriteLock::SetOrQueryLockHolder (
  191. IN BOOL fSet,
  192. IN PCWSTR pszNewOwnerDesc OPTIONAL,
  193. OUT PWSTR* ppszCurrentOwnerDesc OPTIONAL)
  194. {
  195. HRESULT hr;
  196. HKEY hkeyNetwork;
  197. HKEY hkeyLockHolder;
  198. REGSAM samDesired;
  199. BOOL fClear;
  200. // We're clearing the value if we're asked to set it to NULL.
  201. //
  202. fClear = fSet && !pszNewOwnerDesc;
  203. // Initialize the output parameter if specified.
  204. //
  205. if (ppszCurrentOwnerDesc)
  206. {
  207. *ppszCurrentOwnerDesc = NULL;
  208. }
  209. // If we're setting the lock holder, we need write access. Otherwise,
  210. // we only need read access.
  211. //
  212. samDesired = (fSet) ? KEY_READ_WRITE_DELETE : KEY_READ;
  213. hr = HrOpenNetworkKey (samDesired, &hkeyNetwork);
  214. if (S_OK == hr)
  215. {
  216. // The lock holder is represented by the default value of a
  217. // volatile subkey under the Network subtree.
  218. //
  219. if (fClear)
  220. {
  221. RegDeleteKey (hkeyNetwork, LOCK_HOLDER_SUBKEY);
  222. }
  223. else if (fSet)
  224. {
  225. DWORD dwDisposition;
  226. Assert (pszNewOwnerDesc);
  227. hr = HrRegCreateKeyWithWorldAccess (
  228. hkeyNetwork,
  229. LOCK_HOLDER_SUBKEY,
  230. REG_OPTION_VOLATILE,
  231. KEY_WRITE,
  232. &hkeyLockHolder,
  233. &dwDisposition);
  234. // Set the lock holder and close the key.
  235. //
  236. if (S_OK == hr)
  237. {
  238. (VOID) HrRegSetSz (hkeyLockHolder, NULL, pszNewOwnerDesc);
  239. RegCloseKey (hkeyLockHolder);
  240. }
  241. }
  242. else
  243. {
  244. // Query for the lock holder by opening the key (if it exists)
  245. // and reading the default value. We return the string
  246. // allocated with CoTaskMemAlloc because we use this
  247. // directly from the COM implementation.
  248. //
  249. Assert (ppszCurrentOwnerDesc);
  250. hr = HrRegOpenKeyEx (
  251. hkeyNetwork,
  252. LOCK_HOLDER_SUBKEY,
  253. KEY_READ,
  254. &hkeyLockHolder);
  255. if (S_OK == hr)
  256. {
  257. PWSTR pszLockHolder;
  258. hr = HrRegQuerySzWithAlloc (
  259. hkeyLockHolder,
  260. NULL,
  261. &pszLockHolder);
  262. if (S_OK == hr)
  263. {
  264. hr = HrCoTaskMemAllocAndDupSz (
  265. pszLockHolder, ppszCurrentOwnerDesc);
  266. MemFree (pszLockHolder);
  267. }
  268. RegCloseKey (hkeyLockHolder);
  269. }
  270. }
  271. RegCloseKey (hkeyNetwork);
  272. }
  273. }