How does impersonation in DCOM work? - windows

I have a DCOM client and server applications which use OLE automation marshaller. They work fine when run on the same PC but when the server is on a different PC not in the same domain I get E_ACCESSDENIED (0x80070005).
Server PC is configured with dcomcnfg to give all access to any DCOM object to the user whose login and password I specify on the client. ServerApp and its type library are registered on the server pc.
Type library is also registered on the client PC. I specify server name directly in the ClientApp so no dcomcnfg configuration is needed on the Client PC as far as I understand.
CreateInstanceEx() with server name, login, domain and password works fine. It returns IUnknown and at the same time starts ServerApp on server PC.
But when I try to QueryInterface() for the interface which server supports, I get E_ACCESSDENIED.
Analyzing the Security Event Log, I have two records there:
First, a successful network login by the user whose credentials I specify in ClientApp. This happens when I call CreateInstanceEx().
Next, a failed login attempt by the user under which I'm logged in on a client PC. Since two PCs are not in a domain, this user is unknown to server PC.
Now, why the heck would THIS user be logging into server, especially when I call QueryInterface of all things?
Studying CreateInterfaceEx params, it appears there's some kind of impersonation mechanism going on. But it's unclear who impersonates who. There are THREE user credentials involved:
User under which ServerApp runs on the server PC (as configured in dcomcnfg).
User whose credentials ClientApp specifies when connecting.
User under whose credentials ClientApp runs on client PC.
No matter how you look at it, if #3 is involved it's one user too much. If DCOM is going to identify/impersonate #3 on server PC anyway, why do I need to specify #2's credentials? To what point?
It would have seem logical for DCOM to impersonate #2 because this is what I have explicitly specified as my credentials. But why the second login attempt then?
Can someone please explain how exactly the impersonation works, and also if there's a way to just ignore it and run as user which is specified in dcomcnfg?

Answering my own question. After much exploration it became apparent that DCOM has TWO different identification cases:
Authorization for object creation (CoCreateInstanceEx)
Authorization for method calls.
For reasons unknown, #2 doesn't inherit #1 settings. By default it uses the credentials of the client process, hence strange logins.
There are two ways to specify credentials for #2. First one is CoSetProxyBlanket. It sets credentials for a specified proxy (marshaller-unmarshaller) only:
CoCreateInstanceEx(IID_IObject1, /*login, pass*/, obj1); //Success!
//Logged in and recevied IObject1 proxy in obj1
obj1->DoSomething();
//IObject1 proxy in obj1 now tries to login under process credentials.
//Failure! E_ACCESSDENIED
CoSetProxyBlanket(obj1, /*login, pass*/); //Success!
//IObject1 proxy is now authorized.
obj1->DoSomething(); //Success!
obj1->QueryInterface(IID_IObject2, obj2); //Success!
obj2->DoSomethingElse(); //Failure!
//This different proxy for IObject2 have not yet been authorized.
CoSetProxyBlanket(obj2, /*login, pass*/);
//etc.
It's important to note that while CoCreateInstanceEx requires impersonation level to be at least IMPERSONATE, CoSetProxyBlanket doesn't seem to work on anything except IDENTIFY.
Another option is to use CoInitializeSecurity to set default credentials for the whole process. Then you don't have to call CoSetProxyBlanket on every proxy:
CoInitializeSecurity(/* login, pass */);
CoCreateInstanceEx(IID_IUnknown, /*login, pass*/, obj); //Success!
obj->DoSomething(); //Success!
When using CoInitializeSecurity on the client you have to specify asAuthSvc too, even though MSDN says you don't.
The drawback of this method is obviously that if you have several DCOM objects from different PCs you're going to have to specify all the credentials in this call and those are probably going to be tried against every computer every time you open a different proxy.
It also is not reliable when you're running from a DLL (what if a process has different default security?). So, it's probably better to implement a QueryInterface wrapper which CoSetsProxyBlanket before returning from every call.

For those who are working in Delphi there is one little note that can save a lot of your time. After you did obj as ISomeInterface operation, you have to call CoSetProxyBlanket for the new instance. This could be not very obvious, but all we know that as operator calls QueryInterface method, and it can return new instance.

Related

Make Win7 use new password without reboot or screen unlock

