Vista User Access Control and Visual C++

Windows Vista introduces a new security concept called User Access Control (UAC), where local administrators have two access tokens one representing the privileges of a normal user and the other holding the elevated privileges of the local administrator account. By default, an application will run using the lower-privileged token, and this can cause problems if the application attempts an operation that requires the privileges of the local administrator. Windows Vista has various built-in mechanisms that are designed to minimise unintended problems caused by UAC, but there are scenarios where the UAC-handling strategies of Vista may cause unexpected behaviour. This article covers these scenarios, and how Visual C++ developers can deal with them.

Microsoft has been encouraging users to stop running as local administrators for a long time, and this push is reliant on applications that run effectively when not executed under the local administrator account. There are a number of operations that will not work when a user is not running as a local administrator writing to the Program Files directory and Windows directory, opening system-wide Registry keys with write permission, and using WMI to make changes in operating system setting such as power management settings and the system clock. UAC represents an increase in Microsoft’s vigour to end the practice of average users running as local administrators, and every time an application running under the privileges of a local administrator on Vista with UAC enabled attempts an operation that requires elevated privileges, a dialog is shown asking the end-user to authorize the operation, as shown in Figure 1.

Figure 1: Admin Approval Prompt

Although the Admin Approval Prompt is the most visible component of UAC, there is another feature that acts silently and has the potential to cause a significant degree of confusion among developers who write applications that require a full admin token to execute correctly. To understand this new feature, it is worth first briefly considering the motivation for its inclusion. Many applications write a log file to the directory they are installed to, which is typically in the %ProgramFiles% directory. This action, while it requires administrator privileges, is actually fairly benign, and throwing up an Admin Approval Prompt for every application that attempts to write to the %ProgramFiles% directory could create a storm of prompts, particularly as a user logs in and auto-run applications begin firing up and opening a log file. Changing the behaviour of Windows to allow these %ProgramFiles% writes under a non-admin account would open up a huge hole in Windows security, as less privileged applications could inject malicious code in the binary of an application known to run with elevated privileges, so the course of action taken was to virtualize %ProgramFiles% and re-direct writes to a safe location. This has the dual benefits of avoiding an Admin Approval Prompt, and allowing legacy applications to run on Windows Vista under a non-admin account.

Virtualization is a short-term compatibility feature, and Microsoft has made it clear that developers should not rely on the feature for their applications to work correctly.

Consider the following simple C++ application:

int _tmain(int argc, _TCHAR* argv[])
{
   HANDLE hLogFile = CreateFile(_T("c:\\Program Files\\log.txt"),
   FILE_ALL_ACCESS,
   FILE_SHARE_WRITE,
   NULL,
   OPEN_ALWAYS,
   FILE_ATTRIBUTE_NORMAL,
   NULL
);

if (INVALID_HANDLE_VALUE == hLogFile)
   return ::GetLastError();

TCHAR* logText = _T("Text to log\n");

DWORD lengthWritten;
WriteFile(hLogFile, logText, sizeof(TCHAR) * _tcslen(logText),
          &lengthWritten, NULL);

CloseHandle(hLogFile);

return 0;
}

The code has obvious problems. The path to %ProgramFiles% is hard-coded, and the application attempts to write a log file to this directory. When run as a local administrator on Windows XP, this code works fine, and the log file is created. On Windows Vista, the code appears to work fine, but no file is present in c:\Program Files after the code finishes executing, as shown in Figure 2.

Figure 2: Windows Explorer View of Program Files

Notice the Compatibility Files button on the toolbar in Figure 2. When clicked, this will navigate Windows Explorer to the location where virtualized files are stored, as shown in Figure 3. Notice that the location of the virtualized files is in a per-user store, and is in a location that works with features such as Roaming User Profiles and Folder Redirections.

Figure 3: Location of UAC Virtualized Files

Virtualization is a great feature for allowing legacy applications to work under Vista without requiring explicit user permission, but can cause a problem for applications that actually require the ability to write to directories protected through virtualization. For example, an organisation may have a utility application that can go through Program Files, find any .NET configuration file with a database connection string, and allow the user to change the connection string to a new value. A tool like this obviously needs to write to files in the real Program Files directory.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read