2013-07-08 35 views
1

我有代碼創建一個模擬塊允許讀取訪問遠程ini文件,並寫入訪問到遠程目錄。當要寫入的「遠程」目錄是真正的遠程計算機UNC路徑時,系統寫入很好,但是如果「遠程」ini文件確實是遠程UNC路徑,則GetPrivateProfileSectionNames返回0.但是,如果「遠程」 ini文件實際上只是一個本地UNC路徑,該功能按預期工作。有沒有辦法讓ini文件真正在遠程計算機上的情況下按預期工作?GetPrivateProfileSectionNames在模擬塊中運行時返回0當ini文件是遠程

我模擬塊是使用以下一次性類完成:

[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] 
public class Impersonation : IDisposable 
{ 
    private WindowsImpersonationContext _impersonatedUserContext; 

    // Declare signatures for Win32 LogonUser and CloseHandle APIs 
    [DllImport("advapi32.dll", SetLastError = true)] 
    static extern bool LogonUser(
     string principal, 
     string authority, 
     string password, 
     LogonSessionType logonType, 
     LogonProvider logonProvider, 
     out IntPtr token); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    static extern bool CloseHandle(IntPtr handle); 

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

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    static extern bool RevertToSelf(); 

    // ReSharper disable UnusedMember.Local 
    enum LogonSessionType : uint 
    { 
     Interactive = 2, 
     Network, 
     Batch, 
     Service, 
     NetworkCleartext = 8, 
     NewCredentials 
    } 
    // ReSharper disable InconsistentNaming 
    enum LogonProvider : uint 
    { 
     Default = 0, // default for platform (use this!) 
     WinNT35,  // sends smoke signals to authority 
     WinNT40,  // uses NTLM 
     WinNT50  // negotiates Kerb or NTLM 
    } 
    // ReSharper restore InconsistentNaming 
    // ReSharper restore UnusedMember.Local 

    /// <summary> 
    /// Class to allow running a segment of code under a given user login context 
    /// </summary> 
    /// <param name="user">domain\user</param> 
    /// <param name="password">user's domain password</param> 
    public Impersonation(string user, string password) 
    { 
     var token = ValidateParametersAndGetFirstLoginToken(user, password); 

     var duplicateToken = IntPtr.Zero; 
     try 
     { 
      if (DuplicateToken(token, 2, ref duplicateToken) == 0) 
      { 
       throw new Exception("DuplicateToken call to reset permissions for this token failed"); 
      } 

      var identityForLoggedOnUser = new WindowsIdentity(duplicateToken); 
      _impersonatedUserContext = identityForLoggedOnUser.Impersonate(); 
      if (_impersonatedUserContext == null) 
      { 
       throw new Exception("WindowsIdentity.Impersonate() failed"); 
      } 
     } 
     finally 
     { 
      if (token != IntPtr.Zero) 
       CloseHandle(token); 
      if (duplicateToken != IntPtr.Zero) 
       CloseHandle(duplicateToken); 
     } 
    } 

    private static IntPtr ValidateParametersAndGetFirstLoginToken(string user, string password) 
    { 
     if (string.IsNullOrEmpty(user)) 
     { 
      throw new ConfigurationErrorsException("No user passed into impersonation class"); 
     } 
     var userHaves = user.Split('\\'); 
     if (userHaves.Length != 2) 
     { 
      throw new ConfigurationErrorsException("User must be formatted as follows: domain\\user"); 
     } 
     if (!RevertToSelf()) 
     { 
      throw new Exception("RevertToSelf call to remove any prior impersonations failed"); 
     } 

     IntPtr token; 

     var result = LogonUser(userHaves[1], userHaves[0], 
           password, 
           LogonSessionType.Interactive, 
           LogonProvider.Default, 
           out token); 
     if (!result) 
     { 
      throw new ConfigurationErrorsException("Logon for user " + user + " failed."); 
     } 
     return token; 
    } 
    /// <summary> 
    /// Dispose 
    /// </summary> 
    public void Dispose() 
    { 
     // Stop impersonation and revert to the process identity 
     if (_impersonatedUserContext != null) 
     { 
      _impersonatedUserContext.Undo(); 
      _impersonatedUserContext.Dispose(); 
      _impersonatedUserContext = null; 
     } 
    } 
} 

雖然此類的模擬塊實例內,遠程INI文件是通過訪問:

int bufLen = GetPrivateProfileSectionNames(buffer, 
              buffer.GetUpperBound(0),  
              iniFileName); 
if (bufLen > 0) 
{ 
    //process results 
} 

怎麼辦處理遠程計算機時,GetPrivateProfileSectionNames是否返回有效數據?我的用戶在這臺計算機或遠程計算機上需要有權限嗎?

回答

1

在這個時間點,我一直沒能找到有關模擬信息以及它如何與Win32的DLL文件/ API的,但是,我知道下面的交互:

1)如果整個過程用戶下運行能夠訪問遠程文件夾ini文件住在,然後GetPrivateProfileSectionNames工作方式所需

2)如果GetPrivateProfileSectionNames被稱爲模擬塊內,那麼它不根據需要

3工作)如果打開文件流,並將ini文件複製到本地,然後GetPrivateProfileSectio nNames用於本地ini文件,然後GetPrivateProfileSectionNames按需要工作,並允許文件流訪問遠程文件。

我推測,根據結果,win32 api調用GetPrivateProfileSectionNames沒有通過從c#的模擬上下文,因此運行在沒有訪問權限的整個流程上下文中。我通過本地緩存ini文件解決了這個問題,並跟蹤了上次更改的時間,以便知道ini文件是否需要重新緩存,或者本地副本是否正確。

相關問題