資格情報を使用して、信頼されていないリモートドメインから共有ファイル(UNC)にアクセスする


151

解決する必要のある興味深い状況に遭遇し、私の検索結果はまったくわかりませんでした。したがって、私はSOコミュニティに支援を求めます。

問題は次のとおりです。ドメインになく、リモートファイル共有/ UNCを介して信頼できる外部ドメインにない共有ファイルにプログラムでアクセスする必要があります。当然、リモートマシンに資格情報を提供する必要があります。

通常、この問題は次の2つの方法のいずれかで解決します。

  1. ファイル共有をドライブとしてマップし、そのときに資格情報を提供します。これは通常NET USE、複製するコマンドまたはWin32関数を使用して行われNET USEます。
  2. リモートコンピューターがドメイン上にあるかのようにUNCパスを使用してファイルにアクセスし、プログラムを実行するアカウントがローカルユーザーとしてリモートマシンで(パスワードを含めて)複製されていることを確認します。ユーザーが共有ファイルにアクセスしようとすると、Windowsが現在のユーザーの資格情報を自動的に提供するという事実を基本的に利用します。
  3. リモートファイル共有を使用しないでください。FTP(またはその他の手段)を使用してファイルを転送し、ローカルで作業してから、元に戻します。

さまざまな理由により、セキュリティ/ネットワークアーキテクトは最初の2つのアプローチを拒否しました。2番目のアプローチは明らかにセキュリティホールです。リモートコンピューターが侵害された場合、ローカルコンピューターが危険にさらされます。新しくマウントされたドライブは、プログラムによるファイルアクセス中にローカルコンピュータ上の他のプログラムが利用できる共有リソースであるため、最初のアプローチは不十分です。これを一時的にすることはかなり可能ですが、それでも彼らの意見には穴があります。

彼らは3番目のオプションを利用できますが、リモートネットワーク管理者はFTPSではなくSFTPを要求し、FtpWebRequestはFTPSのみをサポートします。SFTP ファイアウォールに適したオプションであり、そのアプローチに使用できるライブラリーがいくつかありますが、可能であれば依存関係を減らしたいと思います。

私はMSDNでリモートファイル共有を使用する管理された手段またはwin32の手段のいずれかを検索しましたが、有用なものを思い付くことができませんでした。

そして私は尋ねます:別の方法はありますか?私が望んでいる超秘密のwin32関数を見逃しましたか?または、オプション3のいくつかの変形を追求する必要がありますか?


なりすましのアプローチで解決しましたが、それはドメイン外の2台のマシン間です。ドメインからドメイン外のコンピュータへの通信に問題があるかどうかはわかりません。stackoverflow.com/questions/17221476/...
Wolf5

回答:


174

問題を解決する方法は、WNetUseConnectionと呼ばれるWin32 APIを使用することです
この関数を使用して、ドライブをマップするのではなく、認証を使用してUNCパスに接続します。

これにより、同じドメイン上になくても、ユーザー名とパスワードが異なっていても、リモートマシンに接続できます。

WNetUseConnectionを使用すると、同じドメインにいるかのように、UNCパスを介してファイルにアクセスできます。最善の方法は、おそらく管理用組み込み共有を使用することです。
例:\\ computername \ c $ \ program files \ Folder \ file.txt

以下は、WNetUseConnectionを使用するサンプルC#コードです。
NetResourceの場合、lpLocalNameおよびlpProviderにnullを渡す必要があります。dwTypeはRESOURCETYPE_DISKである必要があります。lpRemoteNameは\\ ComputerNameである必要があります。

using System;
using System.Runtime.InteropServices ;
using System.Threading;

namespace ExtremeMirror
{
    public class PinvokeWindowsNetworking
    {
        #region Consts
        const int RESOURCE_CONNECTED = 0x00000001;
        const int RESOURCE_GLOBALNET = 0x00000002;
        const int RESOURCE_REMEMBERED = 0x00000003;

        const int RESOURCETYPE_ANY = 0x00000000;
        const int RESOURCETYPE_DISK = 0x00000001;
        const int RESOURCETYPE_PRINT = 0x00000002;

