Win32 API 日本語リファレンス
ホームNetworking.ActiveDirectory › IADsAccessControlList

IADsAccessControlList

COMIDispatch (デュアル)
IDispatch を実装(デュアルインターフェース)。HSP では comobj 経由でメソッド名による遅延バインド呼び出しができます(vtableインデックス不要)。
IIDb7ee91cc-9bdd-11d0-852c-00c04fd8d503継承元IDispatch呼び出し名前(IDispatch) または vtbl自前メソッド開始 vtbl7

公式ドキュメント

IADsAccessControlList インターフェイスは、個々のアクセス制御エントリ (ACE) を管理するデュアルインターフェイスです。

解説(Remarks)

アクセス制御リスト (ACL) は ACE のコレクションであり、同じ ADSI オブジェクトに対してクライアントごとにより細かいアクセス制御を提供できます。一般に、プロバイダーが異なればアクセス制御の実装も異なるため、オブジェクトの動作はプロバイダーに固有のものになります。詳細については、各プロバイダーのドキュメントを参照してください。Microsoft のプロバイダーの詳細については、ADSI System Providers を参照してください。現在、アクセス制御をサポートしているのは LDAP プロバイダーのみです。

オブジェクトの ACE を操作する前に、まずそれらが属する ACL を取得します。ACL はセキュリティ記述子によって管理され、随意アクセス制御リスト (DACL) とシステムアクセス制御リスト (SACL) のいずれかになります。詳細については、 IADsSecurityDescriptor を参照してください。

IADsAccessControlList インターフェイスのプロパティとメソッドを使用すると、ACE の取得や列挙、リストへの新しいエントリの追加、既存のエントリの削除を行えます。

ADSI 上のアクセス制御を管理するには

  1. まず、IADsSecurityDescriptor インターフェイスを実装するオブジェクトのセキュリティ記述子を取得します。
  2. 次に、セキュリティ記述子から ACL を取得します。
  3. 最後に、ACL 内のオブジェクトの ACE を操作します。

新規または変更した ACE を永続化するには

  1. まず、ACE を ACL に追加します。
  2. 次に、ACL をセキュリティ記述子に割り当てます。
  3. 最後に、セキュリティ記述子をディレクトリストアにコミットします。
DACL の詳細については、Null DACLs and Empty DACLs を参照してください。

次のコード例は、随意 ACL のアクセス制御エントリを操作する方法を示しています。

Dim X As IADs
Dim Namespace As IADsOpenDSObject
Dim SecurityDescriptor As IADsSecurityDescriptor
Dim Dacl As IADsAccessControlList

On Error GoTo Cleanup
 
