วิธีระบุชื่อผู้ใช้และรหัสผ่านเมื่อเชื่อมต่อกับเครือข่ายที่ใช้ร่วมกัน


191

เมื่อเชื่อมต่อกับเครือข่ายที่ผู้ใช้ปัจจุบัน (ในกรณีของฉันผู้ใช้บริการที่เปิดใช้งานเครือข่าย) ไม่มีสิทธิ์ชื่อและรหัสผ่าน

ฉันรู้วิธีการทำสิ่งนี้กับฟังก์ชั่น Win32 ( WNet*ครอบครัวจากmpr.dll) แต่อยากจะทำกับฟังก์ชั่น. Net (2.0)

มีตัวเลือกอะไรบ้าง?

อาจมีข้อมูลเพิ่มเติมช่วย:

  • กรณีใช้งานเป็นบริการ windows ไม่ใช่แอปพลิเคชัน Asp.Net
  • บริการทำงานภายใต้บัญชีที่ไม่มีสิทธิ์ในการแบ่งปัน
  • บัญชีผู้ใช้ที่จำเป็นสำหรับการแบ่งปันไม่เป็นที่รู้จักในฝั่งไคลเอ็นต์
  • ไคลเอ็นต์และเซิร์ฟเวอร์ไม่ใช่สมาชิกของโดเมนเดียวกัน

7
ในขณะที่ฉันไม่ได้ให้คำตอบที่เป็นประโยชน์แก่คุณ แต่ฉันสามารถให้คำตอบที่ต่อต้าน .. การเลียนแบบและการวางไข่กระบวนการเนื่องจาก Marc posited จะไม่ทำงานเมื่อเซิร์ฟเวอร์และไคลเอนต์ไม่ได้อยู่ในโดเมนเดียวกันเว้นแต่จะมีความไว้วางใจระหว่าง ทั้งสองโดเมน หากมีความน่าเชื่อถือฉันคิดว่ามันจะได้ผล ฉันเพิ่งจะตอบเป็นความคิดเห็นของ Marc แต่ฉันไม่มีตัวแทนเพียงพอที่จะแสดงความคิดเห็น : - /
Moose

ที่เกี่ยวข้อง - stackoverflow.com/questions/17786037/…
vapcguy

คำตอบ:


152

คุณสามารถเปลี่ยนข้อมูลประจำตัวของเธรดหรือ P / Invoke WNetAddConnection2 ฉันชอบสิ่งหลังเพราะบางครั้งฉันจำเป็นต้องรักษาข้อมูลรับรองหลายอย่างสำหรับสถานที่ที่แตกต่างกัน ฉันห่อมันลงใน IDisposable และโทร WNetCancelConnection2 เพื่อลบเครดิตในภายหลัง (หลีกเลี่ยงข้อผิดพลาดชื่อผู้ใช้หลายคน):

using (new NetworkConnection(@"\\server\read", readCredentials))
using (new NetworkConnection(@"\\server2\write", writeCredentials)) {
   File.Copy(@"\\server\read\file", @"\\server2\write\file");
}

4
บริการไม่ได้เป็นสมาชิกของโดเมนเป้าหมาย - การเลียนแบบไม่สามารถทำงานได้เนื่องจากคุณจะไม่สามารถสร้างโทเค็นความปลอดภัยในเครื่องและปลอมตัวได้ PInvoke เป็นเพียงวิธี
stephbu

@ MarkBrackett ฉันรู้ว่านี่เป็นคำตอบเก่า แต่บางทีคุณอาจจะรู้ว่า ... การเข้าถึงจะได้รับอนุญาตให้โปรแกรมเท่านั้นหรือยังผู้ใช้ที่เข้าสู่ระบบผ่านทาง explorer?
Breeze

@ สายลม - ฉันยังไม่ได้ทดสอบ แต่ฉันคาดว่าจะรับรองความถูกต้องสำหรับเซสชันการเข้าสู่ระบบ ดังนั้นหากโปรแกรมของคุณกำลังทำงานในฐานะผู้ใช้ที่เข้าสู่ระบบพวกเขาจะสามารถเข้าถึงได้เช่นกัน (อย่างน้อยก็ในช่วงระยะเวลาของการดำเนินการ)
Mark Brackett

