次のコード例は、ディレクトリ対応サービスをホスト コンピューターにインストールする基本的な手順を示しています。 次の操作を実行します。
- OpenSCManager 関数を呼び出して、ローカル コンピューター上のサービス コントロール マネージャー (SCM) へのハンドルを開きます。
- CreateService 関数を呼び出して、SCM データベースにサービスをインストールします。 この呼び出しでは、サービスのログオン アカウントとパスワード、サービスの実行可能ファイル、およびサービスに関するその他の情報を指定します。 指定 ログオン アカウントが無効な場合、CreateService は失敗します。 ただし、CreateService は、パスワードの有効性を確認しません。 また、アカウントがローカル コンピューターでサービスとしてのログオンを行っていることを確認しません。 詳細については、「ホスト コンピューターでのサービスとしてのログオン権限の付与」を参照してください。
- サービスの ScpCreate サブルーチンを呼び出して、サービスのこのインスタンスの場所を公開するサービス接続ポイント オブジェクト (SCP) をディレクトリに作成します。 詳細については、「クライアントがサービス接続ポイントを検索して使用する方法」を参照してください。 また、このルーチンは、サービスのバインディング情報を SCP に格納し、SCP に ACE を設定して、サービスが実行時にアクセスできるようにし、SCP の識別名をローカル レジストリにキャッシュして、新しい SCP の識別名を返します。
- サービスのクラス文字列と SCP の識別名を使用してサービス プリンシパル名 (SPN) を構成するサービスの SpnCompose サブルーチンを呼び出します。 詳細については、「SCP を使用したサービスの SPN の作成」を参照してください。 SPN は、サービスのこのインスタンスを一意に識別します。
- サービスのログオン アカウントに関連付けられているアカウント オブジェクトに SPN を登録するサービスの SpnRegister サブルーチンを呼び出します。 詳細については、「サービスの SPN の登録」を参照してください。 SPN を登録すると、クライアント アプリケーションでサービスを認証できます。
このコード例は、ログオン アカウントがローカル ユーザー アカウントかドメイン ユーザー アカウントか LocalSystem アカウントかに関係なく、正しく機能します。 ドメイン ユーザー アカウントの場合、szServiceAccountSAM パラメーターにはアカウントの Domain**\**UserName 名が含まれており、szServiceAccountDN パラメーターにはディレクトリ内のユーザー アカウント オブジェクトの識別名が含まれます。 LocalSystem アカウントの場合、szServiceAccountSAM と szPassword は null 。szServiceAccountSN は、ディレクトリ内のローカル コンピューターのアカウント オブジェクトの識別名です。 szServiceAccountSAM がローカル ユーザー アカウント (名前の形式は ".\UserName") を指定した場合、コード例では、ローカル ユーザー アカウントに対する相互認証がサポートされていないため、SPN 登録をスキップします。
既定のセキュリティ構成では、ドメイン管理者のみがこのコードを実行できます。
また、このコード例は、記述されているように、サービスがインストールされているコンピューターで実行する必要があることに注意してください。 そのため、通常は、スキーマの拡張、UI の拡張、またはグループ ポリシーの設定を行う、サービス インストール コード (存在する場合) とは別のインストール実行可能ファイルに含まれます。 これらの操作では、フォレスト全体のサービス コンポーネントがインストールされますが、このコードでは 1 台のコンピューターにサービスがインストールされます。
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 を使用してサービスの SPN を作成する と、サービス の SPN を登録するを参照してください。