System.Diagnostics.Process.Начать процесс в другом домене

У нас есть сценарий, в котором нам нужны наши пользователи, чтобы иметь возможность запускать SQLServer и аутентифицироваться в нем, используя другой домен, чем они в настоящее время вошли в систему. Поэтому, чтобы прояснить способ настройки:

  • Пользователь приходит в офис и регистрируется в корпоративном домене (для простоты называет его LOCALDOMAIN)
  • Они хотят подключиться к нашей удаленной базе данных в другом домене (назовем его REMOTEDOMAIN)
  • Сначала они запускают инструмент VPN, который устанавливает туннель VPN в REMOTEDOMAIN (все это проверено и отлично работает).
  • Но если они запускают SSMS по умолчанию, он будет разрешать Windows Auth через LOCALDOMAIN, опция выбора REMOTEDOMAIN даже не доступна

Мы обнаружили, что выполнение этого из командной строки будет работать:

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

появится сообщение "Введите пароль для REMOTEDOMAIN\AUserName:", и если вы укажете правильный пароль, SSMS запустится и сможет подключиться к удаленному dbs. Однако, когда я пытаюсь сделать то же самое в С# с более удобным интерфейсом, я получаю "Ошибка входа в систему: неизвестное имя пользователя или неверный пароль", вот мой код:

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);

Я попробовал имя пользователя с доменом и без него, но не работает. Кто-нибудь когда-либо пытался сделать что-то подобное? спасибо

2 ответа

Вы должны удалить следующие строки:

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

В принципе, вы передаете параметр /netonly в SMSS, тогда как в командной строке вы запускаете runas не SMSS. То же самое с глаголом, вы не используете runas.

Вызов Start должен преуспеть в этой точке, так как вы укажете на правильный исполняемый файл с правильными учетными данными.


Я сделал что-то, что может быть связано. Я вхожу в один домен и пытаюсь получить список каталогов общей папки в другом домене. Для этого я использую 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
}

Возможно, вы можете адаптировать его к своей проблеме. ЛМК

licensed under cc by-sa 3.0 with attribution.