.Net 2.0 ServiceController.GetServices ()

У меня есть веб-сайт, на котором включена проверка подлинности Windows. Со страницы на веб-сайте пользователи могут запустить службу, которая выполняет некоторые действия с базой данных.

У меня отлично работает запуск службы, потому что я локальный администратор на сервере. Но я только что попросил пользователя протестировать его, и они не могут запустить службу.

У меня вопрос:


Кто-нибудь знает способ получить список служб на указанном компьютере по имени, используя другую учетную запись Windows, отличную от той, с которой они сейчас вошли в систему?


Я действительно не хочу добавлять всех пользователей, которым необходимо запустить службу, в группу Windows и устанавливать их всех на локального администратора на моем сервере IIS ...

Вот часть кода, который у меня есть:

public static ServiceControllerStatus FindService()
        {
            ServiceControllerStatus status = ServiceControllerStatus.Stopped;

            try
            {
                string machineName = ConfigurationManager.AppSettings["ServiceMachineName"];
                ServiceController[] services = ServiceController.GetServices(machineName);
                string serviceName = ConfigurationManager.AppSettings["ServiceName"].ToLower();

                foreach (ServiceController service in services)
                {
                    if (service.ServiceName.ToLower() == serviceName)
                    {
                        status = service.Status;
                        break;
                    }
                }
            }
            catch(Exception ex)
            {
                status = ServiceControllerStatus.Stopped;
                SaveError(ex, "Utilities - FindService()");
            }

            return status;
        }

Мое исключение исходит из второй строки в блоке try. Вот ошибка:

System.InvalidOperationException: Cannot open Service Control Manager on computer 'server.domain.com'. This operation might require other privileges. ---> System.ComponentModel.Win32Exception: Access is denied --- End of inner exception stack trace --- at System.ServiceProcess.ServiceController.GetDataBaseHandleWithAccess(String machineName, Int32 serviceControlManaqerAccess) at System.ServiceProcess.ServiceController.GetServicesOfType(String machineName, Int32 serviceType) at TelemarketingWebSite.Utilities.StartService()

Спасибо за помощь / информацию

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
0
14 665
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете попробовать использовать олицетворение ASP.NET в файле web.config и указать учетную запись пользователя с соответствующими разрешениями:

    <system.web>
       <identity impersonate = "true" userName = "Username" password = "Password" />
    </system.web

Взгляните на эта статья в MSDN. Я считаю, что есть и другие варианты, которые не требуют хранения пароля в файле web.config, например, вместо этого помещать его в раздел реестра.

Это приведет к тому, что рабочий процесс ASP.NET будет работать в контексте указанного пользователя, а не пользователя, вошедшего в веб-приложение. тем не мение, это создает проблему безопасности, и я бы сильно переосмыслил ваш дизайн. Вы можете подумать о том, чтобы веб-страница ASP.NET в свою очередь запускала запрос к какому-либо другому процессу, который фактически контролирует службы, даже к другой службе Windows, или записывала запрос в таблицу базы данных, которую служба Windows периодически опрашивает.

Мне нужно иметь имя пользователя Windows, потому что я показываю вещи на веб-сайте на основе их входа в Windows. Я не хотел, чтобы у пользователя был дополнительный логин.

Miles 17.10.2008 19:30

Вы можете продолжать использовать их учетную запись Windows для аутентификации. Я предполагаю, что вы используете встроенную проверку подлинности в IIS и модель проверки подлинности ASP.NET. (<authentication mode = "Windows" />). Вы можете использовать оба вместе, и IIS по-прежнему будет согласовывать учетные данные пользователя без дополнительного входа в систему.

Rich 18.10.2008 02:34
Ответ принят как подходящий

Примечание. Это не касается перечисления сервисов от имени другого пользователя, но, учитывая более широкое описание того, что вы делаете, я думаю, что это хороший ответ.

Я думаю, вы можете значительно упростить это и, возможно, частично избежать проблем с безопасностью, если обратитесь непосредственно к интересующей службе. Вместо вызова GetServices попробуйте следующее:

string machineName = ConfigurationManager.AppSettings["ServiceMachineName"];
string serviceName = ConfigurationManager.AppSettings["ServiceName"];
ServiceController service = new ServiceController( serviceName, machineName );
return service.Status;

Это напрямую подключается к интересующей службе и обходит этап перечисления / поиска. Следовательно, для вызывающего абонента не требуется наличие права SC_MANAGER_ENUMERATE_SERVICE в диспетчере управления службами (SCM), которого удаленные пользователи не имеют по умолчанию. Он по-прежнему требует SC_MANAGER_CONNECT, но согласно MSDN, который должен быть предоставлен удаленным аутентифицированным пользователям.

После того, как вы нашли интересующую службу, вам все равно потребуется возможность ее останавливать и запускать, на что ваши удаленные пользователи, вероятно, не имеют прав. Однако можно изменить дескриптор безопасности (DACL) для отдельных служб, что позволит вам предоставить удаленным пользователям доступ для остановки и запуска службы, не требуя, чтобы они были локальными администраторами. Это делается с помощью функции API SetNamedSecurityInfo. Вам необходимо предоставить права доступа SERVICE_START и SERVICE_STOP. В зависимости от того, к каким именно группам принадлежат эти пользователи, вам также может потребоваться предоставить им GENERIC_READ. Все эти права - описан в MSDN.