        const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
        const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001;
        const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
        const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
        const int RESOURCEDISPLAYTYPE_FILE = 0x00000004;
        const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005;

        const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
        const int RESOURCEUSAGE_CONTAINER = 0x00000002;


        const int CONNECT_INTERACTIVE = 0x00000008;
        const int CONNECT_PROMPT = 0x00000010;
        const int CONNECT_REDIRECT = 0x00000080;
        const int CONNECT_UPDATE_PROFILE = 0x00000001;
        const int CONNECT_COMMANDLINE = 0x00000800;
        const int CONNECT_CMD_SAVECRED = 0x00001000;

        const int CONNECT_LOCALDRIVE = 0x00000100;
        #endregion

        #region Errors
        const int NO_ERROR = 0;

        const int ERROR_ACCESS_DENIED = 5;
        const int ERROR_ALREADY_ASSIGNED = 85;
        const int ERROR_BAD_DEVICE = 1200;
        const int ERROR_BAD_NET_NAME = 67;
        const int ERROR_BAD_PROVIDER = 1204;
        const int ERROR_CANCELLED = 1223;
        const int ERROR_EXTENDED_ERROR = 1208;
        const int ERROR_INVALID_ADDRESS = 487;
        const int ERROR_INVALID_PARAMETER = 87;
        const int ERROR_INVALID_PASSWORD = 1216;
        const int ERROR_MORE_DATA = 234;
        const int ERROR_NO_MORE_ITEMS = 259;
        const int ERROR_NO_NET_OR_BAD_PATH = 1203;
        const int ERROR_NO_NETWORK = 1222;

        const int ERROR_BAD_PROFILE = 1206;
        const int ERROR_CANNOT_OPEN_PROFILE = 1205;
        const int ERROR_DEVICE_IN_USE = 2404;
        const int ERROR_NOT_CONNECTED = 2250;
        const int ERROR_OPEN_FILES  = 2401;

        private struct ErrorClass 
        {
            public int num;
            public string message;
            public ErrorClass(int num, string message) 
            {
                this.num = num;
                this.message = message;
            }
        }


        // Created with excel formula:
        // ="new ErrorClass("&A1&", """&PROPER(SUBSTITUTE(MID(A1,7,LEN(A1)-6), "_", " "))&"""), "
        private static ErrorClass[] ERROR_LIST = new ErrorClass[] {
            new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"), 
            new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"), 
            new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"), 
            new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"), 
            new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"), 
            new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"), 
            new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"), 
            new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"), 
            new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"), 
            new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"), 
            new ErrorClass(ERROR_MORE_DATA, "Error: More Data"), 
            new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"), 
            new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"), 
            new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"), 
            new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"), 
            new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"), 
            new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"), 
            new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"), 
            new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"), 
            new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"), 
        };

        private static string getErrorForNumber(int errNum) 
        {
            foreach (ErrorClass er in ERROR_LIST) 
            {
                if (er.num == errNum) return er.message;
            }
            return "Error: Unknown, " + errNum;
        }
        #endregion

        [DllImport("Mpr.dll")] private static extern int WNetUseConnection(
            IntPtr hwndOwner,
            NETRESOURCE lpNetResource,
            string lpPassword,
            string lpUserID,
            int dwFlags,
            string lpAccessName,
            string lpBufferSize,
            string lpResult
        );

        [DllImport("Mpr.dll")] private static extern int WNetCancelConnection2(
            string lpName,
            int dwFlags,
            bool fForce
        );

        [StructLayout(LayoutKind.Sequential)] private class NETRESOURCE
        { 
            public int dwScope = 0;
            public int dwType = 0;
            public int dwDisplayType = 0;
            public int dwUsage = 0;
            public string lpLocalName = "";
            public string lpRemoteName = "";
            public string lpComment = "";
            public string lpProvider = "";
        }


        public static string connectToRemote(string remoteUNC, string username, string password) 
        {
            return connectToRemote(remoteUNC, username, password, false);
        }

