locked
User impersonation and OpenFileDialog C# RRS feed

  • Question

  • I am using the login impersonation in my application and I have a problem. It is a WPF application, when I use OpenFileBrowser then it do not have access to the files that impersonate user have. How can I solve this problem?

    Search for this problem, but I dont find any answers. Pls help me.

    i use this code:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Security.Principal;
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    namespace Utils
    {
        public class dvImpersonator : IDisposable
        {
            private WindowsImpersonationContext ImpersonationContext = null;
            enum LogonType
            {
                Interactive = 2,
                Network = 3,
                Batch = 4,
                Service = 5,
                Unlock = 7,
                NetworkClearText = 8,
                NewCredentials = 9
            }
            enum LogonProvider
            {
                Default = 0,
                WinNT35 = 1,
                WinNT40 = 2,
                WinNT50 = 3
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="userName"></param>
            /// <param name="domainName"></param>
            /// <param name="password"></param>
            /// <returns></returns>
            public bool LogOn(string _UserName, string _DomainName, string _Password)
            {
                return ImpersonateValidUser(_UserName, _DomainName, _Password, LOGON32_LOGON_INTERACTIVE);
            }
    
            public bool CrossDomainLogOn(string _UserName, string _DomainName, string _Password)
            {
                return ImpersonateValidUserCrossDomain(_UserName, _DomainName, _Password);
            }
    
            public void Dispose()
            {
                UndoImpersonation();
            }
    
            [DllImport("advapi32.dll", SetLastError = true)]
            private static extern int LogonUserA(
                          string lpszUserName,
                          string lpszDomain,
                          string lpszPassword,
                          int dwLogonType,
                          int dwLogonProvider,
                          ref IntPtr phToken);
    
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern int DuplicateToken(
                   IntPtr hToken,
                   int impersonationLevel,
                   ref IntPtr hNewToken);
    
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool RevertToSelf();
    
    
            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            private static extern bool CloseHandle(
                     IntPtr handle);
    
    
            private const int LOGON32_PROVIDER_DEFAULT = 0;
            private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
            private const int LOGON32_LOGON_INTERACTIVE = 2;
    
    
            /// <summary>
            /// Does the actual impersonation.
            /// </summary>
            /// <param name="userName">The name of the user to act as.</param>
            /// <param name="domainName">The domain name of the user to act as.</param>
            /// <param name="password">The password of the user to act as.</param>
            private bool ImpersonateValidUser(string _UserName, string _Domain, string _Password, int provider)
            {
                WindowsIdentity tempWindowsIdentity;
                IntPtr token = IntPtr.Zero;
                IntPtr tokenDuplicate = IntPtr.Zero;
                int iRet = 0;
                if (RevertToSelf())
                {
                    //Console.WriteLine("here 1");
                    if ((iRet = LogonUserA(_UserName, _Domain, _Password,
                        provider, LOGON32_PROVIDER_DEFAULT, ref token)) != 0)
                    {
                        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                        {
                            tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                            ImpersonationContext = tempWindowsIdentity.Impersonate();
                            if (ImpersonationContext != null)
                            {
                                CloseHandle(token);
                                CloseHandle(tokenDuplicate);
                                return true;
                            }
                        }
    
    
                    }
                    //Console.WriteLine("iret " + iRet);
                }
                if (token != IntPtr.Zero)
                    CloseHandle(token);
                if (tokenDuplicate != IntPtr.Zero)
                    CloseHandle(tokenDuplicate);
                return false;
    
            }
    
            /// <summary>
            /// Does the actual impersonation.
            /// </summary>
            /// <param name="userName">The name of the user to act as.</param>
            /// <param name="domainName">The domain name of the user to act as.</param>
            /// <param name="password">The password of the user to act as.</param>
            private bool ImpersonateValidUserCrossDomain(string _UserName, string _Domain, string _Password)
            {
                WindowsIdentity tempWindowsIdentity;
                IntPtr token = IntPtr.Zero;
                IntPtr tokenDuplicate = IntPtr.Zero;
                int iRet = 0;
                if (RevertToSelf())
                {
                    //Console.WriteLine("here 1");
                    if ((iRet = LogonUserA(_UserName, _Domain, _Password,
                        (int)LogonType.NewCredentials, (int)LogonProvider.WinNT50, ref token)) != 0)
                    {
                        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                        {
                            tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                            ImpersonationContext = tempWindowsIdentity.Impersonate();
                            if (ImpersonationContext != null)
                            {
                                CloseHandle(token);
                                CloseHandle(tokenDuplicate);
                                return true;
                            }
                        }
    
    
                    }
                    //Console.WriteLine("iret " + iRet);
                }
                if (token != IntPtr.Zero)
                    CloseHandle(token);
                if (tokenDuplicate != IntPtr.Zero)
                    CloseHandle(tokenDuplicate);
                return false;
    
            }
    
    
            /// <summary>
            /// Reverts the impersonation.
            /// </summary>
            private void UndoImpersonation()
            {
                if (ImpersonationContext != null)
                {
                    ImpersonationContext.Undo();
                }
            }
    
        }
    
    
    
    }

    run:

    using (var LogOn = new Utils.dvImpersonator())
    {
        LogOn.CrossDomainLogOn(this.oConfig.User, this.oConfig.Domain, this.oConfig.Password);
    
           //Code to Execute as other users
    }

     and it works, my app have access. but when i want to select folder in OpenFileBrowser i cant open user folders that i impersionate

    Sunday, June 1, 2014 5:24 PM

Answers

  • If you want to start the dialog from a specific network share then you can simply set the InitialDirectory property to a the UNC path of the share: \\computer\share

    If you want to start the dialog in the My Network Places shell folder then you're out of luck, the native file open dialog supports this but the .NET file dialogs do not expose this functionality.

    BTW, if you were trying to use impersonation to access a network share then there may be other ways. I don't know of a .NET API for this but I know it's possible to map a network drive and specify a specify a username/password. When you do that you can access the contents for the share without needing to impersonate.

    • Marked as answer by Caillen Sunday, June 8, 2014 12:31 PM
    Monday, June 2, 2014 5:14 PM

All replies

  • You're probably asking for trouble by using impersonation this way. Impersonation affects only one thread and there's no way to know if some arbitrary code does all the work on the same thread or it uses additional threads. My guess is that the file dialog is such a case, it likely uses a separate thread to enumerate folders & files.
    Sunday, June 1, 2014 6:57 PM
  • Is there any way to do this? to give the file/folder browser the privilege of another user? 
    Sunday, June 1, 2014 7:56 PM
  • The only way I know is to create a separate process that runs as the required user. That process could use OpenFileDialog and communicate the selected file name back to the original process.
    Sunday, June 1, 2014 8:03 PM
  • any help on how to do it?
    Sunday, June 1, 2014 8:50 PM
  • Well, you already have the user name and password so you could simply use the Process class to start the process. To get back the file name you can redirect the process output and have the open file dialog application write the file name to the (redirected) console.

    For example:

    private void button1_Click(object sender, EventArgs e) {
        string fileName;
    
        using (var pwd = new System.Security.SecureString()) {
            foreach (var ch in password)
                pwd.AppendChar(ch);
    
            using (var proc = Process.Start(new ProcessStartInfo {
                FileName = "WindowsFormsApplication2.exe",
                UserName = userName,
                Password = pwd,
                UseShellExecute = false,
                RedirectStandardOutput = true
            })) {
                fileName = proc.StandardOutput.ReadLine();
            }
        }
    
        if (!String.IsNullOrEmpty(fileName))
           MessageBox.Show(fileName);
    }
    

    And WindowsFormsApplication2.exe is a small WinForms app that simply shows the OpenFileDialog:

    static class Program {
        [STAThread]
        static void Main() {
            using (var dlg = new OpenFileDialog()) {
                if (dlg.ShowDialog() != DialogResult.OK)
                    Console.WriteLine();
                else
                    Console.WriteLine(dlg.FileName);
            }
        }
    }
    

    Sunday, June 1, 2014 9:24 PM
  • when i want to use that i have WerFault.exe error that say my application has not start properly

    error (0xc0000142)


    • Edited by bebe_ Monday, June 2, 2014 12:44 PM
    Monday, June 2, 2014 11:01 AM
  • That likely means that the user account you're trying to use doesn't have access to certain resources (files, registry keys...) on your machine. Try using Process Monitor to find "access denied" errors.
    Monday, June 2, 2014 1:52 PM
  • is there any option to start the dialog from shares (my network places)?
    Monday, June 2, 2014 4:57 PM
  • If you want to start the dialog from a specific network share then you can simply set the InitialDirectory property to a the UNC path of the share: \\computer\share

    If you want to start the dialog in the My Network Places shell folder then you're out of luck, the native file open dialog supports this but the .NET file dialogs do not expose this functionality.

    BTW, if you were trying to use impersonation to access a network share then there may be other ways. I don't know of a .NET API for this but I know it's possible to map a network drive and specify a specify a username/password. When you do that you can access the contents for the share without needing to impersonate.

    • Marked as answer by Caillen Sunday, June 8, 2014 12:31 PM
    Monday, June 2, 2014 5:14 PM