Windows Privileges
A privilege is the right of an account, such as a user or group account, to perform various system-related operations on the local computer, such as shutting down the system, loading device drivers, or changing the system time. Privileges differ from access rights in two ways:
Each system has an account database that stores the privileges held by user and group accounts. When a user logs on, the system produces an access token that contains a list of the user's privileges, including those granted to the user or to groups to which the user belongs. Note that the privileges apply only to the local computer; a domain account can have different privileges on different computers. For example, the user Rights assignments on the local computer can be seen through the Local Security Settings (Administrative Tools > Local Security Policy) snap-in. Keep in mind that for Windows server there are another two security policies: Domain Security Policy and DC Security Policy. We can just enable and disable the Windows Rights.
When the user tries to perform a privileged operation, the system checks the user's access token to determine whether the user holds the necessary privileges, and if so, it checks whether the privileges are enabled. If the user fails these tests, the system does not perform the operation. To determine the privileges held in an access token, call the GetTokenInformation() function, which also indicates which privileges are enabled. Most privileges are disabled by default. The Windows API defines a set of string constants, such as SE_ASSIGNPRIMARYTOKEN_NAME, to identify the various privileges. These constants are the same on all systems and are defined in winnt.h. However, the functions those get and adjust the privileges in an access token use the LUID type to identify privileges. The LUID values for a privilege can differ from one computer to another and from one boot to another on the same computer. To get the current LUID that corresponds to one of the string constants, use the LookupPrivilegeValue() function. Use the LookupPrivilegeName() function to convert a LUID to its corresponding string constant. The system provides a set of display names that describe each of the privileges. These are useful when you need to display a description of a privilege to the user. You can use the LookupPrivilegeDisplayName() function to retrieve a description string that corresponds to the string constant for a privilege. For example, on systems that use U.S. English, the display name for the SE_SYSTEMTIME_NAME privilege is Change the system time. You can use the PrivilegeCheck() function to determine whether an access token holds a specified set of privileges. This is useful primarily to server applications that are impersonating a client.
A system administrator can use administrative tools, such as User Manager, to add or remove privileges for user and group accounts. Administrators can programmatically use the LSA functions to work with privileges. The LsaAddAccountRights() and LsaRemoveAccountRights() functions add or remove privileges from an account. The LsaEnumerateAccountRights() function enumerates the privileges held by a specified account. The LsaEnumerateAccountsWithUserRight() function enumerates the accounts that hold a specified privilege. The information for LUID structure is given in the following Table. Do not manipulate LUID directly. Applications should use functions and structures to manipulate LUID values.
Running with Special Privileges
Some functions require special privileges to run correctly. In some cases, the function can only be run by certain users or by members of certain groups. The most common requirement is that the user be a local administrator. Other functions require the user's account to have specific privileges enabled. To reduce the possibility of unauthorized code being able to get control, the system should run with the least privilege necessary. Applications that need to call functions that require special privileges can leave the system open to attack by hackers. Such applications should be designed to run for short periods of time and should inform the user of the security implications involved.
Running with Administrator Privileges
The first step in establishing which type of account your application needs to run under is to examine what resources the application will use and what privileged APIs it will call. You may find that the applications, or large parts of it, do not require administrator privileges. You can provide the privileges your application needs with less exposure to malicious attack by using one of the following approaches:
If you have determined that your application must run under an account with administrator privileges and that an administrator password must be stored in the software system.
Asking the User for Credentials
Your application may need to prompt the user for user name and password information to avoid storing an administrator password or to verify that the token holds the appropriate privileges. However, simply prompting for credentials may train users to supply those to any random, unidentified dialog box that appears on the screen. The following procedure is recommended to reduce that training effect.
Acquiring user credentials
The recommended steps to properly acquire user credentials:
The following code snippet shows how to call CredUIPromptForCredentials() to ask the user for a user name and password. It begins by filling in a CREDUI_INFO structure with information about what prompts to use. Next, the code fills two buffers with zeros. This is done to ensure that no information gets passed to the function that might reveal an old user name or password to the user. The call to CredUIPromptForCredentials() brings up the dialog box. For security reasons, this example uses the CREDUI_FLAGS_DO_NOT_PERSIST flag to prevent the operating system from storing the password because it might then be exposed. If there are no errors, CredUIPromptForCredentials() fills in the pszName and pszPwd variables and returns zero. When the application has finished using the credentials, it should put zeros in the buffers to prevent the information from being accidentally revealed.
#include <windows.h>
#include <wincred.h>
CREDUI_INFO cui;
WCHAR pszName[CREDUI_MAX_USERNAME_LENGTH+1];
WCHAR pszPwd[CREDUI_MAX_PASSWORD_LENGTH+1];
BOOL fSave;
DWORD dwErr;
cui.cbSize = sizeof(CREDUI_INFO);
cui.hwndParent = NULL;
// Ensure that MessageText and CaptionText identify what credentials to use and which application requires them.
cui.pszMessageText = LEnter administrator account information;
cui.pszCaptionText = LCredUITest;
cui.hbmBanner = NULL;
fSave = FALSE;
SecureZeroMemory(pszName, sizeof(pszName));
SecureZeroMemory(pszPwd, sizeof(pszPwd));
dwErr = CredUIPromptForCredentials(
&cui, // CREDUI_INFO structure
LTheServer, // Target for credentials, usually a server
NULL, // Reserved
0, // Reason
pszName, // User name
CREDUI_MAX_USERNAME_LENGTH+1,// Max number of char for user name
pszPwd, // Password
CREDUI_MAX_PASSWORD_LENGTH+1,// Max number of char for password
&fSave, // State of save check box
CREDUI_FLAGS_GENERIC_CREDENTIALS | // flags
CREDUI_FLAGS_ALWAYS_SHOW_UI |
CREDUI_FLAGS_DO_NOT_PERSIST);
if(!dwErr)
{
// TODO: Put code that uses the credentials here.
// When you have finished using the credentials, erase them from memory.
SecureZeroMemory(pszName, sizeof(pszName));
SecureZeroMemory(pszPwd, sizeof(pszPwd));
}
Changing Privileges in a Token
You can change the privileges in either a primary or an impersonation token in two ways:
AdjustTokenPrivileges() cannot add or remove privileges from the token. It can only enable existing privileges that are currently disabled or disable existing privileges that are currently enabled. CreateRestrictedToken() has more extensive capabilities as follows:
Enabling and Disabling Privileges
Enabling a privilege in an access token allows the process to perform system-level actions that it could not previously. Your application should thoroughly verify that the privilege is appropriate to the type of account, especially for the following powerful privileges:
Privilege constant/string |
Display name |
SE_ASSIGNPRIMARYTOKEN_NAME (SeAssignPrimaryTokenPrivilege) |
Replace a process level token. |
SE_BACKUP_NAME (SeBackupPrivilege) |
Backup files and directories. |
SE_DEBUG_NAME (SeDebugPrivilege) |
Debug programs. |
SE_INCREASE_QUOTA_NAME (SeIncreaseQuotaPrivilege) |
Adjust memory quotas for a process. |
SE_TCB_NAME (SeTchPrivilege) |
Act as part of the operating system. |
Table 13 |
Before enabling any of these potentially dangerous privileges, determine that functions or operations in your code actually require the privileges. For example, very few functions in the operating system actually require the SeTchPrivilege.