        public static string connectToRemote(string remoteUNC, string username, string password, bool promptUser) 
        {
            NETRESOURCE nr = new NETRESOURCE();
            nr.dwType = RESOURCETYPE_DISK;
            nr.lpRemoteName = remoteUNC;
            //          nr.lpLocalName = "F:";

            int ret;
            if (promptUser) 
                ret = WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null);
            else 
                ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);

            if (ret == NO_ERROR) return null;
            return getErrorForNumber(ret);
        }

        public static string disconnectRemote(string remoteUNC) 
        {
            int ret = WNetCancelConnection2(remoteUNC, CONNECT_UPDATE_PROFILE, false);
            if (ret == NO_ERROR) return null;
            return getErrorForNumber(ret);
        }
    }
}

このような関数を使用して、現在の資格情報を使用して、つまりユーザー名とパスワードを指定せずに、ネットワークマシンへの接続を明示的に開閉する方法はありますか?ファイル共有にアクセスした後、接続を閉じることに特に興味があります。
フリップダウト2009年

コンピュータ自体にユーザー名またはパスワードがない場合を除き、接続用ではありません。切断する場合は、できることを確認してください。代わりに、コマンドラインからも実行できます。
ブライアンR.ボンディ

1
こんにちはブライアン。リンクするドキュメントでは、ユーザー名とパスワードにNULLを渡して現在の認証情報を使用できるとしています。これが機能するかどうかを確認するために、いくつかのテストを行います。
フリップダウト2009年

ユーザー名/パスワードにnullを渡すと接続できますが、切断したことをどのように証明できますか?私が見ることができるサーバー上に何かがありますか?Server 2003では、セッションを監視できますが、アプリがこれらのAPIを使用しない場合、現在のセッションのリストは同じくらい速く更新されます。
フリップダウト2009年

で開いた接続WNetUseConnectionを呼び出すことによって手動で閉じる必要がありWNetCancelConnection2ますか?または、アイドルタイムアウト(またはその他のメカニズム)があり、気にする必要はありませんか?
w128

123

簡単な解決策を探している人は、NetworkShareAccesser私が最近書いた(この回答に基づいて(どうもありがとう!))

使用法:

using (NetworkShareAccesser.Access(REMOTE_COMPUTER_NAME, DOMAIN, USER_NAME, PASSWORD))
{
    File.Copy(@"C:\Some\File\To\copy.txt", @"\\REMOTE-COMPUTER\My\Shared\Target\file.txt");
}

警告:(アプリがクラッシュした場合でも)が呼び出されることDisposeを確認してください。NetworkShareAccesser呼び出されない場合、開いた接続がWindowsに残ります。cmdプロンプトを開いてと入力すると、開いているすべての接続を表示できますnet use

コード:

/// <summary>
/// Provides access to a network share.
/// </summary>
public class NetworkShareAccesser : IDisposable
{
    private string _remoteUncName;
    private string _remoteComputerName;

    public string RemoteComputerName
    {
        get
        {
            return this._remoteComputerName;
        }
        set
        {
            this._remoteComputerName = value;
            this._remoteUncName = @"\\" + this._remoteComputerName;
        }
    }

    public string UserName
    {
        get;
        set;
    }
    public string Password
    {
        get;
        set;
    }

    #region Consts

    private const int RESOURCE_CONNECTED = 0x00000001;
    private const int RESOURCE_GLOBALNET = 0x00000002;
    private const int RESOURCE_REMEMBERED = 0x00000003;

    private const int RESOURCETYPE_ANY = 0x00000000;
    private const int RESOURCETYPE_DISK = 0x00000001;
    private const int RESOURCETYPE_PRINT = 0x00000002;

    private const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
    private const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001;
    private const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
    private const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
    private const int RESOURCEDISPLAYTYPE_FILE = 0x00000004;
    private const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005;

    private const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
    private const int RESOURCEUSAGE_CONTAINER = 0x00000002;


