Как запустить / остановить службу Windows из ASP.NET app-вопросы безопасности
вот мой стек безопасности Windows / .NET:
- служба Windows, работающая как LocalSystem в окне Windows Server 2003.
- веб-сайт .NET 3.5, работающий в том же поле, в разделе "Настройки IIS производственного сервера по умолчанию" (так, вероятно, как пользователь NETWORKSERVICE?)
в моей среде разработки VS2008 по умолчанию у меня есть этот метод, который вызывается из ASP.NET приложение, которое отлично работает:
private static void StopStartReminderService() {
ServiceController svcController = new ServiceController("eTimeSheetReminderService");
if (svcController != null) {
try {
svcController.Stop();
svcController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10));
svcController.Start();
} catch (Exception ex) {
General.ErrorHandling.LogError(ex);
}
}
}
когда я запускаю это на производство сервер, я получаю следующую ошибку от ServiceController:
Источник: Системы.ServiceProcess - > Система.ServiceProcess.ServiceController - > IntPtr GetServiceHandle (Int32) - > Система.InvalidOperationException Сообщение Об Ошибке : Не удается открыть службу eTimeSheetReminderService на компьютере".'.
почему это происходит и как это исправить?
EDIT:
ответ ниже, в основном в комментарии, но уточнить:
- проблема была связана с безопасностью и возникла из-за того, что учетная запись NETWORKSERVICE не имела достаточных прав для запуска/остановки службы
- Я создал локальную учетную запись Пользователя и добавил ее в группу PowerUsers (эта группа имеет почти права администратора)
- Я не хочу, чтобы все мое веб-приложение олицетворяло этого пользователя все время, поэтому я олицетворяю только в методе, где я манипулирую сервисом. Я делаю это, используя следующее ресурсы, которые помогут мне сделать это в коде:
MS KB статья и это, просто, чтобы лучше понять
Примечание: Я не выдаю себя через интернет.config, я делаю это в коде. См. В MS КБ в статье выше.
6 ответов
чтобы дать IIS разрешение на запуск / остановку определенной службы:
- скачать и установить программы SubInACL.exe. (обязательно получите последнюю версию! Более ранние версии, распространяемые в некоторых наборах ресурсов, не работают!)
- выдать команду:
subinacl /service {yourServiceName} /grant=IIS_WPG=F
это предоставляет полные права управления службой для этой конкретной службы встроенной группе IIS_WPG. (Это работает для IIS6 / Win2k3.) YMMV для более нового версия IIS.)
Это был хороший вопрос, который интересовал меня так же...
Так вот что я сделал, чтобы решить эту проблему:
- Шаг 1: создайте учетную запись пользователя Windows на локальном компьютере с минимальными правами.
- Шаг 2: Дайте этому пользователю права на запуск и остановку службы через subinacl.exe
- т. е. subinacl.exe / service WindowsServiceName / GRANT=PCNAME\TestUser=STOE
- Dowload от : http://www.microsoft.com/en-za/download/details.aspx?id=23510
-
Шаг 3: Используйте олицетворение для олицетворения использования, созданного на Шаге 1, чтобы запустить и остановить службу
public const int LOGON32_PROVIDER_DEFAULT = 0; WindowsImpersonationContext _impersonationContext; [DllImport("advapi32.dll")] // ReSharper disable once MemberCanBePrivate.Global public static extern int LogonUserA(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] // ReSharper disable once MemberCanBePrivate.Global public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] // ReSharper disable once MemberCanBePrivate.Global public static extern bool RevertToSelf(); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] // ReSharper disable once MemberCanBePrivate.Global public static extern bool CloseHandle(IntPtr handle); private bool _impersonate; public bool ImpersonateValidUser(String userName, String domain, String password) { IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; if (RevertToSelf()) { if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0) { if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) { var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); _impersonationContext = tempWindowsIdentity.Impersonate(); if (_impersonationContext != null) { CloseHandle(token); CloseHandle(tokenDuplicate); _impersonate = true; return true; } } } } if (token != IntPtr.Zero) CloseHandle(token); if (tokenDuplicate != IntPtr.Zero) CloseHandle(tokenDuplicate); _impersonate = false; return false; } #region Implementation of IDisposable #endregion #region Implementation of IDisposable private void Dispose(bool dispose) { if (dispose) { if (_impersonate) _impersonationContext.Undo(); _impersonationContext.Dispose(); } } public void Dispose() { Dispose(true); } #endregion public static void StartStopService(bool startService, string serviceName) { using (var impersonateClass = new Impersonation()) { impersonateClass.ImpersonateValidUser(Settings.Default.LocalUsername, Settings.Default.Domain, Settings.Default.Password); using (var sc = new ServiceController(serviceName)) { if (startService) sc.Start(); else if (sc.CanStop) sc.Stop(); } } }
обновление для IIS 8 (и, возможно, некоторые несколько более ранние версии)
в группу группе iis_wpg больше не существует. Он изменился на группу iis_iusrs.
кроме того, для запуска остановки службы не обязательно давать полные разрешения (F). Разрешений для запуска, остановки и приостановки службы (сверху) должно быть достаточно. Как таковая команда должна быть:
subinacl / service {yourServiceName} / grant=IIS_IUSRS=TOP
обратите внимание, что вам нужно указать командную строку (желательно повышенную для запуска от имени администратора) на C:\Windows\System32
папка перед запуском этой команды.
также убедитесь, что вы скопировали subinacl.exe файл в C:\Windows\System32
из каталога установки, если есть ошибка.
просто догадка, но мне не кажется, что ошибка обязательно связана с безопасностью. Вы дали службе то же имя на производственном сервере?
Если ваше веб-приложение имеет базу данных и служба windows может получить к ней доступ, вы можете просто использовать флаг в БД для перезапуска службы. В Службе вы можете прочитать этот флаг и перезапустить, если он не занят и т. д. Только в том случае, если вы можете изменить код сервиса. Если это сторонняя служба, вы можете создать свою собственную службу windows и использовать database config для управления (перезапуска) службами. Это безопасный способ, и дает вам гораздо больше гибкости и безопасности.