Some functions (like ExitWindowsEx) need a privilege (SE_SHUTDOWN_NAME) to be enabled to work properly.
With the help of JWSCL this task is made very easy.

JWSCL provides several ways to enable and disable privileges.

  1. Use the methods of TJwSecurityToken
  2. Use the function JWEnablePrivilege
  3. Use the interface IJwPrivilegeScope

1. Use the methods of TJwSecurityToken

You can use TJwSecurityToken to enable, disable or test a privilege. However there are some tool functions that do it for you already in only a single call. They are called

2.Use the function JwEnablePrivilege and friends

A very convienient way to enable and disable a privilege is to use the function JwEnablePrivilege.

type
  TJwPrivilegeSetType =
   (pst_Enable , pst_EnableIfAvail ,pst_Disable);

function JwEnablePrivilege (const Index : string;
  const Query : JwPrivilegeSetType): boolean;

There are two ways to enabe a privilege and one way to disable it.

  1. Enable a privilege or die if the privilege does not exist
    try
      JwEnablePrivilege(SE_DEBUG_NAME, pst_Enable);
    except
      on E: EJwsclPrivilegeException do
       //do error stuff here
    end;

    You should check for the exception EJwsclPrivilegeException because if the flag pst_Enable is used, the function raises the exception when the privilege does not exist.

  2. Enable a privilege only if it exists
    JwEnablePrivilege(SE_DEBUG_NAME, pst_EnableIfAvail);

    The code above may or may not enable the privilege depending on its availability. This is sometimes useful if you do not really need a privilege, but it might come handy if available. For example you could use SE_DEBUG_NAME privilege in a call to OpenProcess to open a foreign process. In the worst case that happens without the process is that OpenProcess will fail on processes that were not executed by the same user. However in each case you have to check the result of OpenProcess.

  3. Disable a privilege
    Disabling a privilege is not much work. It even won’t throw an exception if the privilege does not exist.

    JwEnablePrivilege(SE_DEBUG_NAME, pst_Disable);

To find out whether a special privilege is available use JwIsPrivilegeSet.
The following code illustrates how to use JwIsPrivilegeSet.

uses JwsclToken;…      

  if JwIsPrivilegeSet(SE_DEBUG_NAME, pqt_Available) then
  begin
    if JwIsPrivilegeSet(SE_DEBUG_NAME, pqt_Enabled) then
      JwEnablePrivilege(SE_DEBUG_NAME, pst_Disable)
    else
      JwEnablePrivilege(SE_DEBUG_NAME, pst_Enable);
  end;

With this helper function JwEnablePrivilege won’t throw the exception EJwsclPrivilegeException if the privilege is not available.
A handy function is JwGetPrivilegesText, which returns a string of available privileges and their status. You also can define which privileges are shown.

JwGetPrivilegesText comes in two versions. The first version does not have any parameters and just returns a string with privilege names and their status. Each privilege is separated by a line break.

WriteLn(JwGetPrivilegesText);

The output may look like depending on your status. The following privileges are from a standard user in Vista:

SeShutdownPrivilege [disabled]
SeChangeNotifyPrivilege [enabled]
SeUndockPrivilege [disabled]
SeIncreaseWorkingSetPrivilege [disabled]
SeTimeZonePrivilege [disabled]

The second version of JwGetPrivilegesText receives a list of privileges you want to be displayed:

WriteLn(JwGetPrivilegesText([
  SE_CHANGE_NOTIFY_NAME,
  SE_DEBUG_NAME,
  SE_SHUTDOWN_NAME,
  SE_CHANGE_NOTIFY_NAME]));

The output may look like this:

SeChangeNotifyPrivilege [enabled]
SeDebugPrivilege [not available]
SeShutdownPrivilege [disabled]
SeChangeNotifyPrivilege [enabled]

Multipe threads and privileges:

You should always use a thread token when you work with several threads. Enabling and disabling privileges on a process token is very problematic. The reason is that you enable or disable a privilege for all threads. If a single thread enables a privilege and another one disables it, the first thread will fail to call a function that depends on that privilege.
It is possible to introduce lock mechanisms like semaphores. But this is not necessary because each thread can (and should) have its own token: An impersonated token or in other words : a thread token.

To use a thread token properly you have to add this code to your main thread function.

procedure TMyThread.Execute;
var Token : TJwSecurityToken;
begin
  Token := TJwSecurityToken.CreateTokenEffective(MAXIMUM_ALLOWED);
  try
    //check for error result
    //you should proceed very carefully if the call fails
    Token.ImpersonateLoggedOnUser;
  except
   on E1 :  EJwsclAccessTypeException do
     //will be raised if the token is an impersonation token and does not have access type TOKEN_QUERY and TOKEN_IMPERSONATE)
   on E2 : EJwsclAccessTypeException do
     //will be raised if the token is a primary token and does not have access type TOKEN_QUERY and TOKEN_DUPLICATE)
   on E3 : EJwsclSecurityException do
     //will be raised if a winapi function failed
  end;      

 try
   //do your thread stuff here
  finally
    Token.Free;
    Token := nil;
  end;