    private const int CONNECT_INTERACTIVE = 0x00000008;
    private const int CONNECT_PROMPT = 0x00000010;
    private const int CONNECT_REDIRECT = 0x00000080;
    private const int CONNECT_UPDATE_PROFILE = 0x00000001;
    private const int CONNECT_COMMANDLINE = 0x00000800;
    private const int CONNECT_CMD_SAVECRED = 0x00001000;

    private const int CONNECT_LOCALDRIVE = 0x00000100;

    #endregion

    #region Errors

    private const int NO_ERROR = 0;

    private const int ERROR_ACCESS_DENIED = 5;
    private const int ERROR_ALREADY_ASSIGNED = 85;
    private const int ERROR_BAD_DEVICE = 1200;
    private const int ERROR_BAD_NET_NAME = 67;
    private const int ERROR_BAD_PROVIDER = 1204;
    private const int ERROR_CANCELLED = 1223;
    private const int ERROR_EXTENDED_ERROR = 1208;
    private const int ERROR_INVALID_ADDRESS = 487;
    private const int ERROR_INVALID_PARAMETER = 87;
    private const int ERROR_INVALID_PASSWORD = 1216;
    private const int ERROR_MORE_DATA = 234;
    private const int ERROR_NO_MORE_ITEMS = 259;
    private const int ERROR_NO_NET_OR_BAD_PATH = 1203;
    private const int ERROR_NO_NETWORK = 1222;

    private const int ERROR_BAD_PROFILE = 1206;
    private const int ERROR_CANNOT_OPEN_PROFILE = 1205;
    private const int ERROR_DEVICE_IN_USE = 2404;
    private const int ERROR_NOT_CONNECTED = 2250;
    private const int ERROR_OPEN_FILES = 2401;

    #endregion

    #region PInvoke Signatures

    [DllImport("Mpr.dll")]
    private static extern int WNetUseConnection(
        IntPtr hwndOwner,
        NETRESOURCE lpNetResource,
        string lpPassword,
        string lpUserID,
        int dwFlags,
        string lpAccessName,
        string lpBufferSize,
        string lpResult
        );

    [DllImport("Mpr.dll")]
    private static extern int WNetCancelConnection2(
        string lpName,
        int dwFlags,
        bool fForce
        );

    [StructLayout(LayoutKind.Sequential)]
    private class NETRESOURCE
    {
        public int dwScope = 0;
        public int dwType = 0;
        public int dwDisplayType = 0;
        public int dwUsage = 0;
        public string lpLocalName = "";
        public string lpRemoteName = "";
        public string lpComment = "";
        public string lpProvider = "";
    }

    #endregion

    /// <summary>
    /// Creates a NetworkShareAccesser for the given computer name. The user will be promted to enter credentials
    /// </summary>
    /// <param name="remoteComputerName"></param>
    /// <returns></returns>
    public static NetworkShareAccesser Access(string remoteComputerName)
    {
        return new NetworkShareAccesser(remoteComputerName);
    }

    /// <summary>
    /// Creates a NetworkShareAccesser for the given computer name using the given domain/computer name, username and password
    /// </summary>
    /// <param name="remoteComputerName"></param>
    /// <param name="domainOrComuterName"></param>
    /// <param name="userName"></param>
    /// <param name="password"></param>
    public static NetworkShareAccesser Access(string remoteComputerName, string domainOrComuterName, string userName, string password)
    {
        return new NetworkShareAccesser(remoteComputerName,
                                        domainOrComuterName + @"\" + userName,
                                        password);
    }

    /// <summary>
    /// Creates a NetworkShareAccesser for the given computer name using the given username (format: domainOrComputername\Username) and password
    /// </summary>
    /// <param name="remoteComputerName"></param>
    /// <param name="userName"></param>
    /// <param name="password"></param>
    public static NetworkShareAccesser Access(string remoteComputerName, string userName, string password)
    {
        return new NetworkShareAccesser(remoteComputerName, 
                                        userName,
                                        password);
    }

    private NetworkShareAccesser(string remoteComputerName)
    {
        RemoteComputerName = remoteComputerName;               

        this.ConnectToShare(this._remoteUncName, null, null, true);
    }