8
นิยามของ readCredentials และ writeCredentials อาจรวมอยู่ในคำตอบ
Anders Lindén

2
หากคุณได้รับข้อผิดพลาด 53ตรวจสอบให้แน่ใจว่าเส้นทางไม่ได้ลงท้ายด้วย "\"
Mustafa S.

327

ฉันชอบคำตอบของMark Brackettมากจนฉันได้นำไปใช้อย่างรวดเร็ว นี่คือถ้าใครต้องการมันรีบ:

public class NetworkConnection : IDisposable
{
    string _networkName;

    public NetworkConnection(string networkName, 
        NetworkCredential credentials)
    {
        _networkName = networkName;

        var netResource = new NetResource()
        {
            Scope = ResourceScope.GlobalNetwork,
            ResourceType = ResourceType.Disk,
            DisplayType = ResourceDisplaytype.Share,
            RemoteName = networkName
        };

        var userName = string.IsNullOrEmpty(credentials.Domain)
            ? credentials.UserName
            : string.Format(@"{0}\{1}", credentials.Domain, credentials.UserName);

        var result = WNetAddConnection2(
            netResource, 
            credentials.Password,
            userName,
            0);

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

    ~NetworkConnection()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        WNetCancelConnection2(_networkName, 0, true);
    }

    [DllImport("mpr.dll")]
    private static extern int WNetAddConnection2(NetResource netResource, 
        string password, string username, int flags);

    [DllImport("mpr.dll")]
    private static extern int WNetCancelConnection2(string name, int flags,
        bool force);
}

[StructLayout(LayoutKind.Sequential)]
public class NetResource
{
    public ResourceScope Scope;
    public ResourceType ResourceType;
    public ResourceDisplaytype DisplayType;
    public int Usage;
    public string LocalName;
    public string RemoteName;
    public string Comment;
    public string Provider;
}

public enum ResourceScope : int
{
    Connected = 1,
    GlobalNetwork,
    Remembered,
    Recent,
    Context
};

public enum ResourceType : int
{
    Any = 0,
    Disk = 1,
    Print = 2,
    Reserved = 8,
}

public enum ResourceDisplaytype : int
{
    Generic = 0x0,
    Domain = 0x01,
    Server = 0x02,
    Share = 0x03,
    File = 0x04,
    Group = 0x05,
    Network = 0x06,
    Root = 0x07,
    Shareadmin = 0x08,
    Directory = 0x09,
    Tree = 0x0a,
    Ndscontainer = 0x0b
}

10
จริงๆมันควรจะเป็นthrow new Win32Exception(result);เนื่องจากผลตอบแทน WNetAddConnection2 Win32 รหัสข้อผิดพลาด ( ERROR_XXX)
torvin

2
นี่เป็นโค้ดเล็ก ๆ ที่สวยงาม จำเป็นต้องลงชื่อเข้าใช้ระบบ UNIX เพื่อรับรายชื่อไดเรกทอรีสำหรับการพิมพ์ไปยังแอปพลิเคชันเว็บ MVC5 และนี่เป็นเคล็ดลับ 1 !!!
Tay

3
จำเป็นต้องใช้คำสั่งการใช้งานต่อไปนี้เพื่อให้โค้ดข้างต้นสามารถคอมไพล์ได้: using System.Net; ใช้ System.Runtime.InteropServices; ใช้ System.ComponentModel;
Matt Nelson

4
ขออภัยที่จะรีเฟรชเธรดเก่า แต่ดูเหมือนว่าจะไม่ปิดการเชื่อมต่อหลังจากบล็อกเสร็จสิ้น ฉันมีโปรแกรมที่จะอัพโหลดรูปไม่กี่รูปอันแรกใช้ได้ดีส่วนที่สองล้มเหลว การเชื่อมต่อถูกปล่อยเมื่อปิดโปรแกรม มีคำแนะนำอะไรบ้าง?
arti

