How do I get a valid user token for CreateProcessAsUser?

Björn picture Björn · Apr 7, 2009 · Viewed 7k times · Source

I have an application that is running as normal user, and a service running as local system. I want the application to be able to tell the service to start the application again, once the service has done some other stuff. (So the application will not be running while the service is doing it's "thing".) In order for the service to be able to start the application as the user that first started it, it needs a user token. The application sends the token to the service before it quits, but the token/handle is invalid when the service is trying to use it. (First thing it does with it is DuplicateTokenEx to get a primary token.)

Is a user token always only valid in the process that called OpenProcessToken?

Is there some other way this could be done? I don't want the user having to "log on" to the application with logonuser. That would just be silly. I guess I could hand over a process handle for "explorer.exe" from the app to the service, which the service could use to get a user token, but that would require PROCESS DUP HANDLE access right. I'm not thrilled about that solution, but maybe it's the way to do it?

Answer

Stephen Martin picture Stephen Martin · Apr 7, 2009

You have multiple issues here so I'll try to address them separately and you can correct me if I have misunderstood:

  1. You appear to have a service and a user application that cannot execute certain functionality at the same time. In order to achieve this you have the service stop the application, execute the special functionality, then restart the application. If this is correct then, in my opinion, you have a design flaw. Rather than stopping, then restarting the application you should be coordinating access to the shared resource through mutual exclusion using a named mutex and/or using an IPC method such as named pipes to communicate intentions.

  2. Is a user token always only valid in the process that called OpenProcessToken? Yes, the token handle you received is an index into the handle table of the process, it is not directly transferable. You would need to use DuplicateHandle which may be what you want but could be messy.

  3. You wish to find the best way to get the user's token to launch the application into the user's (interactive?) session. If this is the case, the best way is to retrieve the user's session token and use that. You can check out this article and the sample code, it's in C# but should be relatively easy to transfer to your language of choice.

EDIT: Updated to include Windows 2000. Since you are running the service under the SYSTEM account it can open a handle to the process itself (if necessary the process can send its process ID). It can then open the token attached to that process, duplicate it and use the resultant token to launch (or re-launch) the target application.