LogonUser returns ERROR_NO_LOGON_SERVERS - c++

I have an application which needs to check the Windows session password of the user.
For this, I am using the LogonUser function from Windows API. The user can be connected to a domain.
result = LogonUserW(wUsername, wDomain, wPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, pH);
When the user is connected to the domain, the function works well, however, when the user turns off the wifi, or unplug the lan-cable so that he is offline, the function always returns with the error code 1311, which has the meaning "There are currrently no logon servers available to service the logon request".
The LogonUser function has as fourth parameter the type of logon operation to perform. The documentation says that if the value of this parameter is "LOGON32_LOGON_INTERACTIVE", the logon type has the additional expense of caching logon information for disconnected operations, so shouldn't this work in the case the user is in the field?
Thanks in advance for your help.

I ended up using the Security Support Provider Interface (SSPI) as described as an alternative to the LogonUser API in this page : How to validate user credentials on Microsoft operating systems
Using the SSPLogonUser function as provided in the code snippet allowed me to check for the user credentials while connected to the domain, but also when the domain controller wasn't reachable (where in that case, it failed with the LogonUser API).

Related

How to call default windows credential in my code?

I have my own implementation of "windows credential provider".
In some scenarios my custom credential must switch to windows default credential and the user must see the "windows credential provider" to do the login process.
How can I exit my own "credential" and call the default "windows credential"?
In new scenario of Microsoft Windows's Credential Providers, you can't direct which other provider user must use to log on to the system.
The only thing you can do is to force logon using your own provider or decline logon using your provider.
To do this you must:
Set pdwDefault to any useful value and pbAutoLogonWithDefault to true inside of call to GetCredentialCount.
Set the CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE *pcpgsr parameter inside of GetSerialization method to one of the following values:
CPGSR_RETURN_CREDENTIAL_FINISHED - to do auto-logon,
CPGSR_RETURN_NO_CREDENTIAL_FINISHED - to cancel logon UI process.
In any case your provider (tile) will loose the focus. Check out this doc.
Update
You can remove your provider from entire logon process by returning E_NOTIMPL value from inside of the call to SetUsageScenario method.
User and/or Logon UI will be forced to use any other existing provider(s).
LogonUI searches for all 'enabled' credential provider on the system and call GetCredentialCount to get all credentials for each particular Provider.
One thing you can do is calling ICredentialProviderEvents::CredentialsChanged which will ask logonUI to 'refresh' the tiles.
You can disable your provider and enable the default one in some way before calling the event.
Another way to do it is to implement your own password credential in your provider i guess. This way, you can choose the index of the credential compared to the others.

How to go back to CTRL+ALT+DELETE logon page if the custom credential provider fails to do any authentication?

I have enabled CTRL+ALT+DELETE secure attention sequence (SAS) for windows logon using local security policy. (secpol.msc , Security Settings->Local Policies->Security Options->Interactive Logon: Do not require CTRL+ALT+DEL -> Disabled )
Currently the machine is using a facial based custom credential provider for login in Windows 10. In the current setup if the custom credential provider fails during authentication, it falls back to normal windows based logon (Password / Pin).
I have disabled the password, pin based mechanism through the group policy ( gpedit.msc, Computer Configuration ->Administrative Templates->System->Logon , Exclude Credential Providers ). This works fine as password and pin cannot be used for authentication. But the login page is still displayed.
How to always go back to Ctrl+Alt+Del logon page if the custom credential provider fails to do any authentication so that the user can retry ?
Is it possible to Control through group policy? Do I have to manage through the credential provider source so the fallback always goes back Ctrl+Alt+Del page.
Additional Info: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc780332(v=ws.10)
Ref section - Winlogon Desktop Dialog Boxes:
In other words it is about switching from "Log On to Windows" desktop "Welcome to Windows" desktop automatically.
Additional Info on the flow:
When Winlogon.exe detects the SAS (Ctrl+Alt+Del), it launches this LogonUI.exe process,which initializes our custom credential provider.
In the normal use case , when our credential provider succeeds , user enters his credentials and the LogonUI.exe process terminates.
Now in the second case, when our custom credential provider fails, desktop becomes blank or if fast user switching is enabled, it displays the switch user button.
In the correct use case , I have to fallback to SAS (Ctrl+Alt+Del)
*pcpgsr = CPGSR_RETURN_NO_CREDENTIAL_FINISHED;
return hr; // return to LogonUI
CPGSR_RETURN_NO_CREDENTIAL_FINISHED will return from your module to windows system without accepting your security structure. Also use unadvise to cleanup while returning from Serialization call.
Do you solve your issue?
I think in the new scenario of credential providers (versus GINA) it is impossible to control this behaviour.
If ctrl+alt+del is enabled there is no legal way to eliminate and/or simulate this secure attention sequence. Have a look at this article.

