Kimlik Bilgilerine Sahip Uzak, Güvenilir Olmayan Bir Etki Alanından Paylaşılan Dosyaya (UNC) Erişim


151

Çözülmesi gereken ilginç bir durumla karşı karşıya kaldık ve aramalarım netleşti. Dolayısıyla SO topluluğuna yardım çağrısında bulunuyorum.

Sorun şudur: Alanımızda olmayan ve uzak dosya paylaşımı / UNC aracılığıyla güvenilir bir harici alanda olmayan paylaşılan bir dosyaya programlı olarak erişmemiz gerekiyor. Doğal olarak, uzak makineye kimlik bilgileri sağlamalıyız.

Tipik olarak, kişi bu sorunu iki yoldan biriyle çözer:

  1. Dosya paylaşımını bir sürücü olarak eşleyin ve kimlik bilgilerini o anda sağlayın. Bu genellikle NET USEkomut veya yinelenen Win32 işlevleri kullanılarak yapılırNET USE .
  2. Uzak bilgisayar etki alanındaymış gibi bir UNC yoluna sahip dosyaya erişin ve programın çalıştığı hesabın yerel makine olarak uzak makinede çoğaltıldığından (parola dahil) emin olun. Temel olarak, kullanıcı paylaşılan bir dosyaya erişmeye çalıştığında Windows'un geçerli kullanıcının kimlik bilgilerini otomatik olarak sağlayacağı gerçeğinden yararlanın.
  3. Uzak dosya paylaşımını kullanmayın. Dosyayı aktarmak için FTP (veya başka bir yolla) kullanın, yerel olarak çalışın, sonra geri aktarın.

Çeşitli ve muhtelif nedenlerden dolayı, güvenlik / ağ mimarlarımız ilk iki yaklaşımı reddetti. İkinci yaklaşım açık bir şekilde bir güvenlik açığıdır; uzak bilgisayarın güvenliği ihlal edilmişse, yerel bilgisayar artık risk altındadır. Yeni yaklaşım, programın dosya erişimi sırasında yerel bilgisayardaki diğer programlar tarafından kullanılabilen paylaşılan bir kaynak olduğundan ilk yaklaşım tatmin edici değildir. Bunu geçici hale getirmek oldukça mümkün olsa da, onların görüşüne göre hala bir delik.

Üçüncü seçeneğe açıktırlar, ancak uzak ağ yöneticileri FTPS yerine SFTP'de ısrar eder ve FtpWebRequest yalnızca FTPS'yi destekler. SFTP : daha duvarı dostu bir seçenek ve ben o yaklaşım için kullanabileceği bir kaç kütüphaneler var ama eğer yapabilirsem benim bağımlılıkları azaltmak için tercih ediyorum.

MSDN'de uzaktan dosya paylaşımı kullanmanın bir yönetilen veya win32 aracı için arama yaptım, ancak yararlı bir şey bulamadım.

Ve ben de soruyorum: Başka bir yol var mı? İstediğimi yapan süper gizli bir win32 işlevini kaçırdım mı? Yoksa seçenek 3'ün bazı varyantlarını mı takip etmeliyim?


Kimliğe bürünme yaklaşımıyla çözdüm, ancak bu bir etki alanı dışındaki 2 makine arasında. Bir etki alanından etki alanı dışındaki bir bilgisayara konuşurken bir sorun olup olmadığını bilmiyorum. stackoverflow.com/questions/17221476/…
Wolf5

Yanıtlar:


174

Sorununuzu çözmenin yolu, WNetUseConnection adlı bir Win32 API kullanmaktır .
Sürücüyü eşlemek için DEĞİL, kimlik doğrulamalı UNC yoluna bağlanmak için bu işlevi kullanın .

Bu, aynı etki alanında olmasa bile ve farklı bir kullanıcı adı ve parolasına sahip olsa bile uzak bir makineye bağlanmanıza izin verir.

WNetUseConnection'ı kullandıktan sonra, dosyaya aynı etki alanındaymışsınız gibi bir UNC yolu üzerinden erişebileceksiniz. En iyi yol, muhtemelen yerleşik hisse senetleri aracılığıyladır.
Örnek: \\ bilgisayaradı \ c $ \ program files \ Folder \ file.txt

İşte WNetUseConnection kullanan bazı örnek C # kodu.
NetResource için, lpLocalName ve lpProvider için null değerini iletmeniz gerektiğini unutmayın. DwType, RESOURCETYPE_DISK olmalıdır. LpRemoteName \\ BilgisayarAdı olmalıdır.

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);
        }
    }
}

Geçerli kimlik bilgilerini kullanarak bir ağ makinesine bağlantıları açıkça açmak / kapatmak için, örneğin kullanıcı adını ve parolayı girmeden, bunun gibi işlevleri kullanmanın bir yolu var mı? Özellikle bir dosya paylaşımına eriştikten sonra bir bağlantıyı kapatmakla ilgileniyorum.
flipdoubt

