修改物件類別的 defaultSecurityDescriptor
下列程式代碼範例會擷取物件類別的預設安全性描述元、將 ACE 加入 DACL,然後在物件類別上設定修改的安全性描述元。
請注意,根據預設,所有 Windows 2000 域控制器上的架構修改都會停用。 若要在特定 DC 啟用架構修改,請在下列登錄機碼下設定名為 “Schema Update Allowed” 的 REG_DWORD 值:
\HKEY_LOCAL_MACHINE系統\CurrentControlSet\Services\NTDS 參數\
如果尚未存在,請新增此值。 將此值設定為 1,以啟用架構修改。 如果此值為零,則會停用架構修改。 架構管理員 MMC 嵌入式管理單元提供複選框,可選取或清除此登錄機碼。
// Add msvcrt.dll to your project
// Add activeds.lib to your project
// Add adsiid.lib to your project
#include "stdafx.h"
#include <wchar.h>
#include <objbase.h>
#include <activeds.h>
#include <ACLAPI.h>
#include <winnt.h>
#include <Sddl.h>
#include "atlbase.h"
#include "stdio.h"
#include "iads.h"
#define _WIN32_WINNT 0x0500
HRESULT ModifyDefaultSecurityDescriptor( IADs *pObject );
// Entry point for the application.
int main(int argc, char *argv[])
{
LPOLESTR szPath = new OLECHAR[MAX_PATH];
LPOLESTR pszBuffer = new WCHAR[MAX_PATH];
HRESULT hr = S_OK;
IADs *pObject = NULL;
VARIANT var;
wprintf(L"This program modifies the default security descriptor of an object class\n");
wprintf(L"Specify the object class:");
#ifdef _MBCS
_getws_s(pszBuffer);
if (!pszBuffer)
return TRUE;
wcscpy_s(szPath,L"LDAP://cn=");
wcscat_s(szPath,pszBuffer);
wcscat_s(szPath,L",");
#endif _MBCS
// Initialize COM.
CoInitialize(NULL);
// Get rootDSE and the schema container DN. Bind to the
// current user's domain using current user's security context.
hr = ADsOpenObject(L"LDAP://rootDSE",
NULL,
NULL,
ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
IID_IADs,
(void**)&pObject);
if (SUCCEEDED(hr)) {
hr = pObject->Get(CComBSTR("schemaNamingContext"), &var);
if (SUCCEEDED(hr)) {
#ifdef _MBCS
wcscat_s(szPath,var.bstrVal);
#endif _MBCS
VariantClear(&var);
if (pObject) {
pObject->Release();
pObject = NULL;
}
hr = ADsOpenObject(szPath,
NULL,
NULL,
ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
IID_IADs,
(void**)&pObject);
if (SUCCEEDED(hr)) {
wprintf(L"Modify the default SD for the %s class\n", pszBuffer);
hr = ModifyDefaultSecurityDescriptor( pObject );
}
}
}
if (FAILED(hr))
wprintf(L"Failed with the following HRESULT: 0x%x\n", hr);
if (pObject)
pObject->Release();
// Uninitialize COM.
CoUninitialize();
return TRUE;
}
HRESULT ModifyDefaultSecurityDescriptor(
IADs *pObject
)
{
HRESULT hr = E_FAIL;
VARIANT var;
PSECURITY_DESCRIPTOR pSDCNV = NULL;
SECURITY_DESCRIPTOR SD = {0};
DWORD dwSDSize = sizeof(SECURITY_DESCRIPTOR);
PSID pOwnerSID = NULL;
DWORD dwOwnerSIDSize = 0;
PSID pGroupSID = NULL;
DWORD dwGroupSIDSize = 0;
PACL pDACL = NULL;
DWORD dwDACLSize = 0;
PACL pSACL = NULL;
DWORD dwSACLSize = 0;
BOOL bDaclPresent = FALSE;
BOOL bDaclDefaulted = FALSE;
PACL pOldDACL, pNewDACL;
ULONG ulLen;
EXPLICIT_ACCESS ea;
DWORD dwRes;
// Get the default security descriptor. Type should be VT_BSTR.
hr = pObject->Get(CComBSTR("defaultSecurityDescriptor"), &var);
if (FAILED(hr) || var.vt!=VT_BSTR ) {
wprintf(L"Error getting default SD: 0x%x\n", hr );
goto Cleanup;
}
wprintf(L"Old Default SD: %s\n", var.bstrVal);
// Convert the security descriptor string to a security descriptor.
if ( ! ConvertStringSecurityDescriptorToSecurityDescriptor (
var.bstrVal, SDDL_REVISION_1, &pSDCNV, NULL )) {
wprintf(L"Error converting string security descriptor: %d\n",
GetLastError() );
goto Cleanup;
}
// Convert self-relative security descriptor to absolute.
// First, get the required buffer sizes.
if (! MakeAbsoluteSD(pSDCNV, &SD, &dwSDSize,
pDACL, &dwDACLSize,
pSACL, &dwSACLSize,
pOwnerSID, &dwOwnerSIDSize,
pGroupSID, &dwGroupSIDSize) ) {
// Allocate the buffers.
pDACL = (PACL) GlobalAlloc(GPTR, dwDACLSize);
pSACL = (PACL) GlobalAlloc(GPTR, dwSACLSize);
pOwnerSID = (PACL) GlobalAlloc(GPTR, dwOwnerSIDSize);
pGroupSID = (PACL) GlobalAlloc(GPTR, dwGroupSIDSize);
if (! (pDACL && pSACL && pOwnerSID && pGroupSID) ) {
wprintf(L"GlobalAlloc failed: %d\n", GetLastError() );
goto Cleanup;
}
// Perform the conversion.
if (! MakeAbsoluteSD(pSDCNV, &SD, &dwSDSize, pDACL, &dwDACLSize,
pSACL, &dwSACLSize, pOwnerSID, &dwOwnerSIDSize,
pGroupSID, &dwGroupSIDSize) ) {
wprintf(L"MakeAbsoluteSD: %d\n", GetLastError() );
goto Cleanup;
}
}
// Get the DACL from the security descriptor.
if (! GetSecurityDescriptorDacl(&SD, &bDaclPresent,
&pOldDACL, &bDaclDefaulted) ) {
wprintf(L"GetSecurityDescriptorDacl failed: %d\n", GetLastError() );
goto Cleanup;
}
// Initialize an EXPLICIT_ACCESS structure for the new ACE.
// The ACE grants Everyone the right to read properties.
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = ADS_RIGHT_DS_READ_PROP;
ea.grfAccessMode = GRANT_ACCESS;
ea.grfInheritance= 0;
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.ptstrName = TEXT("Everyone");
// Create a new ACL that merges the new ACE into the existing DACL.
dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
if (ERROR_SUCCESS != dwRes) {
wprintf(L"SetEntriesInAcl Error %u\n", dwRes );
goto Cleanup;
}
// Put the modified DACL into the security descriptor.
if (! SetSecurityDescriptorDacl(&SD, TRUE, pNewDACL, FALSE) ) {
wprintf(L"SetSecurityDescriptorOwner failed: %d\n",
GetLastError() );
goto Cleanup;
}
// Convert the security descriptor back to string format.
VariantClear(&var);
if ( ! ConvertSecurityDescriptorToStringSecurityDescriptor (
&SD, SDDL_REVISION_1,
GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
&var.bstrVal, &ulLen )) {
wprintf(L"Error converting security descriptor to string: %d\n",
GetLastError() );
goto Cleanup;
}
wprintf(L"New default SD: %s\n", var.bstrVal);
V_VT(&var) = VT_BSTR;
// Use Put and SetInfo to set the modified security descriptor.
hr = pObject->Put(CComBSTR("defaultSecurityDescriptor"), var);
if (FAILED(hr)) {
wprintf(L"Error putting default SD: 0x%x\n", hr );
goto Cleanup;
}
hr = pObject->SetInfo();
if (FAILED(hr)) {
wprintf(L"Error setting default SD: 0x%x\n", hr );
goto Cleanup;
}
Cleanup:
VariantClear(&var);
if (pSDCNV)
LocalFree(pSDCNV);
if (pDACL)
GlobalFree(pDACL);
if (pSACL)
GlobalFree(pSACL);
if (pOwnerSID)
GlobalFree(pOwnerSID);
if (pGroupSID)
GlobalFree(pGroupSID);
if (pNewDACL)
LocalFree(pNewDACL);
return hr;
}