다음을 통해 공유


서비스 계정에서 SCP 속성에 액세스할 수 있도록 설정

다음 코드 예제에서는 SCP(서비스 연결 지점) 개체에 API(Access Control Entries) 쌍을 설정합니다. ACE는 서비스 인스턴스가 실행될 사용자 또는 컴퓨터 계정에 대한 읽기/쓰기 권한을 부여합니다. 서비스 설치 관리자는 다음과 유사한 코드를 사용하여 서비스가 런타임에 해당 속성을 업데이트할 수 있는지 확인합니다. 이와 유사한 ACE가 설정되지 않은 경우 서비스는 SCP의 속성에 액세스할 수 없습니다.

일반적으로 서비스 설치 관리자는 SCP 개체를 만든 후 이러한 ACE를 설정합니다. 자세한 내용 및 SCP를 만들고 이 함수를 호출하는 코드 예제는 클라이언트가 서비스 커넥트Ion Point를 찾고 사용하는 방법을 참조하세요. 서비스가 다른 계정으로 실행되도록 다시 구성된 경우 ACE를 업데이트해야 합니다. 성공적으로 실행하려면 이 코드 예제를 do기본 관리자의 보안 컨텍스트에서 실행해야 합니다.

샘플 함수의 첫 번째 매개 변수는 액세스 권한을 부여할 사용자 계정의 이름을 지정합니다. 함수는 이름이 Do기본**\**UserName 형식이라고 가정합니다. 계정이 지정되지 않은 경우 함수는 서비스에서 LocalSystem 계정을 사용한다고 가정합니다. 즉, 함수는 서비스가 실행 중인 호스트 서버의 컴퓨터 계정에 대한 액세스 권한을 부여해야 합니다. 이를 위해 코드 예제에서는 GetComputerObjectName 함수를 호출하여 로컬 컴퓨터의 do기본 및 사용자 이름을 가져옵니다.

다음 코드 예제는 서비스에 SCP 개체에 대한 모든 액세스 권한을 부여하도록 수정할 수 있지만 런타임에 서비스에 필요한 특정 액세스 권한만 부여하는 것이 가장 좋습니다. 이 경우 함수는 두 속성에 대한 액세스 권한을 부여합니다.

속성 설명
serviceDNSName 서비스가 실행 중인 호스트 서버의 이름입니다.
serviceBindingInformation 서비스가 시작될 때 업데이트하는 프라이빗 바인딩 정보입니다.

 

각 속성은 속성의 attributeSchema 클래스의 schemaIDGUID로 식별됩니다. 스키마의 모든 속성에는 고유한 schemaIDGUID가 있습니다. 다음 코드 예제에서는 문자열을 사용하여 GUID를 지정합니다. GUID 문자열에는 각 "X"가 16진수로 대체되는 형식이 있습니다. {XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXX}.

액세스 권한을 부여하거나 거부할 속성에 할당된 schemaIDGUID 값에 대한 Active Directory 스키마 참조 페이지를 참조하세요.

다음 코드 예제에서는 IADsSecurityDescriptor, IADsAccessControlListIADsAccessControlEntry 인터페이스를 사용하여 다음 작업을 수행합니다.

  1. SCP 개체의 보안 설명자를 가져옵니다.
  2. 보안 설명자의 DACL(임의 액세스 제어 목록)에서 적절한 ACE를 설정합니다.
  3. 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;
}