Bilgisayarın bir kullanıcı adı veya şifresi yoksa, bağlantı için değil. Bağlantıyı kesmek için yapabileceğinizden emin olun. Bunun yerine komut satırı üzerinden de yapabilirsiniz.
Brian R. Bondy

1
Merhaba Brian. Bağlantı verdiğiniz dokümanlar, geçerli kimlik bilgilerini kullanmak için kullanıcı adı ve parola için NULL iletebilirsiniz. Bunun işe yarayıp yaramadığını görmek için bazı testler yapacağım.
flipdoubt

Kullanıcı adı / parola için null iletmek bağlanmamı sağlıyor, ancak bağlantıyı kestiğimi nasıl kanıtlayabilirim? Sunucuda bakabileceğim bir şey var mı? Server 2003'te oturumları izleyebilirim, ancak geçerli oturumların listesi, uygulamam bu API'ları kullanmadığında aynı hızda güncellenir.
flipdoubt

İle açılan bağlantılar aranarak WNetUseConnectionmanuel olarak kapatılmalı WNetCancelConnection2mıdır? Yoksa boşta kalma zaman aşımı (veya başka bir mekanizma) var mı?
w128 26:13

123

Hızlı bir çözüm arayan insanlar için, NetworkShareAccesseryakın zamanda yazdım ( bu cevaba dayanarak (çok teşekkürler!)) Kullanabilirsiniz :

Kullanımı:

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");
}

UYARI: Bu, mutlak olarak emin olunuz Disposearasında NetworkShareAccesser, (! Kilitlenmeler app bile) denir aksi açık bir bağlantı Windows üzerinde kalacaktır. cmdİstemi açıp girerek tüm açık bağlantıları görebilirsiniz net use.

Kod:

/// <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
Ayrıca ihtiyaç using System.Runtime.InteropServices;ve using System.ComponentModel;için DllImportveWin32Exception
Kᴀτᴢ

Bu çözüm uzun gün aramamı durdurdu. Teşekkürler!!! Gerektiği gibi oldukça iyi çalışır.
Venkat

1
Çözümünüzü uzak makinedeki bir yerel kullanıcı hesabıyla kullanmaya çalışıyorum, ancak erişim reddedildi hatası alıyorum. Çözümünüz yalnızca ağ hesapları için mi çalışacak?
M3NTA7

1
Hesap uzak makinede var, ancak bir ağ hesabı değil. Yerel bir makine hesabı. Alan adını makinenin adına ayarlamayı denedim. Paylaşılan klasördeki yerel kullanıcı hesabına da tam izin verdim, ancak erişim reddedildi. Bunun neden olabileceğine dair bir fikrin var mı? Teşekkürler.
M3NTA7

2
Not: nesneyi atmak kimlik bilgilerini sistemden silmiyor gibi görünüyor (Windows 10); Bağlantı "iptal edildikten" sonra uzak bilgisayardaki dosyalara erişebiliyorum. Kullanıcı hesabıma tekrar giriş yapmak veya bilgisayarımı yeniden başlatmak bu dahili önbelleği temizliyor gibi görünüyor.
Tim Cooper

16

AFAIK, bir sunucu için kimlik bilgileri oluşturmak amacıyla UNC yolunu bir sürücü harfiyle eşlemenize gerek yoktur . Düzenli olarak toplu komut dosyaları kullandım:

net use \\myserver /user:username password

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

net use /delete \\my.server.com

Ancak, programınızla aynı hesapta çalışan herhangi bir program yine de erişimi olan her şeye username:passworderişebilir. Olası bir çözüm, programınızı kendi yerel kullanıcı hesabında izole etmek olabilir (UNC erişimi çağrılan hesap için yereldir NET USE).

Not: KOBİ'lerin etki alanları arasında kullanılması, IMO teknolojisinin iyi bir kullanımı değildir. Güvenlik bu kadar önemliyse, SMB'nin şifrelemeden yoksun olması tek başına bir damperdir.


UNC erişiminin yalnızca çağrılan hesap için kullanılabilir olması konusunda haklıysanız NET USE, bu uygun bir yaklaşım olabilir. Bununla birlikte, yerel bir hesap kullanmamız gerektiğinden emin misiniz? NET USEÇağrı, çağrıldığı makinede yerel olmaz mı? Bana iyi bir araştırma yolu verdin
Randolpho

AFAIK, ve yanılıyor olabilirim, UNC erişimi yalnızca NET USE çağrısının yapıldığı belirli güvenlik sorumlusu (SAM hesabı) için kullanılabilir olacaktır. Yolu eşlemek için RunAs'ı kullanarak ve daha sonra başka bir hesaptan erişmeye çalışarak bunu doğrulayabilirsiniz.
Jacob

benim durumumda, kullanıcı farklı bir etki alanında olduğu gibi net use \\ myserver / user: kullanıcıadı @ etki alanı parolasını kullanmak zorunda kaldım.
StarCub

4

WNetUseConnection yerine NetUseAdd öneririm . WNetUseConnection, WNetUseConnection2 ve WNetUseConnection3 tarafından üstlenilen eski bir işlevdir, ancak bu işlevlerin tümü Windows Gezgini'nde görünür bir ağ aygıtı oluşturur. NetUseAdd, uzak bir bilgisayarda kimlik doğrulaması yapmak için bir DOS komut isteminde net use çağrılmasına eşdeğerdir.

