IADsAccessControlList
COMIDispatch (デュアル)comobj 経由でメソッド名による遅延バインド呼び出しができます(vtableインデックス不要)。公式ドキュメント
IADsAccessControlList インターフェイスは、個々のアクセス制御エントリ (ACE) を管理するデュアルインターフェイスです。
解説(Remarks)
アクセス制御リスト (ACL) は ACE のコレクションであり、同じ ADSI オブジェクトに対してクライアントごとにより細かいアクセス制御を提供できます。一般に、プロバイダーが異なればアクセス制御の実装も異なるため、オブジェクトの動作はプロバイダーに固有のものになります。詳細については、各プロバイダーのドキュメントを参照してください。Microsoft のプロバイダーの詳細については、ADSI System Providers を参照してください。現在、アクセス制御をサポートしているのは LDAP プロバイダーのみです。
オブジェクトの ACE を操作する前に、まずそれらが属する ACL を取得します。ACL はセキュリティ記述子によって管理され、随意アクセス制御リスト (DACL) とシステムアクセス制御リスト (SACL) のいずれかになります。詳細については、 IADsSecurityDescriptor を参照してください。
IADsAccessControlList インターフェイスのプロパティとメソッドを使用すると、ACE の取得や列挙、リストへの新しいエントリの追加、既存のエントリの削除を行えます。
ADSI 上のアクセス制御を管理するには
- まず、IADsSecurityDescriptor インターフェイスを実装するオブジェクトのセキュリティ記述子を取得します。
- 次に、セキュリティ記述子から ACL を取得します。
- 最後に、ACL 内のオブジェクトの ACE を操作します。
新規または変更した ACE を永続化するには
- まず、ACE を ACL に追加します。
- 次に、ACL をセキュリティ記述子に割り当てます。
- 最後に、セキュリティ記述子をディレクトリストアにコミットします。
例
次のコード例は、随意 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。
| retval | INT* | out | ACLのリビジョン番号を受け取る出力先。INT*で返る。 |
| lnAclRevision | INT | in | 設定するACLのリビジョン番号を指定する。 |
| retval | INT* | out | ACLに含まれるACEの数を受け取る出力先。INT*で返る。 |
| lnAceCount | INT | in | 設定するACEの数を指定する。 |
IADsAccessControlList::AddAce メソッドは、IADsAccessControlEntry オブジェクトを IADsAccessControlList オブジェクトに追加します。
| pAccessControlEntry | IDispatch* | inoptional | 追加する IADsAccessControlEntry オブジェクトの IDispatch インターフェイスへのポインター。このパラメーターに NULL を指定することはできません。 |
戻り値
以下を含む標準の HRESULT 値を返します。
解説(Remarks)
アクセス制御エントリは、セキュリティ記述子のアクセス制御リスト内で次の順序で並んでいる必要があります。
- オブジェクト自体に適用されるアクセス拒否 ACE
- プロパティセットやプロパティなど、オブジェクトの子に適用されるアクセス拒否 ACE
- オブジェクト自体に適用されるアクセス許可 ACE
- プロパティセットやプロパティなど、オブジェクトの子に適用されるアクセス許可 ACE
- すべての継承された ACE
例
次の 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;
}
アクセス制御リスト (ACL) からアクセス制御エントリ (ACE) を削除します。
| pAccessControlEntry | IDispatch* | inoptional | ACL から削除する ACE の IDispatch インターフェイスへのポインター。 |
戻り値
このメソッドは標準の戻り値を返します。
詳細については、ADSI Error Codes を参照してください。
IADsAccessControlList::CopyAccessList メソッドは、アクセス制御リスト (ACL) 内のすべてのアクセス制御エントリ (ACE) を呼び出し元のプロセス空間にコピーします。
| ppAccessControlList | IDispatch** | 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;
}
IADsAccessControlList::get__NewEnum メソッドは、ACE を列挙するために ACL の列挙子オブジェクトを取得するのに使用します。
| retval | IUnknown** | out | ACL の列挙子オブジェクトの IEnumVARIANT インターフェイスを取得するために使用する IUnknown インターフェイスへのポインターへのポインター。 |
戻り値
このメソッドは、S_OK や E_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 公式リファレンス: 英語 (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 不要)。#define global IID_IADsAccessControlList "{B7EE91CC-9BDD-11D0-852C-00C04FD8D503}" #usecom global IADsAccessControlList IID_IADsAccessControlList "{}" #comfunc global IADsAccessControlList_get_AclRevision 7 sptr #comfunc global IADsAccessControlList_put_AclRevision 8 int #comfunc global IADsAccessControlList_get_AceCount 9 sptr #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が無いため "{}"(他メソッド/アクティベーションで取得)。 ; ※出力/バッファ引数はポインタ方式(token=sptr / 呼び出しは varptr(変数))。 ; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。 ; ※IDispatch 実装。HSP では comobj 経由でメソッド名による呼び出しも可能(vtbl 不要)。