SCP プロパティにアクセスするためのサービス アカウントの有効化
次のコード例では、サービス接続ポイント (SCP) オブジェクトにアクセス制御エントリ (ACE) のペアを設定します。 ACE は、サービス インスタンスが実行されるユーザーまたはコンピューター アカウントへの読み取り/書き込みアクセスを許可します。 サービス インストーラーは、次のようなコードを使用して、サービスが実行時にそのプロパティを更新できるようにします。 このような ACE が設定されていない場合、サービスは SCP のプロパティにアクセスできません。
通常、サービス インストーラーは、SCP オブジェクトの作成後にこれらの ACE を設定します。 詳細と、SCP を作成してこの関数を呼び出すコード例については、「クライアントがサービス接続ポイントを検索して使用する方法」を参照してください。 サービスが別のアカウントで実行されるように再構成された場合は、ACE を更新する必要があります。 正常に実行するには、このコード例をドメイン管理者のセキュリティ コンテキストで実行する必要があります。
サンプル関数の最初のパラメーターは、アクセス権を付与するユーザー アカウントの名前を指定します。 この関数は、名前が Domain**\**UserName 形式であることを前提としています。 アカウントが指定されていない場合、この関数はサービスが LocalSystem アカウントを使用することを前提としています。 つまり、この関数は、サービスが実行されているホスト サーバーのコンピューター アカウントへのアクセス権を付与する必要があります。 これを行うために、コード例では GetComputerObjectName 関数を呼び出して、ローカル コンピューターのドメインとユーザー名を取得します。
次のコード例は、サービスに SCP オブジェクトへのフル アクセスを許可するように変更できますが、ベスト プラクティスは、実行時にサービスが必要とする特定のアクセス権のみを付与することです。 この場合、関数は 2 つのプロパティへのアクセスを許可します。
プロパティ | 説明 |
---|---|
serviceDNSName | サービスが実行されているホスト サーバーの名前。 |
serviceBindingInformation | サービスの起動時に更新されるプライベート バインド情報。 |
各プロパティは、プロパティの attributeSchema クラスの schemaIDGUID によって識別されます。 スキーマ内のすべてのプロパティには、独自の一意の schemaIDGUID があります。 次のコード例では、文字列を使用して GUID を指定します。 GUID 文字列の形式は次のとおりです。各 "X" は 16 進数で置き換えられます: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}。
アクセスを許可または拒否するプロパティに割り当てられている schemaIDGUID 値については、「Active Directory スキーマのリファレンス」ページを参照してください。
次のコード例では、IADsSecurityDescriptor、IADsAccessControlList、および IADsAccessControlEntry インターフェイスを使用して、次の操作を実行します。
- SCP オブジェクトのセキュリティ記述子を取得します。
- セキュリティ記述子の随意アクセス制御リスト (DACL) に適切な ACE を設定します。
- SCP オブジェクトのセキュリティ記述子を変更します。
#include <atlbase.h>
//******************************
//
// AllowAccessToScpProperties()
//
//******************************
HRESULT AllowAccessToScpProperties(
LPWSTR wszAccountSAM, // Service account to allow access.
IADs *pSCPObject) // IADs pointer to the SCP object.
{
HRESULT hr = E_FAIL;
IADsAccessControlList *pACL = NULL;
IADsSecurityDescriptor *pSD = NULL;
IDispatch *pDisp = NULL;
IADsAccessControlEntry *pACE1 = NULL;
IADsAccessControlEntry *pACE2 = NULL;
IDispatch *pDispACE = NULL;
long lFlags = 0L;
CComBSTR sbstrTrustee;
CComBSTR sbstrSecurityDescriptor = L"nTSecurityDescriptor";
VARIANT varSD;
if(NULL == pSCPObject)
{
return E_INVALIDARG;
}
VariantInit(&varSD);
/*
If no service account is specified, service runs under
LocalSystem. Allow access to the computer account of the
service's host.
*/
if (wszAccountSAM)
{
sbstrTrustee = wszAccountSAM;
}
else
{
LPWSTR pwszComputerName;
DWORD dwLen;
// Get the size required for the SAM account name.
dwLen = 0;
GetComputerObjectNameW(NameSamCompatible,
NULL, &dwLen);
pwszComputerName = new WCHAR[dwLen + 1];
if(NULL == pwszComputerName)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
/*
Get the SAM account name of the computer object for
the server.
*/
if(!GetComputerObjectNameW(NameSamCompatible,
pwszComputerName, &dwLen))
{
delete pwszComputerName;
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
sbstrTrustee = pwszComputerName;
wprintf(L"GetComputerObjectName: %s\n", pwszComputerName);
delete pwszComputerName;
}
// Get the nTSecurityDescriptor.
hr = pSCPObject->Get(sbstrSecurityDescriptor, &varSD);
if (FAILED(hr) || (varSD.vt != VT_DISPATCH))
{
_tprintf(TEXT("Get nTSecurityDescriptor failed: 0x%x\n"), hr);
goto cleanup;
}
/*
Use the V_DISPATCH macro to get the IDispatch pointer from
VARIANT structure and QueryInterface for an
IADsSecurityDescriptor pointer.
*/
hr = V_DISPATCH( &varSD )->QueryInterface(
IID_IADsSecurityDescriptor,
(void**)&pSD);
if (FAILED(hr))
{
_tprintf(
TEXT("Cannot get IADsSecurityDescriptor: 0x%x\n"),
hr);
goto cleanup;
}
/*
Get an IADsAccessControlList pointer to the security
descriptor's DACL.
*/
hr = pSD->get_DiscretionaryAcl(&pDisp);
if (SUCCEEDED(hr))
{
hr = pDisp->QueryInterface(
IID_IADsAccessControlList,
(void**)&pACL);
}
if (FAILED(hr))
{
_tprintf(TEXT("Cannot get DACL: 0x%x\n"), hr);
goto cleanup;
}
// Create the COM object for the first ACE.
hr = CoCreateInstance(CLSID_AccessControlEntry,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsAccessControlEntry,
(void **)&pACE1);
// Create the COM object for the second ACE.
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_AccessControlEntry,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsAccessControlEntry,
(void **)&pACE2);
}
if (FAILED(hr))
{
_tprintf(TEXT("Cannot create ACEs: 0x%x\n"), hr);
goto cleanup;
}
// Set the properties of the two ACEs.
// Allow read and write access to the property.
hr = pACE1->put_AccessMask(
ADS_RIGHT_DS_READ_PROP | ADS_RIGHT_DS_WRITE_PROP);
hr = pACE2->put_AccessMask(
ADS_RIGHT_DS_READ_PROP | ADS_RIGHT_DS_WRITE_PROP);
// Set the trustee, which is either the service account or the
// host computer account.
hr = pACE1->put_Trustee( sbstrTrustee );
hr = pACE2->put_Trustee( sbstrTrustee );
// Set the ACE type.
hr = pACE1->put_AceType( ADS_ACETYPE_ACCESS_ALLOWED_OBJECT );
hr = pACE2->put_AceType( ADS_ACETYPE_ACCESS_ALLOWED_OBJECT );
// Set AceFlags to zero because ACE is not inheritable.
hr = pACE1->put_AceFlags( 0 );
hr = pACE2->put_AceFlags( 0 );
// Set Flags to indicate an ACE that protects a specified object.
hr = pACE1->put_Flags( ADS_FLAG_OBJECT_TYPE_PRESENT );
hr = pACE2->put_Flags( ADS_FLAG_OBJECT_TYPE_PRESENT );
// Set ObjectType to the schemaIDGUID of the attribute.
// serviceDNSName
hr = pACE1->put_ObjectType(
L"{28630eb8-41d5-11d1-a9c1-0000f80367c1}");
// serviceBindingInformation
hr = pACE2->put_ObjectType(
L"{b7b1311c-b82e-11d0-afee-0000f80367c1}");
/*
Add the ACEs to the DACL. Need an IDispatch pointer for
each ACE to pass to the AddAce method.
*/
hr = pACE1->QueryInterface(IID_IDispatch,(void**)&pDispACE);
if (SUCCEEDED(hr))
{
hr = pACL->AddAce(pDispACE);
}
if (FAILED(hr))
{
_tprintf(TEXT("Cannot add first ACE: 0x%x\n"), hr);
goto cleanup;
}
else
{
if (pDispACE)
pDispACE->Release();
pDispACE = NULL;
}
// Repeat for the second ACE.
hr = pACE2->QueryInterface(IID_IDispatch, (void**)&pDispACE);
if (SUCCEEDED(hr))
{
hr = pACL->AddAce(pDispACE);
}
if (FAILED(hr))
{
_tprintf(TEXT("Cannot add second ACE: 0x%x\n"), hr);
goto cleanup;
}
// Write the modified DACL back to the security descriptor.
hr = pSD->put_DiscretionaryAcl(pDisp);
if (SUCCEEDED(hr))
{
/*
Write the ntSecurityDescriptor property to the
property cache.
*/
hr = pSCPObject->Put(sbstrSecurityDescriptor, varSD);
if (SUCCEEDED(hr))
{
// SetInfo updates the SCP object in the directory.
hr = pSCPObject->SetInfo();
}
}
cleanup:
if (pDispACE)
pDispACE->Release();
if (pACE1)
pACE1->Release();
if (pACE2)
pACE2->Release();
if (pACL)
pACL->Release();
if (pDisp)
pDisp->Release();
if (pSD)
pSD->Release();
VariantClear(&varSD);
return hr;
}