2
votes

I'm trying to run my winform app with a local window user credential, for this I'm using below class for impersonation,

public class Impersonation
{

    /// <summary>
    /// Impersonate given logon information.
    /// </summary>
    /// <param name="logon">Windows logon name.</param>
    /// <param name="password">password</param>
    /// <param name="domain">domain name</param>
    /// <returns></returns>
    public static bool Impersonate(string logon, string password, string domain)
    {
        WindowsIdentity tempWindowsIdentity;
        IntPtr token = IntPtr.Zero;
        IntPtr tokenDuplicate = IntPtr.Zero;

        if (LogonUser(logon, domain, password, LOGON32_LOGON_INTERACTIVE,
        LOGON32_PROVIDER_DEFAULT, ref token) != 0)
        {

            if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
            {
                tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                impersonationContext = tempWindowsIdentity.Impersonate();
                if (null != impersonationContext) return true;
            }
        }

        return false;
    }

    /// <summary>
    /// Unimpersonate.
    /// </summary>
    public static void UnImpersonate()
    {
        impersonationContext.Undo();
    }

    [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
    public static extern int LogonUser(
    string lpszUserName,
    String lpszDomain,
    String lpszPassword,
    int dwLogonType,
    int dwLogonProvider,
    ref IntPtr phToken);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public extern static int DuplicateToken(
    IntPtr hToken,
    int impersonationLevel,
    ref IntPtr hNewToken);

    private const int LOGON32_LOGON_INTERACTIVE = 2;
    private const int LOGON32_LOGON_NETWORK_CLEARTEXT = 4;
    private const int LOGON32_PROVIDER_DEFAULT = 0;
    private static WindowsImpersonationContext impersonationContext;
}

Now here is the code for 'winform` startup code,

static class Program
{
    [STAThread]
    static void Main()
    {
        try
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            string userName = Microsoft.VisualBasic.Interaction.InputBox("Enter User Name", "User Name");
            string password = Microsoft.VisualBasic.Interaction.InputBox("Enter Password", "Password");

            if (!Impersonation.Impersonate(userName, password, Environment.MachineName))
            {
                MessageBox.Show("Login failed.");
                return;
            }

            Application.Run(new Form1());

            Impersonation.UnImpersonate();
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error: " + ex.ToString());
        }
    }
}

Now when I'm passing the credential for local window user, login is successful and while loading the form, I'm getting error,

System.Security.SecurityException: 'Requested registry access is not allowed.'

and here is the full stack trace,

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) 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.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

What could be the reason?

1

1 Answers

2
votes

If you are trying to access the registry hive of another user, i think you'll find you will need the to be an administrator or LocalSystem account.

You can find a snippet of information at the bottom of the LoadUserProfileA function Win32 Api

Starting with Windows XP Service Pack 2 (SP2) and Windows Server 2003, the caller must be an administrator or the LocalSystem account. It is not sufficient for the caller to merely impersonate the administrator or LocalSystem account.

Note : (This is speculative) however, you could possibly launch a new process (under the admin credentials) to load the profile and access the registry.