Open a shared file under another user and domain?

匿名 (未验证) 提交于 2019-12-03 00:56:02

问题:

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 local user does not have permission to access the shared resource.

Currently I overcome this problem manually by open the shared folder from the run and put the username and password into the windows authentication dialog then run the application.

How can I do it programmatically?

回答1:

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.



回答2:

I used the point "a" as "Anton" suggested, I developed two versions for one class, first one using Win32 APIs and second uses 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();                 }             } 


回答3:

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.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!