3
เรามีปัญหาเช่นเดียวกับคุณ @arti เพียงแค่ตั้งชื่อผู้ใช้และรหัสผ่านบนNetworkCredentialวัตถุแอปพลิเคชันก็สามารถเชื่อมต่อกับไดรฟ์เครือข่ายหนึ่งครั้ง หลังจากนั้นเราได้รับERROR_LOGON_FAILUREทุกครั้งจนกว่าจะมีการเริ่มแอปพลิเคชันใหม่ จากนั้นเราพยายามให้โดเมนบนNetworkCredentialวัตถุด้วยเช่นกันและทันใดนั้นก็ใช้งานได้! ฉันไม่รู้ว่าทำไมสิ่งนี้จึงแก้ไขปัญหาได้โดยเฉพาะอย่างยิ่งความจริงที่ว่ามันทำงานเพื่อเชื่อมต่อครั้งเดียวโดยไม่มีโดเมน
lsmeby

50

วันนี้ 7 ปีต่อมาฉันประสบปัญหาเดียวกันและฉันต้องการแบ่งปันวิธีแก้ไขปัญหาของฉัน

คัดลอกและวางพร้อม :-) นี่คือ:

ขั้นตอนที่ 1

ในรหัสของคุณ (เมื่อใดก็ตามที่คุณจำเป็นต้องทำบางสิ่งด้วยสิทธิ์)

ImpersonationHelper.Impersonate(domain, userName, userPassword, delegate
                            {
                                //Your code here 
                                //Let's say file copy:
                                if (!File.Exists(to))
                                {
                                    File.Copy(from, to);
                                }
                            });

ขั้นตอนที่ 2

ไฟล์ตัวช่วยซึ่งใช้เวทมนตร์

using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;    
using Microsoft.Win32.SafeHandles;


namespace BlaBla
{
    public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeTokenHandle()
            : base(true)
        {
        }

        [DllImport("kernel32.dll")]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);

        protected override bool ReleaseHandle()
        {
            return CloseHandle(handle);
        }
    }

    public class ImpersonationHelper
    {
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
        int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private extern static bool CloseHandle(IntPtr handle);

        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        public static void Impersonate(string domainName, string userName, string userPassword, Action actionToExecute)
        {
            SafeTokenHandle safeTokenHandle;
            try
            {

                const int LOGON32_PROVIDER_DEFAULT = 0;
                //This parameter causes LogonUser to create a primary token.
                const int LOGON32_LOGON_INTERACTIVE = 2;

                // Call LogonUser to obtain a handle to an access token.
                bool returnValue = LogonUser(userName, domainName, userPassword,
                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                    out safeTokenHandle);
                //Facade.Instance.Trace("LogonUser called.");

                if (returnValue == false)
                {
                    int ret = Marshal.GetLastWin32Error();
                    //Facade.Instance.Trace($"LogonUser failed with error code : {ret}");

                    throw new System.ComponentModel.Win32Exception(ret);
                }

                using (safeTokenHandle)
                {
                    //Facade.Instance.Trace($"Value of Windows NT token: {safeTokenHandle}");
                    //Facade.Instance.Trace($"Before impersonation: {WindowsIdentity.GetCurrent().Name}");

                    // Use the token handle returned by LogonUser.
                    using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
                    {
                        using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
                        {
                            //Facade.Instance.Trace($"After impersonation: {WindowsIdentity.GetCurrent().Name}");
                            //Facade.Instance.Trace("Start executing an action");

                            actionToExecute();

                            //Facade.Instance.Trace("Finished executing an action");
                        }
                    }
                    //Facade.Instance.Trace($"After closing the context: {WindowsIdentity.GetCurrent().Name}");
                }

            }
            catch (Exception ex)
            {
                //Facade.Instance.Trace("Oh no! Impersonate method failed.");
                //ex.HandleException();
                //On purpose: we want to notify a caller about the issue /Pavel Kovalev 9/16/2016 2:15:23 PM)/
                throw;
            }
        }
    }
}

