Abilitazione dell'account del servizio per accedere alle proprietà SCP
Nell'esempio di codice seguente viene impostata una coppia di voci di Controllo di accesso (ACL) in un oggetto SCP (Service Connection Point). Gli ACL concedono l'accesso in lettura/scrittura all'account utente o computer in cui verrà eseguita l'istanza del servizio. Il programma di installazione del servizio usa codice simile al seguente per assicurarsi che il servizio possa aggiornarne le proprietà in fase di esecuzione. Se gli ACL simili a questi non sono impostati, il servizio non avrà accesso alle proprietà di SCP.
In genere, un programma di installazione del servizio imposta questi ACL dopo la creazione dell'oggetto SCP. Per altre informazioni e un esempio di codice che crea un SCP e chiama questa funzione, vedere How Clients Find and Use a Service Connessione ion Point. Se il servizio viene riconfigurato per l'esecuzione con un account diverso, gli ACL devono essere aggiornati. Per eseguire correttamente, questo esempio di codice deve essere eseguito nel contesto di sicurezza di un amministratore di dominio.
Il primo parametro della funzione di esempio specifica il nome dell'account utente a cui concedere l'accesso. La funzione presuppone che il nome sia in formato Domain**\**UserName. Se non viene specificato alcun account, la funzione presuppone che il servizio usi l'account LocalSystem. Ciò significa che la funzione deve concedere l'accesso all'account computer del server host in cui è in esecuzione il servizio. A tale scopo, l'esempio di codice chiama la funzione GetComputerObjectName per ottenere il dominio e il nome utente del computer locale.
L'esempio di codice seguente può essere modificato per concedere al servizio l'accesso completo all'oggetto SCP, ma la procedura consigliata consiste nel concedere solo i diritti di accesso specifici richiesti dal servizio in fase di esecuzione. In questo caso, la funzione concede l'accesso a due proprietà.
Proprietà | Descrizione |
---|---|
serviceDNSName | Nome del server host in cui è in esecuzione il servizio. |
serviceBindingInformation | Informazioni sull'associazione privata aggiornate dal servizio all'avvio. |
Ogni proprietà è identificata dallo schemaIDGUID della classe attributeSchema della proprietà. Ogni proprietà nello schema ha un proprio schemaIDGUID univoco. Nell'esempio di codice seguente vengono utilizzate stringhe per specificare i GUID. Le stringhe GUID hanno il formato seguente in cui ogni "X" viene sostituito da una cifra esadecimale: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}.
Fare riferimento alle pagine di riferimento dello schema di Active Directory per i valori schemaIDGUID assegnati alle proprietà per concedere o negare l'accesso.
Nell'esempio di codice seguente vengono usate le interfacce IADsSecurityDescriptor, IADsAccessControlList e IADsAccessControlEntry per eseguire le operazioni seguenti.
- Ottenere il descrittore di sicurezza dell'oggetto SCP.
- Impostare gli ACL appropriati nell'elenco di controllo di accesso discrezionale (DACL) del descrittore di sicurezza.
- Modificare il descrittore di sicurezza dell'oggetto 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;
}