Set Namespace = GetObject("LDAP://")
Set X= Namespace.OpenDSObject("LDAP://DC=Fabrikam,DC=Com, vbNullString, vbNullString,  ADS_SECURE_AUTHENTICATION)
 
Set SecurityDescriptor = X.Get("ntSecurityDescriptor")
Debug.Print SecurityDescriptor.Owner
Debug.Print SecurityDescriptor.Group
 
Set Dacl = SecurityDescriptor.DiscretionaryAcl
Debug.Print Dacl.AceCount
 
For Each Obj In Dacl
   Debug.Print Obj.Trustee
   Debug.Print Obj.AccessMask
   Debug.Print Obj.AceFlags
   Debug.Print Obj.AceType
Next

Cleanup:
    If (Err.Number<>0) Then
        MsgBox("An error has occurred. " & Err.Number)
    End If
    Set X = Nothing
    Set Namespace = Nothing
    Set SecurityDescriptor = Nothing
    Set Dacl = Nothing

次のコード例は、DACL から ACE を列挙します。

IADs *pADs = NULL;
IDispatch *pDisp = NULL;
IADsSecurityDescriptor *pSD = NULL;
VARIANT var;
HRESULT hr = S_OK;
 
VariantInit(&var);

hr = ADsOpenObject(L"LDAP://OU=Sales, DC=Fabrikam,DC=com",NULL,NULL,
                   ADS_SECURE_AUTHENTICATION, IID_IADs,(void**)&pADs);
if(FAILED(hr)) {goto Cleanup;}

hr = pADs->Get(CComBSTR("ntSecurityDescriptor"), &var);
if(FAILED(hr)) {goto Cleanup;}

pDisp = V_DISPATCH(&var);

hr = pDisp->QueryInterface(IID_IADsSecurityDescriptor,(void**)&pSD);
if(FAILED(hr)) {goto Cleanup;}
pDisp->Release();


pSD->get_DiscretionaryAcl(&pDisp);

hr = pDisp->QueryInterface(IID_IADsAccessControlList,(void**)&pACL);
if(FAILED(hr)) {goto Cleanup;}

hr = DisplayAccessInfo(pSD);
if(FAILED(hr)) {goto Cleanup;}
VariantClear(&var);

Cleanup:
    if(pADs) pADs->Release();
    if(pDisp) pDisp->Release();
    if(pSD) pSD->Release();
    return hr;



HRESULT DisplayAccessInfo(IADsSecurityDescriptor *pSD)
{
    LPWSTR lpszFunction = L"DisplayAccessInfo";
    IDispatch *pDisp = NULL;
    IADsAccessControlList *pACL = NULL;
    IADsAccessControlEntry *pACE = NULL;
    IEnumVARIANT *pEnum = NULL;
    IUnknown *pUnk = NULL;
    HRESULT hr = S_OK;
    ULONG nFetch = 0;
    BSTR bstrValue = NULL;
    VARIANT var;
    LPWSTR lpszOutput = NULL;
    LPWSTR lpszMask = NULL;
    size_t nLength = 0;
    
    VariantInit(&var);
    
    hr = pSD->get_DiscretionaryAcl(&pDisp);
    if(FAILED(hr)){goto Cleanup;}
    hr = pDisp->QueryInterface(IID_IADsAccessControlList,(void**)&pACL);
    if(FAILED(hr)){goto Cleanup;}
    
    hr = pACL->get__NewEnum(&pUnk);
    if(FAILED(hr)){goto Cleanup;}
    
    hr = pUnk->QueryInterface(IID_IEnumVARIANT,(void**)&pEnum);
    
    if(FAILED(hr)){goto Cleanup;}
    hr = pEnum->Next(1,&var,&nFetch);
    
    while(hr == S_OK)
    {
        if(nFetch==1)
        {
            if(VT_DISPATCH != V_VT(&var))
            {
                goto Cleanup;
            }
            
            pDisp = V_DISPATCH(&var);
            hr = pDisp->QueryInterface(IID_IADsAccessControlEntry,(void**)&pACE);
            
            if(SUCCEEDED(hr))
            {
                lpszMask = L"Trustee: %s";
                hr = pACE->get_Trustee(&bstrValue);
                nLength = wcslen(lpszMask) + wcslen(bstrValue) + 1;
                lpszOutput = new WCHAR[nLength];
                swprintf_s(lpszOutput,lpszMask,bstrValue);
                printf(lpszOutput);
                delete [] lpszOutput;
                SysFreeString(bstrValue);
                
                pACE->Release();
                pACE = NULL;
                pDisp->Release();
                pDisp = NULL;
            }       
            
            VariantClear(&var);
        }       
        hr = pEnum->Next(1,&var,&nFetch);
    }
    
Cleanup:
    if(pDisp) pDisp->Release();
    if(pACL) pACL->Release();
    if(pACE) pACE->Release();
    if(pEnum) pEnum->Release();
    if(pUnk) pUnk->Release();
    if(szValue) SysFreeString(szValue);
    return hr;
}

メソッド 8

vtbl = vtable インデックス(0始まり)。IDispatch 実装のため HSP ではメソッド名でも呼べます(上記)。低レベルの index 呼び出し用に vtbl も掲載。0〜2 は IUnknown。

vtbl 7 HRESULT get_AclRevision(INT* retval)
retvalINT*outACLのリビジョン番号を受け取る出力先。INT*で返る。
vtbl 8 HRESULT put_AclRevision(INT lnAclRevision)
lnAclRevisionINTin設定するACLのリビジョン番号を指定する。
vtbl 9 HRESULT get_AceCount(INT* retval)
retvalINT*outACLに含まれるACEの数を受け取る出力先。INT*で返る。
vtbl 10 HRESULT put_AceCount(INT lnAceCount)
lnAceCountINTin設定するACEの数を指定する。
vtbl 11 HRESULT AddAce(IDispatch* pAccessControlEntry)

IADsAccessControlList::AddAce メソッドは、IADsAccessControlEntry オブジェクトを IADsAccessControlList オブジェクトに追加します。

pAccessControlEntryIDispatch*inoptional追加する IADsAccessControlEntry オブジェクトの IDispatch インターフェイスへのポインター。このパラメーターに NULL を指定することはできません。

戻り値

以下を含む標準の HRESULT 値を返します。

解説(Remarks)

アクセス制御エントリは、セキュリティ記述子のアクセス制御リスト内で次の順序で並んでいる必要があります。

このメソッドは ACE を ACL の先頭に追加するため、必ずしも正しい順序になるとは限りません。

次の Visual Basic のコード例は、IADsAccessControlList::AddAce メソッドを使用して 2 つの ACE を ACL に追加する方法を示しています。

Const ACL_REVISION_DS = &H4

Dim x as IADs
Dim sd as IADsSecurityDescriptor
Dim Ace1 As new IADsAccessControlEntry
Dim Ace2 As new IADsAccessControlEntry
Dim Dacl As new IADsAccessControlList
On Error GoTo Cleanup

Set x = GetObject("LDAP://OU=Sales,DC=Fabrikam,DC=com")
Set sd = x.Get("ntSecurityDescriptor")

' Add the ACEs to the Discretionary ACL.
 
Dacl.AclRevision = ACL_REVISION_DS 'DS ACL Revision
' Set up the first ACE.
Ace1.AccessMask = -1 'Full Permission (Allowed)
Ace1.AceType = ADS_ACETYPE_ACCESS_ALLOWED
Ace1.AceFlags = ADS_ACEFLAG_INHERIT_ACE
Ace1.Trustee = "myMachine\Administrator"
 
' Set up the 2nd ACE.
Ace2.AccessMask = -1 'Full Permission (Denied)
Ace2.AceType = ADS_ACETYPE_ACCESS_DENIED
Ace2.AceFlags = ADS_ACEFLAG_INHERIT_ACE
Ace2.Trustee = "aDomain\aUser"
 
' Add the ACEs to the Discretionary ACL.
Dacl.AddAce Ace1
Dacl.AddAce Ace2

'Commit the changes. 
sd.DiscretionaryAcl = Dacl
x.Put "ntSecurityDescriptor", Array(sd)
x.SetInfo

Cleanup:
    If (Err.Number<>0) Then
        MsgBox("An error has occurred. " & Err.Number)
    End If
    Set Ace1 = Nothing
    Set Ace2 = Nothing
    Set Dacl = Nothing
    Set x = Nothing
    Set sd = Nothing

次の C++ のコード例は、IADsAccessControlList::AddAce メソッドを使用して ACE を ACL に追加します。追加される ACE は、フル権限を持つアクセス許可 (allowed) のアクセス権を持ちます。

HRESULT addAceTo(IADsAccessControlList *pAcl)
{
    if(!pAcl) 
    {
        return E_FAIL;
    }

    HRESULT hr = pAcl->put_AclRevision(ACL_REVISION_DS);
    if(FAILED(hr)) 
    {
        return hr;
    }

    IADsAccessControlEntry *pAce = NULL; 
    pAce = createAce(-1,                    // Full permissions.
                     ADS_ACETYPE_ACCESS_ALLOWED,
                     ADS_ACEFLAG_INHERIT_ACE,
                     CComBSTR("aDomain\\aUser"));

    if(!pAce)
    {
        return E_FAIL;
    }

    IDispatch *pDisp;
    hr = pAce->QueryInterface(IID_IDispatch,(void**)&pDisp);
    if(FAILED(hr)) 
    {
        pAce->Release();
        return hr;
    }

    hr = pAcl->AddAce(pDisp);
    pDisp->Release();
    if(pAce) pAce->Release();
    if(FAILED(hr)) 
    {
        return hr;
    }

    printf("Ace has been added to ACL.\n");

    return hr;
}

////////////////////////////////////
// function to create an allowed ACE
////////////////////////////////////
IADsAccessControlEntry *createAce(
                   long mask,
                   long type, 
                   long flag,
                   BSTR trustee)
{
    HRESULT hr;
    IADsAccessControlEntry *pAce;
    hr = CoCreateInstance(CLSID_AccessControlEntry,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_IADsAccessControlEntry,
                          (void**)&pAce);
    if(FAILED(hr)) 
    {
        if(pAce) 
        {
            pAce->Release();
        }

        return NULL;
    }

    hr = pAce->put_AccessMask(mask); 
    hr = pAce->put_AceType(type);
    hr = pAce->put_AceFlags(flag);
    hr = pAce->put_Trustee(trustee); 

    return pAce;
}
vtbl 12 HRESULT RemoveAce(IDispatch* pAccessControlEntry)

アクセス制御リスト (ACL) からアクセス制御エントリ (ACE) を削除します。

pAccessControlEntryIDispatch*inoptionalACL から削除する ACE の IDispatch インターフェイスへのポインター。

戻り値

このメソッドは標準の戻り値を返します。

詳細については、ADSI Error Codes を参照してください。

vtbl 13 HRESULT CopyAccessList(IDispatch** ppAccessControlList)

IADsAccessControlList::CopyAccessList メソッドは、アクセス制御リスト (ACL) 内のすべてのアクセス制御エントリ (ACE) を呼び出し元のプロセス空間にコピーします。

ppAccessControlListIDispatch**out元のアクセスリストのコピーとなる ACL への IDispatch インターフェイスポインターのアドレス。戻り時にこのパラメーターが NULL の場合、ACL のコピーを作成できなかったことを示します。

戻り値

このメソッドは標準の戻り値を返します。

その他の戻り値の詳細については、ADSI Error Codes を参照してください。

解説(Remarks)

呼び出し元は、コピーされた ACE の IDispatch ポインターを介して Release を呼び出す必要があります。

次のコード例は、ある ADSI オブジェクトから別の ADSI オブジェクトへ ACL をコピーする方法を示しています。

Dim x As IADs
Dim sd As IADsSecurityDescriptor
Dim Dacl As IADsAccessControlList
Dim CopyDacl As IADsAccessControlList
 
' Get the ACL from one object.
Set x = GetObject("LDAP://OU=Sales, DC=activeD,DC=mydomain,DC=fabrikam,DC=com")
Set sd = x.Get("ntSecurityDescriptor")
Set Dacl = sd.DiscretionaryAcl
Set CopyDacl = Dacl.CopyAccessList()
 
' Copy the ACL to another object in the Directory.
Set x = GetObject("LDAP://OU=Sales, DC=Fabrikam,DC=com")
Set sd = x.Get("ntSecurityDescriptor")
sd.DiscretionaryAcl = CopyDacl
x.Put "ntSecurityDescriptor", Array(sd)
x.SetInfo

Cleanup:
    If (Err.Number<>0) Then
        MsgBox("An error has occurred. " & Err.Number)
    End If
    Set x = Nothing
    Set sd = Nothing
    Set Dacl = Nothing
    Set CopyDacl = Nothing

次のコード例は、ソースオブジェクトからターゲットオブジェクトへ ACL をコピーします。

HRESULT CopyACL(IADs *pSource, IADs *pTarget)
{
    IADsSecurityDescriptor *pSourceSD = NULL;
    IADsSecurityDescriptor *pTargetSD = NULL;    
    IDispatch *pDisp = NULL;
    
    HRESULT hr = S_OK;
    VARIANT varSource, varTarget;
    
    VariantInit(&varSource);
    VariantInit(&varTarget);

    if((pSource==NULL) || (pTarget==NULL))
    {
        return E_FAIL;
    }
    
    hr = pSource->Get(CComBSTR("ntSecurityDescriptor"), &varSource);
    if(FAILED(hr))
    {
        goto Cleanup;
    }
    
    hr = pTarget->Get(CComBSTR("ntSecurityDescriptor"), &varTarget);
    if(FAILED(hr))
    {
        goto Cleanup;
    }
    
    hr = V_DISPATCH(&varSource)->QueryInterface(IID_IADsSecurityDescriptor,
                    (void**)&pSourceSD);
    if(FAILED(hr))
    {
        goto Cleanup;
    }    

    hr = V_DISPATCH(&varTarget)->QueryInterface(IID_IADsSecurityDescriptor,
                    (void**)&pTargetSD);
    if(FAILED(hr))
    {
        goto Cleanup;
    }    
    
    hr = pSourceSD->get_DiscretionaryAcl(&pDisp);
    if(FAILED(hr))
    {
        goto Cleanup;
    }    

    hr = pTargetSD->put_DiscretionaryAcl(pDisp);
    if(FAILED(hr))
    {
        goto Cleanup;
    }    
    
    hr = pTarget->SetInfo();
        
Cleanup:
    VariantClear(&varSource);
    VariantClear(&varTarget);
    if(pSourceSD) 
    {
        pSourceSD->Release();
    }
    if(pTargetSD) 
    {
        pTargetSD->Release();
    }
    if(pDisp) 
    {
        pDisp->Release();
    }
    return hr;
}
vtbl 14 HRESULT get__NewEnum(IUnknown** retval)

IADsAccessControlList::get__NewEnum メソッドは、ACE を列挙するために ACL の列挙子オブジェクトを取得するのに使用します。

retvalIUnknown**outACL の列挙子オブジェクトの IEnumVARIANT インターフェイスを取得するために使用する IUnknown インターフェイスへのポインターへのポインター。

戻り値

このメソッドは、S_OKE_FAIL を含む標準の戻り値を返します。その他の戻り値の詳細については、ADSI Error Codes を参照してください。

解説(Remarks)

get__NewEnum にはアンダースコアが 2 つあることに注意してください。

次のコード例は、For Each ループの実行時に get__NewEnum メソッドを暗黙的に呼び出します。

Dim Dacl As IADsAccessControlList
Dim ace As IADsAccessControlEntry

On Error GoTo Cleanup

' Get DACL. Code omitted.

' Display the trustees for each of the ACEs
For Each ace In Dacl 
    Debug.Print ace.trustee
Next ace

Cleanup:
    If (Err.Number<>0) Then
        MsgBox("An error has occurred. " & Err.Number)
    End If
    Set Dacl = Nothing
    Set ace = Nothing

次のコード例は、IADsAccessControlList::get__NewEnum を使用して ACE を列挙する方法を示しています。

HRESULT ListTrustees(IADsAccessControlList *pACL)
{
    IEnumVARIANT *pEnum = NULL;
    LPUNKNOWN     pUnk = NULL;
    ULONG  lFetch = 0;
    BSTR    bstr = NULL;
    IADsAccessControlEntry *pACE = NULL;
    IDispatch *pDisp = NULL;
    VARIANT var;
    HRESULT hr = S_OK;
    
    VariantInit(&var);
     
    hr = pACL->get__NewEnum(&pUnk);
    if (FAILED(hr)){goto Cleanup;}
    
    hr = pUnk->QueryInterface( IID_IEnumVARIANT, (void**) &pEnum );
    pUnk->Release();
    if (FAILED(hr)){goto Cleanup;}
     
    hr = pEnum->Next( 1, &var, &lFetch );
    if (FAILED(hr)){goto Cleanup;}
     
    while( hr == S_OK )
    {
        if ( lFetch == 1 )
        {
            if ( VT_DISPATCH != V_VT(&var) )
            {
                goto Cleanup;
            }
            pDisp = V_DISPATCH(&var);
            /////////////////////////
            // Get the individual ACE
            /////////////////////////
            hr = pDisp->QueryInterface( IID_IADsAccessControlEntry,(void**)&pACE ); 
            if ( SUCCEEDED(hr) )
            {
                pACE->get_Trustee(&bstr);
                printf("\n %S:\n", bstr);
                //ACE manipulation here
                SysFreeString(bstr);
                pACE->Release();
            }
            pACE->Release();
            pDisp->Release();
            VariantClear(&var);
        }
        hr = pEnum->Next( 1, &var, &lFetch );
    }
    Cleanup:        
        if(pEnum) pEnum->Release();
        if(pUnk) pUnk->Release();
        if(bstr) SysFreeString(bstr);
        if(pACE) pACE->Release();
        VariantClear(&var);
        return hr;
}
出典・ライセンス: 上記「公式ドキュメント」の内容は Microsoft の Win32 API ドキュメント(MicrosoftDocs/sdk-api)を日本語に翻訳・改変したものです。© Microsoft Corporation. CC BY 4.0 で提供。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)

