Mengubah Pengguna Tidak Dapat Mengubah Kata Sandi (Penyedia LDAP)
Kemampuan pengguna untuk mengubah kata sandi mereka sendiri adalah izin yang dapat diberikan atau ditolak. Untuk menolak izin ini, atur dua ACE dalam daftar kontrol akses diskresi deskriptor keamanan (DACL) objek pengguna dengan jenis as ADS_ACETYPE_ACCESS_DENIED_OBJECT . Satu ACE menolak izin kepada pengguna dan ACE lainnya menolak izin ke grup Semua Orang. Kedua ACE adalah ACE penolakan khusus objek yang menentukan GUID izin yang diperluas untuk mengubah kata sandi. Untuk memberikan izin ini, atur ACE yang sama dengan jenis as ADS_ACETYPE_ACCESS_ALLOWED_OBJECT .
Prosedur berikut menjelaskan cara mengubah atau menambahkan ACE untuk izin ini.
Untuk mengubah atau menambahkan ACE untuk izin ini
Ikat ke objek pengguna.
Dapatkan objek IADsSecurityDescriptor dari properti ntSecurityDescriptor objek pengguna.
Dapatkan antarmuka IADsAccessControlList untuk deskriptor keamanan dari properti IADsSecurityDescriptor.DiscretionaryAcl.
Menghitung ACE untuk objek dan mencari ACE yang memiliki GUID kata sandi perubahan ({AB721A53-1E2F-11D0-9819-00AA0040529B}) untuk properti IADsAccessControlEntry.ObjectType dan "Everyone" atau "NT AUTHORITY\SELF" untuk properti IADsAccessControlEntry.Trustee.
Catatan
String "Everyone" dan "NT AUTHORITY\SELF" dilokalkan berdasarkan bahasa pengontrol domain pertama di domain. Karena itu, string tidak boleh digunakan secara langsung. Nama akun harus diperoleh pada waktu proses dengan memanggil fungsi LookupAccountSid dengan SID untuk "Everyone" ("S-1-1-0") dan "NT AUTHORITY\SELF" ("S-1-5-10") prinsip keamanan terkenal. Fungsi contoh GetSidAccountName, GetSidAccountName_Everyone, dan GetSidAccountName_Self C++ yang ditunjukkan dalam Membaca Pengguna Tidak Dapat Mengubah Kata Sandi (Penyedia LDAP) menunjukkan cara melakukan ini.
Ubah properti IADsAccessControlEntry.AceType dari ACE yang ditemukan ADS_ACETYPE_ACCESS_DENIED_OBJECT jika pengguna tidak dapat mengubah kata sandi atau ADS_ACETYPE_ACCESS_ALLOWED_OBJECT jika pengguna dapat mengubah kata sandi mereka.
Jika ACE "Semua Orang" tidak ditemukan, buat objek IADsAccessControlEntry baru yang berisi nilai properti yang ditampilkan dalam tabel di bawah ini dan tambahkan entri baru ke ACL dengan metode IADsAccessControlList.AddAce.
Jika ACE "NT AUTHORITY\SELF" tidak ditemukan, buat objek IADsAccessControlEntry baru dengan nilai properti yang sama yang ditunjukkan dalam tabel di bawah ini kecuali properti Trustee berisi nama akun untuk SID "S-1-5-10" ("NT AUTHORITY\SELF"). Tambahkan entri ke ACL dengan metode IADsAccessControlList.AddAce.
Untuk memperbarui properti ntSecurityDescriptor objek, panggil metode IADs.Put dengan IADsSecurityDescriptor yang sama yang diperoleh di Langkah 2.
Terapkan perubahan lokal ke server dengan metode IADs.SetInfo.
Jika salah satu ACE dibuat, Anda harus menyusun ulang ACL sehingga ACL berada dalam urutan yang benar. Untuk melakukan ini, panggil fungsi GetNamedSecurityInfo dengan LDAP ADsPath objek dan kemudian fungsi SetNamedSecurityInfo dengan DACL yang sama. Pengubahan ulang ini akan terjadi secara otomatis ketika ACE ditambahkan.
Tabel berikut mencantumkan nilai properti objek IADsAccessControlEntry .
Properti IADsAccessControlEntry | Value |
---|---|
AccessMask | ADS_RIGHT_DS_CONTROL_ACCESS |
AceType | ADS_ACETYPE_ACCESS_DENIED_OBJECT jika pengguna tidak dapat mengubah kata sandi atau ADS_ACETYPE_ACCESS_ALLOWED_OBJECT jika pengguna dapat mengubah kata sandi mereka. |
AceFlags | 0 |
Bendera | ADS_FLAG_OBJECT_TYPE_PRESENT |
ObjectType | "{AB721A53-1E2F-11D0-9819-00AA0040529B}" yang merupakan GUID kata sandi perubahan dalam bentuk string. |
InheritedObjectType | Tidak digunakan |
Wali | Nama akun untuk SID "S-1-1-0" (Semua Orang). |
Contoh Kode
Contoh kode berikut menunjukkan cara mendapatkan antarmuka untuk mengubah DACL. Antarmuka IADsObjectOptions dapat digunakan dengan mengatur opsi ADS_SECURITY_INFO_DACL .
Catatan
Untuk menggunakan kode yang didokumenkan dalam contoh ini, Anda harus menjadi Administrator. Jika Anda bukan Administrator, maka Anda harus menambahkan lebih banyak kode yang akan menggunakan antarmuka yang akan memungkinkan pengguna untuk mengubah cara cache sisi klien dihapus kembali ke Layanan Domain Direktori Aktif.
//
// 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.
//
Contoh kode berikut menunjukkan cara mengubah Izin Pengguna Tidak Dapat Mengubah Kata Sandi menggunakan penyedia LDAP. Contoh kode ini menggunakan fungsi utilitas GetObjectACE yang ditentukan di atas.
Contoh ini menggunakan fungsi contoh GetSidAccountName_Everyone dan GetSidAccountName_Self C++ yang ditunjukkan dalam Membaca Pengguna Tidak Dapat Mengubah Kata Sandi (Penyedia LDAP).
#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;
}
Contoh kode berikut menunjukkan cara mengubah Izin Pengguna Tidak Dapat Mengubah Kata Sandi menggunakan penyedia LDAP.
Catatan
Contoh di bawah ini hanya akan berfungsi pada domain di mana bahasa utamanya adalah bahasa Inggris karena string "Everyone" dan "NT AUTHORITY\SELF" dilokalkan berdasarkan bahasa pengontrol domain pertama di domain. Tidak ada cara di Visual Basic untuk mendapatkan nama akun untuk perwakilan keamanan terkenal tanpa memanggil fungsi LookupAccountSid. Jika menggunakan Visual Basic, disarankan agar Anda menggunakan penyedia WinNT untuk mengubah Izin Pengguna Tidak Dapat Mengubah Kata Sandi seperti yang ditunjukkan dalam Mengubah Pengguna Tidak Dapat Mengubah Kata Sandi (Penyedia 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