2
@MohammadRashid ตามเอกสารในLogonUserนั้นจะทำงานเฉพาะกับผู้ใช้บนคอมพิวเตอร์ในระบบ: "ฟังก์ชั่น LogonUser พยายามที่จะเข้าสู่ระบบของผู้ใช้คอมพิวเตอร์ท้องถิ่นคอมพิวเตอร์ในท้องถิ่นคือคอมพิวเตอร์ที่ถูกเรียก LogonUser คุณไม่สามารถใช้ LogonUser เพื่อเข้าสู่ระบบคอมพิวเตอร์ระยะไกล "คุณจะได้รับข้อผิดพลาด" Win32Exception: ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง " ดังนั้นฉันคิดว่าเครื่องต้องอยู่ในโดเมนเดียวกันอย่างน้อย
Charles Chen

1
@CharlesChen เพิ่งพิสูจน์ว่าใช้ได้ผลดีในทุกโดเมน FYI เซิร์ฟเวอร์ที่ฉันใช้งานอยู่นั้นอยู่ใน DMZ และกำลังเชื่อมต่อกับไฟล์เซิร์ฟเวอร์ในโดเมนอื่นผ่านไฟร์วอลล์อย่างแน่นอน Pavlet นักฆ่าคุณเป็นผู้ชายและน่าจะเป็นคำตอบที่ได้รับการยอมรับในวันนี้
Brian MacKay

นี่คือทางออกที่ดี! ขอบคุณ Pavel Kovalev
STLDev

มันทำงานบน ldap ได้ไหม? มันบอกว่าฉันไม่มีเซิร์ฟเวอร์เข้าสู่ระบบ ฉันใช้ ldap auth
Julius Limson

28

ฉันค้นหาวิธีการมากมายและทำตามวิธีของตัวเอง คุณต้องเปิดการเชื่อมต่อระหว่างสองเครื่องผ่านทาง command prompt คำสั่ง NET USE และหลังจากเสร็จงานของคุณให้ล้างการเชื่อมต่อด้วย command prompt NET USE "myconnection" / ลบ

คุณต้องใช้กระบวนการพรอมต์คำสั่งจากโค้ดด้านหลังดังนี้:

var savePath = @"\\servername\foldername\myfilename.jpg";
var filePath = @"C:\\temp\myfileTosave.jpg";

การใช้งานง่าย:

SaveACopyfileToServer(filePath, savePath);

นี่คือฟังก์ชั่น:

using System.IO
using System.Diagnostics;


public static void SaveACopyfileToServer(string filePath, string savePath)
    {
        var directory = Path.GetDirectoryName(savePath).Trim();
        var username = "loginusername";
        var password = "loginpassword";
        var filenameToSave = Path.GetFileName(savePath);

        if (!directory.EndsWith("\\"))
            filenameToSave = "\\" + filenameToSave;

        var command = "NET USE " + directory + " /delete";
        ExecuteCommand(command, 5000);

        command = "NET USE " + directory + " /user:" + username + " " + password;
        ExecuteCommand(command, 5000);

        command = " copy \"" + filePath + "\"  \"" + directory + filenameToSave + "\"";

        ExecuteCommand(command, 5000);


        command = "NET USE " + directory + " /delete";
        ExecuteCommand(command, 5000);
    }

และฟังก์ชั่น ExecuteCommand คือ:

public static int ExecuteCommand(string command, int timeout)
    {
        var processInfo = new ProcessStartInfo("cmd.exe", "/C " + command)
                              {
                                  CreateNoWindow = true, 
                                  UseShellExecute = false, 
                                  WorkingDirectory = "C:\\",
                              };

        var process = Process.Start(processInfo);
        process.WaitForExit(timeout);
        var exitCode = process.ExitCode;
        process.Close();
        return exitCode;
    } 

ฟังก์ชั่นนี้ทำงานเร็วและเสถียรสำหรับฉัน


1
ในกรณีที่การจับคู่ส่วนแบ่งล้มเหลวรหัสส่งคืนจะเป็นอย่างไร
surega

14

โซลูชัน Luke Quinane ดูดี แต่ทำงานได้เพียงบางส่วนในแอปพลิเคชัน ASP.NET MVC ของฉัน การมีสองการแชร์บนเซิร์ฟเวอร์เดียวกันที่มีหนังสือรับรองที่แตกต่างกันฉันสามารถใช้การแอบอ้างบุคคลอื่นเป็นครั้งแรกเท่านั้น

