ユーザがパスワードを変更できない (LDAPプロバイダー) の変更
ユーザが自分のパスワードを変更できるかどうかは、許可または拒否できるアクセス許可です。 このアクセス許可を拒否するには、ADS_ACETYPE_ACCESS_DENIED_OBJECTエースタイプを使用して、ユーザオブジェクトのセキュリティ記述子随意アクセス制御リスト (DACL) に2つのACEを設定します。 1つのACEはユーザに対するアクセス許可を拒否し、もう1つのACEはEveryoneグループに対するアクセス許可を拒否します。 どちらのACEも、パスワードを変更するための拡張アクセス許可のGUIDを指定するオブジェクト固有の拒否ACEです。 このアクセス許可を付与するには、同じACEをADS_ACETYPE_ACCESS_ALLOWED_OBJECT エースタイプで設定します。
次の手順では、このアクセス許可のACEを変更または追加する方法について説明します。
このアクセス許可のACEを変更または追加するには
ユーザーオブジェクトにバインドします。
ユーザーオブジェクトのntSecurityDescriptorプロパティからIADsSecurityDescriptorオブジェクトを取得します。
IADsSecurityDescriptor.DiscretionaryAclからセキュリティ記述子のIADsAccessControlListインターフェイスを取得します。
オブジェクトの ACE を列挙し、IADsAccessControlEntry.ObjectType プロパティに対して変更パスワード GUID ({AB721A53-1E2F-11D0-9819-00AA0040529B}) を持つ ACE と、IADsAccessControlEntry.トラス プロパティの "Everyone" または "NT AUTHORITY\Standard Edition LF" を検索します
Note
"Everyone"と"NT AUTHORITY\SELF"の文字列は、ドメイン内の最初のドメインコントローラーの言語に基づいてローカライズされます。 このため、文字列を直接使用しないでください。 アカウント名は、実行時に"Everyone"("S-1-1-0")と"NT AUTHORITY\SELF"("S-1-5-10")の既知のセキュリティプリンシパルのSIDを指定してLookupAccountSid関数を呼び出すことによって取得する必要があります。 ユーザーがパスワードを変更できない (LDAPプロバイダー) の読み取り に示されているGetSidAccountName、GetSidAccountName_Everyone、およびGetSidAccountName_Self C++関数の例では、この方法を示しています。
見つかったACEのIADsAccessControlEntry.AceTypeプロパティを、ユーザーがパスワードを変更できない場合はADS_ACETYPE_ACCESS_DENIED_OBJECTに、ユーザーがパスワードを変更できる場合はADS_ACETYPE_ACCESS_ALLOWED_OBJECTに変更します。
"Everyone"ACEが見つからない場合は、次の表に示すプロパティ値を含む新しいIADsAccessControlEntryオブジェクトを作成し、IADsAccessControlList.AddAceを使用して新しいエントリをACLに追加します。AddAceメソッド。"。
NT AUTHORITY\SELF"ACEが見つからない場合は、次の表に示すのと同じプロパティ値を持つ新しいIIADsAccessControlEntryオブジェクトを作成します。ただし、TrusteeプロパティにはSID"S-1-5-10"("NT AUTHORITY\SELF")のアカウント名が含まれています。 IADsAccessControlList.AddAceメソッドでACLにエントリーを追加します。
オブジェクトのntSecurityDescriptorプロパティを更新するには、IADs.Putメソッドを、ステップ2で取得したのと同じIADsSecurityDescriptorで呼び出します。
IADs.SetInfoメソッドで、ローカルの変更をサーバーにコミットする。
Aceのいずれかが作成された場合は、Aceが正しい順序になるようにACLを並べ替える必要があります。 これを行うには、オブジェクトのLDAP ADsPathを使用してGetNamedSecurityInfo関数を呼び出し、同じDACLを使用してSetNamedSecurityInfo関数を呼び出します。 この並べ替えは、Aceが追加されると自動的に行われます。
次の表に、IADsAccessControlEntryオブジェクトプロパティの値を示します。
IADsAccessControlEntryプロパティ | Value |
---|---|
AccessMask | ADS_RIGHT_DS_CONTROL_ACCESS |
AceType | ユーザーがパスワードを変更できない場合はADS_ACETYPE_ACCESS_DENIED_OBJECT、ユーザーがパスワードを変更できる場合はADS_ACETYPE_ACCESS_ALLOWED_OBJECT。 |
AceFlags | 0 |
フラグ | ADS_FLAG_OBJECT_TYPE_PRESENT |
ObjectType | 文字列形式の変更パスワードGUIDである"{AB721A53-1E2F-11D0-9819-00AA0040529B}"。 |
InheritedObjectType | 非使用 |
トラスティ | SID"S-1-1-0" (すべてのユーザー) のアカウント名。 |
コード例
次のコード例は、DACLを変更するためのインターフェイスを取得する方法を示しています。 IADsObjectOptionsインターフェイスは、ADS_SECURITY_INFO_DACLオプションを設定することによって使用できます。
Note
この例に記載されているコードを使用するには、管理者である必要があります。 管理者でない場合は、クライアント側キャッシュをActive Directoryドメインサービスにフラッシュバックする方法をユーザーが変更できるようにするインターフェイスを使用するコードを追加する必要があります。
//
// Obtain an IADsObjectOptions interface from the object whose
// DACL you wish to modify.
//
long CanReadSetDACL = ADS_SECURITY_INFO_DACL;
CComPtr<IADsObjectOptions> spObjOps;
hr = pads->QueryInterface(IID_IADsObjectOptions, (void**)&spObjOps);
if(SUCCEEDED(hr))
{
//
// Set the option mask you want to change. In this case
// we want to change the objects security information, so we'll
// use the ADS_OPTION_SECURITY_MASK. Since we want to modify the
// DACL, we'll set the variant to ADS_SEDCURITY_INFO_DACL flag.
//
CComVariant svar;
svar = CanReadSetDACL;
hr = spObjOps->SetOption(ADS_OPTION_SECURITY_MASK, svar);
}
//
// The smart pointer declared for pObjOptions can be released
// or it will be destroyed and released once the pointer goes
// out of scope.
//
次のコード例は、LDAPプロバイダーを使用してユーザーがパスワードを変更できないアクセス許可を変更する方法を示しています。 このコード例では、上で定義したGetObjectACEユーティリティ関数を使用します。
この例では、ユーザーがパスワードを変更できない (LDAPプロバイダー) の読み取りに示されている GetSidAccountName_EveryoneおよびGetSidAccountName_Self C++サンプル関数を使用します。
#include <aclapi.h>
#define CHANGE_PASSWORD_GUID_W L"{AB721A53-1E2F-11D0-9819-00AA0040529B}"
/***************************************************************************
CreateACE()
Creates an ACE and returns the IDispatch pointer for the ACE. This
pointer can be passed directly to IADsAccessControlList::AddAce.
bstrTrustee - Contains the Trustee for the ACE.
bstrObjectType - Contains the ObjectType for the ACE.
lAccessMask - Contains the AccessMask for the ACE.
lACEType - Contains the ACEType for the ACE.
lACEFlags - Contains the ACEFlags for the ACE.
lFlags - Contains the Flags for the ACE.
***************************************************************************/
IDispatch* CreateACE(BSTR bstrTrustee,
BSTR bstrObjectType,
long lAccessMask,
long lACEType,
long lACEFlags,
long lFlags)
{
HRESULT hr;
IDispatch *pDisp = NULL;
IADsAccessControlEntry *pACE = NULL;
hr = CoCreateInstance(CLSID_AccessControlEntry,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsAccessControlEntry,
(void**)&pACE);
if(SUCCEEDED(hr))
{
hr = pACE->put_Trustee(bstrTrustee);
hr = pACE->put_ObjectType(bstrObjectType);
hr = pACE->put_AccessMask(lAccessMask);
hr = pACE->put_AceType(lACEType);
hr = pACE->put_AceFlags(lACEFlags);
hr = pACE->put_Flags(lFlags);
hr = pACE->QueryInterface(IID_IDispatch, (LPVOID*)&pDisp);
pACE->Release();
}
return pDisp;
}
/***************************************************************************
ReorderACEs()
Causes the ACEs of an object DACL to be reordered properly. The ACEs are
automatically put in the proper order when they are added to the DACL.
On older systems however, this does not occur automatically, so this
function is necessary so the deny ACEs are ordered in the list before
the allow ACEs.
pwszDN - A null-terminated Unicode string that contains the LDAP
ADsPath of the DS object to reorder the DACL for.
***************************************************************************/
HRESULT ReorderACEs(LPCWSTR pwszDN)
{
HRESULT hr = E_FAIL;
DWORD dwResult;
ACL *pdacl;
PSECURITY_DESCRIPTOR psd;
dwResult = GetNamedSecurityInfoW( (LPWSTR)pwszDN,
SE_DS_OBJECT_ALL,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
&pdacl,
NULL,
&psd);
if(ERROR_SUCCESS == dwResult)
{
dwResult = SetNamedSecurityInfoW( (LPWSTR)pwszDN,
SE_DS_OBJECT_ALL,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
pdacl,
NULL);
LocalFree(psd);
if(ERROR_SUCCESS == dwResult)
{
hr = S_OK;
}
}
return hr;
}
/***************************************************************************
SetUserCannotChangePassword()
Sets the "User Cannot Change Password" permission using the LDAP provider
to the specified setting. To do this, find the existing
ACEs and modify the AceType. If the ACE is not found, a new one of the
proper type is created and added. The ACEs should always be present, but
it is possible that the default DACL excludes them, so this situation
will be handled correctly.
pwszUserDN - A null-terminated Unicode string that contains the LDAP
ADsPath of the user object to modify.
pwszUsername - A null-terminated Unicode string that contains the user
name to use for authorization. If this is NULL, the credentials of the
current user are used.
pwszPassword - A null-terminated Unicode string that contains the
password to use for authorization. This is ignored if pwszUsername is
NULL.
fCannotChangePassword - Contains the new setting for the privilege.
Contains nonzero if the user cannot change their password or zero if
the can change their password.
***************************************************************************/
HRESULT SetUserCannotChangePassword(LPCWSTR pwszUserDN,
LPCWSTR pwszUsername,
LPCWSTR pwszPassword,
BOOL fCannotChangePassword)
{
HRESULT hr;
CComBSTR sbstrEveryone;
hr = GetSidAccountName_Everyone(&sbstrEveryone);
if(FAILED(hr))
{
return hr;
}
CComBSTR sbstrSelf;
hr = GetSidAccountName_Self(&sbstrSelf);
if(FAILED(hr))
{
return hr;
}
if(NULL == pwszUserDN)
{
return E_INVALIDARG;
}
IADs *pads;
hr = ADsOpenObject( pwszUserDN,
pwszUsername,
pwszPassword,
ADS_SECURE_AUTHENTICATION,
IID_IADs,
(LPVOID*)&pads);
if(SUCCEEDED(hr))
{
CComBSTR sbstrSecDesc = "ntSecurityDescriptor";
CComVariant svar;
hr = pads->Get(sbstrSecDesc, &svar);
if(SUCCEEDED(hr))
{
IADsSecurityDescriptor *psd;
hr = svar.pdispVal->QueryInterface(IID_IADsSecurityDescriptor, (LPVOID*)&psd);
if(SUCCEEDED(hr))
{
IDispatch *pDisp;
hr = psd->get_DiscretionaryAcl(&pDisp);
if(SUCCEEDED(hr))
{
IADsAccessControlList *pACL;
hr = pDisp->QueryInterface(IID_IADsAccessControlList, (void**)&pACL);
if(SUCCEEDED(hr))
{
BOOL fMustReorder = FALSE;
/*
Get the existing ACE for the change password permission
for Everyone. If it exists, just modify the existing
ACE. If it does not exist, create a new one and add it
to the ACL.
*/
IADsAccessControlEntry *pACEEveryone = NULL;
hr = GetObjectACE(pACL, CHANGE_PASSWORD_GUID_W, sbstrEveryone, &pACEEveryone);
if(pACEEveryone)
{
hr = pACEEveryone->put_AceType(fCannotChangePassword ?
ADS_ACETYPE_ACCESS_DENIED_OBJECT :
ADS_ACETYPE_ACCESS_ALLOWED_OBJECT);
pACEEveryone->Release();
}
else
{
IDispatch *pDispEveryone = NULL;
pDispEveryone = CreateACE(sbstrEveryone,
CComBSTR(CHANGE_PASSWORD_GUID_W),
ADS_RIGHT_DS_CONTROL_ACCESS,
fCannotChangePassword ?
ADS_ACETYPE_ACCESS_DENIED_OBJECT :
ADS_ACETYPE_ACCESS_ALLOWED_OBJECT,
0,
ADS_FLAG_OBJECT_TYPE_PRESENT);
if(pDispEveryone)
{
//add the new ACE for everyone
hr = pACL->AddAce(pDispEveryone);
pDispEveryone->Release();
fMustReorder = TRUE;
}
}
/*
Get the existing ACE for the change password permission
for Self. If it exists, just modify the existing
ACE. If it does not exist, create a new one and add it
to the ACL.
*/
IADsAccessControlEntry *pACESelf = NULL;
hr = GetObjectACE(pACL, CHANGE_PASSWORD_GUID_W, sbstrSelf, &pACESelf);
if(pACESelf)
{
hr = pACESelf->put_AceType(fCannotChangePassword ?
ADS_ACETYPE_ACCESS_DENIED_OBJECT :
ADS_ACETYPE_ACCESS_ALLOWED_OBJECT);
pACESelf->Release();
}
else
{
IDispatch *pDispSelf = NULL;
pDispSelf = CreateACE(sbstrSelf,
CComBSTR(CHANGE_PASSWORD_GUID_W),
ADS_RIGHT_DS_CONTROL_ACCESS,
fCannotChangePassword ?
ADS_ACETYPE_ACCESS_DENIED_OBJECT :
ADS_ACETYPE_ACCESS_ALLOWED_OBJECT,
0,
ADS_FLAG_OBJECT_TYPE_PRESENT);
if(pDispSelf)
{
//add the new ACE for self
hr = pACL->AddAce(pDispSelf);
pDispSelf->Release();
fMustReorder = TRUE;
}
}
//update the security descriptor property
hr = pads->Put(sbstrSecDesc, svar);
//commit the changes
hr = pads->SetInfo();
if(fMustReorder)
{
ReorderACEs(pwszUserDN);
}
pACL->Release();
}
pDisp->Release();
}
psd->Release();
}
}
}
return hr;
}
次のコード例は、LDAPプロバイダーを使用してユーザーがパスワードを変更できないアクセス許可を変更する方法を示しています。
Note
次の例は、"Everyone"と"NT AUTHORITY\SELF"の文字列がドメイン内の最初のドメインコントローラーの言語に基づいてローカライズされるため、プライマリ言語が英語であるドメインでのみ機能します。 Visual Basicでは、LookupAccountSid関数を呼び出さずに、既知のセキュリティプリンシパルのアカウント名を取得する方法はありません。 Visual Basicを使用する場合は、WinNTプロバイダーを使用して、 ユーザーがパスワードを変更できないようにする (WinNTプロバイダー) に示すように、ユーザーがパスワードを変更できないアクセス許可を変更することをお勧めします。
'******************************************************************************
'
' SetUserCannotChangePassword
'
' Sets the "User Cannot Change Password" permission using the LDAP provider
' to the specified setting. This is accomplished by finding the existing
' ACEs and modifying the AceType. The ACEs should always be present, but
' it is possible that the default DACL excludes them. This function will not
' work correctly if both ACEs are not present.
'
' strUserDN - A string that contains the LDAP ADsPath of the user object to
' modify.
'
' strUsername - A string that contains the user name to use for
' authorization. If this is an empty string, the credentials of the current
' user are used.
'
' strPassword - A string that contains the password to use for authorization.
' This is ignored if strUsername is empty.
'
' fCannotChangePassword - Contains the new setting for the privilege.
' Contains True if the user cannot change their password or False if
' the can change their password.
'
'******************************************************************************
Sub SetUserCannotChangePassword(strUserDN As String, strUsername As String, strPassword As String, fUserCannotChangePassword As Boolean)
Dim oUser As IADs
Dim oSecDesc As IADsSecurityDescriptor
Dim oACL As IADsAccessControlList
Dim oACE As IADsAccessControlEntry
fEveryone = False
fSelf = False
If "" <> strUsername Then
Dim dso As IADsOpenDSObject
' Bind to the group with the specified user name and password.
Set dso = GetObject("LDAP:")
Set oUser = dso.OpenDSObject(strUserDN, strUsername, strPassword, 1)
Else
' Bind to the group with the current credentials.
Set oUser = GetObject(strUserDN)
End If
Set oSecDesc = oUser.Get("ntSecurityDescriptor")
Set oACL = oSecDesc.DiscretionaryAcl
' Modify the existing entries.
For Each oACE In oACL
If UCase(oACE.ObjectType) = UCase(CHANGE_PASSWORD_GUID) Then
If oACE.Trustee = "Everyone" Then
' Modify the ace type of the entry.
If fUserCannotChangePassword Then
oACE.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT
Else
oACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
End If
End If
If oACE.Trustee = "NT AUTHORITY\SELF" Then
' Modify the ace type of the entry.
If fUserCannotChangePassword Then
oACE.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT
Else
oACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
End If
End If
End If
Next
' Update the ntSecurityDescriptor property.
oUser.Put "ntSecurityDescriptor", oSecDesc
' Commit the changes to the server.
oUser.SetInfo
End Sub