How to invoke a function impersonating another user instead of SYSTEM - c++

A Win32 API was invoked in my DLL, which will be loaded by SYSTEM user, and that API returns different results depending on current user, so I cannot get the results corresponding to the current user, how can I invoke that API under current logon user context when the DLL is running in SYSTEM context?

I've made some research and concluded this (I'm not a Win32 API expert, but I'm really interested in it):
You can use ImpersonateLoggedOnUser, which asks for a primary or an impersonation token handle (with at least TOKEN_QUERY in both, TOKEN_DUPLICATE on a primary token, or TOKEN_IMPERSONATE on an impersonation token).
It would be very easy, if you had the current logged on user token, and the right privileges, you'd just use ImpersonateLoggedOnUser, call the API function that you want, and then call RevertToSelf to return to its original owner token.
But it's not that easy to get the current logged on user token. You'd have to either use LogonUser specifying the user's name and password (which doesn't seem right), or own a Windows service with sufficient privileges to let you call WTSQueryUserToken, which may differ from what type of project you are developing.
Or, if you are really willing to do this with an ordinary process, you could also explore the Authentication Functions, where you can take advantage of the newly Windows UAC and security contexts, which may be a little complex to work with.
There is also this method which I'm not sure if it works: Impersonate standard user (getting the token by using OpenProcessToken on explorer.exe).
Some links I found useful:
MSDN - Client Impersonation (Windows)
MSDN - Access Tokens (Windows)
MSDN - LsaLogonUser function (Windows)
A Simple Impersonation Program Example
CodeProject - User Impersonation
CodeProject - Vista UAC: The Definitive Guide
I suggest: make sure you really need to impersonate an user when calling the API function you mentioned, before going on. See if there is another path to accomplish what you want.
You could also specify which API function you are trying to use, which may redirect you to another simpler question.

Related

Profile folder, NetGetUserInfo and SHGetKnownFolderPath return different things for Active Directory and non-AD users

Provided LogonUser can be used to retrieve an impersonation token also for an Active Directory user, I found myself at odds when trying to retrieve that user's profile directory.
SHGetKnownFolderPath(FOLDERID_Profile, ...) works for non AD users just fine, but it errors out for an AD user, even if their Profile path in the user's properties' Profile tab is set. The HRESULT it returns is 0x80070002. I tried passing the flags KF_FLAG_CREATE and KF_FLAG_DONT_VERIFY to SHGetKnownFolderPath, but it doesn't help, same error.
On the other hand, NetGetUserInfo(...) returns an AD user's profile path correctly set in the USER_INFO_4::usri4_profile field, but returns an empty string for non-AD users.
Why is it so? How to get a consistent behavior? Is there any other API I could/should use?
ANSWER: Anders has provided an answer to the dilemma, below. Read my comment there for more info.
When you pass a token to SHGetKnownFolderPath, all it does is extracting the SID from the token and use that to look up the path under that users registry in HKU.
MSDN hints at this:
In addition to passing the user's hToken, the registry hive of that specific user must be mounted.
You could try helping it by calling LoadUserProfile but I'm not sure what happens if that user has never logged into that specific machine before.
I'd say, try SHGetKnownFolderPath first since it can return paths customized on that specific computer. If it fails, try NetGetUserInfo.
Retrieving a users profile directory is not a common operation because regular programs are not supposed to store files there...

Windows: How to get full users' accounts

Is there any way to get users' system account? I want to make authorisation in my prog with Windows account. Trying to use Active Directory, but it only helps with names and other information, but what about passwords? I understand that I can't get passwords in free access, and I don't need this. But is there any way just to compare input string with real user's windows password?
Or is there any other way to embed authorisation into my program with windows users' accounts?
You may start with NetUserEnum, and with NetQueryDisplayInformation.
There is no way to determine password of a user.
You may use LogonUser API to authenticate users based on password they'd give on your logon window. You should not keep the password after this API succeeds - that's a breach of safety.
Use CredUIPromptForCredentials for asking the user credentials.
The easiest way is to observe that you are in fact running in a login session for the current user, so he does know his password. From there on, Windows will handle all authorisations automatically.

Open default browser as standard user (C++)

