簡體   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