How do I get the original user token? UAC, manifest, installer


We have a program with manifest attached and option "level="requireAdministrator". After program launched under standard user(not as admin), its elevating to admin user and from that moment SHGetFolderPath(0,CSIDL_LOCAL_APPDATA,0,SHGFP_TYPE_CURRENT,@buf)) returns admin local directory but not user's where it was originally started. Of course we could pass standard user token as third parameter to SHGetFolderPath but how we can get it in elevated program? Is there any way to do it?

Of course because of this problem we have another question. How to start another program with ShellExecute not as admin in elevated program? Of course we could use CreateProcessWithTokenW but still the problem with token exists(how to get this token). Right now we looking for IShellDispatch2 interface and try to start application not as administrator using explorer, but something tells me that this is wrong way.

I know that we have to start program as standard user then using com objects elevate only parts of code which should be executed with admin's rights. But still, the main question is with token.

Also there was an idea to make manifest with "level="asInvoker" and start first program as standard user, detect all local user paths and pass it as parameters to ShellExecuteEx with runas and SEE_MASK_NOCLOSEPROCESS options and run the same program but as admin. After the elevated program will exit we can execute any program from not elevated program not as admin. Is this right way?

From Raymond Chen:

How can I launch an unelevated process from my elevated process and vice versa?

Going from an unelevated process to an elevated process is easy. You can run a process with elevation by passing the runas verb to Shell­Execute or Shell­Execute­Ex.

Going the other way is trickier. For one thing, it's really hard to munge your token to remove the elevation nature properly. And for another thing, even if you could do it, it's not the right thing to do, because the unelevated user may be different from the elevated user.

The solution here is to go back to Explorer and ask Explorer to launch the program for you. Since Explorer is running as the original unelevated user, the program will run as the original unelevated user.

i tried to translate the code out of C++, but it got too hairy to manage.

The short version is: it's very hard.