We call DirectoryEntry.Invoke("SetPassword",newpwd) to change the password of a local user, but the new password is not being used immediately when doing Windows Authentication to a remote SQL server. It does get used after a reboot, but that's not really an option for me here. How can I make it take effect without rebooting? I need currently running processes on the client to begin using the new password immediately.
The environment is two Windows 7 Embedded systems, call them 'server' and 'client', and there is no domain, but they are both in the same workgroup. We use the same username on both systems. There are multiple servers out there with different passwords (computed based on various things). When we need to switch to use a different server, we change the password locally. The change itself is successful, but SQL accesses from client to server fail with
SSPI handshake failed with error code 0x8009030c, state 14 while establishing a connection with integrated security; the connection has been closed. Reason: AcceptSecurityContext failed. The Windows error code indicates the cause of failure.
and
Login failed. The login is from an untrusted domain and cannot be used with Windows authentication.
But as soon as client reboots it can access server's database successfully.
SQL Express 2008 on both systems, configured to use only Windows Authentication.
Wireshark shows me the SMB2 NTLMSSP_AUTH packet with what looks like the usual info although I don't know how to decode the security blob. Otherwise it matches the packet from a successful session. In the failure case this packet is followed by an SMB2 response with STATUS_LOGON_FAILURE and a missing security blob. I can only think that the client presents some kind of hash of the password in that security blob and the server is finding that it doesn't match its own password hash - or something like that.
Changing the environment ('Use Active Directory', 'Use Kerberos', etc.) is unfortunately not an option for me here. Also, these are consumer touch-screen kiosks, where no human ever knows the password, and wouldn't have a keyboard to enter it anyway.
ADD: FYI, The changing of the password is done thus:
DirectoryEntry directoryEntry = new DirectoryEntry(string.Format("WinNT://localhost/{0}", username));
directoryEntry.Invoke("SetPassword", newPassword);
ADD: Made that parameter new object[] {newPassword}, and called .CommitChanges(), because those look like correct things to do. No change in behavior.

Working around the Windows OS limitation of not allowing multiple connections to a server/shared resource

We are building a system on windows where we centrally (server) need to do fopen to either local files or remote smb resources. The idea is to authenticate in the case of remote resources before doing fopen (with unc paths).
We need to authenticate with the credentials the user (client application) supplied for this resource on that remote share. We don't want to copy any resources.
Using the Win Net Api this works smoothly since it stores the given credentials so that subsequent fopens in the same or in different processes succeed.
But there is a problem:
Many of you probably know the following message from windows when trying to connect to a smb share with different credentials then the ones used for a previous connection:
"Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again."
See http://support.microsoft.com/kb/938120 for the defined limitation and possible "work arounds".
Since we have a central server application running as a service ('Local System' account) we hit this limitation with having already two different users :).
Closing the previously established connection to allow for the 2nd one is not an option (ongoing processing).
On the one hand it's great that windows caches authentication information on the other hand it's too limited.
Modifying the hosts file for each user does not look very nice.
Using smb client libraries (like libsmb++, impacket) doesn't seem to be the solution since we need "over process" authentication.
Configuring a "master" smb share user is also not wanted.
Maybe passing windows user auth tokens around is a way?
This problem is of general nature (i.e. independent of language) and I'm convinced that there are people out there who solved it (in a more or less elegant way ;))
I hope my explanation is understandable.
Thanks in advance for any hint.
felix

how to create a session with a proxy server

I have the following problem. I have an application (3rd party) that needs to connect to API via a proxy to request various data again and again. The application has a configuration section where the necessary details can be entered (the app then stores them in a config.ini file). However, one client doesn't like the proxy user/password to be stored in config files;
As I don't have access to the application's code, the simplest solution I can think of is something along the lines of a tunnel, i.e. write a simple app/script that would open a connection to the proxy, prompts the user for the username/password and then keep the connection open so that the application can access the proxy without needing username/password everytime. Is something like this possible? I mean I don't to create sort of full blown proxy that would sit between the app and the real proxy server, all I really want is something like a session so that once the IP is authorized to get through the proxy, the consequent requests go through as well.
I'd appreciate help and/or any suggestions for an alternate solution
p.s. the app is win32 only so the solution is for win32 only as well (ie no cygwin, etc.)
Thank you
Proxy credential caching typically works on a per-process basis, not a per-machine basis. So, having Application A make a request through the proxy rarely allows Application B to make a request without getting challenged.
If you can change the application's code, make a single request through the proxy using the desired credentials; e.g. make a HEAD request for your server's homepage. Most HTTP stacks (e.g. WinINET) will cache the proxy credentials for the life of the process.

remote login a windows user knowing it's name and password

