2

別のドメインのマシンで共有ファイルを読み取る必要があるC#コンソールアプリケーションがあります。アプリケーションがファイルにアクセスしようとすると、ローカルユーザーが共有リソースにアクセスする権限を持っていないため、例外が発生します。

現在、実行から共有フォルダーを開き、ユーザー名とパスワードをWindows認証ダイアログに入力してからアプリケーションを実行することにより、この問題を手動で克服しています。

プログラムでそれを行うにはどうすればよいですか?

4

3 に答える 3

3

a)p / invokeLogonUserを使用して、新しいトークンを使用してLOGON32_LOGON_NEW_CREDENTIALSnewを作成してから、通常のファイルアクセスを使用します。WindowsIdentity

b)WNetAddConnection3をp/invokeします。これにより、リモート共有がマシン上の他のすべてのプロセスにアクセスできるようになることに注意してください。

c)System.Managementおよびを介したWMI CIM_DataFile; p/invokeも必要ありません。System.Managementリモートマシンの資格情報を指定できます。

于 2009-07-28T08:48:35.823 に答える
3

Anton が提案したように、ポイント "a" を使用しました。1 つのクラスに対して 2 つのバージョンを開発しました。1 つ目は Win32 API を使用し、2 つ目はWindowsIdentityクラスを使用します。

バージョン 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 (小さな変更を加えたMSDNから):

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
}

使い方(どちらも同じ):

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();
    }
}
于 2009-07-28T10:43:39.133 に答える
0

メモリから、Windows API 呼び出しを使用し、他のドメインのユーザーとしてログインする必要があります。例については、このリンクを参照してください。

もう 1 つのアイデアは、RunAs コマンド ライン引数を使用してファイルを読み取り、ローカル ドメイン/サーバー上のファイルに保存することです。

于 2009-07-28T08:32:37.040 に答える