How To Manage User Privileges Programmatically in Windows NT

This article was previously published under Q132958
In Windows NT, privileges are used to provide a means of access controlthat differs from discretionary access control. A system manager usesprivileges to control which users/groups are able to manipulate variousaspects of the system. An application may use privileges when it changes asystem resource, such as the system time, or when it shuts down the system.

The User Manager tool can be used to grant and revoke privileges fromaccounts.

Windows NT 3.51 provides functionality which allows the developer to manageprivileges programmatically. This functionality is made available throughLSA (Local Security Authority).

An example of an application that would benefit from LSA is a serviceinstall program. If the service is configured to run under a user account,it is necessary for that account to have the SeServiceLogonRight "logon asa service" privilege. This article discusses how to take advantage of LSAto grant and revoke privileges from users and groups.
Managing user privileges can be achieved programmatically using thefollowing steps:
  1. Open the policy on the target machine with LsaOpenPolicy(). To grant privileges, open the policy with POLICY_CREATE_ACCOUNT and POLICY_LOOKUP_NAMES access. To revoke privileges, open the policy with POLICY_LOOKUP_NAMES access.
  2. Obtain a SID (security identifier) representing the user/group of interest. The LookupAccountName() and LsaLookupNames() APIs can obtain a SID from an account name.
  3. Call LsaAddAccountRights() to grant privileges to the user(s) represented by the supplied SID.
  4. Call LsaRemoveAccountRights() to revoke privileges from the user(s) represented by the supplied SID.
  5. Close the policy with LsaClose().
To successfully grant and revoke privileges, the caller needs to be anadministrator on the target system.

The LSA API LsaEnumerateAccountRights() can be used to determine whichprivileges have been granted to an account.

The LSA API LsaEnumerateAccountsWithUserRight() can be used to determinewhich accounts have been granted a specified privilege.

Documentation and header files for these LSA APIs is provided in theWindows 32 SDK in the MSTOOLS\SECURITY directory.

In the lastest versions of the Win32 SDK, the headers appear in themstools\samples\win32\winnt\security\include directory and thedocumentation is in ....\security\lsasamp\lsaapi.hlp.

NOTE: These LSA APIs are currently implemented as Unicode only.

This sample will grant the privilege SeServiceLogonRight to the accountspecified on argv[1].

This sample is dependant on these import libs
advapi32.lib (for LsaXxx)
user32.lib (for wsprintf)
This sample will work properly compiled ANSI or Unicode.

Sample Code