HSP用 COM定義

#usecom / #comfunc によるHSPのCOM呼び出し定義。数字は vtbl インデックス(0始まり)。クラスIDが無い場合 #usecom の末尾は "{}"、ある場合は "{CLSID}"

出力引数:
#define global IID_IADsAccessControlList "{B7EE91CC-9BDD-11D0-852C-00C04FD8D503}"
#usecom global IADsAccessControlList IID_IADsAccessControlList "{}"
#comfunc global IADsAccessControlList_get_AclRevision  7 var
#comfunc global IADsAccessControlList_put_AclRevision  8 int
#comfunc global IADsAccessControlList_get_AceCount     9 var
#comfunc global IADsAccessControlList_put_AceCount     10 int
#comfunc global IADsAccessControlList_AddAce           11 sptr
#comfunc global IADsAccessControlList_RemoveAce        12 sptr
#comfunc global IADsAccessControlList_CopyAccessList   13 sptr
#comfunc global IADsAccessControlList_get__NewEnum     14 sptr
; ※数字は vtbl インデックス(0始まり)。0/1/2 は IUnknown(QueryInterface/AddRef/Release)。
; ※このインターフェースは直接 CoCreateInstance するクラスIDが無いため "{}"(他メソッド/アクティベーションで取得)。
; ※出力/バッファ引数は var(変数直渡し)。varptr 方式にも切替可。
; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。
; ※IDispatch 実装。HSP では comobj 経由でメソッド名による呼び出しも可能(vtbl 不要)。