Udostępnij za pośrednictwem


Instalowanie usługi na komputerze hosta

Poniższy przykład kodu przedstawia podstawowe kroki instalowania usługi z obsługą katalogów na komputerze hosta. Wykonuje następujące operacje:

  1. Wywołuje funkcję OpenSCManager, aby otworzyć dojście do menedżera kontroli usług (SCM) na komputerze lokalnym.
  2. Wywołuje funkcję CreateService, aby zainstalować usługę w bazie danych SCM. To wywołanie określa konto logowania i hasło usługi, a także plik wykonywalny usługi i inne informacje o usłudze. CreateService kończy się niepowodzeniem, jeśli określone konto logowania jest nieprawidłowe. Jednak createService nie sprawdza poprawności hasła. Nie sprawdza również, czy konto ma logowanie jako usługę bezpośrednio na komputerze lokalnym. Aby uzyskać więcej informacji, zobacz przyznawanie prawa logowania jako usługa na komputerze hosta.
  3. Wywołuje podprocedurę ScpCreate usługi, która tworzy obiekt punktu połączenia usługi (SCP) w katalogu, aby opublikować lokalizację tego wystąpienia usługi. Aby uzyskać więcej informacji, zobacz Jak klienci znajdują i używają punktu łączenia usług. Ta rutyna przechowuje również informacje o powiązaniu usługi w SCP, ustawia ACE na SCP, umożliwiając usłudze dostęp do niego w trakcie działania, buforuje nazwę wyróżniającą SCP w rejestrze lokalnym i zwraca nazwę wyróżniającą nowego SCP.
  4. Wywołuje usługi SpnCompose podroutine, która używa ciągu klasy usługi i nazwy wyróżniającej punktu połączenia usługi, aby utworzyć nazwę główną usługi (SPN). Aby uzyskać więcej informacji, zobacz Komponowanie nazw SPN dla usługi z SCP. Nazwa SPN jednoznacznie identyfikuje to konkretne wystąpienie usługi.
  5. Wywołuje podprocedurę usługi SpnRegister, która rejestruje SPN w obiekcie konta skojarzonym z kontem logowania usługi. Aby uzyskać więcej informacji, zobacz Rejestrowanie SPN dla usługi. Rejestracja SPN (głównej nazwy usługi) umożliwia aplikacjom klienckim uwierzytelnianie usługi.

Ten przykładowy kod działa poprawnie niezależnie od tego, czy konto logowania jest kontem użytkownika lokalnego, czy domeny, czy kontem LocalSystem. W przypadku konta użytkownika domeny parametr szServiceAccountSAM zawiera nazwę konta Domain**\**UserName, a parametr szServiceAccountDN zawiera nazwę wyróżniającą obiektu konta użytkownika w katalogu. Dla konta LocalSystem szServiceAccountSAM i szPasswordNULL, a szServiceAccountSN jest nazwą wyróżniającą obiektu konta komputera lokalnego w katalogu. Jeśli szServiceAccountSAM określa konto użytkownika lokalnego (format nazwy to ".\UserName"), przykład kodu pomija rejestrację nazwy SPN, ponieważ wzajemne uwierzytelnianie nie jest obsługiwane dla kont użytkowników lokalnych.

Należy pamiętać, że domyślna konfiguracja zabezpieczeń zezwala tylko administratorom domeny na wykonywanie tego kodu.

Należy również pamiętać, że ten przykład kodu, jak napisano, musi być wykonywany na komputerze, na którym jest zainstalowana usługa. W związku z tym zazwyczaj jest to oddzielny plik wykonywalny instalacji niż kod instalacji usługi, o ile taki istnieje, który rozszerza schemat, rozszerza interfejs użytkownika lub konfiguruje zasady grupy. Te operacje instalują składniki usługi dla całego lasu, natomiast ten kod instaluje usługę na jednym komputerze.

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

Aby uzyskać więcej informacji na temat poprzedniego przykładu kodu, zobacz Komponowanie SPN-ów dla usługi z SCP oraz Rejestrowanie SPN-ów dla usługi.