Show Changes Show Changes
Edit Edit
Print Print
Recent Changes Recent Changes
Subscriptions Subscriptions
Lost and Found Lost and Found
Find References Find References
Rename Rename
Search

History

7/25/2004 2:13:52 PM
List all versions List all versions
How To Use A Privilege
.

Remember that before you can use a privilege it must be in your token. The only way to get a privilege into your token is to have security policy grant it to you, and then to establish a fresh logon. The resulting token will have the new privilege, and it will be available for your use (in other words, don't forget to log off and log back on if you want a recent change to your groups or privileges to affect the programs you want to run).

Most functions don't require any special privileges, but if the documentation for a particular function indicates that a privilege is required, pay special attention to whether that function automatically enables the privilege or not. Some Win32 functions that use privileges can be called with the privilege enabled or disabled, and their behavior changes if you have a privilege enabled. Other functions always require a privilege and therefore will attempt to enable it for you as a convenience (since you always need to enable it to call the function successfully anyway).

With a desktop application designed to be run by many different users, some with high privilege and some with low privilege, you should plan how you'll deal with failure in case the user running your app doesn't have the required privilege. With a server application, you'll normally run under an identity that has all the privileges you need, so this won't be so much of an issue.

Some privileges are very dangerous to grant to code that accepts input from untrusted sources. Especially if that input comes over from an untrusted network such as the Internet. For example, SeDebugPrivilege can be used to elevate privileges because it allows a program to open any other process (including sensitive operating system daemons) for full permissions. If your server application has this privilege and accidentally gives control to an attacker who has sent you some malformed input, the attacker can use the privilege to read and write memory in any process he likes. This is really bad.

So, if you need a program to be both highly privileged and highly exposed to attack, consider factoring it into two parts: Pull out the small bits that require high privilege and host that code in a COM+ server application that runs under an account that’s granted those sensitive privileges but doesn’t accept input from the network. Use COM+ roles (HowToImplementRoleBasedSecurityForAManagedCOMApp) to limit the callers so that only the account under which your main server application runs can call it. This factoring technique can significantly slow down an attack, giving detection and reaction countermeasures (WhatIsACountermeasure) time to kick in.

If you need to manually enable or disable a privilege, you'll have to use the Win32 API because as of this writing the .NET Framework doesn't wrap this functionality, and it doesn't look like version 2.0 will provide it either. But fear not: I've provided some Managed C++ code that will do the trick. A sample is shown in Figure 22.1.

 ResetPrivileges* Token::EnablePrivileges(WindowsIdentity* ident,
   String* privs[], bool wantResetObject) {
   if (0 == ident) {
     throw new ArgumentException(S"Cannot be null", S"ident");
   }
   if (0 == privs) {
     throw new ArgumentException(S"Cannot be null", S"privs");
   }
   const int privCount = privs->Length;
   if (privCount < 1 || privCount > 50) {
     // sanity check on number of privileges
     // (only about 30 are even defined)
     throw new ArgumentOutOfRangeException(S"privs",
       S"Number of privileges in array is out of range");
   }


   TOKEN_PRIVILEGES tp_simple;
   TOKEN_PRIVILEGES* ptpNew;
   if (1 == privCount) {
     tp_simple.PrivilegeCount = 1;
     ptpNew = &tp_simple;
   }
   else {
     ptpNew = _allocTokenPrivileges(privCount);
   }


   ResetPrivileges* resetter = 0;
   try {
     int i = privCount;
     LUID_AND_ATTRIBUTES* j = ptpNew->Privileges + privCount;
     while (i--) {
       _setupEnabledLuidAndAttributes(privs[i], --j);
     }


     int cb = 0;
     if (wantResetObject) {
       resetter = new ResetPrivileges(ident, privCount, &cb);
     }


     HANDLE htok = ident->Token.ToPointer();
     DWORD dummy;
     if (!AdjustTokenPrivileges(htok, FALSE, ptpNew, (DWORD)cb,
                      resetter ? resetter->old : 0, &dummy)) {
       throwWin32Exception(S"AdjustTokenPrivileges failed");
     }
     if (ERROR_NOT_ALL_ASSIGNED == GetLastError()) {
       throw new ApplicationException(S"One or more privileges "
         + "could not be enabled: the most likely problem is "
         + "that the token being adjusted does not have one "
         + "or more of the requested privileges");
     }
   }
   __finally {
     if (privCount > 1) {
       LocalFree(ptpNew);
     }
   }
   return resetter;
 }


 static TOKEN_PRIVILEGES* _allocTokenPrivileges(int privCount,
                                                int* pcb) {
   const size_t cb = sizeof(TOKEN_PRIVILEGES) +
     ((privCount - 1) * sizeof(LUID_AND_ATTRIBUTES));
   void* p = LocalAlloc(LMEM_FIXED, cb);
   if (!p) {
     throw new OutOfMemoryException(S"LocalAlloc failed");
   }
   if (pcb) *pcb = cb;
   return (TOKEN_PRIVILEGES*)p;
 }


 static void _setupEnabledLuidAndAttributes(String* priv,
                                    LUID_AND_ATTRIBUTES* p) {
   const wchar_t __pin* internalPriv = PtrToStringChars(priv);
   if (!LookupPrivilegeValue(0, internalPriv, &p->Luid)) {
     throw new ArgumentException(S"Unrecognized privilege name",
                                 priv);
   }
   p->Attributes = SE_PRIVILEGE_ENABLED;
 }

Figure 22.1 Enabling a privilege from Managed C++

The key Win32 function here is AdjustTokenPrivileges, which is what enables or disables privileges in a token. Each privilege in a token is represented with a 64-bit "Locally Unique Identifier" (LUID), which is allowed to change across reboots of the machine. So, before enabling privileges in a token, you need to look up the LUID for each one you plan on enabling. This is what LookupPrivilegeValue is for. Given a string like "SeBackupPrivilege", this function will look up the corresponding LUID.

The AdjustTokenPrivileges function can also return a data structure that indicates the previous state of the privileges you enabled. This makes it really easy to reset them after you're done using them, which is what my ResetPrivileges class is for. Because this class implements IDisposable, C# programmers can rely on a using statement to disable a privilege when it's no longer needed. Here's some sample code that shows how this works. For the entire sample library, see the website for the book.

 using (ResetPrivileges r =
        Token.EnablePrivilege(WindowsIdentity.GetCurrent(),
                              "SeShutdownPrivilege", true)) {
   // use the privilege...
 } // privilege will be disabled again here

PortedBy KeithBrown

PluralsightTraining

Keith's first book-in-a-wiki. If you would like to read the book online or order a physical copy to throw at annoying coworkers, surf to the HomePage. Please note that due to overwhelming wikispam, this particular wiki is no longer editable.

About FlexWiki.

Recent Topics