end;

ImpersonateLoggedOnUser has a lot of possible exception handlers. This is because there are several ways how the call can fail. You should make sure that your main thread code is not executed without an assigned thread token.

Additionally you should also never call TerminateThread or ExitThread because in this case the finally Block would not be executed (memory leak).

3. Use the interface IJwPrivilegeScope

It is always a good thing to disable a privilege after it was used. The only way to do it safe is to use a try finally catch. If something happens the privilege is disabled at least.

try
  wEnablePrivilege ( SE_SHUTDOWN_NAME , pst_Enable );
except
  on E : EJwsclPrivilegeException do
  // error handling
end;      

try
  //do your stuff here
finally
  JwEnablePrivilege ( SE_SHUTDOWN_NAME , pst_Disable);
end;

This codes needs a lot of work to write if several other privileges are necessary. Fortunately there is a way to accomplish this task much more convenient. We use COM and the unit JwsclPrivileges which implements the interface IJwPrivilegeScope.
IJwPrivilegeScope allows to enable several privileges at once and also disable them as soon as the internal reference counter drops to zero. A huge advantage is that Delphi helps a lot with the reference counting. It automatically increases or decreases the reference counter for several actions like passing the interface to another function. Find out more about scopes and Delphi’s reference counting for interfaces here.
The automatic privilege mangagment can be used in the following way:

procedure YourClass.FooMethod;
var Privs : IJwPrivilegeScope;
begin
  try
    Privs := JwGetPrivilegeScope([SE_SHUTDOWN_NAME, SE_TCB_NAME, SE_SECURITY_NAME]);
  except
    on E : EJwsclPrivilegeException do
      //do things on error and exit
  end;
  //do things on success that needs privileges enabled
end; //here the privileges are automatically disabled      

begin
  FooMethod;
  //SE_SHUTDOWN_NAME, SE_TCB_NAME, SE_SECURITY_NAME are disabled.

The interface Privs will run out of scope as soon as the method FooMethod exits. In this last step the activated privileges are disabled automatically.
If you combine this mechanism with the thread token shown in “procedure TYourThread.Execute;” you can easily play with privileges without disturbing other thread tokens. However you need a thread token only if you run several threads. In a single thread application the effort isn’t usually necessary for the discussed task (but there may be exceptions).

var Text : String ;      

procedure YourClass.FooMethod;
var PrivScope : IJwPrivilegeScope ;
begin
  // Privilege is only active in this procedure
  PrivScope := JwGetPrivilegeScope ([ SE_SHUTDOWN_NAME ],
          pst_EnableIfAvail );
  Text := JwGetPrivilegesText ([ SE_SHUTDOWN_NAME ]); // enabled
  writeln(Text);
end;      

var ImpToken : TJwSecurityToken;
begin
  // create thread token from the process token
  ImpToken := TJwSecurityToken . CreateTokenByProcess (0,
    TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY or TOKEN_READ or
    TOKEN_IMPERSONATE or TOKEN_DUPLICATE );      

  try
    ImpToken . ImpersonateLoggedOnUser ;
  except
    //exception handling left out
  end;      

  try
    FooMethod;
  finally
    ImpToken.Free;
  end;
end


Some hints to remember:

  1. You cannot add privileges that were not granted to the token. There are two ways to do so with a SYSTEM account (like a service)
    1. Use another process token that contains the necessary privilege
    2. Create your own token by using LsaLogonUser. It allows to add groups and privileges.

    Be warned that using these mechanisms incorrectly may create a security hole.

  2. You can remove privileges by recreating the token using CreateRestrictedToken. The new token is then called restricted token. Maybe you already know the word from Vista and the twin token.
  3. Using a (restricted) thread token on code that is not trustworthy is very risky because the code can always return to the process token. This is done by calling RevertToSelf. In this case you must execute the code in a seperate process. Create the process with CreateProcessAsUser and pass the (restricted) token to the hToken parameter. If you fear the inter-process communication you can also use an out-of process COM DLL.
  4. Always use an exception handler if the method could raise an exception. If an exception is raised within a thread, the thread will immediately stop working and leave resource leaks.
  5. Do not force a user to have a special privilege. Many privileges aren’t needed anyway. For example, the SE_DEBUG_NAME privilege – despite its name – isn’t needed for debugging applications. In fact you can debug an application that was started under your user’s account. However you need the debug privilege only for foreign processes. This includes system processes of course. Raymond answers the question why the debug privilege grants administrator accesss.

Tell me how you liked this blog entry by adding a comment.