Changing Integrity Levels
There are times when you might want to create a process with a different integrity level than your current process. For example, you might want to launch IE at medium or low integrity from an installer that is running at high integrity. If you just call CreateProcess, then IE would be launched at high integrity instead of low, and would not run in protected mode.
There are plenty of samples on the net showing how to do this, for example: http://www.codeproject.com/KB/vista-security/createprocessexplorerleve.aspx?display=Print
The commonly shown technique is simple: Get the token that is used by explorer.exe (in the current session), and use CreateProcessWithTokenW to create the new process using the explorer.exe security token. Note that the key to these techniques is to use CreateProcessWithTokenW, and not CreateProcessAsUser because user accounts do not typically have the necessary privileges to call CreateProcessAsUser.
Creating Processes from Services
There are other times when you might want to create a process on behalf of a user in a particular session from a service (running as SYSTEM). An example of this scenario would be a broker service for an IE extension, where you may want to execute the process under an administrative account, but in the same session as a particular user.
You might think you could use the same technique as above where you just get the token from the process you want to emulate (e.g. winlogon.exe to execute as SYSTEM), modify the token to use the desired session ID, and use CreateProcessWithTokenW to create the process. However, you would find that for reasons unknown, you cannot use CreateProcessWithTokenW to create a process in a different session (as revealed by MSFT here: http://social.msdn.microsoft.com/Forums/en-US/windowssecurity/thread/f38b0dd4-d69f-4b7e-b85c-af40a1425636/)
In this case you will need to use CreateProcessAsUser, which you can use if you are running under the SYSTEM account.
Which Session to Use?
A frequent, if troubling, question I've seen asked is how to get a handle on the "current" session so a process can be created from a service in the "correct" session and not in the service session. Perhaps more troubling is the frequent display of examples of how to get the "active" session. Even on reputable sites like codeproject.com.
Here is an entertaining exerpt from Raymond Chen's blog on the topic:
Original source: http://blogs.msdn.com/oldnewthing/archive/2006/08/22/712677.aspx
How do I impersonate the currently logged-on user?"
"Which user? There can be more than one. "
"I want the one on the desktop."
"They all have their own desktop."
"I want the one on the current desktop."
"What do you mean by 'the' current desktop? There is one current desktop for each user."
"I want the desktop I should display my UI on."
"Your question has become circular. You want to display your UI on the desktop that your UI should be displayed on."
The answer is: You have to know which session to create a process in. If you are writing a broker service, then your communication with your service should include the session from which the original request is being made so the service knows where to display the UI. And the service can then use that to create the new process in the correct session.
Putting it all together
To meet all of the needs above, I created a simple helper function that looks like this:
BOOL ExecuteWithProcessTokenW(
DWORD dwSessionId,
LPCWSTR pwszCmdLine,
LPCWSTR pwszProcessName,
PROCESS_INFORMATION *pi);
To make sure this function will work from either a service or a user account and create the process in the correct session, this function first attempts to use CreateProcessAsUser (which works from the SYSTEM account and can specify a different session id), and then falls back to CreateProcessWithTokenW if that fails (which works from a standard user account).
hope that helps.