Using LogonUser() only to Validate Credentials - c++

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.

Related

How to Fix Error 1935 on Win32 API LogonUser() Function

I'm trying to use this Function.
The User I'm trying to impersonate is not in the same domain.
I can mount the Server using the credentials just fine.
But whenever I call LogonUser
bLogonSucc = ::LogonUser(sUserName
, sDomain
, sUserPW
, LOGON32_LOGON_INTERACTIVE
, LOGON32_PROVIDER_DEFAULT
, &hToken);
I get the error 1935:
ERROR_AUTHENTICATION_FIREWALL_FAILED
1935 (0x78F)
The computer you are signing into is protected by an authentication firewall. The specified account is not allowed to authenticate to the computer.
My goal is to open a File on a Server, where the User is used as Login to said destination and open the File.
If I use LOGON32_LOGON_NEW_CREDENTIALS as Parameter, the LogonUser Function & Impersonate works, but somehow still doesn't work later on in the code.
Can't seem to find a solution for this.
Any Ideas on how to solve this?
The Firewall should be setup correctly.
This error occurs because the user or group, has been granted the correct rights to access the share. But the share is in another domain, and even though that domain trusts the one the user is coming from, the trust was set up with ‘selective authentication’.
You can try this.
Go to the domain that’s providing the share, log into a domain controller
Open 'Control Panel\System and Security\Administrative Tools'
Open ‘Active Directory Users and Computers’
View
Advanced Features
Locate the COMPUTER you are trying to authenticate
Properties
Security
Add in the user (or group) that requires access
Grant the “Allowed to authenticate” right
Apply and OK

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.

Kerberos administrator authorization

I'm writing linux application that integrates with MS Active Directory. For this purpose I'm using Kerberos. I've already implemented mechanism that authenticates domain user with given credentials, but now I want to check if user is member of administrators group.
So I have creds obtained from the function.
error = krb5_get_init_creds_password(context, &creds, principals,
password.c_str(), NULL, NULL, 0, NULL, NULL);
And here I want to implement logic that authorizes user/administrator
if(!error) {
// admin check
}
I'm thinking of using the krb5_verify_init_creds function but I'm not sure how can I do that.
Kerberos does not do authorization, only authentication. (i.e. it can figure out who you are, but not what you are allowed to do).
In general, once you have the kerberos ID, you would ask some authorization service what that ID is allowed to do. In this case, the most straightforward thing to do is to make an ldap query to find out if the user is a member in the group you are interested in.
MS kerberos violates this principle by adding extra group information that AD knows about to the kerberos service tickets. However, I am not aware of any standard kerberos API's that provide access to this information.
As Fred noted, Kerberos is for authentication, not for authorization. While Kerberos ticket issued by an AD DC contains MS-PAC record with additional information about membership of the AD object mapped to this Kerberos principal, you need more than just knowing format of the records presented in the ticket to make use of it.
In a typical Linux environment your application is better to rely on PAM stack to decouple authentication and authorization steps. Typically a PAM session setup is used to run authorization checks. If your Linux machines are configured to use SSSD (either with id_provider = ad or with id_provider=ipa and cross-forest trust between FreeIPA and AD), you can rely on pam_sss to handle both authentication and authorization steps via SSSD.
Recent versions of SSSD support GPO-based access by mapping GPO logon rights to PAM services.
With SSSD your AD users and groups would be presented as POSIX users and groups. This allows you to build a simple access control based on the group membership that you can obtain via getgrouplist(3) call after you mapped Kerberos principal to local user name with krb5_aname_to_localname().
If you still need to know additional information about the user mapped from Kerberos principal, you can utilize infopipe interface of SSSD. The information available through infopipe is gathered from both Kerberos ticket (when available) and AD LDAP (Global Catalog or DC directly). By using infopipe you wouldn't need to resolve SIDs in MS-PAC to names, resolve group membership and verify signatures of the MS-PAC and other components of the ticket as SSSD does it for you. See https://fedorahosted.org/sssd/wiki/DesignDocs/DBusResponder and http://www.adelton.com/apache/mod_lookup_identity/ for practical implementation.

LogonUser returns ERROR_NO_LOGON_SERVERS

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).

WTSConnectSession

I am trying to use this function to connect to a specific user session. I have tried everything and the function always fails with either ERROR_ACCESS_DENIED 5 (0x5) Access is denied or ERROR_CTX_WINSTATION_ACCESS_DENIED 7045 (0x1B85) The requested session access is denied. Even hard-coding the session ID in and the password like this
WTSConnectSession(2, 1 ,TEXT("test1"),false);
Is there a better way to start a user session than to use this function. I am trying to implement Fast User Switching and this is the last piece in the puzzle is to logon a user session. Thank you.
Are sure that you are connecting with username (specified by TargetLogonId parameter) in "Remote Desktop Users" group?
You can check it using
net localgroup "Remote Desktop users"
Another option is to enable security auditing and analyzing security event log.
It will tells you exact root cause of ERROR_CTX_WINSTATION_ACCESS_DENIED