ปัญหาเกี่ยวกับ WNetAddConnection2 ก็คือมันจะทำงานแตกต่างกันในรุ่น windows ที่แตกต่างกัน นั่นคือเหตุผลที่ฉันค้นหาทางเลือกและพบฟังก์ชันLogonUser นี่คือรหัสของฉันซึ่งใช้งานได้ใน ASP.NET:

public sealed class WrappedImpersonationContext
{
    public enum LogonType : int
    {
        Interactive = 2,
        Network = 3,
        Batch = 4,
        Service = 5,
        Unlock = 7,
        NetworkClearText = 8,
        NewCredentials = 9
    }

    public enum LogonProvider : int
    {
        Default = 0,  // LOGON32_PROVIDER_DEFAULT
        WinNT35 = 1,
        WinNT40 = 2,  // Use the NTLM logon provider.
        WinNT50 = 3   // Use the negotiate logon provider.
    }

    [DllImport("advapi32.dll", EntryPoint = "LogonUserW", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool LogonUser(String lpszUsername, String lpszDomain,
        String lpszPassword, LogonType dwLogonType, LogonProvider dwLogonProvider, ref IntPtr phToken);

    [DllImport("kernel32.dll")]
    public extern static bool CloseHandle(IntPtr handle);

    private string _domain, _password, _username;
    private IntPtr _token;
    private WindowsImpersonationContext _context;

    private bool IsInContext
    {
        get { return _context != null; }
    }

    public WrappedImpersonationContext(string domain, string username, string password)
    {
        _domain = String.IsNullOrEmpty(domain) ? "." : domain;
        _username = username;
        _password = password;
    }

    // Changes the Windows identity of this thread. Make sure to always call Leave() at the end.
    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public void Enter()
    {
        if (IsInContext)
            return;

        _token = IntPtr.Zero;
        bool logonSuccessfull = LogonUser(_username, _domain, _password, LogonType.NewCredentials, LogonProvider.WinNT50, ref _token);
        if (!logonSuccessfull)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        WindowsIdentity identity = new WindowsIdentity(_token);
        _context = identity.Impersonate();

        Debug.WriteLine(WindowsIdentity.GetCurrent().Name);
    }

    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public void Leave()
    {
        if (!IsInContext)
            return;

        _context.Undo();

        if (_token != IntPtr.Zero)
        {
            CloseHandle(_token);
        }
        _context = null;
    }
}

การใช้งาน:

var impersonationContext = new WrappedImpersonationContext(Domain, Username, Password);
impersonationContext.Enter();

//do your stuff here

impersonationContext.Leave();

2
วิธีการนี้ใช้งานได้ดีสำหรับฉัน แต่พบว่าในการทดสอบของฉันว่าเมื่อใช้รหัสผ่านไม่ดีกับบัญชีผู้ใช้โดเมนผู้ใช้รายนั้นจะถูกล็อคสถานะทันที นโยบายโดเมนของเราเรียกร้องให้มีความพยายามในการเข้าสู่ระบบ 3 ครั้งล้มเหลวก่อนที่จะเกิดขึ้น แต่ด้วยวิธีการนี้คุณจะถูกล็อคหนึ่งครั้ง ดังนั้นควรใช้ด้วยความระมัดระวัง ...
kellyb

5

สำหรับ VB.lovers ค่า VB.NET ที่เทียบเท่ากับโค้ดของ Luke Quinane (ขอบคุณ Luke!)

Imports System
Imports System.Net
Imports System.Runtime.InteropServices
Imports System.ComponentModel

Public Class NetworkConnection
    Implements IDisposable

    Private _networkName As String

    Public Sub New(networkName As String, credentials As NetworkCredential)
        _networkName = networkName

        Dim netResource = New NetResource() With {
             .Scope = ResourceScope.GlobalNetwork,
             .ResourceType = ResourceType.Disk,
             .DisplayType = ResourceDisplaytype.Share,
             .RemoteName = networkName
        }

        Dim userName = If(String.IsNullOrEmpty(credentials.Domain), credentials.UserName, String.Format("{0}\{1}", credentials.Domain, credentials.UserName))

        Dim result = WNetAddConnection2(NetResource, credentials.Password, userName, 0)

        If result <> 0 Then
            Throw New Win32Exception(result, "Error connecting to remote share")
        End If
    End Sub

    Protected Overrides Sub Finalize()
        Try
            Dispose (False)
        Finally
            MyBase.Finalize()
        End Try
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose (True)
        GC.SuppressFinalize (Me)
    End Sub

    Protected Overridable Sub Dispose(disposing As Boolean)
        WNetCancelConnection2(_networkName, 0, True)
    End Sub

    <DllImport("mpr.dll")> _
    Private Shared Function WNetAddConnection2(netResource As NetResource, password As String, username As String, flags As Integer) As Integer
    End Function

    <DllImport("mpr.dll")> _
    Private Shared Function WNetCancelConnection2(name As String, flags As Integer, force As Boolean) As Integer
    End Function

End Class

<StructLayout(LayoutKind.Sequential)> _
Public Class NetResource
    Public Scope As ResourceScope
    Public ResourceType As ResourceType
    Public DisplayType As ResourceDisplaytype
    Public Usage As Integer
    Public LocalName As String
    Public RemoteName As String
    Public Comment As String
    Public Provider As String
End Class

Public Enum ResourceScope As Integer
    Connected = 1
    GlobalNetwork
    Remembered
    Recent
    Context
End Enum

Public Enum ResourceType As Integer
    Any = 0
    Disk = 1
    Print = 2
    Reserved = 8
End Enum

Public Enum ResourceDisplaytype As Integer
    Generic = &H0
    Domain = &H1
    Server = &H2
    Share = &H3
    File = &H4
    Group = &H5
    Network = &H6
    Root = &H7
    Shareadmin = &H8
    Directory = &H9
    Tree = &HA
    Ndscontainer = &HB
End Enum

3

ตัวเลือกหนึ่งที่ทำงานอาจจะใช้WindowsIdentity.Impersonate(และเปลี่ยนหลักด้าย) ที่จะกลายเป็นผู้ใช้ที่ต้องการเช่นดังนั้น กลับไปที่ p / เรียกใช้ แต่ฉันกลัว ...

หน้าด้านอื่น (และเท่าเทียมกันไกลจากอุดมคติ) ตัวเลือกที่อาจจะมีการวางไข่กระบวนการที่จะทำผลงาน ... ProcessStartInfoยอมรับ.UserName, และ.Password.Domain

ในที่สุด - อาจใช้บริการในบัญชีเฉพาะที่มีการเข้าถึงหรือไม่ (ลบออกเนื่องจากคุณได้ชี้แจงว่านี่ไม่ใช่ตัวเลือก)


ฉันไม่คิดว่ากระบวนการนี้เป็นความคิดที่เลว google นำเสนอรายงานเกี่ยวกับประโยชน์ของการประมวลผลหลายส่วนในโครเมี่ยม
ดัสตินเก็ตซ์

เป็นไปได้ไหมที่จะเปลี่ยนเธรดหลักให้กับผู้ใช้ที่ไม่มีบัญชีบนเครื่องโลคัล?
gyrolf

บอกตามตรงฉันไม่รู้ ... คุณต้องลอง LogonUser กับโดเมนอื่นเพื่อค้นหา
Marc Gravell

3

ตกลง ... ฉันสามารถขายต่อได้ ..

ข้อจำกัดความรับผิดชอบ: ฉันเพิ่งมีเวลา 18+ ชั่วโมง (อีกครั้ง) .. ฉันแก่แล้วและลืม .. ฉันไม่สามารถสะกดได้ .. ฉันมีสมาธิสั้น ๆ ดังนั้นฉันจึงตอบสนองได้เร็วขึ้น .. :-)

คำถาม:

เป็นไปได้ไหมที่จะเปลี่ยนเธรดหลักให้กับผู้ใช้ที่ไม่มีบัญชีบนเครื่องโลคัล?

ตอบ:

ใช่คุณสามารถเปลี่ยนเธรดหลักแม้ว่าข้อมูลประจำตัวที่คุณใช้ไม่ได้กำหนดไว้ในเครื่องหรืออยู่นอก "ฟอเรสต์"

ฉันพบปัญหานี้เมื่อพยายามเชื่อมต่อกับเซิร์ฟเวอร์ SQL ที่มีการตรวจสอบสิทธิ์ NTLM จากบริการ การโทรนี้ใช้ข้อมูลรับรองที่เกี่ยวข้องกับกระบวนการซึ่งหมายความว่าคุณต้องการบัญชีท้องถิ่นหรือบัญชีโดเมนเพื่อตรวจสอบสิทธิ์ก่อนที่คุณจะสามารถรับบทบาท บลาบลา ...

แต่...

การเรียก LogonUser (.. ) ด้วยแอททริบิวของ ???? _ NEW_CREDENTIALS จะส่งคืนโทเค็นความปลอดภัยโดยไม่พยายามพิสูจน์ตัวตนของข้อมูลประจำตัว Kewl .. ไม่จำเป็นต้องกำหนดบัญชีภายใน "forest" เมื่อคุณมีโทเค็นแล้วคุณอาจต้องเรียก DuplicateToken () พร้อมตัวเลือกเพื่อเปิดใช้งานการรับบทบาทเป็นโทเค็นใหม่ ตอนนี้เรียก SetThreadToken (NULL โทเค็น); (อาจเป็น & โทเค็น?) .. การโทรไปที่ ImpersonateLoggedonUser (โทเค็น); อาจจำเป็น แต่ฉันไม่คิดอย่างนั้น ค้นดูสิ..

ทำสิ่งที่คุณต้องทำ ..

โทร RevertToSelf () ถ้าคุณเรียกว่า ImpersonateLoggedonUser () จากนั้น SetThreadToken (NULL, NULL); (ฉันคิดว่า ... เงยหน้าขึ้น) แล้วปิด () บนด้ามจับที่สร้างขึ้น ..

ไม่มีสัญญา แต่สิ่งนี้ใช้ได้ผลกับฉัน ... นี่คือส่วนหัวของฉัน (เหมือนผมของฉัน) และฉันไม่สามารถสะกด !!!


1

หากคุณไม่สามารถสร้างโทเค็นการรักษาความปลอดภัยที่ถูกต้องภายในเครื่องดูเหมือนว่าคุณได้จัดการแถบตัวเลือก Win32 Win32 และ WNetAddConnection * ทั้งหมดแล้ว

ข้อมูลมากมายเกี่ยวกับ MSDN เกี่ยวกับ WNet - ข้อมูล PInvoke และรหัสตัวอย่างที่เชื่อมต่อกับเส้นทาง UNC ที่นี่:

http://www.pinvoke.net/default.aspx/mpr/WNetAddConnection2.html#

การอ้างอิง MSDN ที่นี่:

http://msdn.microsoft.com/en-us/library/aa385391(VS.85).aspx


1

พอร์ตไปยังF #เพื่อใช้กับFAKEด้วย

module NetworkShare

open System
open System.ComponentModel
open System.IO
open System.Net
open System.Runtime.InteropServices

type ResourceScope =
| Connected = 1
| GlobalNetwork = 2
| Remembered = 3
| Recent = 4
type ResourceType =
| Any = 0
| Disk = 1
| Print = 2
| Reserved = 8
type ResourceDisplayType =
| Generic = 0x0
| Domain = 0x01
| Server = 0x02
| Share = 0x03
| File = 0x04
| Group = 0x05
| Network = 0x06
| Root = 0x07
| Shareadmin = 0x08
| Directory = 0x09
| Tree = 0x0a
| Ndscontainer = 0x0b

//Uses of this construct may result in the generation of unverifiable .NET IL code.
#nowarn "9"
[<StructLayout(LayoutKind.Sequential)>]
type NetResource =
  struct
    val mutable Scope : ResourceScope
    val mutable ResourceType : ResourceType
    val mutable DisplayType : ResourceDisplayType
    val mutable Usage : int
    val mutable LocalName : string
    val mutable RemoteName : string
    val mutable Comment : string
    val mutable Provider : string
    new(name) = {
      // lets preset needed fields
      NetResource.Scope = ResourceScope.GlobalNetwork
      ResourceType = ResourceType.Disk
      DisplayType = ResourceDisplayType.Share
      Usage = 0
      LocalName = null
      RemoteName = name
      Comment = null
      Provider = null
    }
  end

type WNetConnection(networkName : string, credential : NetworkCredential) =
  [<Literal>]
  static let Mpr = "mpr.dll"
  [<DllImport(Mpr, EntryPoint = "WNetAddConnection2")>]
  static extern int connect(NetResource netResource, string password, string username, int flags)
  [<DllImport(Mpr, EntryPoint = "WNetCancelConnection2")>]
  static extern int disconnect(string name, int flags, bool force)

