gcount.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 12k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //
  2. // Global counters
  3. //
  4. //
  5. #include "priv.h"
  6. typedef struct _SHELL_USER_SID
  7. {
  8.     SID_IDENTIFIER_AUTHORITY sidAuthority;
  9.     DWORD dwUserGroupID;
  10.     DWORD dwUserID;
  11. } SHELL_USER_SID, *PSHELL_USER_SID;
  12. const SHELL_USER_SID susSystem = {SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID, 0};                                     // the "SYSTEM" group
  13. const SHELL_USER_SID susAdministrators = {SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS};     // the "Administrators" group
  14. const SHELL_USER_SID susEveryone = {SECURITY_WORLD_SID_AUTHORITY, SECURITY_WORLD_RID, 0};                                   // the "Everyone" group
  15. typedef struct _SHELL_USER_PERMISSION
  16. {
  17.     SHELL_USER_SID susID;       // identifies the user for whom you want to grant permissions to
  18.     DWORD dwAccessType;         // currently, this is either ACCESS_ALLOWED_ACE_TYPE or  ACCESS_DENIED_ACE_TYPE
  19.     DWORD dwAccessMask;         // access granted (eg FILE_LIST_CONTENTS or KEY_ALL_ACCESS, etc...)
  20. } SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION;
  21. //
  22. // AllocSafeFullAccessACL
  23. //
  24. // Allocate an ACL and fill it in with values that allow system and administrators
  25. // to do everything and for everyone to do everything except change the acls.
  26. //
  27. // Caller must LocalFree the returned ACL or face the wrath of the LeakMeister.
  28. // BUGBUG That said, we will leak one of these per process below in CreateAllAccessSecurityAttributes
  29. //
  30. // NOTE: This is yanked and simplified from Shell32 securent.c GetShellSecurityDescriptor
  31. //
  32. STDAPI_(PACL)  AllocSafeFullAccessACL()
  33. {
  34.     BOOL fSuccess = TRUE;   // assume success
  35.     SECURITY_DESCRIPTOR* pSD = NULL;
  36.     PSID* apSids = NULL;
  37.     int cUserPerm = 3;
  38.     int cAces = cUserPerm;  // one ACE for each entry to start with
  39.     int iAceIndex = 0;      // helps us keep count of how many ACE's we have added (count as we go)
  40.     DWORD cbSidLength = 0;
  41.     DWORD cbAcl;
  42.     PACL pAcl = NULL;
  43.     int i;
  44.     SHELL_USER_PERMISSION supEveryone;
  45.     SHELL_USER_PERMISSION supSystem;
  46.     SHELL_USER_PERMISSION supAdministrators;
  47.     PSHELL_USER_PERMISSION apUserPerm[3] = {&supEveryone, &supAdministrators, &supSystem};
  48.     // we want the everyone to have read, write, exec and sync only 
  49.     supEveryone.susID = susEveryone;
  50.     supEveryone.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
  51.     supEveryone.dwAccessMask = (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | SYNCHRONIZE);
  52.     // we want the SYSTEM to have full control
  53.     supSystem.susID = susSystem;
  54.     supSystem.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
  55.     supSystem.dwAccessMask = GENERIC_ALL;
  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.     
  61.     // alloc the array to hold all the SID's
  62.     apSids = (PSID*)LocalAlloc(LPTR, cUserPerm * sizeof(PSID));
  63.     
  64.     if (!apSids)
  65.     {
  66.         DWORD dwLastError = GetLastError();
  67.         TraceMsg(TF_WARNING, "Failed allocate memory for %i SID's.  Error = %d", cUserPerm, dwLastError);
  68.         fSuccess = FALSE;
  69.         goto cleanup;
  70.     }
  71.     // initialize the SID's
  72.     for (i = 0; i < cUserPerm; i++)
  73.     {
  74.         DWORD cbSid;
  75.         SID_IDENTIFIER_AUTHORITY sidAuthority = apUserPerm[i]->susID.sidAuthority;
  76.         if (!AllocateAndInitializeSid(&sidAuthority,
  77.                                       (BYTE)(apUserPerm[i]->susID.dwUserID ? 2 : 1),    // if dwUserID is nonzero, then there are two SubAuthorities
  78.                                       apUserPerm[i]->susID.dwUserGroupID,
  79.                                       apUserPerm[i]->susID.dwUserID,
  80.                                       0, 0, 0, 0, 0, 0, &apSids[i]))
  81.         {
  82.             DWORD dwLastError = GetLastError();
  83.             TraceMsg(TF_WARNING, "AllocateAndInitializeSid: Failed to initialze SID.  Error = %d", cUserPerm, dwLastError);
  84.             fSuccess = FALSE;
  85.             goto cleanup;
  86.         }
  87.         // add up all the SID lengths for an easy ACL size computation later...
  88.         cbSid = GetLengthSid(apSids[i]);
  89.         cbSidLength += cbSid;
  90.     }
  91.     // calculate the size of the ACL we will be building (note: used sizeof(ACCESS_ALLOWED_ACE) b/c all ACE's are the same
  92.     // size (excepting wacko object ACE's which we dont deal with). 
  93.     //
  94.     // this makes the size computation easy, since the size of the ACL will be the size of all the ACE's + the size of the SID's.
  95.     cbAcl = SIZEOF(ACL) + (cAces * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))) + cbSidLength;
  96.     pAcl = (PACL)LocalAlloc(LPTR, cbAcl);
  97.     if (!pAcl)
  98.     {
  99.         DWORD dwLastError = GetLastError();
  100.         TraceMsg(TF_WARNING, "Failed to allocate space for the ACL.  Error = %d", dwLastError);
  101.         fSuccess = FALSE;
  102.         goto cleanup;
  103.     }
  104.     
  105.     if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION))
  106.     {
  107.         DWORD dwLastError = GetLastError();
  108.         TraceMsg(TF_WARNING, "InitializeAcl: Failed to init the ACL.  Error = %d", dwLastError);
  109.         fSuccess = FALSE;
  110.         goto cleanup;
  111.     }
  112.     for (i = 0; i < cUserPerm; i++)
  113.     {
  114.         BOOL bRet;
  115.         // add the ACE's to the ACL
  116.         if (apUserPerm[i]->dwAccessType == ACCESS_ALLOWED_ACE_TYPE)
  117.         {
  118.             bRet = AddAccessAllowedAce(pAcl, ACL_REVISION, apUserPerm[i]->dwAccessMask, apSids[i]);
  119.         }
  120.         else
  121.         {
  122.             bRet = AddAccessDeniedAce(pAcl, ACL_REVISION, apUserPerm[i]->dwAccessMask, apSids[i]);
  123.         }
  124.         if (!bRet)
  125.         {
  126.             DWORD dwLastError = GetLastError();
  127.             TraceMsg(TF_WARNING, "AddAccessAllowed/DeniedAce: Failed to add SID.  Error = %d", dwLastError);
  128.             fSuccess = FALSE;
  129.             goto cleanup;
  130.         }
  131.         // sucessfully added an ace
  132.         iAceIndex++;
  133.         ASSERT(iAceIndex <= cAces);
  134.     }
  135. cleanup:
  136.     if (apSids)
  137.     {
  138.         for (i = 0; i < cUserPerm; i++)
  139.         {
  140.             if (apSids[i])
  141.             {
  142.                 FreeSid(apSids[i]);
  143.             }
  144.         }
  145.         LocalFree(apSids);
  146.     }
  147.     if (!fSuccess && pAcl)
  148.     {
  149.         LocalFree(pAcl);
  150.         pAcl = NULL;
  151.     }
  152.     return pAcl;
  153.     
  154. }
  155. #ifdef DEBUG
  156. #define GLOBAL_COUNTER_WAIT_TIMEOUT 30*1000  // on debug we set this to 30 seconds
  157. #else
  158. #define GLOBAL_COUNTER_WAIT_TIMEOUT 0        // on retail its zero so we test the objects state and return immedaeately
  159. #endif
  160. LPSECURITY_ATTRIBUTES g_psaCached;
  161. SECURITY_ATTRIBUTES g_sa;
  162. SECURITY_DESCRIPTOR g_sd;
  163. PACL g_pacl;        //BUGBUG I am leaked, once per process.
  164. //
  165. // This function fills in a SECURITY_ATTRIBUTES struct such that it will be full access to everyone.
  166. // This is needed when multiple processes need access to the same named kernel objects.
  167. //
  168. // If you pass (NULL, NULL, NULL), then we return a static security object with
  169. // full access.  If you get the ACL back, you must LocalFree it.
  170. //
  171. STDAPI_(SECURITY_ATTRIBUTES*) CreateAllAccessSecurityAttributes(SECURITY_ATTRIBUTES* psa, SECURITY_DESCRIPTOR* psd, PACL *ppacl)
  172. {
  173.     PACL    pAcl = NULL;
  174.     
  175.     // Win9x doesn't use dacls
  176.     if (!g_bRunningOnNT)
  177.         return NULL;
  178.     if (ppacl)
  179.     {
  180.         *ppacl = NULL;
  181.     }
  182.     
  183.     // App is lazy and wants to piggyback off our copy of the dacl
  184.     if (!psa)
  185.     {
  186.         if (!g_psaCached)
  187.         {
  188.             ENTERCRITICAL;
  189.             if (!g_psaCached)
  190.             {
  191.                 g_psaCached = CreateAllAccessSecurityAttributes(&g_sa, &g_sd, &g_pacl);
  192.             }
  193.             LEAVECRITICAL;
  194.         }
  195.         return g_psaCached;
  196.     }
  197.     //
  198.     //  When creating a kernel syncronization object, make sure it is 
  199.     //  created w/ "allow everyone full access".  If we weren't explicit,
  200.     //  then we'd inherit whatever permissions belong to the current
  201.     //  thread, which might be overly restrictive.
  202.     //
  203.     //
  204.     //  There are three kinds of null-type DACLs.
  205.     //
  206.     //  1. No DACL.  This means that we inherit the ambient DACL
  207.     //     from our thread.
  208.     //  2. Null DACL.  This means "full access to everyone".
  209.     //  3. Empty DACL.  This means "deny all access to everyone".
  210.     //
  211.     //  InitializeSecurityDescriptor gives you a (1) so we need to
  212.     //  change it to a (2).
  213.     //
  214.     pAcl = AllocSafeFullAccessACL();
  215.     
  216.     if (pAcl && 
  217.         InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION) &&
  218.         SetSecurityDescriptorDacl(psd, TRUE, pAcl, FALSE))
  219.     {
  220.         psa->nLength = sizeof(*psa);
  221.         psa->lpSecurityDescriptor = psd;
  222.         psa->bInheritHandle = FALSE;
  223.         
  224.         if (ppacl)
  225.         {
  226.             *ppacl = pAcl;
  227.         }
  228.         else
  229.         {
  230.             LocalFree(pAcl);
  231.         }
  232.     }
  233.     else
  234.     {
  235.         // Horrible failure
  236.         return NULL;
  237.     }
  238.     return psa;
  239. }
  240. STDAPI_(void) FreeCachedAcl()
  241. {
  242.     if (g_pacl)
  243.     {
  244.         LocalFree(g_pacl);
  245.         g_pacl = NULL;
  246.         g_psaCached = NULL;
  247.     }
  248. }
  249. //
  250. // This lets the user pass an ANSI String as the name of the global counter, as well as an inital value
  251. //
  252. STDAPI_(HANDLE) SHGlobalCounterCreateNamedA(LPCSTR szName, LONG lInitialValue)
  253. {
  254.     HANDLE hSem;
  255.     //
  256.     //  Explicitly ANSI so it runs on Win95.
  257.     //
  258.     char szCounterName[MAX_PATH];    // "shell.szName"
  259.     LPSECURITY_ATTRIBUTES psa;
  260.     lstrcpyA(szCounterName, "shell.");
  261.     StrCatBuffA(szCounterName, szName, ARRAYSIZE(szCounterName));
  262.     psa = CreateAllAccessSecurityAttributes(NULL, NULL, NULL);
  263.     hSem = CreateSemaphoreA(psa, lInitialValue, 0x7FFFFFFF, szCounterName);
  264.     if (!hSem)
  265.         hSem = OpenSemaphoreA(SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, FALSE, szCounterName);
  266.     return hSem;
  267. }
  268. //
  269. // This lets the user pass an UNICODE String as the name of the global counter, as well as an inital value
  270. //
  271. STDAPI_(HANDLE) SHGlobalCounterCreateNamedW(LPCWSTR szName, LONG lInitialValue)
  272. {
  273.     CHAR szCounterName[MAX_PATH];
  274.     SHUnicodeToAnsi(szName, szCounterName, ARRAYSIZE(szCounterName));
  275.     return SHGlobalCounterCreateNamedA(szCounterName, lInitialValue);
  276. }
  277. //
  278. // This lets the user pass a GUID. The name of the global counter will be "shell.{guid}",
  279. // and its initial value will be zero.
  280. //
  281. STDAPI_(HANDLE) SHGlobalCounterCreate(REFGUID rguid)
  282. {
  283.     CHAR szGUIDString[GUIDSTR_MAX];
  284.     SHStringFromGUIDA(rguid, szGUIDString, ARRAYSIZE(szGUIDString));
  285.     return SHGlobalCounterCreateNamedA(szGUIDString, 0);
  286. }
  287. // returns current value of the global counter
  288. // Note: The result is not thread-safe in the sense that if two threads
  289. // look at the value at the same time, one of them might read the wrong
  290. // value.
  291. STDAPI_(long) SHGlobalCounterGetValue(HANDLE hCounter)
  292.     long lPreviousValue = 0;
  293.     DWORD dwRet;
  294.     ReleaseSemaphore(hCounter, 1, &lPreviousValue); // poll and bump the count
  295.     dwRet = WaitForSingleObject(hCounter, GLOBAL_COUNTER_WAIT_TIMEOUT); // reduce the count
  296.     // this shouldnt happen since we just bumped up the count above
  297.     ASSERT(dwRet != WAIT_TIMEOUT);
  298.     
  299.     return lPreviousValue;
  300. }
  301. // returns new value
  302. // Note: this _is_ thread safe
  303. STDAPI_(long) SHGlobalCounterIncrement(HANDLE hCounter)
  304.     long lPreviousValue = 0;
  305.     ReleaseSemaphore(hCounter, 1, &lPreviousValue); // bump the count
  306.     return lPreviousValue + 1;
  307. }
  308. // returns new value
  309. // Note: The result is not thread-safe in the sense that if two threads
  310. // try to decrement the value at the same time, whacky stuff can happen.
  311. STDAPI_(long) SHGlobalCounterDecrement(HANDLE hCounter)
  312.     DWORD dwRet;
  313.     long lCurrentValue = SHGlobalCounterGetValue(hCounter);
  314. #ifdef DEBUG
  315.     // extra sanity check
  316.     if (lCurrentValue == 0)
  317.     {
  318.         ASSERTMSG(FALSE, "SHGlobalCounterDecrement called on a counter that was already equal to 0 !!");
  319.         return 0;
  320.     }
  321. #endif
  322.     dwRet = WaitForSingleObject(hCounter, GLOBAL_COUNTER_WAIT_TIMEOUT); // reduce the count
  323.     ASSERT(dwRet != WAIT_TIMEOUT);
  324.     return lCurrentValue - 1;
  325. }