I write a c++ windows application (A), that uses LogonUser, LoadUserProfile and ImpersonateLoggedOnUser to gain the rights of another user (Y).
Meaning the A starts using the user that is logged on on the workstation (X). If the user wants to elevate his rights he can just press a button and logon as another user without having to log himself out of windows and back in.
The situation now is (according to the return values of the functions): LogonUser works, LoadUserProfile works and ImpersonateLoggedOnUser works as well.
After the impersonation I start another process. This process is an application (B) that needs an OCX control.
This fails and the application tells me that the .oxc file is not properly installed.
The thing is, if I start B directly as the user that is logged on to the machine (X), it works.
If I start B directly as the user (Y) to which I want to elevate my rights using A, it works.
If I am logged in as (X) and choose "run as" (Y) in the explorer, it works!
Do you know which steps I need to do to do the same as the "run as" dialog from windows?
I'm not sure, but looks like impersonation is not enough - impersonation relates only to process (A), instead try CreateProcess with ProcessAttributes/ThreadAttributes explicitly set to impersonated user from windows' ACL
Thank you all for your help.
The following was able to solve the issue for me:
I start the desired process using CreateProcessWithLogonW().
To get that function working properly I have to RevertToSelf() before I call it and do the impersonation again afterwards.
So the sequence is now:
LogonUser()
LoadUserProfile()
ImpersonateLoggedOnUser()
// work with the app
RevertToSelf()
CreateProcessWithLogonW()
// do the impersonation stuff again
Related
Overview
The Process
exe/dll compiled in C++ to be run
Scenario
Log in (win 7) to a standard user account (no admin)
run The Process as admin
The Process opens some app (exe) using ShellExecute
Problem
The app is opened in the scope of the admin user
Expecting
The app is opened in the scope of the standard user
Solutions
1. CreateProcessAsUser
Use CreateProcessAsUser (Assuming I managed to get hToken right that should have solved the issue).
However, I get the call failed with error code 1314 - ERROR_PRIVILEGE_NOT_HELD. Going back to the documentation tells me:
If this function fails with ERROR_PRIVILEGE_NOT_HELD (1314), use the
CreateProcessWithLogonW function instead
So I digged in and found this CreateProcessAsUser Error 1314 which wasn't very helpful.
2. ImpersonateLoggedOnUser
using ImpersonateLoggedOnUser generated the same error code: 1314 - ERROR_PRIVILEGE_NOT_HELD.
3. CreateProcessWithLogonW
CreateProcessWithLogonW requires lpPassword which naturally I don't have
The Question
How can an admin process open an application in the logged in user?
Have you tried using CreateProcessWithTokenW which is mentioned in the CreateProcessWithLogonW documentation? It seems to require a much weaker privilege than CreateProcessAsUser, one you should posses (SE_IMPERSONATE_NAME rather than SE_ASSIGNPRIMARYTOKEN_NAME).
You said you already have a token for the interactive user so I won't go into it.
(Note: Strange bugs have been reported with all of this, including CreateProcessWithTokenW. Don't give up on the first attempt. A bug and a fix for example: why is CreateProcessWithTokenW failing with ERROR_ACCESS_DENIED )
hToken is not a "right". It's a token. What the error says is that you lack a privilege.
Holding a privilege is not a fundamental right! Some privileges are given to certain users by default. Others need to be given through the Local Security Policy (in the "User Right Assignment" node in the MMC snap-in or with LsaAddAccountRights - all of which is documented in the page Assigning Privileges to an Account).
Besides that you sometimes have to enable privileges using AdjustTokenPrivileges. This is documented in the sibling page Changing Privileges in a Token.
Some APIs enable them if you hold them. Others don't and require you to do so yourself. The obvious way to go is to enable a privilege before calling and API that's documented to require it.
The MS Forum link may not have been but the error message is quite clear. MSDN says about the function:
Typically, the process that calls the CreateProcessAsUser
function must have the SE_INCREASE_QUOTA_NAME privilege
and may require the SE_ASSIGNPRIMARYTOKEN_NAME privilege
if the token is not assignable.
and the error is (from the page you linked to!):
ERROR_PRIVILEGE_NOT_HELD
1314 (0x522)
A required privilege is not held by the client.
This is actually a very tricky Task you want to accomplish. There are very strict security policies which make it very difficult.
As far as I know you can do it with psexec. It has a commandline Switch which enables user interaction but running the process as admin. I think your command should look like the following:
psexec \\target-computer -i -s [your command]
Another way to do it is using WMI. But for this you Need to Change the security Settings of the target machine (probably using GPO's). You Need to connect to the target machine using impersonation Level deletgate see here. Additionally as said before, you Need to Change the security Settings. See here
My service start an interactive client process with something really similar to this: https://msdn.microsoft.com/en-us/library/windows/desktop/aa379608(v=vs.85).aspx
It works when the service Log On as Local System, and it work if it's running under an Administrator account with the SE_ASSIGNPRIMARYTOKEN_NAME and SE_INCREASE_QUOTA_NAME privileges.
My issue is when using a Standard User account OR Local Service, it fails at OpenWindowStation with error code 5 (ACCESS DENIED).
// Get a handle to the interactive window station.
hwinsta = OpenWindowStation(_T("winsta0"), // the interactive window station
FALSE, // handle is not inheritable
READ_CONTROL | WRITE_DAC); // rights to read/write the DACL
Is it possible to call OpenWindowStation from a Standard User account or my service must run under an Administrator account? I tried almost all Local Policies without success
Thanks!
Unfortunately it can't be done, it seems that only an Administrator can open the interactive station.
I'm using CreateProcessAsUser to create a process under user-specified credentials.
I'm posting what are hopefully the relevant parts of the code. Let me know if you want to see anything more.
First LogonUser to get the token:
result = LogonUser(
username,
wcschr(username, '#') ? NULL : (domain ? domain : L"."),
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&hrunastoken);
I then load the profile, set the lpDesktop value of the STARTUPINFO structure to NULL (which makes it use the desktop of the calling process), and call CreateProcessAsUser:
result = CreateProcessAsUser(
hrunastoken,
NULL,
apptorun,
NULL,
NULL,
FALSE,
CREATE_UNICODE_ENVIRONMENT,
envblock ? envblock : NULL,
NULL,
&si,
&pi);
This works fine - it logs in and creates the process successfully, and the process "works". The problem is that the windows it creates are black, as in this screenshot of a notepad process started with my program:
Possibly relevant context:
My account is a local account on a Windows 7 machine with full admin rights, and I am logged on with that account. I used psexec (Sysinternals utility) to open a command prompt running interactively under the local system account. I am launching my program from that command prompt. The credentials I am passing to it are from my account.
I have not done anything with permissions to windowstations/desktops; I assume the process I create should have rights to those as the process is being created in my session and using the same account I'm already logged in with - albeit going through the SYSTEM account first. Using Process Explorer, I don't see any difference in the permissions on the values and handles to windowstation/desktop by the process opened via my program vs opened normally. Maybe that's completely irrelevant.
I also cannot use CreateProcessWithLogonW function because it must work when run from the SYSTEM account - that function as well as the "runas" program that comes with Windows don't work under SYSTEM.
Funnily enough, I can't use my current method to open processes unless I'm running it under the SYSTEM account, as "a required privilege is not held by the client", so I can't compare the windows created when starting my program under my account vs the SYSTEM account...
The default DACL for window stations and desktops grant full access to the logon SID (which is unique to the current logon session) rather than to the user's SID. (The user's SID also appears in the DACL for the window station but has only limited permissions. It does not appear in the desktop DACL.)
The call to LogonUser generates a new session (and associated logon SID) rather than reusing the existing one, so your process does not have access to the desktop, and only has minimal access to the window station. (Actually I'm slightly puzzled as to how the process manages to run at all; when I tried to reproduce your results the process exited immediately with exit code 0xC0000142, as expected.)
The second piece of code in this answer shows how to change the DACL on the window station and desktop to allow the process to run properly. (This may not be the best solution, however, depending on your specific goals.)
i am using c++ win32 API.
i tried to get user details using GetUserNameExA();
i have use this function into system logondialog source(GINA).
in my logfile,it gives
CN=ComputerName,CN=Computers,DC=JEGAN,DC=COM".
But it's used after logon on to system,at that time it gives user details like "CN=sanju,CN=USERS,DC=JEGAN,DC=COM" in my other solution.
i want user details only,but it gives system details at the logon time,how can i achieve user details at logontime?
note: i have already tried ADSI,LDAP functions & directoryservices cant able to use.so suggest any other system functions.
David is correct - the GINA DLL is loaded by the WinLogon.exe process. Check Task Manager and you'll see that WinLogon.exe runs as Local System. The GetUserName and GetUserNameEx functions provide information about the identity for the current thread:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724435.aspx
From a 20,000 foot view, after a user's credentials have been validated, the GINA notifies all Network Providers of the successful login. After this, it loads the user's profile and creates the user's shell (Explorer.exe) which is then displayed.
You might try using a Network Provider instead. They are fully supported up through Windows 8 and multiple NPs can be defined for the system so you won't run into the 'chaining' issues that GINAs have.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa378775.aspx
The NPLogonNotify function will receive the user's cleartext name, domain and password (sometimes you'll receive a UPN as username in which case the domain is blank). You can use this information as is, perform LDAP-based lookups to AD or use LogonUser & ImpersonateLoggedOnUser before calling GetUserNameEx. Be extremely careful with this last approach since network providers run as Local system within the WinLogon.exe process. Always call RevertToSelf and CloseHandle to undo/clean up the previous calls.
The only (quite quirky) workaround for what you are trying to do is to log on some other user account on the side which has access to the domain and can thus query user details (don't remember the permissions needed in detail, though). Otherwise I'd suggest you go with Gregg's answer.
With a thread impersonated as such user you should then be able to query the information for the user that you are going to log on (how do you even know by that time?) via NetUserGetInfo() and friends. Choose the USER_INFO_* struct that best suits your needs and simply ask the domain server for the information. This should also work on earlier and later systems (the functionality, not the GINA itself).
Is there any APIs in windows to detect whether the current user(current now) has the admin authority?
BOOL IsHasAuthority()
{
}
Many Thanks!
How to Determine Whether a Process or Thread Is Running As an Administrator
Use this solution when you are writing
an application that must determine
whether any of the following is true:
The current user can perform administrative tasks. The current
user is a member of the
Administrators group. A supplied token handle represents an
administrator with an elevated token.
A token handle represents a user who is a member of the
Administrators group.
The program is running with an elevated token or needs to spawn a
child program that is elevated so it
can perform administrative tasks.
You can use the Windows API function CheckTokenMembership(). The MSDN documentation for that function has an example demonstrating how to check for membership in the Administrators local group.