I'm currently using ShellExecute "open" to open a URL in the user's browser, but running into a bit of trouble in Win7 and Vista because the program runs elevated as a service.
When ShellExecute opens the browser, it seems to read the "Local Admin" profile instead of the user's. So for example, if the user at the keyboard has Firefox as his default browser, it may open IE (which is the admin's default).
I know that the "runas" verb can be used to elevate, but how do you do it the other way around? Is there a way to open a URL in the default browser on a standard user's desktop from a service?
ShellExecute will execute the program in the context of the same session and same user as the process you are running.
If you'd like to use a different session or user token you can use the CreateProcessAsUser Win32 API.
There are several ways to obtain a user token, for example you can call the Win32 API:
LogonUser if you know the username and password
WTSQueryUserToken for any given session ID.
OpenProcessToken if you have another process handle
After a while of testing, the best way to determine the default browser is the following:
NOTE: It is strange but it's true...
It has nothing to say that an application is the default application for
some file type or web protocol like 'http'. What matters to determine the default
web browser is just what is registered in the start menu entry (see reg key below).
So forget all the HKCR\http, HKCU\Software\Classes\http, HKLM\Software\Classes\http and their friends.
read from "HKEY_CURRENT_USER\Software\Clients\StartMenuInternet"
read command line from "HKEY_LOCAL_MACHINE\Software\Clients\StartMenuInternet\\shell\open\command"
truncate the command line after ".exe"
Of course you need to impersonate as the logged on user first.
If this solution does not work (like with w2k), use the handler for the http protocol.
To actually start the default browser from a service we use an extra process which is within the service using the logged on user-context. This process starts the above commandline (using ShellExecute on platforms >= Vista). Be sure to use same integrity level (medium) as a default user (else IE won't work because it uses DDE).
HTH.
Aaron Margosis has a seven-step native code example at http://blogs.msdn.com/aaron_margosis/archive/2009/06/06/faq-how-do-i-start-a-program-as-the-desktop-user-from-an-elevated-app.aspx. Won't help you from your service if that is what you have - I agree your service shouldn't be trying to launch an app as the logged in user, especially since there might not be one.

How to obtain Windows special paths for a user account from a service

I want to be able to retrieve Windows "special paths" (e.g. temporary files folder, desktop) for user accounts, but from a service.
I know the normal way to do this is by using SHGetFolderPath with the appropriate CSIDL for the folder type. Is there any way to get this type of info for each user without the service having to log in as each user in turn?
I'm no expert on this, but it seems you can use the hToken argument to SHGetFolderPath to pass in another user's token. I think you can create such a token using impersonation.
If that does not work: these folders are in the registry under HKEY_USERS/<user's-sid>/Software/Microsoft/Windows/CurrentVersion/Explorer/Shell Folders. How to get the SID is explained in this question. It's in C# but I think it'll actually be easier in C++.

Problem using AddIPAddress when impersonating an Admin User

I am attempting to add a temporary IP address to a NIC using AddIPAddress when logged in as a non-admin user. The MSDN documentation for AddIPAddress states that ERROR_INVALID_HANDLE is returned as as error if the function is called by a non-admin user.
Given that I have preceeded the call to AddIPAddress with API calls to LogonUser() and ImpersonateLoggedOnUser(). Now my application thinks it's logged in as an Admin, but AddIPAddress still fails with ERROR_INVALID_HANDLE.
MSDN also states that..
"Note Group policies, enterprise policies, and other restrictions on the network may prevent these functions from completing successfully. Ensure that the application has the necessary network permissions before attempting to use these functions."
Is it possible to call AddIPAddress using impersonation? if so how? I'm guessing I need to change the permissions mentioned above but I am at a loss as to what to chnage in this area.
Any help would be appreciated!
Additonal: I've also drawn a blank while attempting to call out to netsh (again logged in as a normal user) using CreateProcessAsUser using a handle to an impersonated admin user to launch the process. Always returns errors indicating insufficent priviledges.
If you are using windows Vista you may need to elevate privileges.
In Vista by default UAC is enabled. This makes it so that even as an administrator you are using a limited user token unless you explicitly elevate. When you do this the user is presented with a dialog to allow or deny the request.
For more information on this see Windows Vista Application Development Requirements for User Account Control Compatibility.
You may want to try using CheckTokenMembership to verify you are properly elevated after you log on as admin. I would suspect you are getting the limited user token and thus failing requests for privileged resources.
Best of luck.