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.

222 lines
6.8 KiB

  1. #include "priv.h"
  2. //
  3. // #defines
  4. //
  5. #ifdef DEBUG
  6. #define GLOBAL_COUNTER_WAIT_TIMEOUT 30*1000 // on debug we set this to 30 seconds
  7. #else
  8. #define GLOBAL_COUNTER_WAIT_TIMEOUT 0 // on retail its zero so we test the objects state and return immedaeately
  9. #endif
  10. //
  11. // Globals
  12. //
  13. SECURITY_ATTRIBUTES* g_psa = NULL;
  14. // There are three kinds of null-type DACL's.
  15. //
  16. // 1. No DACL. This means that we inherit the ambient DACL from our thread.
  17. // 2. Null DACL. This means "full access to everyone".
  18. // 3. Empty DACL. This means "deny all access to everyone".
  19. //
  20. // NONE of these are correct for our needs. We used to use Null DACL's (2),
  21. // but the issue with these is that someone can change the ACL on the object thus
  22. // locking us out so we can't synchronize to the object anymore.
  23. //
  24. // So now we create a specific DACL with 3 ACE's in it:
  25. //
  26. // ACE #1: Everyone - GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | SYNCHRONIZE
  27. // ACE #2: SYSTEM - GENERIC_ALL (full control)
  28. // ACE #3: Administrators - GENERIC_ALL (full control)
  29. //
  30. STDAPI_(SECURITY_ATTRIBUTES*) SHGetAllAccessSA()
  31. {
  32. if (g_psa == NULL)
  33. {
  34. SECURITY_ATTRIBUTES* psa = (SECURITY_ATTRIBUTES*)LocalAlloc(LPTR, sizeof(*psa));
  35. if (psa)
  36. {
  37. SECURITY_DESCRIPTOR* psd;
  38. SHELL_USER_PERMISSION supEveryone;
  39. SHELL_USER_PERMISSION supSystem;
  40. SHELL_USER_PERMISSION supAdministrators;
  41. PSHELL_USER_PERMISSION apUserPerm[3] = {&supEveryone, &supAdministrators, &supSystem};
  42. // we want the everyone to have read, write, exec and sync only
  43. supEveryone.susID = susEveryone;
  44. supEveryone.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
  45. supEveryone.dwAccessMask = (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | SYNCHRONIZE);
  46. supEveryone.fInherit = FALSE;
  47. supEveryone.dwInheritMask = 0;
  48. supEveryone.dwInheritAccessMask = 0;
  49. // we want the SYSTEM to have full control
  50. supSystem.susID = susSystem;
  51. supSystem.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
  52. supSystem.dwAccessMask = GENERIC_ALL;
  53. supSystem.fInherit = FALSE;
  54. supSystem.dwInheritMask = 0;
  55. supSystem.dwInheritAccessMask = 0;
  56. // we want the Administrators to have full control
  57. supAdministrators.susID = susAdministrators;
  58. supAdministrators.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
  59. supAdministrators.dwAccessMask = GENERIC_ALL;
  60. supAdministrators.fInherit = FALSE;
  61. supAdministrators.dwInheritMask = 0;
  62. supAdministrators.dwInheritAccessMask = 0;
  63. // allocate the global SECURITY_DESCRIPTOR
  64. psd = GetShellSecurityDescriptor(apUserPerm, ARRAYSIZE(apUserPerm));
  65. if (psd)
  66. {
  67. // setup the psa
  68. psa->nLength = sizeof(*psa);
  69. psa->lpSecurityDescriptor = psd;
  70. psa->bInheritHandle = FALSE;
  71. if (InterlockedCompareExchangePointer((void**)&g_psa, psa, NULL))
  72. {
  73. // someone else beat us to initing s_psa, free ours
  74. LocalFree(psd);
  75. LocalFree(psa);
  76. }
  77. }
  78. else
  79. {
  80. LocalFree(psa);
  81. }
  82. }
  83. }
  84. return g_psa;
  85. }
  86. //
  87. // called at process detach to release our global all-access SA
  88. //
  89. STDAPI_(void) FreeAllAccessSA()
  90. {
  91. SECURITY_ATTRIBUTES* psa = (SECURITY_ATTRIBUTES*)InterlockedExchangePointer((void**)&g_psa, NULL);
  92. if (psa)
  93. {
  94. LocalFree(psa->lpSecurityDescriptor);
  95. LocalFree(psa);
  96. }
  97. }
  98. STDAPI_(HANDLE) SHGlobalCounterCreateNamedW(LPCWSTR szName, LONG lInitialValue)
  99. {
  100. HANDLE hSem = NULL;
  101. WCHAR szCounterName[MAX_PATH]; // "shell.szName"
  102. if (SUCCEEDED(StringCchCopyW(szCounterName, ARRAYSIZE(szCounterName), L"shell.")) &&
  103. SUCCEEDED(StringCchCatW(szCounterName, ARRAYSIZE(szCounterName), szName)))
  104. {
  105. SECURITY_ATTRIBUTES* psa = SHGetAllAccessSA();
  106. if (psa)
  107. {
  108. hSem = CreateSemaphoreW(psa, lInitialValue, 0x7FFFFFFF, szCounterName);
  109. }
  110. if (!hSem)
  111. {
  112. hSem = OpenSemaphoreW(SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, FALSE, szCounterName);
  113. }
  114. }
  115. return hSem;
  116. }
  117. STDAPI_(HANDLE) SHGlobalCounterCreateNamedA(LPCSTR szName, LONG lInitialValue)
  118. {
  119. HANDLE hSem = NULL;
  120. WCHAR szCounterName[MAX_PATH];
  121. if (SHAnsiToUnicode(szName, szCounterName, ARRAYSIZE(szCounterName)))
  122. {
  123. hSem = SHGlobalCounterCreateNamedW(szCounterName, lInitialValue);
  124. }
  125. return hSem;
  126. }
  127. //
  128. // This lets the user pass a GUID. The name of the global counter will be "shell.{guid}",
  129. // and its initial value will be zero.
  130. //
  131. STDAPI_(HANDLE) SHGlobalCounterCreate(REFGUID rguid)
  132. {
  133. HANDLE hSem = NULL;
  134. WCHAR szGUIDString[GUIDSTR_MAX];
  135. if (SHStringFromGUIDW(rguid, szGUIDString, ARRAYSIZE(szGUIDString)))
  136. {
  137. hSem = SHGlobalCounterCreateNamedW(szGUIDString, 0);
  138. }
  139. return hSem;
  140. }
  141. // returns current value of the global counter
  142. // Note: The result is not thread-safe in the sense that if two threads
  143. // look at the value at the same time, one of them might read the wrong
  144. // value.
  145. STDAPI_(long) SHGlobalCounterGetValue(HANDLE hCounter)
  146. {
  147. long lPreviousValue = 0;
  148. DWORD dwRet;
  149. ReleaseSemaphore(hCounter, 1, &lPreviousValue); // poll and bump the count
  150. dwRet = WaitForSingleObject(hCounter, GLOBAL_COUNTER_WAIT_TIMEOUT); // reduce the count
  151. // this shouldnt happen since we just bumped up the count above
  152. ASSERT(dwRet != WAIT_TIMEOUT);
  153. return lPreviousValue;
  154. }
  155. // returns new value
  156. // Note: this _is_ thread safe
  157. STDAPI_(long) SHGlobalCounterIncrement(HANDLE hCounter)
  158. {
  159. long lPreviousValue = 0;
  160. ReleaseSemaphore(hCounter, 1, &lPreviousValue); // bump the count
  161. return lPreviousValue + 1;
  162. }
  163. // returns new value
  164. // Note: The result is not thread-safe in the sense that if two threads
  165. // try to decrement the value at the same time, whacky stuff can happen.
  166. STDAPI_(long) SHGlobalCounterDecrement(HANDLE hCounter)
  167. {
  168. DWORD dwRet;
  169. long lCurrentValue = SHGlobalCounterGetValue(hCounter);
  170. #ifdef DEBUG
  171. // extra sanity check
  172. if (lCurrentValue == 0)
  173. {
  174. ASSERTMSG(FALSE, "SHGlobalCounterDecrement called on a counter that was already equal to 0 !!");
  175. return 0;
  176. }
  177. #endif
  178. dwRet = WaitForSingleObject(hCounter, GLOBAL_COUNTER_WAIT_TIMEOUT); // reduce the count
  179. ASSERT(dwRet != WAIT_TIMEOUT);
  180. return lCurrentValue - 1;
  181. }