gpt4 book ai didi

c# - 使用凭据从远程、不受信任的域访问共享文件 (UNC)

转载 作者:IT王子 更新时间:2023-10-29 03:31:56 27 4
gpt4 key购买 nike

我们遇到了一个需要解决的有趣情况,但我的搜索没有结果。因此,我向 SO 社区寻求帮助。

问题是这样的:我们需要通过远程文件共享/UNC 以编程方式访问不在我们域中且不在受信任外部域中的共享文件。自然地,我们需要向远程机器提供凭据。

通常,可以通过以下两种方式之一解决此问题:

  1. 将文件共享映射为驱动器并在那时提供凭据。这通常是使用 NET USE 命令或复制 NET USE 的 Win32 函数来完成的。
  2. 使用 UNC 路径访问文件,就像远程计算机在域中一样,并确保运行程序的帐户在远程计算机上作为本地用户复制(包括密码)。基本上利用 Windows 将在用户尝试访问共享文件时自动提供当前用户的凭据这一事实。
  3. 不要使用远程文件共享。使用 FTP(或其他方式)传输文件,在本地处理,然后传回。

出于各种各样的原因,我们的安全/网络架构师拒绝了前两种方法。第二种方法显然是一个安全漏洞;如果远程计算机受到威胁,则本地计算机现在也处于危险之中。第一种方法并不令人满意,因为新挂载的驱动器是本地计算机上其他程序在程序访问文件时可用的共享资源。尽管很有可能将此临时化,但在他们看来这仍然是一个漏洞。

他们对第三种选择持开放态度,但远程网络管理员坚持使用 SFTP 而不是 FTPS,而 FtpWebRequest 仅支持 FTPS。 SFTP 对防火墙更友好的选项,我可以使用几个库来实现这种方法,但如果可以的话,我更愿意减少依赖性。

我在 MSDN 上搜索了使用远程文件共享的托管方式或 win32 方式,但我没有找到任何有用的东西。

所以我问:还有别的办法吗?我错过了一个 super secret 的 win32 函数吗?还是我必须追求选项 3 的某种变体?

最佳答案

解决问题的方法是使用名为 WNetUseConnection 的 Win32 API .
使用此函数通过身份验证连接到 UNC 路径,而不是映射驱动器

这将允许您连接到远程机器,即使它不在同一个域中,即使它具有不同的用户名和密码。

使用 WNetUseConnection 后,您将能够通过 UNC 路径访问该文件,就好像您在同一域中一样。最好的方法可能是通过管理内置共享。
示例:\\计算机名\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);
}
}
}

关于c# - 使用凭据从远程、不受信任的域访问共享文件 (UNC),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/659013/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com