/*++You can use domain\account as argv[1]. For instance, mydomain\scott willgrant the privilege to the mydomain domain account scott.The optional target machine is specified as argv[2], otherwise, theaccount database is updated on the local machine.The LSA APIs used by this sample are Unicode only.Use LsaRemoveAccountRights() to remove account rights.Scott Field (sfield)    12-Jul-95--*/ #ifndef UNICODE#define UNICODE#endif // UNICODE#include <windows.h>#include <stdio.h>#include "ntsecapi.h"NTSTATUSOpenPolicy(    LPWSTR ServerName,          // machine to open policy on (Unicode)    DWORD DesiredAccess,        // desired access to policy    PLSA_HANDLE PolicyHandle    // resultant policy handle    );BOOLGetAccountSid(    LPTSTR SystemName,          // where to lookup account    LPTSTR AccountName,         // account of interest    PSID *Sid                   // resultant buffer containing SID    );NTSTATUSSetPrivilegeOnAccount(    LSA_HANDLE PolicyHandle,    // open policy handle    PSID AccountSid,            // SID to grant privilege to    LPWSTR PrivilegeName,       // privilege to grant (Unicode)    BOOL bEnable                // enable or disable    );voidInitLsaString(    PLSA_UNICODE_STRING LsaString, // destination    LPWSTR String                  // source (Unicode)    );voidDisplayNtStatus(    LPSTR szAPI,                // pointer to function name (ANSI)    NTSTATUS Status             // NTSTATUS error value    );voidDisplayWinError(    LPSTR szAPI,                // pointer to function name (ANSI)    DWORD WinError              // DWORD WinError    );#define RTN_OK 0#define RTN_USAGE 1#define RTN_ERROR 13// // If you have the ddk, include ntstatus.h.// #ifndef STATUS_SUCCESS#define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)#endifint _cdeclmain(int argc, char *argv[]){    LSA_HANDLE PolicyHandle;    WCHAR wComputerName[256]=L"";   // static machine name buffer    TCHAR AccountName[256];         // static account name buffer    PSID pSid;    NTSTATUS Status;    int iRetVal=RTN_ERROR;          // assume error from main    if(argc == 1)    {        fprintf(stderr,"Usage: %s <Account> [TargetMachine]\n",            argv[0]);        return RTN_USAGE;    }    //     // Pick up account name on argv[1].    // Assumes source is ANSI. Resultant string is ANSI or Unicode    //     wsprintf(AccountName, TEXT("%hS"), argv[1]);    //     // Pick up machine name on argv[2], if appropriate    // assumes source is ANSI. Resultant string is Unicode.    //     if(argc == 3) wsprintfW(wComputerName, L"%hS", argv[2]);    //     // Open the policy on the target machine.    //     if((Status=OpenPolicy(                wComputerName,      // target machine                POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,                &PolicyHandle       // resultant policy handle                )) != STATUS_SUCCESS) {        DisplayNtStatus("OpenPolicy", Status);        return RTN_ERROR;    }    //     // Obtain the SID of the user/group.    // Note that we could target a specific machine, but we don't.    // Specifying NULL for target machine searches for the SID in the    // following order: well-known, Built-in and local, primary domain,    // trusted domains.    //     if(GetAccountSid(            NULL,       // default lookup logic            AccountName,// account to obtain SID            &pSid       // buffer to allocate to contain resultant SID            )) {        //         // We only grant the privilege if we succeeded in obtaining the        // SID. We can actually add SIDs which cannot be looked up, but        // looking up the SID is a good sanity check which is suitable for        // most cases.        //         // Grant the SeServiceLogonRight to users represented by pSid.        //         if((Status=SetPrivilegeOnAccount(                    PolicyHandle,           // policy handle                    pSid,                   // SID to grant privilege                    L"SeServiceLogonRight", // Unicode privilege                    TRUE                    // enable the privilege                    )) == STATUS_SUCCESS)            iRetVal=RTN_OK;        else            DisplayNtStatus("AddUserRightToAccount", Status);    }    else {        //         // Error obtaining SID.        //         DisplayWinError("GetAccountSid", GetLastError());    }    //     // Close the policy handle.    //     LsaClose(PolicyHandle);    //     // Free memory allocated for SID.    //     if(pSid != NULL) HeapFree(GetProcessHeap(), 0, pSid);    return iRetVal;}voidInitLsaString(    PLSA_UNICODE_STRING LsaString,    LPWSTR String    ){    DWORD StringLength;    if (String == NULL) {        LsaString->Buffer = NULL;        LsaString->Length = 0;        LsaString->MaximumLength = 0;        return;    }    StringLength = wcslen(String);    LsaString->Buffer = String;    LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);    LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);}NTSTATUSOpenPolicy(    LPWSTR ServerName,    DWORD DesiredAccess,    PLSA_HANDLE PolicyHandle    ){    LSA_OBJECT_ATTRIBUTES ObjectAttributes;    LSA_UNICODE_STRING ServerString;    PLSA_UNICODE_STRING Server = NULL;    //     // Always initialize the object attributes to all zeroes.    //     ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));    if (ServerName != NULL) {        //         // Make a LSA_UNICODE_STRING out of the LPWSTR passed in        //         InitLsaString(&ServerString, ServerName);        Server = &ServerString;    }    //     // Attempt to open the policy.    //     return LsaOpenPolicy(                Server,                &ObjectAttributes,                DesiredAccess,                PolicyHandle                );}/*++This function attempts to obtain a SID representing the suppliedaccount on the supplied system.If the function succeeds, the return value is TRUE. A buffer isallocated which contains the SID representing the supplied account.This buffer should be freed when it is no longer needed by callingHeapFree(GetProcessHeap(), 0, buffer)If the function fails, the return value is FALSE. Call GetLastError()to obtain extended error information.Scott Field (sfield)    12-Jul-95--*/ BOOLGetAccountSid(    LPTSTR SystemName,    LPTSTR AccountName,    PSID *Sid    ){    LPTSTR ReferencedDomain=NULL;    DWORD cbSid=128;    // initial allocation attempt    DWORD cchReferencedDomain=16; // initial allocation size    SID_NAME_USE peUse;    BOOL bSuccess=FALSE; // assume this function will fail    __try {    //     // initial memory allocations    //     if((*Sid=HeapAlloc(                    GetProcessHeap(),                    0,                    cbSid                    )) == NULL) __leave;    if((ReferencedDomain=(LPTSTR)HeapAlloc(                    GetProcessHeap(),                    0,                    cchReferencedDomain * sizeof(TCHAR)                    )) == NULL) __leave;    //     // Obtain the SID of the specified account on the specified system.    //     while(!LookupAccountName(                    SystemName,         // machine to lookup account on                    AccountName,        // account to lookup                    *Sid,               // SID of interest                    &cbSid,             // size of SID                    ReferencedDomain,   // domain account was found on                    &cchReferencedDomain,                    &peUse                    )) {        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {            //             // reallocate memory            //             if((*Sid=HeapReAlloc(                        GetProcessHeap(),                        0,                        *Sid,                        cbSid                        )) == NULL) __leave;            if((ReferencedDomain=(LPTSTR)HeapReAlloc(                        GetProcessHeap(),                        0,                        ReferencedDomain,                        cchReferencedDomain * sizeof(TCHAR)                        )) == NULL) __leave;        }        else __leave;    }    //     // Indicate success.    //     bSuccess=TRUE;    } // finally    __finally {    //     // Cleanup and indicate failure, if appropriate.    //     HeapFree(GetProcessHeap(), 0, ReferencedDomain);    if(!bSuccess) {        if(*Sid != NULL) {            HeapFree(GetProcessHeap(), 0, *Sid);            *Sid = NULL;        }    }    } // finally    return bSuccess;}NTSTATUSSetPrivilegeOnAccount(    LSA_HANDLE PolicyHandle,    // open policy handle    PSID AccountSid,            // SID to grant privilege to    LPWSTR PrivilegeName,       // privilege to grant (Unicode)    BOOL bEnable                // enable or disable    ){    LSA_UNICODE_STRING PrivilegeString;    //     // Create a LSA_UNICODE_STRING for the privilege name.    //     InitLsaString(&PrivilegeString, PrivilegeName);    //     // grant or revoke the privilege, accordingly    //     if(bEnable) {        return LsaAddAccountRights(                PolicyHandle,       // open policy handle                AccountSid,         // target SID                &PrivilegeString,   // privileges                1                   // privilege count                );    }    else {        return LsaRemoveAccountRights(                PolicyHandle,       // open policy handle                AccountSid,         // target SID                FALSE,              // do not disable all rights                &PrivilegeString,   // privileges                1                   // privilege count                );    }}voidDisplayNtStatus(    LPSTR szAPI,    NTSTATUS Status    ){    //     // Convert the NTSTATUS to Winerror. Then call DisplayWinError().    //     DisplayWinError(szAPI, LsaNtStatusToWinError(Status));}voidDisplayWinError(    LPSTR szAPI,    DWORD WinError    ){    LPSTR MessageBuffer;    DWORD dwBufferLength;    //     // TODO: Get this fprintf out of here!    //     fprintf(stderr,"%s error!\n", szAPI);    if(dwBufferLength=FormatMessageA(                        FORMAT_MESSAGE_ALLOCATE_BUFFER |                        FORMAT_MESSAGE_FROM_SYSTEM,                        NULL,                        WinError,                        GetUserDefaultLangID(),                        (LPSTR) &MessageBuffer,                        0,                        NULL                        ))    {        DWORD dwBytesWritten; // unused        //         // Output message string on stderr.        //         WriteFile(            GetStdHandle(STD_ERROR_HANDLE),            MessageBuffer,            dwBufferLength,            &dwBytesWritten,            NULL            );        //         // Free the buffer allocated by the system.        //         LocalFree(MessageBuffer);    }}				
/*++This function enables system access on the account represented by thesupplied SID. An example of such access is the SeLogonServiceRight.Note: to disable a given system access, simply remove the suppliedaccess flag from the existing flag, and apply the result to theaccount.If the function succeeds, the return value is STATUS_SUCCESS.If the function fails, the return value is an NTSTATUS value.Scott Field (sfield)    14-Jul-95--*/ NTSTATUSAddSystemAccessToAccount(   LSA_HANDLE PolicyHandle,   PSID AccountSid,   ULONG NewAccess   ){   LSA_HANDLE AccountHandle;   ULONG PreviousAccess;   NTSTATUS Status;   //    // open the account object. If it doesn't exist, create a new one   //    if((Status=LsaOpenAccount(           PolicyHandle,           AccountSid,           ACCOUNT_ADJUST_SYSTEM_ACCESS | ACCOUNT_VIEW,           &AccountHandle           )) == STATUS_OBJECT_NAME_NOT_FOUND)   {       Status=LsaCreateAccount(               PolicyHandle,               AccountSid,               ACCOUNT_ADJUST_SYSTEM_ACCESS | ACCOUNT_VIEW,               &AccountHandle               );   }   //    // if an error occurred opening or creating, return   //    if(Status != STATUS_SUCCESS) return Status;   //    // obtain current system access flags   //    if((Status=LsaGetSystemAccessAccount(           AccountHandle,           &PreviousAccess           )) == STATUS_SUCCESS)   {       //        // Add the specified access to the account       //        Status=LsaSetSystemAccessAccount(               AccountHandle,               PreviousAccess | NewAccess               );   }   LsaClose(AccountHandle);   return Status;}/*++This function grants a privilege to the account represented by thesupplied SID. An example of such a privilege is theSeBackupPrivilege.Note: To revoke a privilege, use LsaRemovePrivilegesFromAccount.If the function succeeds, the return value is STATUS_SUCCESS.If the function fails, the return value is an NTSTATUS value.Scott Field (sfield)    13-Jul-95--*/ NTSTATUSAddPrivilegeToAccount(   LSA_HANDLE PolicyHandle,   PSID AccountSid,   LPWSTR PrivilegeName   ){   PRIVILEGE_SET ps;   LUID_AND_ATTRIBUTES luidattr;   LSA_HANDLE AccountHandle;   LSA_UNICODE_STRING PrivilegeString;   NTSTATUS Status;   //    // Create a LSA_UNICODE_STRING for the privilege name   //    InitLsaString(&PrivilegeString, PrivilegeName);   //    // obtain the LUID of the supplied privilege   //    if((Status=LsaLookupPrivilegeValue(           PolicyHandle,           &PrivilegeString,           &luidattr.Luid           )) != STATUS_SUCCESS) return Status;   //    // setup PRIVILEGE_SET   //    luidattr.Attributes=0;   ps.PrivilegeCount=1;   ps.Control=0;   ps.Privilege[0]=luidattr;   //    // open the account object if it doesn't exist, create a new one   //    if((Status=LsaOpenAccount(           PolicyHandle,           AccountSid,           ACCOUNT_ADJUST_PRIVILEGES,           &AccountHandle           )) == STATUS_OBJECT_NAME_NOT_FOUND)   {       Status=LsaCreateAccount(               PolicyHandle,               AccountSid,               ACCOUNT_ADJUST_PRIVILEGES,               &AccountHandle               );   }   //    // if an error occurred opening or creating, return   //    if(Status != STATUS_SUCCESS) return Status;   //    // add the privileges to the account   //    Status=LsaAddPrivilegesToAccount(           AccountHandle,           &ps           );   LsaClose(AccountHandle);   return Status;}				
Privilege User Right

ID d'article : 132958 - Dernière mise à jour : 03/01/2005 15:35:00 - Révision : 3.2

Microsoft Win32 Application Programming Interface

  • kbhowto kbapi kbkernbase kbsecurity kblsa KB132958