Open a shared file under another user and domain?

前端 未结 3 1116
一生所求
一生所求 2020-12-06 03:47

I have a C# console application that needs to read a shared file on a machine in another domain. When the application tries to access the file an exception occurs as the loc

相关标签:
3条回答
  • 2020-12-06 04:31

    From memory you'll need to use a Windows API call and login as a user on the other domain. See this link for an example.

    Another idea could be to use the RunAs command line argument to read the file and save it into a file on your local domain/server.

    0 讨论(0)
  • 2020-12-06 04:32

    a) p/invoke LogonUser with LOGON32_LOGON_NEW_CREDENTIALS and create a new WindowsIdentity with the new token, then use normal file access.

    b) p/invoke WNetAddConnection3. Be advised that this makes your remote share accessible to every other process on your machine.

    c) WMI via System.Management and CIM_DataFile; you won't even need p/invoke. System.Management lets you specify credentials for remote machine.

    0 讨论(0)
  • 2020-12-06 04:35

    I used the point "a" as Anton suggested, I developed two versions for one class, the first one using the Win32 APIs, and the second uses the WindowsIdentity class.

    Version 1:

    class UserImpersonation : IDisposable
    {       
        [DllImport("advapi32.dll")]
        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 static extern int DuplicateToken(IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);
    
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool RevertToSelf();
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);
    
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_INTERACTIVE = 2;
    
        WindowsImpersonationContext wic;
        string _userName;
        string _domain;
        string _passWord;
        
        public UserImpersonation(string userName, string domain, string passWord)
        {
            _userName = userName;
            _domain = domain;
            _passWord = passWord;
        }
        
        public bool ImpersonateValidUser()
        {
            WindowsIdentity wi;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;
    
            if (RevertToSelf())
            {
                if (LogonUser(_userName, _domain, _passWord, LOGON32_LOGON_INTERACTIVE,
                    LOGON32_PROVIDER_DEFAULT, ref token) != 0)
                {
                    if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                    {
                        wi = new WindowsIdentity(tokenDuplicate);
                        wic = wi.Impersonate();
                        if (wic != null)
                        {
                            CloseHandle(token);
                            CloseHandle(tokenDuplicate);
                            return true;
                        }
                    }
                }
            }
            
            if (token != IntPtr.Zero)
            {
                CloseHandle(token);
            }
            if (tokenDuplicate != IntPtr.Zero)
            {
                CloseHandle(tokenDuplicate);
            }
            return false;
        }
    
        #region IDisposable Members
        public void Dispose()
        {
            if (wic != null)
            {
                wic.Dispose();
            }
            RevertToSelf();
        }
        #endregion
    }
    

    Version2 (from MSDN with small changes):

    class UserImpersonation2 : IDisposable
    {
        [DllImport("advapi32.dll")]
        public static extern bool LogonUser(String lpszUserName,
            String lpszDomain,
            String lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);
    
        WindowsImpersonationContext wic;
        IntPtr tokenHandle;
        string _userName;
        string _domain;
        string _passWord;
    
        public UserImpersonation2(string userName, string domain, string passWord)
        {
            _userName = userName;
            _domain = domain;
            _passWord = passWord;
        }
    
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_INTERACTIVE = 2;
    
        public bool ImpersonateValidUser()
        {
            bool returnValue = LogonUser(_userName, _domain, _passWord,
                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                    ref tokenHandle);
    
            Console.WriteLine("LogonUser called.");
    
            if (false == returnValue)
            {
                int ret = Marshal.GetLastWin32Error();
                Console.WriteLine("LogonUser failed with error code : {0}", ret);
                return false;
            }
    
            Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));
            Console.WriteLine("Value of Windows NT token: " + tokenHandle);
    
            // Check the identity.
            Console.WriteLine("Before impersonation: "
                + WindowsIdentity.GetCurrent().Name);
                
            // Use the token handle returned by LogonUser.
            WindowsIdentity newId = new WindowsIdentity(tokenHandle);
            wic = newId.Impersonate();
    
            // Check the identity.
            Console.WriteLine("After impersonation: "
                + WindowsIdentity.GetCurrent().Name);
                
            return true;
        }
        
        #region IDisposable Members
        public void Dispose()
        {
            if(wic!=null)
            {
                wic.Undo();
            }
            if (tokenHandle != IntPtr.Zero)
            {
                CloseHandle(tokenHandle);
            }
        }
        #endregion
    }
    

    How to use (both are the same):

    const string file = @"\\machine\test\file.txt";
    
    using (UserImpersonation user = new UserImpersonation("user", "domain", "password"))
    {
        if (user.ImpersonateValidUser())
        {
            StreamReader reader = new StreamReader(file);
            Console.WriteLine(reader.ReadToEnd());
            reader.Close();
        }
    }
    
    0 讨论(0)
提交回复
热议问题