我们有一个场景,我们需要我们的用户能够启动SQLServer并使用与当前登录时不同的域进行身份验证。所以要澄清这个设置的方式:
我们发现从命令行运行它将起作用:
RUNAS /user:REMOTEDOMAIN\AUserName /netonly "C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Ssms.exe
它将显示“输入REMOTEDOMAIN \ AUserName:的密码”消息,如果您提供了正确的密码,SSMS将启动并可以连接到远程dbs。但是,当我尝试在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);
我尝试使用带有和没有域预先填写的用户名,但都不起作用。有人试图做类似的事吗?感谢
答案 0 :(得分:0)
您应该删除以下行:
// 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
的调用应该会成功,因为您将使用正确的凭据指向正确的可执行文件。
答案 1 :(得分:0)
我做过一些可能相关的事情。我登录到一个域并尝试获取不同域上的共享文件夹的目录列表。为此,我使用LogonUser和Impersonate。代码如下所示(抱歉,我没有SQL服务器来尝试您的确切方案)...
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
答案 2 :(得分:0)
我尝试了所有可以找到的各种用户模拟代码示例。他们都没有工作。
最后,我想出了以下代码。它使用cmd.exe
参数/C
执行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");
}