7

We are developing a C# .NET windows service.

Our service is running under the system account, and we are trying to impersonate the logged in user USER. The impersonation works ok, i.e. when calling System.Security.Principal.WindowsIdentity.GetCurrent() after the impersonation we get the correct user 'USER'.

The problem is that when we try to access the user profile we do not get the expected results. One example is accessing the registry CURRENT_USER. We get an access denied error. When using a third party function, which we assume uses the registry in part, we get the details for the "real" (prior to impersonation) user. Also when callingEnvironment.ExpandEnvironmentVariables("%TEMP%") we get the system profile instead of the logged-in user profile.

Is there a way to completly impersonate a different user?. I know we can use LoadUserProfile to get a specific user profile, but this is not good for us, because we are running a third party dll that uses the current user profile.

Our impersonation code is base on this

user844541
  • 2,868
  • 5
  • 32
  • 60
  • 1
    First of all, you should be using System.IO.Path.GetTempPath(); and if that still doesn't work this could be your problem: http://stackoverflow.com/questions/944483/how-to-get-temporary-folder-for-current-user See the accepted answer and how it works. – lahsrah Jan 08 '13 at 13:50
  • let me be more specific. we are using calls to a third party dll that we can't change. so if they are expecing a specific user profile we have to make the process run with that user profile. – user844541 Jan 08 '13 at 13:52
  • @user844541 please read my link again. – lahsrah Jan 08 '13 at 13:54
  • 1
    @David - this is not correct, I tried to run a console application in order to check that. the app was running under user A and impersonated user B. when calling Environment.ExpandEnvironmentVariables("%TEMP%") after the impersonation I still got user A. – user844541 Jan 08 '13 at 13:55
  • 1
    "trying to impersonate the logged in user" - there can be more than one user logged into a machine... – Damien_The_Unbeliever Jan 08 '13 at 14:07
  • OK. Suggestion deleted. Good jo bat being thorough! – David Jan 08 '13 at 14:10
  • @Damien_The_Unbeliever - this is just an example.I can try to impersonate any other user. – user844541 Jan 08 '13 at 14:28
  • @user844541 - Which third-party library are you using exactly? – Security Hound Jan 08 '13 at 17:51

2 Answers2

3

As you have discovered, impersonation won't set up HKEY_CURRENT_USER or the environment.

This is because the impersonation token is per-thread, and HKCU and environment are per-process.

If you need to access the user's usual environment, you will need to use HKEY_USERS\SID and the impersonated user's SID e.g. HKEY_USERS\S-1-5-21-12345678-12345678-12345678-1234 for example. Call LoadUserProfile to ensure the key is loaded. (If it is supposed to be the the currently logged-on user it should be loaded already, so you should probably not do that, but check it exists and return an error if not).

You can also work out what their usual environment would be, because this is under the key "Environment" within the HKCU. You merely need to combine that with the system environment.

If the third party DLL actually requires HKCU and the environment to be set up correctly, you will need to create a process within the user's logon session to host the DLL, and send the results of whatever operation back somehow. If only the environment is required, you can create a child process and set the environment manually.

However you haven't said why you want to do this. It sounds like you have settled on this as a portion of the solution to a larger problem. If possible I'd recommend that you see if there is a way to do what you need without getting the user's environment or HKCU at all.

Why can't the DLL just run directly in the user's own session? Why is a service required at all? Can you re-architect your solution so there is a user-mode part which runs in the logon session and hosts the third-party DLL, and it communicates with the service so that the service only does what is absolutely required?

Ben
  • 34,935
  • 6
  • 74
  • 113
  • 1
    +1 For the suggestion of having something running in the users session. Almost every time I get a similar problem with services and user accounts, that's the way to go. – Basic Jan 08 '13 at 14:58
2

I notice that the code doesn't call LoadUserProfile, so the users profile isn't loaded.

Note in the remarks of that function, HKEY_CURRENT_USER still isn't replaced though.

I think you can solve this issue (before calling the third party DLL) by calling RegOverridePredefKey.

Note that a lot of voodoo might be involved in getting this all working right - I'd try to make sure the override happens as late as possible before the third party call, and is reverted as soon as possible afterwards (hoping that this is all a single call to the library).

As an alternative, I'd seriously try looking around for a different 3rd party offering that doesn't require all of this jumping through hoops.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • Calling `RegOverridePredefKey` won't help in this case because that is per-process and impersonation is per-thread. – Ben Apr 13 '14 at 20:10