Вот некоторый код C++, который будет выполнять эту настройку, предполагая, что интересующие вас пользователи находятся в группе «Контроллеры удаленных служб» (которую вы должны создать), а имя службы - «my-service-name». Обратите внимание: если вы хотите предоставить доступ известной группе, такой как Пользователи (не обязательно хорошая идея), а не группе, которую вы создали, вам необходимо изменить TRUSTEE_IS_GROUP на TRUSTEE_IS_WELL_KNOWN_GROUP.

В коде нет проверки ошибок, которую вы бы хотели добавить. Все три функции, которые могут дать сбой (Get / SetNamedSecurityInfo и SetEntriesInAcl), возвращают 0, чтобы указать на успех.

Еще одно примечание: вы также можете установить дескриптор безопасности службы с помощью инструмент SC, который можно найти в% WINDIR% \ System32, но это не требует никакого программирования.

#include "windows.h"
#include "accctrl.h"
#include "aclapi.h"

int main()
{
    char serviceName[] = "my-service-name";
    char userGroup[] = "Remote Service Controllers";

    // retrieve the security info
    PACL pDacl = NULL;
    PSECURITY_DESCRIPTOR pDescriptor = NULL;
    GetNamedSecurityInfo( serviceName, SE_SERVICE,
        DACL_SECURITY_INFORMATION, NULL, NULL,
        &pDacl, NULL, &pDescriptor );

    // add an entry to allow the users to start and stop the service
    EXPLICIT_ACCESS access;
    ZeroMemory( &access, sizeof(access) );
    access.grfAccessMode = GRANT_ACCESS;
    access.grfAccessPermissions = SERVICE_START | SERVICE_STOP;
    access.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    access.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
    access.Trustee.ptstrName = userGroup;
    PACL pNewDacl;
    SetEntriesInAcl( 1, &access, pDacl, &pNewDacl );

    // write the changes back to the service
    SetNamedSecurityInfo( serviceName, SE_SERVICE,
        DACL_SECURITY_INFORMATION, NULL, NULL,
        pNewDacl, NULL );

    LocalFree( pNewDacl );
    LocalFree( pDescriptor );
}

Это также можно сделать из C# с помощью P / Invoke, но это немного больше работы.

Если вы по-прежнему хотите иметь возможность перечислять службы в качестве этих пользователей, вам необходимо предоставить им право SC_MANAGER_ENUMERATE_SERVICE на SCM. К сожалению, согласно MSDN, безопасность SCM может быть изменена только в Windows Server 2003 с пакетом обновления 1 или более поздней версии.

Спасибо за эту строчку кода, Чарли. Вот что я в итоге сделал. Я получил идею с этого сайта: http://www.codeproject.com/KB/cs/svcmgr.aspx?display=Print

Мне также пришлось добавить учетную запись, к которой я обращаюсь, как к группе опытных пользователей на сервере.

public static ServiceControllerStatus FindService()
        {
            ServiceControllerStatus status = ServiceControllerStatus.Stopped;
    try
            {
                string machineName = ConfigurationManager.AppSettings["ServiceMachineName"];
                string serviceName = ConfigurationManager.AppSettings["ServiceName"].ToLower();

                ImpersonationUtil.Impersonate();

                ServiceController service = new ServiceController(serviceName, machineName);
                status = service.Status;
            }
            catch(Exception ex)
            {
                status = ServiceControllerStatus.Stopped;
                SaveError(ex, "Utilities - FindService()");
            }

            return status;
        }

А вот другой мой класс с ImpersonationUtil.Impersonate ():

public static class ImpersonationUtil
    {
        public static bool Impersonate()
        {
            string logon = ConfigurationManager.AppSettings["ImpersonationUserName"];
            string password = ConfigurationManager.AppSettings["ImpersonationPassword"];
            string domain = ConfigurationManager.AppSettings["ImpersonationDomain"];

            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;
            WindowsImpersonationContext impersonationContext = null;

            if (LogonUser(logon, domain, password, 2, 0, ref token) != 0)
                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                    impersonationContext = new WindowsIdentity(tokenDuplicate).Impersonate();
            //

            return (impersonationContext != null);
        }

        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern int LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
        public extern static int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);
    }

Круто, удачи в этом. Я был бы очень осторожен, чтобы убедиться, что вы правильно отменили олицетворение, когда закончите. Для этого вам нужно избавиться от контекста олицетворения, возвращаемого из Impersonate. Невыполнение этого требования приведет к утечке имитации и вызовет проблемы в будущем.

Charlie 17.10.2008 19:53

Чтобы было ясно, если вы не отмените олицетворение, этот поток будет продолжать олицетворять указанную учетную запись на неопределенный срок. В лучшем случае это вероятная причина ошибок, а в худшем - брешь в безопасности. Лучше быть с этим поосторожнее.

Charlie 17.10.2008 20:01

Другие вопросы по теме