繁体   English   中英

System.Diagnostics.Process。针对另一个域启动进程

[英]System.Diagnostics.Process.Start a process against a different domain

我们有一种情况,我们需要用户能够使用与当前登录的域不同的域来启动SQLServer并对其进行身份验证。 因此,要澄清设置方法:

  1. 用户到达办公室并登录到公司域(为简单起见,将其称为LOCALDOMAIN)
  2. 他们希望连接到另一个域上的远程数据库(我们称其为REMOTEDOMAIN)
  3. 首先,他们启动了VPN工具,该工具建立了到REMOTEDOMAIN的VPN隧道(这已经过测试并且运行良好)
  4. 但是,如果他们默认启动SSMS,它将仅允许通过LOCALDOMAIN进行Windows身份验证,因此选择REMOTEDOMAIN的选项甚至不可用

我们发现,可以从命令行运行此命令:

RUNAS /user:REMOTEDOMAIN\AUserName /netonly "C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Ssms.exe

它将提示消息“输入REMOTEDOMAIN \\ AUserName的密码:”,如果提供正确的密码,SSMS将启动并可以连接到远程数据库。 但是,当我尝试使用更好的接口在C#中执行相同的操作时,出现“登录失败:未知的用户名或错误的密码”,这是我的代码:

System.Security.SecureString password = new System.Security.SecureString();
foreach(char c in txtPassword.Text.ToCharArray()){
    password.AppendChar(c);
}
System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo();
procInfo.Arguments = "/netonly";
procInfo.FileName = @"C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Ssms.exe"; ;
procInfo.Domain = "REMOTEDOMAIN";
procInfo.Verb = "runas";
procInfo.UserName = txtUsername.Text;
procInfo.Password = password;
procInfo.UseShellExecute = false;
System.Diagnostics.Process.Start(procInfo);

我尝试使用带或不带域名的用户名,但都无法使用。 是否有人尝试做类似的事情? 谢谢

您应该删除以下几行:

// Not passing /netonly to SMSS, it was passed to RunAs originally.
procInfo.Arguments = "/netonly";
// Again, SMSS is not getting the verb, it's being run
procInfo.Verb = "runas";

基本上,您将/netonly参数传递给SMSS,而在命令行上,您正在运行runas 而不是SMSS 与动词相同,您没有运行runas

此时,对Start的调用应该会成功,因为您将指向具有正确凭据的正确可执行文件。

我做了一些可能相关的事情。 我登录到一个域,并尝试获取另一域上共享文件夹的目录列表。 为此,我使用LogonUser和Impersonate。 该代码如下所示(抱歉,我没有SQL Server来尝试您的确切方案)...

public class Login : IDisposable
{
    public Login(string userName, string domainName)
    {
        _userName = userName;
        _domainName = domainName;
    }

    string _userName = null;
    string _domainName = null;

    IntPtr tokenHandle = new IntPtr(0);
    IntPtr dupeTokenHandle = new IntPtr(0);
    WindowsImpersonationContext impersonatedUser = null;

    const int LOGON32_PROVIDER_DEFAULT = 0;
    const int LOGON32_LOGON_INTERACTIVE = 2;
    const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

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

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

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

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
        int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

    public void AccessShare(string password)
    {
        tokenHandle = IntPtr.Zero;

        bool returnValue = LogonUser(_userName, _domainName, password,
            LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT,
            ref tokenHandle);

        if (false == returnValue)
        {
            int ret = Marshal.GetLastWin32Error();
            throw new System.ComponentModel.Win32Exception(ret);
        }

        // Use the token handle returned by LogonUser.
        WindowsIdentity newId = new WindowsIdentity(tokenHandle);
        impersonatedUser = newId.Impersonate();
    }

#region IDisposable Members
    public void  Dispose()
    {
        impersonatedUser.Undo();

        // Free the tokens.
        if (tokenHandle != IntPtr.Zero)
            CloseHandle(tokenHandle);
    }
#endregion
}

我已经将它与Directory.GetDirectories(UNCPath)一起使用,其中该路径通向另一个域上的计算机,并且在那里可以正常工作。 我尚未尝试实现“ runas”。

我这样称呼它...

using(var login = new Login("myname","mydomain))
{
    login.AccessShare("mypassword");
    // do stuff
}

也许您可以使其适应您的问题。 LMK

我尝试了所有可以找到的各种用户模拟代码示例。 他们都没有工作。

最后,我想出了以下代码。 它使用/C参数执行cmd.exe ,该参数Carries out the command specified by string and then terminates 我执行的命令是runas /netonly ...

注意事项

不幸的是,必须手动输入密码。 我的下一步是研究向process发送关键笔画。 我尝试重定向标准输入并将其写入,但是没有用。 我在某处读到,大多数密码提示仅接受直接来自键盘的输入。

同样,当SSMS打开时,“ 连接到服务器”对话框将显示您当前的域\\用户名,但它将使用您给runas提供的身份进行身份验证。

最后,如果您的AD帐户已锁定,则在尝试连接到SQL Server之前不会收到错误消息。 我忽略了复制收到的错误消息,但没有提及该帐户已被锁定。

    public static void RunAsNetonly(string username, string domain, string exePath)
    {

        var psi = new ProcessStartInfo();

        psi.FileName = "cmd.exe";
        psi.Arguments = $"/C runas /netonly /user:{domain}\\{username} \"{exePath}\"";            
        psi.UseShellExecute = false;

        var process = Process.Start(psi);

        // not sure if this is required
        process.WaitForExit();

    }        

    // usage example
    public static void RunSSMS()
    {
        RunAsNetonly("walter", "domain123", @"C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\ManagementStudio\ssms.exe");
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM