Предоставление учетной записи службы доступа к свойствам SCP
В следующем примере кода устанавливается пара записей управления доступом (ACEs) в объекте точки подключения сервиса (SCP). ACE предоставляют доступ на чтение и запись учетной записи пользователя или компьютера, от имени которой будет работать экземпляр службы. Установщик службы использует код, аналогичный приведенному ниже, чтобы убедиться, что служба может обновлять его свойства во время выполнения. Если ACEs, аналогичные этим, не заданы, служба не будет иметь доступа к свойствам SCP.
Как правило, установщик службы задает эти ACE после создания объекта SCP. Дополнительные сведения и пример кода, который создает SCP и вызывает эту функцию, см. в разделе Как клиенты находят и используют точку подключения службы. Если служба перенастроена для запуска под другой учетной записью, необходимо обновить ACE. Для успешного выполнения этот пример кода должен выполняться в контексте безопасности администратора домена.
Первый параметр примера функции указывает имя учетной записи пользователя, к которому будет предоставлен доступ. Функция предполагает, что имя имеет формат Домен**\**ИмяПользователя. Если учетная запись не указана, функция предполагает, что служба использует учетную запись LocalSystem. Это означает, что функция должна предоставить доступ к учетной записи компьютера сервера узла, на котором запущена служба. Для этого в примере кода вызывается функция GetComputerObjectName для получения домена и имени пользователя локального компьютера.
В следующем примере кода можно изменить, чтобы предоставить службе полный доступ к объекту SCP, но рекомендуется предоставить только определенные права доступа, необходимые службе во время выполнения. В этом случае функция предоставляет доступ к двум свойствам.
Собственность | Описание |
---|---|
serviceDNSName | Имя сервера узла, на котором выполняется служба. |
serviceBindingInformation | Информация о частной привязке, которую служба обновляет при запуске. |
Каждое свойство определяется schemaIDGUID класса attributeSchema свойства. Каждое свойство в схеме имеет уникальный schemaIDGUID. В следующем примере кода используются строки для указания идентификаторов GUID. Строки GUID имеют следующий формат, в котором каждая строка X заменяется шестнадцатеричной цифрой: {XXXXXXXXX-XXXXX-XXXXXXXXXXXXXX}.
Ознакомьтесь со страницами справки по схеме Active Directory для значений schemaIDGUID, назначенных свойствам для предоставления или запрета доступа.
В следующем примере кода используетсяIADsSecurityDescriptor, IADsAccessControlListи интерфейсы IADsAccessControlEntry для выполнения следующих операций.
- Получите дескриптор безопасности объекта SCP.
- Установите соответствующие ACE в списке управления доступом (DACL) дескриптора безопасности.
- Измените дескриптор безопасности объекта 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;
}