建立服務 連線 點
下列程式代碼範例示範如何建立及初始化服務連接點。 程式代碼範例會執行額外的步驟,讓服務在運行時間更新 SCP 值。 一般而言,服務安裝程式會在主計算機上安裝服務實例時執行這些步驟。
此程式代碼範例會將SCP物件建立為本機計算機物件的子物件。 它會使用 GetComputerObjectName 函式來取得本機計算機物件的 DN。 然後,它會使用 DN 系結至 計算機物件的 IDirectoryObject 指標。 IDirectoryObject::CreateDSObject 方法會建立 SCP,並指定重要 SCP 屬性的初始值。
CreateDSObject 會傳回新 SCP 的指標,程式代碼範例會使用此指標來擷取 SCP 的 IADs 指標。 程序代碼範例會使用 IADs 方法來擷取 SCP 的 objectGUID 和 distinguishedName 屬性。 程式代碼範例會 使用 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;
}