サービス接続ポイントの作成
次のコード例は、サービス接続ポイントを作成し、初期化する方法を示しています。 このコード例では、サービスが実行時にSCP値を更新できるようにするための追加ステップを実行している。 通常、サービスインストーラは、ホストコンピュータにサービスインスタンスをインストールする一環として、これらの手順を実行する。
このコード例では、SCPオブジェクトをローカルコンピュータのオブジェクトの子オブジェクトとして作成します。 を使用している。 コンピュータオブジェクト名 関数を使用して、ローカル・コンピュータ・オブジェクトのDNを取得する。 そして、そのDNを使って IDirectoryObject コンピュータ・オブジェクトのポインタ。 について IDirectoryObject::CreateDSObject メソッドは SCP を作成し、重要な SCP 属性の初期値を指定します。
CreateDSObject は新しい SCP へのポインタを返します。IADs ポインタを使用する。 コード例では IADs メソッドを呼び出します。 objectGUID そして distinguishedName SCPの属性。 コード例では objectGUID を使用して SCP へのバインドに使用する文字列を作成し、GUID バインド文字列をローカルレジストリにキャッシュします。 について distinguishedName は、サービスインスタンスのサービスプリンシパル名(SPN)を構成する際に使用するために、関数呼び出し元に返されます。
以下のコード例では、ディレクトリ対応サービスをインストールする基本ステップの一部として、この関数を呼び出している。 詳しくは ホストコンピュータへのサービスのインストール.
// ScpCreate
//
// Create a new service connection point as a child object of the
// local server computer object.
//
DWORD
ScpCreate(
USHORT usPort, // Service's default port to store in SCP.
LPTSTR szClass, // Service class string to store in SCP.
LPTSTR szAccount, // Logon account that must access SCP.
UINT ccDN, // Length of the pszDN buffer in characters
TCHAR *pszDN) // Returns distinguished name of SCP.
{
DWORD dwStat, dwAttr, dwLen;
HRESULT hr;
IDispatch *pDisp; // Returned dispinterface of new object.
IDirectoryObject *pComp; // Computer object; parent of SCP.
IADs *pIADsSCP; // IADs interface on new object.
if(!szClass || !szAccount || !pszDN || !(ccDN > 0))
{
hr = ERROR_INVALID_PARAMETER;
ReportError(TEXT("Invalid parameter."), hr);
return hr;
}
// Values for SCPs keywords attribute.
TCHAR* KwVal[]={
TEXT("83C29870-1DFC-11d3-A193-0000F87A9099"), // Vendor GUID.
TEXT("A762885A-AA44-11d2-81F1-00C04FB9624E"), // Product GUID.
TEXT("Microsoft"), // Vendor Name.
TEXT("Windows 2000 Auth-O-Matic"), // Product Name.
};
TCHAR szServer[MAX_PATH];
TCHAR szDn[MAX_PATH];
TCHAR szAdsPath[MAX_PATH];
TCHAR szPort[6];
HKEY hReg;
DWORD dwDisp;
ADSVALUE cn,objclass,keywords[4],binding,classname,dnsname,nametype;
// SCP attributes to set during creation of SCP.
ADS_ATTR_INFO ScpAttribs[] =
{
{
TEXT("cn"),
ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING,
&cn,
1
},
{
TEXT("objectClass"),
ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING,
&objclass,
1
},
{
TEXT("keywords"),
ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING,
keywords,
4
},
{
TEXT("serviceDnsName"),
ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING,
&dnsname,
1
},
{
TEXT("serviceDnsNameType"),
ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING,
&nametype,
1
},
{
TEXT("serviceClassName"),
ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING,
&classname,
1
},
{
TEXT("serviceBindingInformation"),
ADS_ATTR_UPDATE,
ADSTYPE_CASE_IGNORE_STRING,
&binding,
1
},
};
BSTR bstrGuid = NULL;
TCHAR pwszBindByGuidStr[1024];
VARIANT var;
// Get the DNS name of the local computer.
dwLen = sizeof(szServer);
if (!GetComputerNameEx(ComputerNameDnsFullyQualified,szServer,&dwLen))
return GetLastError();
_tprintf(TEXT("GetComputerNameEx: %s\n"), szServer);
// Enter the attribute values to be stored in the SCP.
keywords[0].dwType = ADSTYPE_CASE_IGNORE_STRING;
keywords[1].dwType = ADSTYPE_CASE_IGNORE_STRING;
keywords[2].dwType = ADSTYPE_CASE_IGNORE_STRING;
keywords[3].dwType = ADSTYPE_CASE_IGNORE_STRING;
keywords[0].CaseIgnoreString=KwVal[0];
keywords[1].CaseIgnoreString=KwVal[1];
keywords[2].CaseIgnoreString=KwVal[2];
keywords[3].CaseIgnoreString=KwVal[3];
cn.dwType = ADSTYPE_CASE_IGNORE_STRING;
cn.CaseIgnoreString = TEXT("SockAuthAD");
objclass.dwType = ADSTYPE_CASE_IGNORE_STRING;
objclass.CaseIgnoreString = TEXT("serviceConnectionPoint");
dnsname.dwType = ADSTYPE_CASE_IGNORE_STRING;
dnsname.CaseIgnoreString = szServer;
classname.dwType = ADSTYPE_CASE_IGNORE_STRING;
classname.CaseIgnoreString = szClass;
_stprintf_s(szPort,TEXT("%d"),usPort);
binding.dwType = ADSTYPE_CASE_IGNORE_STRING;
binding.CaseIgnoreString = szPort;
nametype.dwType = ADSTYPE_CASE_IGNORE_STRING;
nametype.CaseIgnoreString = TEXT("A");
/*
Get the distinguished name of the computer object for the local
computer.
*/
dwLen = sizeof(szDn);
if (!GetComputerObjectName(NameFullyQualifiedDN,szDn,&dwLen))
return GetLastError();
_tprintf(TEXT("GetComputerObjectName: %s\n"), szDn);
/*
Compose the ADSpath and bind to the computer object for the local
computer.
*/
_tcsncpy_s(szAdsPath,TEXT("LDAP://"),MAX_PATH);
_tcsncat_s(szAdsPath,szDn,MAX_PATH - _tcslen(szAdsPath));
hr = ADsGetObject(szAdsPath, IID_IDirectoryObject, (void **)&pComp);
if (FAILED(hr)) {
ReportError(TEXT("Failed to bind Computer Object."),hr);
return hr;
}
//*******************************************************************
// Publish the SCP as a child of the computer object
//*******************************************************************
// Calculate attribute count.
dwAttr = sizeof(ScpAttribs)/sizeof(ADS_ATTR_INFO);
// Complete the action.
hr = pComp->CreateDSObject(TEXT("cn=SockAuthAD"),
ScpAttribs, dwAttr, &pDisp);
if (FAILED(hr)) {
ReportError(TEXT("Failed to create SCP:"), hr);
pComp -> Release();
return hr;
}
pComp -> Release();
// Query for an IADs pointer on the SCP object.
hr = pDisp->QueryInterface(IID_IADs,(void **)&pIADsSCP);
if (FAILED(hr)) {
ReportError(TEXT("Failed to QueryInterface for IADs:"),hr);
pDisp->Release();
return hr;
}
pDisp->Release();
// Set ACEs on the SCP so a service can modify it.
hr = AllowAccessToScpProperties(
szAccount, // Service account to allow access.
pIADsSCP); // IADs pointer to the SCP object.
if (FAILED(hr)) {
ReportError(TEXT("Failed to set ACEs on SCP DACL:"), hr);
return hr;
}
// Get the distinguished name of the SCP.
VariantInit(&var);
hr = pIADsSCP->Get(CComBSTR("distinguishedName"), &var);
if (FAILED(hr)) {
ReportError(TEXT("Failed to get distinguishedName:"), hr);
pIADsSCP->Release();
return hr;
}
_tprintf(TEXT("distinguishedName via IADs: %s\n"), var.bstrVal);
// Return the DN of the SCP, which is used to compose the SPN.
// The best practice is to either accept and return the buffer
// size or do this in a _try / _except block, both omitted here
// for clarity.
_tcsncpy_s(pszDN, var.bstrVal, ccDN);
// Retrieve the SCP objectGUID in format suitable for binding.
hr = pIADsSCP->get_GUID(&bstrGuid);
if (FAILED(hr)) {
ReportError(TEXT("Failed to get GUID:"), hr);
pIADsSCP->Release();
return hr;
}
// Build a string for binding to the object by GUID.
_tcsncpy_s(pwszBindByGuidStr,
TEXT("LDAP://<GUID="),
1024);
_tcsncat_s(pwszBindByGuidStr,
bstrGuid,
1024 -_tcslen(pwszBindByGuidStr));
_tcsncat_s(pwszBindByGuidStr,
TEXT(">"),
1024 -_tcslen(pwszBindByGuidStr));
_tprintf(TEXT("GUID binding string: %s\n"),
pwszBindByGuidStr);
pIADsSCP->Release();
// Create a registry key under
// HKEY_LOCAL_MACHINE\SOFTWARE\Vendor\Product.
dwStat = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
TEXT("Software\\Fabrikam\\Auth-O-Matic"),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hReg,
&dwDisp);
if (dwStat != NO_ERROR) {
ReportError(TEXT("RegCreateKeyEx failed:"), dwStat);
return dwStat;
}
// Cache the GUID binding string under the registry key.
dwStat = RegSetValueEx(hReg, TEXT("GUIDBindingString"), 0, REG_SZ,
(const BYTE *)pwszBindByGuidStr,
2*(_tcslen(pwszBindByGuidStr)));
if (dwStat != NO_ERROR) {
ReportError(TEXT("RegSetValueEx failed:"), dwStat);
return dwStat;
}
RegCloseKey(hReg);
// Cleanup should delete the SCP and registry key if an error occurs.
return dwStat;
}