  let mutable disposed = false;

  do
    let userName = if String.IsNullOrWhiteSpace credential.Domain
                   then credential.UserName
                   else credential.Domain + "\\" + credential.UserName
    let resource = new NetResource(networkName)

    let result = connect(resource, credential.Password, userName, 0)

    if result <> 0 then
      let msg = "Error connecting to remote share " + networkName
      new Win32Exception(result, msg)
      |> raise

  let cleanup(disposing:bool) =
    if not disposed then
      disposed <- true
      if disposing then () // TODO dispose managed resources here
      disconnect(networkName, 0, true) |> ignore

  interface IDisposable with
    member __.Dispose() =
      disconnect(networkName, 0, true) |> ignore
      GC.SuppressFinalize(__)

  override __.Finalize() = cleanup(false)

type CopyPath =
  | RemotePath of string * NetworkCredential
  | LocalPath of string

let createDisposable() =
  {
    new IDisposable with
      member __.Dispose() = ()
  }

let copyFile overwrite destPath srcPath : unit =
  use _srcConn =
    match srcPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  use _destConn =
    match destPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  match srcPath, destPath with
  | RemotePath(src, _), RemotePath(dest, _)
  | LocalPath(src), RemotePath(dest, _)
  | RemotePath(src, _), LocalPath(dest)
  | LocalPath(src), LocalPath(dest) ->
    if FileInfo(src).Exists |> not then
      failwith ("Source file not found: " + src)
    let destFilePath =
      if DirectoryInfo(dest).Exists then Path.Combine(dest, Path.GetFileName src)
      else dest
    File.Copy(src, destFilePath, overwrite)

let rec copyDir copySubDirs filePattern destPath srcPath =
  use _srcConn =
    match srcPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  use _destConn =
    match destPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  match srcPath, destPath with
  | RemotePath(src, _), RemotePath(dest, _)
  | LocalPath(src), RemotePath(dest, _)
  | RemotePath(src, _), LocalPath(dest)
  | LocalPath(src), LocalPath(dest) ->
    let dir = DirectoryInfo(src)
    if dir.Exists |> not then
      failwith ("Source directory not found: " + src)