NetUseAdd öğesini çağırırsanız, dizine erişmeye yönelik sonraki denemeler başarılı olmalıdır.


1
@Adam Robinson: Bu doğru değil. Böyle bir WNetUseConnection2 veya WNetUseConnection3 yoktur. WNetAddConnection'ın WNetAddConnection2 ve WnetAddConnection3 tarafından üstlenildiğini düşünüyorum. Ayrıca bu konuda verdiğiniz bilgiler doğru değildir.
Brian R. Bondy

WNetUseConnection, WNetAddConnection3 gibidir, ancak aynı zamanda eşlenmiş bir yerel sürücü oluşturma konusunda isteğe bağlı bir yeteneğe sahiptir. Hangi kullanmak zorunda değilsiniz.
Brian R. Bondy

@ BrianR.Bondy Gerçekten varlar, sadece C # olarak uygulanmadılar. Kaynak: docs.microsoft.com/da-dk/windows/win32/api/lmuse/… Alıntı: "Yerel bir cihazı bir ağ kaynağına yönlendirmek için WNetAddConnection2 ve WNetAddConnection3 işlevlerini de kullanabilirsiniz."
Thomas Williams

4

Kendimi bilmesem de, kesinlikle # 2'nin yanlış olduğunu umuyorum ... Windows'un herhangi bir makineye giriş bilgilerimi (en azından şifrem!) OTOMATİK olarak vermeyeceğini düşünmek isterim. , bırakın benim güvenimin bir parçası değil.

Ne olursa olsun, kimliğe bürünme mimarisini keşfettiniz mi? Kodunuz şuna benzer:

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

    context.Undo();
}

Bu durumda, tokendeğişken bir IntPtr'dir. Bu değişken için bir değer elde etmek için, yönetilmeyen LogonUser Windows API işlevini çağırmanız gerekir. Pinvoke.net'e hızlı bir yolculuk bize aşağıdaki imzayı verir:

[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
);

Kullanıcı adı, alan adı ve şifre oldukça açık görünmelidir. Gereksinimlerinize en uygun olanı belirlemek için dwLogonType ve dwLogonProvider'a geçirilebilen çeşitli değerlere göz atın.

Burada doğrulayabileceğim ikinci bir alan adım olmadığı için bu kod test edilmedi, ancak bu umarım sizi doğru yola koymalıdır.


7
Güvenilir olmayan bir alan adından bir giriş kimliği kullanmaya çalıştığınızda kimliğe bürünme özelliği çalışmaz. Kullanıcı kimliği yerel olarak oturum açabilmelidir.
Moose

Evet, bu rotayı denedik, @Moose'un dediği gibi oldu: Etki alanı güvenilmez ve bu nedenle kimliğe bürünme işe yaramaz.
Randolpho

Evet, bu yorumu gördükten sonra cevabı NetUseAdd kullanarak (NetNetEseAdd'ın bağlantıyı Windows Gezgini'nde görmemesi olan WNetUseConnection ve WNetAddConnection işlevleri arasındaki birincil fark) kullandım.
Adam Robinson

Kimliğe bürünme de aynı etki alanında çalışmaz, testlerimde erişim reddedildi ve yönetici hesabıyla (her iki makinede de yönetici) paylaşılan bir klasördeki bir dosyayı okumaya çalışırken bana yanıt vermeye devam ediyor. Bence bu doğru bir yaklaşım değil.
lidermin

4

Burada çıkarılan tüm rüzgârlar ile minimum POC sınıfı

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;
        }
    }
}

Doğrudan \\server\share\folderw / kullanabilirsiniz WNetUseConnection, \\serversadece önceden parçalara ayırmaya gerek yoktur .


2

Çoğu SFTP sunucusu, kütüphaneleri bulmak çok daha kolay olabilecek SCP'yi de destekler. Hatta sadece mevcut bir istemciyi kodunuzdan PuTTY ile birlikte verilen pscp .

Çalıştığınız dosya türü bir metin veya XML dosyası gibi basit bir şeyse, .NET Remoting veya web hizmetleri gibi bir dosyayı kullanarak dosyayı değiştirmek için kendi istemci / sunucu uygulamanızı yazmak için bile gidebilirsiniz.



1

im benim takmak vb.net kodunu dayalı Brian referans

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

bu nasıl kullanılır

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

Cevapları bulmak için MS'e baktım. İlk çözüm, uygulama işlemini çalıştıran kullanıcı hesabının paylaşılan klasöre veya sürücüye (Aynı etki alanı) erişimi olduğunu varsayar. DNS'inizin çözümlendiğinden emin olun veya IP adresini kullanmayı deneyin. Sadece aşağıdakileri yapın:

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

Kimlik bilgileriyle .NET 2.0 farklı etki alanları arasında istiyorsanız bu modeli izleyin:

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();

ilginç görünüyor
DeerSpotter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.