Search code examples
c#.netimpersonationsecurityexceptionlinklabel

Impersonation in .Net crashes when reading registry keys (LinkLabel SecurityException)


My app needs to impersonate a service account, which I do through a native-call to LogonUser. However, it appears that random components in the .Net library try to access registry keys the account doesn't have access to, causing a SecurityException to be thrown.

Specifically, when I load a LinkLabel, it crashes trying to determine the default hyperlink color in IE:

System.Security.SecurityException: Requested registry access is not allowed.
      at System.ThrowHelper.ThrowSecurityException(ExceptionResource resource)
      at Microsoft.Win32.RegistryKey.OpenSubKey(String name, Boolean writable)
      at Microsoft.Win32.RegistryKey.OpenSubKey(String name)
      at System.Windows.Forms.LinkUtilities.GetIEColor(String name)
      at System.Windows.Forms.LinkUtilities.get_IELinkColor()
      at System.Windows.Forms.LinkLabel.get_LinkColor()
      at System.Windows.Forms.LinkLabel.OnPaint(PaintEventArgs e)
      at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
      at System.Windows.Forms.Control.WmPaint(Message& m)
      at System.Windows.Forms.Control.WndProc(Message& m)
      at System.Windows.Forms.Label.WndProc(Message& m)
      at System.Windows.Forms.LinkLabel.WndProc(Message& msg)
      at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
      at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
      at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
The Zone of the assembly that failed was:  MyComputer

No, setting the default color does not help.


I found this thread with the exact same problem, but I'm afraid I don't understand the solution:

Registry hives loaded with LoadUserProfile are stored under HKU, HKCU remains the interactive logon user's hive (loaded by winlogon.exe).

So if you need to get at the newly loaded hive you need to:
- set Regkey to Registry.Users
- Open the subkey using the string SID of the user account you are impersonating.

Does anyone know of any workarounds for this?


Solution

  • The problem is you are impersonating too long and your code (indirectly through the .NET framework) is accessing more resources than you intended while impersonating. This exception seems to be caused by the fact your impersonation code is running on a GUI (STA) thread.

    You can:

    1. Impersonate for a shorter period of time - only as long as you need to so call impersonate followed by undo as soon as you can. Even if one statement later you have to re-impersonate. This is the typical impersonation pattern.
    2. Move the impersonating code to a worker (MTA) thread and you should avoid this particular symptom. Now you have the problem of how to communicate with the impersonation code but it's not terrible.
    3. If you really want the whole process to run as the system account (as a least privilege sort of thing perhaps), the only supported solution I know of is to have HKEY_CURRENT_USER be something the system account can access. That's done by calling LoadUserProfile and then call CreateProcessAsUser; but that's a whole new architecture for you to spin a new process to handle the impersonation.