Поделиться через


Установка службы на хост-компьютере

В следующем примере кода показаны основные шаги по установке службы с поддержкой каталогов на хост-компьютере. Он выполняет следующие операции:

  1. Вызывает функцию OpenSCManager, чтобы открыть дескриптор диспетчера управления службами (SCM) на локальном компьютере.
  2. Вызывает функцию CreateService для установки службы в базе данных SCM. Этот вызов указывает учетную запись входа и пароль службы, а также исполняемый файл службы и другие сведения о службе. CreateService завершается ошибкой, если указанная учетная запись входа недопустимая. Однако CreateService не проверка срок действия пароля. Он также не проверяет, имеет ли учетная запись вход в качестве службы прямо на локальном компьютере. Дополнительные сведения см. в разделе "Предоставление входа в качестве службы справа на хост-компьютере".
  3. Вызывает вложенный объект ScpCreate службы, который создает объект точки подключения службы (SCP) в каталоге, чтобы опубликовать расположение этого экземпляра службы. Дополнительные сведения см. в разделе "Поиск клиентов и использование точки Подключение ion" службы. Эта подпрограмма также хранит сведения о привязке службы в SCP, задает ACE в SCP, чтобы служба ей была доступ во время выполнения, кэширует различающееся имя SCP в локальном реестре и возвращает различающееся имя нового SCP.
  4. Вызывает вложенный запрос spnCompose службы, использующий строку класса службы и различающееся имя SCP для создания имени субъекта-службы (SPN). Дополнительные сведения см. в статье Создание имен субъектов-служб для службы с помощью SCP. Имя субъекта-службы однозначно идентифицирует этот экземпляр службы.
  5. Вызывает вложенный запрос spnRegister службы, который регистрирует имя участника-службы в объекте учетной записи, связанном с учетной записью входа в службу. Дополнительные сведения см. в разделе "Регистрация имен субъектов-служб для службы". Регистрация имени участника-службы позволяет клиентским приложениям проходить проверку подлинности службы.

Этот пример кода работает правильно независимо от того, является ли учетная запись входа локальной или доменной учетной записью или учетной записью LocalSystem. Для учетной записи пользователя домена параметр szServiceAccountSAM содержит имя пользователя домена**\** учетной записи, а параметр szServiceAccountDN содержит различающееся имя объекта учетной записи пользователя в каталоге. Для учетной записи LocalSystem имена szServiceAccountSAM и szPassword имеют значение NULL, а szServiceAccountSN — это различающееся имя объекта учетной записи локального компьютера в каталоге. Если szServiceAccountSAM указывает учетную запись локального пользователя (формат имени — ".\UserName"), пример кода пропускает регистрацию имени участника-службы, так как для локальных учетных записей пользователей не поддерживается взаимная проверка подлинности.

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

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

void InstallServiceOnLocalComputer(
            LPTSTR szServiceAccountDN,  // Distinguished name of logon account.
            LPTSTR szServiceAccountSAM, // SAM name of logon account.
            LPTSTR szPassword)          // Password of logon account.
{
SC_HANDLE   schService = NULL;
SC_HANDLE   schSCManager = NULL;
TCHAR szPath[512];
LPTSTR lpFilePart;
TCHAR szDNofSCP[MAX_PATH];
TCHAR szServiceClass[]=TEXT("ADSockAuth");
 
DWORD dwStatus;
TCHAR **pspn=NULL;
ULONG ulSpn=1;
 
// Get the full path of the service's executable.
// The code example assumes that the executable is in the current directory.
dwStatus = GetFullPathName(TEXT("service.exe"), 512, szPath, &lpFilePart);
if (dwStatus == 0) {
    _tprintf(TEXT("Unable to install %s - %s\n"), 
            TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
    return;
}
_tprintf(TEXT("path of service.exe: %s\n"), szPath);
 
// Open the Service Control Manager on the local computer.
schSCManager = OpenSCManager(
                NULL,                   // Computer (NULL == local)
                NULL,                   // Database (NULL == default)
                SC_MANAGER_ALL_ACCESS   // Access required
                );
if (! schSCManager) {
    _tprintf(TEXT("OpenSCManager failed - %s\n"), 
                   GetLastErrorText(szErr,256));
    goto cleanup;
}
        
// Install the service in the SCM database.
schService = CreateService(
            schSCManager,               // SCManager database
            TEXT(SZSERVICENAME),        // Name of service
            TEXT(SZSERVICEDISPLAYNAME), // Name to display
            SERVICE_ALL_ACCESS,         // Desired access
            SERVICE_WIN32_OWN_PROCESS,  // Service type
            SERVICE_DEMAND_START,       // Start type
            SERVICE_ERROR_NORMAL,       // Error control type
            szPath,                     // Service binary
            NULL,                       // No load ordering group
            NULL,                       // No tag identifier
            TEXT(SZDEPENDENCIES),       // Dependencies
            szServiceAccountSAM,        // Service account
            szPassword);                // Account password
if (! schService) {
    _tprintf(TEXT("CreateService failed - %s\n"), 
                   GetLastErrorText(szErr,256));
    goto cleanup;
}
 
_tprintf(TEXT("%s installed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
 
// Create the service's Service Connection Point (SCP).
dwStatus = ScpCreate(
        2000,                 // Service default port number
        szServiceClass,       // Specifies the service class string
        szServiceAccountSAM,  // SAM name of logon account for ACE
        szDNofSCP             // Buffer returns the DN of the SCP
        );
if (dwStatus != 0) {
    _tprintf(TEXT("ScpCreate failed: %d\n"), dwStatus );
    DeleteService(schService);
    goto cleanup;
}
 
// Compose and register a service principal name for this service.
// This is performed on the install path because this requires elevated
// privileges for updating the directory.
// If a local account of the format ".\user name", skip the SPN.
if ( szServiceAccountSAM[0] == '.' ) 
{
    _tprintf(TEXT("Do not register SPN for a local account.\n"));
    goto cleanup;
}
 
dwStatus = SpnCompose(
        &pspn,            // Receives pointer to the SPN array.
        &ulSpn,           // Receives number of SPNs returned.
        szDNofSCP,        // Input: DN of the SCP.
        szServiceClass);  // Input: the service's class string.
 
if (dwStatus == NO_ERROR) 
    dwStatus = SpnRegister(
        szServiceAccountDN,  // Account on which SPNs are registered.
        pspn,                // Array of SPNs to register.
        ulSpn,               // Number of SPNs in array.
        DS_SPN_ADD_SPN_OP);  // Operation code: Add SPNs.
 
if (dwStatus != NO_ERROR) 
{
    _tprintf(TEXT("Failed to compose SPN: Error was %X\n"), 
                  dwStatus);
    DeleteService(schService);
    ScpDelete(szDNofSCP, szServiceClass, szServiceAccountDN);
    goto cleanup;
}
 
cleanup:
if (schSCManager)
    CloseServiceHandle(schSCManager);
if (schService)
    CloseServiceHandle(schService);
DsFreeSpnArray(ulSpn, pspn);
return;
}

Дополнительные сведения о предыдущем примере кода см. в статье Создание имен субъектов-служб для службы с помощью SCP и регистрация имен субъектов-служб для службы.