    private NetworkShareAccesser(string remoteComputerName, string userName, string password)
    {
        RemoteComputerName = remoteComputerName;
        UserName = userName;
        Password = password;

        this.ConnectToShare(this._remoteUncName, this.UserName, this.Password, false);
    }

    private void ConnectToShare(string remoteUnc, string username, string password, bool promptUser)
    {
        NETRESOURCE nr = new NETRESOURCE
        {
            dwType = RESOURCETYPE_DISK,
            lpRemoteName = remoteUnc
        };

        int result;
        if (promptUser)
        {
            result = WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null);
        }
        else
        {
            result = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);
        }

        if (result != NO_ERROR)
        {
            throw new Win32Exception(result);
        }
    }

    private void DisconnectFromShare(string remoteUnc)
    {
        int result = WNetCancelConnection2(remoteUnc, CONNECT_UPDATE_PROFILE, false);
        if (result != NO_ERROR)
        {
            throw new Win32Exception(result);
        }
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    /// <filterpriority>2</filterpriority>
    public void Dispose()
    {
        this.DisconnectFromShare(this._remoteUncName);
    }
}

2
あなたも必要using System.Runtime.InteropServices;using System.ComponentModel;するためにDllImportWin32Exception
Kᴀτᴢ

この解決策は私の長い一日の検索を止めました。ありがとう!!! 必要に応じてかなりうまく動作します。
Venkat

1
リモートマシンのローカルユーザーアカウントでソリューションを使用しようとしていますが、アクセス拒否エラーが発生し続けます。ソリューションはネットワークアカウントでのみ機能しますか?
M3NTA7 2017年

1
アカウントはリモートマシンに存在しますが、ネットワークアカウントではありません。ローカルマシンアカウントです。ドメインをマシンの名前に設定してみました。また、共有フォルダーのローカルユーザーアカウントに完全なアクセス許可を与えましたが、アクセスが拒否されます。なぜこれが起こっているのかについてのアイデアはありますか?どうも。
M3NTA7 2017年

2
注:オブジェクトを破棄しても、システム(Windows 10)から資格情報がワイプされないようです。接続が「キャンセル」された後、リモートコンピュータ上のファイルにアクセスできます。ユーザーアカウントに再度ログインするか、コンピューターを再起動すると、この内部キャッシュがクリアされるようです。
Tim Cooper、

16

私の知る限り、サーバーの資格情報を確立するために、UNCパスをドライブ文字にマップする必要はありません。私は定期的に次のようなバッチスクリプトを使用しました。

net use \\myserver /user:username password

:: do something with \\myserver\the\file\i\want.xml

net use /delete \\my.server.com

ただし、プログラムと同じアカウントで実行されているプログラムは、アクセスできるすべてのものusername:passwordにアクセスできます。考えられる解決策は、プログラムを独自のローカルユーザーアカウントに分離することです(UNCアクセスは、を呼び出したアカウントに対してローカルNET USEです)。

注:ドメイン全体でSMBを使用することは、IMO技術を十分に活用するものではありません。セキュリティがそれほど重要である場合、SMBが暗号化を欠いているという事実は、それ自体が少しダンパーです。


UNCへのアクセスがを呼び出したアカウントでのみ利用可能であることについて正しい場合NET USE、それは実行可能なアプローチである可能性があります。ただし、ローカルアカウントを使用する必要がありますか?NET USE呼び出しは、呼び出されたマシンに対してローカルではありませんか?あなたは私によい研究のパスを与えてくれた
Randolpho

私の知る限り、私は間違っているかもしれませんが、UNCアクセスは、NET USEへの呼び出しが行われた特定のセキュリティプリンシパル(SAMアカウントなど)でのみ使用できます。これを確認するには、RunAsを使用してパスをマップし、別のアカウントからアクセスを試みます。
ジェイコブ

私の場合、ユーザーが別のドメインにいるため、net use \\ myserver / user:username @ domain passwordを使用する必要がありました。
StarCub

4

