Erstellen eines Dienstverbindungspunkts
Das folgende Codebeispiel zeigt, wie Sie einen Dienstverbindungspunkt erstellen und initialisieren. Das Codebeispiel führt zusätzliche Schritte aus, die es dem Dienst ermöglichen, die SCP-Werte zur Laufzeit zu aktualisieren. In der Regel führt ein Dienstinstallationsprogramm diese Schritte im Rahmen der Installation eines Diensts instance auf einem Hostcomputer aus.
In diesem Codebeispiel wird das SCP-Objekt als untergeordnetes Objekt für das Objekt des lokalen Computers erstellt. Sie verwendet die GetComputerObjectName-Funktion , um den DN des lokalen Computerobjekts abzurufen. Anschließend wird der DN verwendet, um eine Bindung an einen IDirectoryObject-Zeiger für das Computerobjekt zu erstellen. Die IDirectoryObject::CreateDSObject-Methode erstellt den SCP und gibt Anfangswerte für die wichtigen SCP-Attribute an.
CreateDSObject gibt einen Zeiger auf den neuen SCP zurück, den das Codebeispiel verwendet, um einen IADs-Zeiger für den SCP abzurufen. Im Codebeispiel werden IADs-Methoden verwendet, um die Attribute objectGUID und distinguishedName des SCP abzurufen. Im Codebeispiel wird die objectGUID verwendet, um eine Zeichenfolge zu erstellen, die zum Binden an den SCP verwendet wird, und speichert dann die GUID-Bindungszeichenfolge in der lokalen Registrierung zwischen, wo sie vom Dienst zur Laufzeit abgerufen werden kann. Der distinguishedName wird an den Funktionsaufrufer zurückgegeben, um einen Dienstprinzipalnamen (Service Principal Name, SPN) für den Dienst instance zu erstellen.
Im folgenden Codebeispiel wird diese Funktion im Rahmen der grundlegenden Schritte zum Installieren eines verzeichnisfähigen Diensts aufgerufen. Weitere Informationen finden Sie unter Installieren eines Diensts auf einem Hostcomputer.
// 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;
}