    let dirs = dir.GetDirectories()
    if Directory.Exists(dest) |> not then
      Directory.CreateDirectory(dest) |> ignore

    let files = dir.GetFiles(filePattern)
    for file in files do
      let tempPath = Path.Combine(dest, file.Name)
      file.CopyTo(tempPath, false) |> ignore

    if copySubDirs then
      for subdir in dirs do
        let subdirSrc =
          match srcPath with
          | RemotePath(_, credential) -> RemotePath(Path.Combine(dest, subdir.Name), credential)
          | LocalPath(_) -> LocalPath(Path.Combine(dest, subdir.Name))
        let subdirDest =
          match destPath with
          | RemotePath(_, credential) -> RemotePath(subdir.FullName, credential)
          | LocalPath(_) -> LocalPath(subdir.FullName)
        copyDir copySubDirs filePattern subdirDest subdirSrc

0

คุณควรจะดูการเพิ่มเช่นนี้:

<identity impersonate="true" userName="domain\user" password="****" />

ลงในเว็บของคุณ

ข้อมูลมากกว่านี้.


ความปลอดภัยองค์กรบางอย่างป้องกันการใช้การแอบอ้างบุคคลอื่นเพราะพวกเขาไม่สามารถติดตามแอปพลิเคชันที่ใช้งานได้และต้องอยู่ในโดเมนเดียวกันหรือเชื่อถือได้ ฉันคิดว่ามีคนแอบอ้างเป็นตัวของตัวเอง บัญชีบริการโดเมนที่มี pinvoke ดูเหมือนจะเป็นวิธีที่จะไป
จิม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.