WNetUseConnectionではなく、NetUseAddをお勧めします。WNetUseConnectionは、WNetUseConnection2とWNetUseConnection3に取って代わられたレガシー関数ですが、これらの関数はすべて、Windowsエクスプローラーに表示されるネットワークデバイスを作成します。NetUseAddは、リモートコンピューターで認証するためにDOSプロンプトでnet useを呼び出すのと同じです。

NetUseAddを呼び出すと、その後のディレクトリへのアクセス試行は成功します。


1
@Adam Robinson:これは真実ではありません。そのようなWNetUseConnection2もWNetUseConnection3もありません。私は、WNetAddConnectionがWNetAddConnection2とWnetAddConnection3に取って代わられることについて考えていると思います。また、あなたがそれについて与えた情報は真実ではありません。
ブライアンR.ボンディ

WNetUseConnectionはWNetAddConnection3に似ていますが、マップされたローカルドライブを作成するオプション機能もあります。使用する必要はありません。
ブライアンR.ボンディ

@ BrianR.Bondyそれらは確かに存在し、C#として実装されていないだけです。ソース:docs.microsoft.com/da-dk/windows/win32/api/lmuse/…引用:「WNetAddConnection2関数とWNetAddConnection3関数を使用して、ローカルデバイスをネットワークリソースにリダイレクトすることもできます。」
Thomas Williams

4

私は自分自身を知りませんが、#2が正しくないことを私は確かに願っています... Windowsが私のマシンにログイン情報(すべてのパスワードのうちの最も少ない!)を自動的に提供することはないと思いたいのですが。 、もちろん私の信頼の一部ではないものは。

とにかく、なりすましのアーキテクチャを調べましたか?コードは次のようになります。

using (System.Security.Principal.WindowsImpersonationContext context = System.Security.Principal.WindowsIdentity.Impersonate(token))
{
    // Do network operations here

    context.Undo();
}

この場合、token変数はIntPtrです。この変数の値を取得するには、アンマネージLogonUser Windows API関数を呼び出す必要があります。pinvoke.netにすばやくアクセスすると、次の署名が得られます。