is it possible to use LogonUser API without password?

I am developing a c++ application and this application runs as a windows service.
I need to impersonate the current user to access the network location and for this I am using Windows API LogonUser and ImpersonateLoggedOnUser.
The problem is that I only have username and domain information but not the password. So is it possible to call the LogonUser without providing the password to get the user handle?
No, that would be a rather obvious security leak.
You may however use a named pipe between a UI process for the current user and your service. Your service can then impersonate the other side of the named pipe. This is secure because you control both ends of the pipe.

Using LogonUser() only to Validate Credentials

We are developing an application with an internal user accounts system, but would like to be able to use credentials from Active Directory and/or Windows accounts. To that end we store the User SID in a field in the application's users table. Our login mechanism functions like this:
Prompt user for domain, login, password
Call LogonUser(logon, domain, password, logon_type, logon_provider, &hToken)
If successful, get User SID from hToken
Close hToken
Search our application's database for a user with the given SID; if found, we are considered logged in to that account.
The problem that has come up is this: we have been using LOGON32_LOGON_NETWORK for the logon_type, but we have now run into some security configurations where "Access this computer from the network" is denied, meaning the Network logon type is prohibited.
My question is what logon type should we be using for this situation? Interactive? We are not actually using the Logon token for anything other than extracting the user's SID. Our application has its own internal groups and permissions; we do not use Windows groups or permissions in any way. From the perspective of Windows and the domain controller, all we are doing is logging on and quickly logging off.
Or are we looking at this in a completely wrong way, and we should be using some other login method entirely?
Thanks
I also have been surprised to find out that the LogonUser() with the LOGON32_LOGON_NETWORK type fails when user right "Access this computer from the network" is not granted for Everyone on local computer.
I use the following workaround:
First try LogonUser() with the LOGON32_LOGON_NETWORK type.
If it fails with error ERROR_LOGON_TYPE_NOT_GRANTED, call LogonUser() with the LOGON32_LOGON_NEW_CREDENTIALS type and the LOGON32_PROVIDER_WINNT50 logon provider.
You can communicate with the SSPI services to validate a user's credentials and acquire a token, without requiring special privileges. This requires a lot of obscure code and
See http://support.microsoft.com/kb/180548 for an example; the SSPLogonUser function is where the token is acquired.
The convention is to use LOGON32_LOGON_BATCH, as documented:
This logon type is intended for batch servers, where processes may be executing on behalf of a user without their direct intervention. This type is also for higher performance servers that process many plaintext authentication attempts at a time, such as mail or web servers.
(emphasis mine).
The system administrators may still need to reconfigure the server to grant batch logon access to the users in question, but because this does not grant the user access to any Windows functionality (e.g., the ability to use Remote Desktop, to connect to a network share, or to log on interactively if they somehow gain access to the console) this should not be a problem.

LogonUser() not authenticating user for invalid domain when computer is not on a domain

I'm having some problems with the LogonUser() API function in C++. The computer I'm testing this on is not on a domain. The account I'm testing with exists on the computer, but when i supply an invalid domain, it authenticates the login.
This does not seem right to me.
HANDLE token;
if (!LogonUser("LocalUser", "InvalidDomain", "Password",
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &token))
{
unsigned long error = GetLastError();
}
Is this the right behavior?
I believe that workgroup members don't support domain logons so the domain parameter is ignored. This explains what you are seeing.
You can confirm this. Try to authenticate using a real domain user (ensuring there isn't a local account with the same name). The logon should fail.
There is an exception. If you use the LOGON32_LOGON_NEW_CREDENTIALS flag (which amends the existing logon rather than creating a new one) then a domain logon will always succeed because it isn't authenticated until you attempt to access a remote resource.
According to this site, you should use a "." (or "", but this is not documented) as domain to only use the local database.
I believe the undocumented behaviour of "" explains your login. If it fails to identify the user in the domain, it will try to identify it locally.
I based my answer on this page: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378184(v=vs.85).aspx