ホストコンピューターへのサービスのインストール
次のコード例は、ディレクトリ対応サービスをホストコンピューターにインストールする基本的な手順を示しています。 このプロセスでは、以下の処理を実行します。
- OpenSCManager関数を呼び出して、ローカルコンピューター上のサービスコントロールマネージャー (SCM) へのハンドルを開きます。
- CreateService関数を呼び出して、SCMデータベースにサービスをインストールします。 この呼び出しでは、サービスのログオンアカウントとパスワード、およびサービスの実行可能ファイルとサービスに関するその他の情報を指定します。 指定したログオンアカウントが無効な場合、CreateServiceは失敗します。 ただし、CreateServiceはパスワードの有効性を確認しません。 また、アカウントがローカルコンピューターでサービスとしてログオンする権利を持っているかどうかも確認しません。 詳細については、 「ホストコンピューターでのサービスとしてのログオンの許可」 を参照してください。
- ディレクトリにサービス接続ポイントオブジェクト (SCP) を作成するサービスのScpCreateサブルーチンを呼び出して、サービスのこのインスタンスの場所を公開します。 詳細については、 「クライアントがサービス接続ポイントを検索して使用する方法」 を参照してください。 また、このルーチンは、サービスのバインディング情報を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の登録」 を参照してください。