[System.Runtime.InteropServices.DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(
    string lpszUsername,
    string lpszDomain,
    string lpszPassword,
    int dwLogonType,
    int dwLogonProvider,
    out IntPtr phToken
);

ユーザー名、ドメイン、パスワードはかなり明白に見えるはずです。dwLogonTypeおよびdwLogonProviderに渡すことができるさまざまな値を見て、ニーズに最適な値を決定してください。

確認できる2つ目のドメインがないので、このコードはテストされていませんが、これでうまくいくと思います。


7
信頼されていないドメインのログインIDを使用しようとすると、偽装は機能しません。ユーザーIDはローカルにログオンできる必要があります。
ムース

ええ、私たちはこのルートを試しましたが、@ Mooseが言うようになりました:ドメインは信頼されていないため、なりすましは機能しません。
Randolpho

ええ、そのコメントを見たら、NetUseAddを使用して回答を投稿したのはそのためです(NetUseAdd関数とWNetAddConnection関数の主な違いは、NetUseAddがWindowsエクスプローラーで接続を表示しないことです)。
アダムロビンソン

偽装は同じドメインでも機能しません。私のテストでは、管理者アカウント(両方のマシンの管理者)で共有フォルダーのファイルを読み取ろうとすると、アクセス拒否で応答し続けます。だから、これは正しいアプローチではないと思います。
Lidermin

4

ここでは、すべての残骸が削除された最小限のPOCクラス

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

public class UncShareWithCredentials : IDisposable
{
    private string _uncShare;

    public UncShareWithCredentials(string uncShare, string userName, string password)
    {
        var nr = new Native.NETRESOURCE
        {
            dwType = Native.RESOURCETYPE_DISK,
            lpRemoteName = uncShare
        };

        int result = Native.WNetUseConnection(IntPtr.Zero, nr, password, userName, 0, null, null, null);
        if (result != Native.NO_ERROR)
        {
            throw new Win32Exception(result);
        }
        _uncShare = uncShare;
    }

    public void Dispose()
    {
        if (!string.IsNullOrEmpty(_uncShare))
        {
            Native.WNetCancelConnection2(_uncShare, Native.CONNECT_UPDATE_PROFILE, false);
            _uncShare = null;
        }
    }

    private class Native
    {
        public const int RESOURCETYPE_DISK = 0x00000001;
        public const int CONNECT_UPDATE_PROFILE = 0x00000001;
        public const int NO_ERROR = 0;

        [DllImport("mpr.dll")]
        public static extern int WNetUseConnection(IntPtr hwndOwner, NETRESOURCE lpNetResource, string lpPassword, string lpUserID,
            int dwFlags, string lpAccessName, string lpBufferSize, string lpResult);

        [DllImport("mpr.dll")]
        public static extern int WNetCancelConnection2(string lpName, int dwFlags, bool fForce);

        [StructLayout(LayoutKind.Sequential)]
        public class NETRESOURCE
        {
            public int dwScope;
            public int dwType;
            public int dwDisplayType;
            public int dwUsage;
            public string lpLocalName;
            public string lpRemoteName;
            public string lpComment;
            public string lpProvider;
        }
    }
}

\\server\share\folderw / を直接使用できます。事前WNetUseConnection\\server分割する必要はありません。


2

ほとんどのSFTPサーバーはSCPもサポートしており、ライブラリの検索がはるかに簡単になります。PuTTYに含まれているpscpのようなコードから既存のクライアントを呼び出すこともできます。

作業しているファイルの種類がテキストファイルやXMLファイルのような単純なものである場合、独自のクライアント/サーバー実装を記述して、.NET RemotingやWebサービスなどを使用してファイルを操作することもできます。


1

オプション3はJScapeツールでかなり単純な方法で実装されているのを見てきました。あなたはそれを試してみるかもしれません。それは無料ではありませんが、その仕事をします。


1

イムは、私の添付vb.netコードをに基づいて、ブライアン・リファレンス

Imports System.ComponentModel

Imports System.Runtime.InteropServices

Public Class PinvokeWindowsNetworking

Const NO_ERROR As Integer = 0



Private Structure ErrorClass

    Public num As Integer

    Public message As String



    Public Sub New(ByVal num As Integer, ByVal message As String)

        Me.num = num

        Me.message = message

    End Sub

End Structure



Private Shared ERROR_LIST As ErrorClass() = New ErrorClass() {

    New ErrorClass(5, "Error: Access Denied"),

    New ErrorClass(85, "Error: Already Assigned"),

    New ErrorClass(1200, "Error: Bad Device"),

    New ErrorClass(67, "Error: Bad Net Name"),

    New ErrorClass(1204, "Error: Bad Provider"),

    New ErrorClass(1223, "Error: Cancelled"),

    New ErrorClass(1208, "Error: Extended Error"),

    New ErrorClass(487, "Error: Invalid Address"),

    New ErrorClass(87, "Error: Invalid Parameter"),

    New ErrorClass(1216, "Error: Invalid Password"),

    New ErrorClass(234, "Error: More Data"),

    New ErrorClass(259, "Error: No More Items"),

    New ErrorClass(1203, "Error: No Net Or Bad Path"),

    New ErrorClass(1222, "Error: No Network"),

    New ErrorClass(1206, "Error: Bad Profile"),

    New ErrorClass(1205, "Error: Cannot Open Profile"),

    New ErrorClass(2404, "Error: Device In Use"),

    New ErrorClass(2250, "Error: Not Connected"),

    New ErrorClass(2401, "Error: Open Files")}



Private Shared Function getErrorForNumber(ByVal errNum As Integer) As String

    For Each er As ErrorClass In ERROR_LIST

        If er.num = errNum Then Return er.message

    Next



    Try

        Throw New Win32Exception(errNum)

    Catch ex As Exception

        Return "Error: Unknown, " & errNum & " " & ex.Message

    End Try



    Return "Error: Unknown, " & errNum

End Function



<DllImport("Mpr.dll")>

Private Shared Function WNetUseConnection(ByVal hwndOwner As IntPtr, ByVal lpNetResource As NETRESOURCE, ByVal lpPassword As String, ByVal lpUserID As String, ByVal dwFlags As Integer, ByVal lpAccessName As String, ByVal lpBufferSize As String, ByVal lpResult As String) As Integer

End Function



<DllImport("Mpr.dll")>

Private Shared Function WNetCancelConnection2(ByVal lpName As String, ByVal dwFlags As Integer, ByVal fForce As Boolean) As Integer

End Function



<StructLayout(LayoutKind.Sequential)>

Private Class NETRESOURCE

    Public dwScope As Integer = 0

    Public dwType As Integer = 0

    Public dwDisplayType As Integer = 0

    Public dwUsage As Integer = 0

    Public lpLocalName As String = ""

    Public lpRemoteName As String = ""

    Public lpComment As String = ""

    Public lpProvider As String = ""

End Class



Public Shared Function connectToRemote(ByVal remoteUNC As String, ByVal username As String, ByVal password As String) As String

    Return connectToRemote(remoteUNC, username, password, False)

End Function



Public Shared Function connectToRemote(ByVal remoteUNC As String, ByVal username As String, ByVal password As String, ByVal promptUser As Boolean) As String

    Dim nr As NETRESOURCE = New NETRESOURCE()

    nr.dwType = ResourceTypes.Disk

    nr.lpRemoteName = remoteUNC

    Dim ret As Integer



    If promptUser Then

        ret = WNetUseConnection(IntPtr.Zero, nr, "", "", Connects.Interactive Or Connects.Prompt, Nothing, Nothing, Nothing)

    Else

        ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, Nothing, Nothing, Nothing)

    End If



    If ret = NO_ERROR Then Return Nothing

    Return getErrorForNumber(ret)