Here's what I want to do:
a program that listens in the network for a message, and when that message is received, if the user is not logged in (for example the computer just powered on and windows displays the classic login screen), it automatically logs in a certain user accordingly to the message. the username and password are known and stored safely inside the computer in a configuration for the program i'm talking about.
What I had in mind was a windows service that starts with the computer and also listens to those messages, and if one is received, then it does it's job
but I have no idea of where to start
(basically i'm trying to login a user without having to type the password, which I said is stored and known - need something mostly like the fingerprint software windows 7 comes with, and the ones that you had to install in vista/xp so that fingerprint login would work (fingerprint was only an example) )
There's two methods to pursue depending upon which operating system you're looking to run under.
For Windows XP, Windows 2000, and Windows Server 2003 you need to create a GINA.DLL. This is a replacement DLL which must follow specific rules which handles the authentication process. In your case your replacement DLL would be known by the service which was listening for your start signal, and it would make a call into the DLL with the username and password as appropriate.
MSDN Magazine article on customizing GINA.DLL
MSDN entry on GINA
For Windows Vista/7 and above you'll need to look into the Credential Provider API.
MSDN Magazine article on Credential Provider API in Vista.
MSDN entry on Credential Provider API
You can use windows auto logon feature to do this.
Create a service which waits for the required data on a network socket. Make sure this service is started after the network service (Tcpip). Modify winlogon service properties (manually) so that it depends on your service. By depends, I mean that winlogon service is started after your service.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\AutoAdminLogon to 1
Once you receive the data on your network socket, set the following registry keys:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\DefaultUserName
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\DefaultPassword
Once the registry settings are in place, then the winlogon service can read those values and proceed with the login process.
For more details on setting the registry values refer: http://support.microsoft.com/kb/315231
I want clarify a little the suggestion of Vikram.exe.
Of cause the usage of AutoAdminLogon seems native for the problem, but saving of the password in registry as a clear text under HKLM\...\Winlogon\DefaultPassword is not good. Since Windows 2000 it is supported the usage of the secrets DefaultPassword which makes the same effect as the DefaultPassword registry value (see Protecting the Automatic Logon Password for the code example).
Another way to force user login or to do any other actions on the login screen is switching to the Winlogon desktop (full name WinSta0\Winlogon). You can use SwitchDesktop and SetProcessWindowStation to do this (see Window Stations and Desktops). If the service run under System account you will have all rights to do this. Depend on the configuration of your service it could be also needed to use SetTokenInformation with TokenSessionId to change the current session id. After the service process will run on the WinSta0\Winlogon desktop you can use functions like FindWindow and other GUI API to place any information in controls of the window (user name, password and so on) of other process. So you can implement more complex scenarios.
Firstly let me just say im not 100% sure how to fully complete such a application but I have a few tips.
you will need to create a Windows Service that starts during the Pre-Login, you can create a service in C#, An example of creating a C# Service is linked below:
http://msdn.microsoft.com/en-us/library/zt39148a(VS.80).aspx
Within your application you would set the property Startup Type to Automatic, This will automatically start your service on boot.
You should know that windows services run under a secure context by account so you will have to get your service to run with privs do do this.
In your Service Properties you can Click Log On and you can
To specify that the service uses the Local Service account, click This account, and then type the following NT AUTHORITY\LocalService.
To specify that the service uses the Network Service account, click This account, and then type the following NT AUTHORITY\NetworkService.
As your trying to do this remotly you will have to look at WMI (Windows Management Instrumentation) and you will be able to start/stop and send commands to your service.
Your service then would send a command to the Login Management (Not Sure of the name).
you may also wish to check this WOL class which will switch the computer on remotely as long as it supports Wake On LAN, If this is for a corporate environment then I advise you to check your network cards to make sure they are supported
http://www.codeproject.com/KB/IP/wolclass.aspx
I know of some education software that I use for schools that's called CC4 ( http://www.rm.com/shops/rmshop/story.aspx?cref=PS1026195 ) and we can do exactly what you need within this system, I'm not fully sure of how it works fully but i believe it takes the same principles described above.

Pass current user credentials to remote server

I have an application server (webservice or remoting, not yet decided) on a remote machine and a client on the same domain. I want to authenticate the user as a domain user on the server.
I can ask the user to enter their Windows username/password and send those to the server and get the server to check them against Active Directory but I would rather not. Is there any way I can get the client to send some kind of token which the server can then use to identify which domain user is sending it a request? Obviously I want to protect the server against someone sending a fake user ID and impersonating another user.
Clarification
The client on computer A will communicate with the server on computer B. I think I will probably using .NET remoting for this communication. On the server I merely need to know the ID of the user on computer A; if the app on computer A must send the ID I need to be sure that it hasn't sent the ID of a different user.
I don't need to impersonate the other user, I merely need to know (for certain) who it is.
Are you saying that the client communicates against your server, and you need to use the client's privileges at a third server? That scenario describes The Double-Hop Problem. The blog most describes it in detail, and what can be done to circumvent it (domain modifications).
[...] you can get around the problem and use proper delegation if you set up your network to use Kerberos and set up the web server in question as trusted for delegation.
Added:
I know of no way you can identify the user on computer A. Would it be enough if it was just the user executing your program? You could use windows authentication in a domain scenario, but that would only give you the privileges used by the program to authenticate, which may differ from the actual evil user in front of the keyboard.
Added:
Your comments to this post indicates that windows authentication with impersonation would work for you. Check http://community.bartdesmet.net/blogs/bart/archive/2006/08/26/4277.aspx for code examples.

Resources