Ändern des Benutzers kann das Kennwort nicht ändern (LDAP-Anbieter)
Die Möglichkeit eines Benutzers, sein eigenes Kennwort zu ändern, ist eine Berechtigung, die erteilt oder verweigert werden kann. Um diese Berechtigung zu verweigern, legen Sie zwei ACEs in der sicherheitsdeskriptor discretionary access control list (DACL) des Benutzerobjekts mit dem ADS_ACETYPE_ACCESS_DENIED_OBJECT ace-Typ fest. Ein ACE verweigert dem Benutzer die Berechtigung, und ein anderer ACE verweigert der Gruppe "Jeder" die Berechtigung. Beide ACEs sind objektspezifische Deny-ACEs, die die GUID der erweiterten Berechtigung zum Ändern von Kennwörtern angeben. Um diese Berechtigung zu erteilen, legen Sie dieselben ACEs mit dem ADS_ACETYPE_ACCESS_ALLOWED_OBJECT ace-Typ fest.
Im folgenden Verfahren wird beschrieben, wie Sie ACEs für diese Berechtigung ändern oder hinzufügen.
So ändern oder fügen Sie die ACEs für diese Berechtigung hinzu
Binden Sie an das Benutzerobjekt.
Rufen Sie das IADsSecurityDescriptor-Objekt aus der ntSecurityDescriptor-Eigenschaft des Benutzerobjekts ab.
Rufen Sie eine IADsAccessControlList-Schnittstelle für den Sicherheitsdeskriptor aus der IADsSecurityDescriptor.DiscretionaryAcl-Eigenschaft ab.
Aufzählen Sie die ACEs für das -Objekt, und suchen Sie nach den ACEs mit dem Änderungskennwort GUID ({AB721A53-1E2F-11D0-9819-00AA0040529B}) für die IADsAccessControlEntry.ObjectType-Eigenschaft und "Everyone" oder "NT AUTHORITY\SELF" für die IADsAccessControlEntry.Trustee-Eigenschaft .
Hinweis
Die Zeichenfolgen "Jeder" und "NT AUTHORITY\SELF" werden basierend auf der Sprache des ersten Domänencontrollers in der Domäne lokalisiert. Aus diesem Fall sollten die Zeichenfolgen nicht direkt verwendet werden. Die Kontonamen sollten zur Laufzeit abgerufen werden, indem sie die LookupAccountSid-Funktion mit den bekannten Sicherheitsprinzipalen "Jeder" ("S-1-1-0") und "NT AUTHORITY\SELF" ("S-1-5-10") aufrufen. Die Beispielfunktionen GetSidAccountName, GetSidAccountName_Everyone und GetSidAccountName_Self C++-Beispielfunktionen in Reading User Cannot Change Password (LDAP-Anbieter) veranschaulichen dies.
Ändern Sie die IADsAccessControlEntry.AceType-Eigenschaft der ACEs, die als ADS_ACETYPE_ACCESS_DENIED_OBJECT erkannt wurden, wenn der Benutzer sein Kennwort nicht ändern kann oder ADS_ACETYPE_ACCESS_ALLOWED_OBJECT , wenn der Benutzer sein Kennwort ändern kann.
Wenn der ACE "Jeder" nicht gefunden wird, erstellen Sie ein neues IADsAccessControlEntry-Objekt , das die in der folgenden Tabelle angezeigten Eigenschaftenwerte enthält, und fügen Sie den neuen Eintrag mit der IADsAccessControlList.AddAce-Methode zur ACL hinzu.
Wenn das ACE "NT AUTHORITY\SELF" nicht gefunden wird, erstellen Sie ein neues IADsAccessControlEntry-Objekt mit den gleichen Eigenschaftenwerten, die in der folgenden Tabelle angezeigt werden, außer die Trustee-Eigenschaft enthält den Kontonamen für sid "S-1-5-10" ("NT AUTHORITY\SELF"). Fügen Sie den Eintrag mit der IADsAccessControlList.AddAce-Methode zur ACL hinzu.
Um die ntSecurityDescriptor-Eigenschaft des -Objekts zu aktualisieren, rufen Sie die IADs.Put-Methode mit demselben IADsSecurityDescriptor auf, der in Schritt 2 abgerufen wurde.
Committen Sie die lokalen Änderungen auf dem Server mit der IADs.SetInfo-Methode .
Wenn eines der ACEs erstellt wurde, müssen Sie die ACL neu anordnen, damit sich die ACEs in der richtigen Reihenfolge befinden. Rufen Sie hierzu die GetNamedSecurityInfo-Funktion mit dem LDAP-ADsPath des Objekts und dann die SetNamedSecurityInfo-Funktion mit derselben DACL auf. Diese Neuanordnung erfolgt automatisch, wenn die ACEs hinzugefügt werden.
In der folgenden Tabelle sind die Eigenschaftenwerte des IADsAccessControlEntry-Objekts aufgeführt.
IADsAccessControlEntry-Eigenschaft | Wert |
---|---|
Accessmask | ADS_RIGHT_DS_CONTROL_ACCESS |
AceType | ADS_ACETYPE_ACCESS_DENIED_OBJECT , wenn der Benutzer sein Kennwort nicht ändern kann oder ADS_ACETYPE_ACCESS_ALLOWED_OBJECT , wenn der Benutzer sein Kennwort ändern kann. |
AceFlags | 0 |
Flaggen | ADS_FLAG_OBJECT_TYPE_PRESENT |
Objecttype | "{AB721A53-1E2F-11D0-9819-00AA0040529B}" ist die Änderungskennwort-GUID in Zeichenfolgenform. |
Inheritedobjecttype | Nicht verwendet |
Treuhänder | Kontoname für SID "S-1-1-0" (Jeder). |
Beispielcode
Das folgende Codebeispiel zeigt, wie Sie eine Schnittstelle abrufen, um eine DACL zu ändern. Die IADsObjectOptions-Schnittstelle kann verwendet werden, indem Sie die Option ADS_SECURITY_INFO_DACL festlegen.
Hinweis
Um den in diesem Beispiel dokumentierten Code zu verwenden, müssen Sie Administrator sein. Wenn Sie kein Administrator sind, müssen Sie weiteren Code hinzufügen, der eine Schnittstelle verwendet, die es einem Benutzer ermöglicht, die Art und Weise zu ändern, in der der clientseitige Cache zum Active Directory-Domäne-Dienst geleert wird.
//
// 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.
//
Im folgenden Codebeispiel wird gezeigt, wie sie die Berechtigung Benutzer kann kennwort kann nicht ändern mithilfe des LDAP-Anbieters geändert werden. In diesem Codebeispiel wird die oben definierte Hilfsprogrammfunktion GetObjectACE verwendet.
In diesem Beispiel werden die GetSidAccountName_Everyone - und GetSidAccountName_Self C++-Beispielfunktionen verwendet, die in Reading User Cannot Change Password (LDAP-Anbieter) angezeigt werden.
#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;
}
Im folgenden Codebeispiel wird gezeigt, wie sie die Berechtigung Benutzer kann kennwort kann nicht ändern mithilfe des LDAP-Anbieters geändert werden.
Hinweis
Das folgende Beispiel funktioniert nur für Domänen, in denen die primäre Sprache Englisch ist, da die Zeichenfolgen "Jeder" und "NT AUTHORITY\SELF" basierend auf der Sprache des ersten Domänencontrollers in der Domäne lokalisiert werden. In Visual Basic gibt es keine Möglichkeit, die Kontonamen für einen bekannten Sicherheitsprinzipal abzurufen, ohne die LookupAccountSid-Funktion aufzurufen. Wenn Sie Visual Basic verwenden, wird empfohlen, den WinNT-Anbieter zu verwenden, um die Berechtigung "Benutzer kann Kennwort nicht ändern" zu ändern, wie unter Ändern des Benutzers kann kennwort kann nicht geändert werden (WinNT-Anbieter) gezeigt.
'******************************************************************************
'
' 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