End Function



Public Shared Function disconnectRemote(ByVal remoteUNC As String) As String

    Dim ret As Integer = WNetCancelConnection2(remoteUNC, Connects.UpdateProfile, False)

    If ret = NO_ERROR Then Return Nothing

    Return getErrorForNumber(ret)

End Function


Enum Resources As Integer

    Connected = &H1

    GlobalNet = &H2

    Remembered = &H3

End Enum


Enum ResourceTypes As Integer

    Any = &H0

    Disk = &H1

    Print = &H2

End Enum


Enum ResourceDisplayTypes As Integer

    Generic = &H0

    Domain = &H1

    Server = &H2

    Share = &H3

    File = &H4

    Group = &H5

End Enum


Enum ResourceUsages As Integer

    Connectable = &H1

    Container = &H2

End Enum


Enum Connects As Integer

    Interactive = &H8

    Prompt = &H10

    Redirect = &H80

    UpdateProfile = &H1

    CommandLine = &H800

    CmdSaveCred = &H1000

    LocalDrive = &H100

End Enum


End Class

どうやって使うのですか

Dim login = PinvokeWindowsNetworking.connectToRemote("\\ComputerName", "ComputerName\UserName", "Password")

    If IsNothing(login) Then



        'do your thing on the shared folder



       PinvokeWindowsNetworking.disconnectRemote("\\ComputerName")

    End If

-1

私は答えを見つけるためにMSを探しました。最初のソリューションは、アプリケーションプロセスを実行しているユーザーアカウントが共有フォルダーまたはドライブ(同じドメイン)にアクセスできることを前提としています。DNSが解決されていることを確認するか、IPアドレスを使用してみてください。次のようにしてください。

 DirectoryInfo di = new DirectoryInfo(PATH);
 var files = di.EnumerateFiles("*.*", SearchOption.AllDirectories);

資格情報付きの異なるドメイン.NET 2.0が必要な場合は、次のモデルに従ってください。

WebRequest req = FileWebRequest.Create(new Uri(@"\\<server Name>\Dir\test.txt"));

        req.Credentials = new NetworkCredential(@"<Domain>\<User>", "<Password>");
        req.PreAuthenticate = true;

        WebResponse d = req.GetResponse();
        FileStream fs = File.Create("test.txt");

        // here you can check that the cast was successful if you want. 
        fs = d.GetResponseStream() as FileStream;
        fs.Close();

面白そうだ
DeerSpotter
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.