ID: Q194809
The information in this article applies to:
The permissions on a particular Exchange container object like the organization, site, and/or configuration may need to be changed. For example, it may be necessary to add a specific user to the organization, site, and/or configuration containers. To accomplish this you need to use the Directory Application Program Interface (DAPI) to read and write the security descriptor. You can manipulate the security descriptor after it has been read by using Windows NT security APIs.
Using the DAPIRead() function, the security descriptor is read from the Exchange container object. Exchange stores the security descriptor as SelfRelative. Before modifying the security descriptor, you need to convert it to Absolute. The API to change a security descriptor from SelfRelative to Absolute is MakeAbsoluteSD(). Once the security descriptor is in an absolute form, you can add to it. There are a number of APIs that you can use to manipulate the security descriptor. Some of these APIs are in the function CreateMySecurityDescriptor() that follows.
NOTE: You can use similar code with Active Directory Service Interface (ADSI)/ Lightweight Directory Access Protocol (LDAP) to manipulate security descriptors in Exchange 5.5 and later environments.
The following code reads the security descriptor, converts it to absolute form, manipulates it, and writes it back to the organization container. The Dapi.lib is the only additional library required to compile this Win32 console application.
The command line parameters required follow:
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <lmcons.h>
#include <winnt.h>
#include <dapi.h>
#include <dapimsg.h> // error codes
//Defining the rights.
#define RIGHT_DS_ADD_CHILD 0x00000001L
#define RIGHT_DS_MODIFY_USER_ATT 0x00000002L
#define RIGHT_DS_MODIFY_ADMIN_ATT 0x00000004L
#define RIGHT_DS_DELETE DELETE
#define RIGHT_MAIL_SEND_AS 0x00000008L
#define RIGHT_MAIL_RECEIVE_AS 0x00000010L
#define RIGHT_MAIL_ADMIN_AS 0x00000020L
#define RIGHT_DS_REPLICATION 0x00000040L
#define RIGHT_DS_MODIFY_SEC_ATT 0x00000080L
#define GENERIC_READ_MAPPING 0x00000000L
// Generic execute.
#define GENERIC_EXECUTE_MAPPING
((RIGHT_MAIL_SEND_AS)|(RIGHT_MAIL_RECEIVE_AS))
// Generic right.
#define GENERIC_WRITE_MAPPING
((RIGHT_DS_ADD_CHILD)|(RIGHT_DS_MODIFY_USER_ATT)|
(RIGHT_DS_MODIFY_ADMIN_ATT)|(RIGHT_DS_DELETE))
// Generic all.
#define GENERIC_ALL_MAPPING
((GENERIC_READ_MAPPING)|(GENERIC_EXECUTE_MAPPING)|
(RIGHT_DS_MODIFY_SEC_ATT)|(GENERIC_WRITE_MAPPING))
// Standard DS generic access rights mapping.//
#define DS_GENERIC_MAPPING
{GENERIC_READ_MAPPING,GENERIC_WRITE_MAPPING,
GENERIC_EXECUTE_MAPPING,GENERIC_ALL_MAPPING}
#define NORMAL_USER_RIGHTS
((RIGHT_DS_MODIFY_USER_ATT)|(GENERIC_EXECUTE_MAPPING))
#define NORMAL_ADMIN_RIGHTS (GENERIC_WRITE_MAPPING)
#define NORMAL_SEC_ADMIN_RIGHTS
(NORMAL_ADMIN_RIGHTS | RIGHT_DS_MODIFY_SEC_ATT)
DWORD MakeSDAbsolute (
PSECURITY_DESCRIPTOR OldSD,
PSECURITY_DESCRIPTOR *NewSD );
BOOL CreateMySecurityDescriptor(
PSECURITY_DESCRIPTOR pSecurityDescriptor,
char *Owner );
void ReadMBAttr(
DAPI_HANDLE hDAPISession, char * szHomeServer,
char * szCN, char * szCN2 );
void ReportDAPIEvent(
DAPI_EVENT* pDAPIEvent );
char *MyUser;
FILE *ef;
void main(int argc, char* argv[])
{
DAPI_HANDLE hDAPISession;
DAPI_EVENT* pDAPIEvent = NULL;
DAPI_PARMS DAPIParms = {0};
// Command line syntax:
// DAPIRead ExchangeServerName Organization Site DomainName\UserName
if (4 > argc) {
printf("\nDAPIRead ExchangeServerName Organization Site"
printf(" Domain_User");
printf("\n\nExample:");
printf("\nDAPIRead MyServer /O=org SiteName Administrator ");
return;
}
// Create a log file.
ef = fopen("DAPIREAD.LOG", "a+");
printf("\nExchange Server: %s", argv[1]);
fprintf(ef,"\nExchange Server: %s",argv[1]);
printf("\nBasePoint Container DN: %s", argv[2]);
fprintf(ef,"\nBasePoint Container DN: %s", argv[2]);
printf("\nUser: %s", argv[4]);
fprintf(ef,"\nUser: %s", argv[4]);
// Start DAPI for this session.
// Initialize the DAPI Parms structure and the
// DAPI operation session.
DAPIParms.dwDAPISignature = DAPI_SIGNATURE;
DAPIParms.dwFlags = DAPI_EVENT_ALL |
DAPI_MODIFY_REPLACE_PROPERTIES | DAPI_RAW_MODE ;
DAPIParms.pszDSAName = argv[1];
DAPIParms.pszBasePoint = argv[2];
DAPIParms.pszContainer = NULL;
DAPIParms.pszNTDomain = NULL;
DAPIParms.pszCreateTemplate = NULL;
DAPIParms.pAttributes = NULL;
MyUser= argv[4];
pDAPIEvent = DAPIStart(&hDAPISession, &DAPIParms);
if(pDAPIEvent)
{
printf("\nDAPIStart() returned %08x - check app eventlog",
pDAPIEvent->dwDAPIError);
fprintf(ef,"\nDAPIStart() returned %08x - check app eventlog",
pDAPIEvent->dwDAPIError);
ReportDAPIEvent(pDAPIEvent);
// Note: dwDAPIError < 0 does NOT necessarily mean
// DAPIStart failed.
if (0==hDAPISession || INVALID_HANDLE_VALUE == hDAPISession)
return;
}
else
{
printf("\nDAPIStart() was successful");
fprintf(ef,"\nDAPIStart() was successful");
}
ReadMBAttr(hDAPISession, argv[1],argv[2], argv[3]);
DAPIEnd(&hDAPISession);
printf("\nEND PROGRAM");
fprintf(ef,"\nEND PROGRAM\n");
fclose(ef);
}
void ReadMBAttr(DAPI_HANDLE hDAPISession, char * szHomeServer,
char * szCN, char * szCN2)
{
DAPI_EVENT* pDAPIEvent = NULL;
DAPI_ENTRY Attributes;
DAPI_ENTRY Values;
ATT_VALUE AttName[5];
ATT_VALUE AttValue[5];
PDAPI_ENTRY ppValues = NULL;
PDAPI_ENTRY ppAttribs = NULL;
BOOL bToken = TRUE;
SECURITY_DESCRIPTOR *pRelativeSD = NULL;
SECURITY_DESCRIPTOR *pAbsoluteSecurityDescriptor = NULL;
DWORD dwAbs;
ULONG ulAbsSecLength = 0;
BOOL present;
BOOL systemDefault;
PACL dacl;
printf("\nIN ReadMBAttr()");
fprintf(ef,"\nIN ReadMBAttr()");
// Add Permissions to the Organization.
AttName[0].DapiType = DAPI_STRING8;
AttName[0].Value.pszValue = "Obj-Class";
AttName[0].size = strlen(AttName[0].Value.pszValue);
AttName[0].pNextValue = NULL;
AttName[1].DapiType = DAPI_STRING8;
AttName[1].Value.pszValue = "NT-Security-Descriptor";
AttName[1].size = strlen(AttName[1].Value.pszValue);
AttName[1].pNextValue = NULL;
AttName[2].DapiType = DAPI_STRING8;
AttName[2].Value.pszValue = "Organization-Name";
AttName[2].size = strlen(AttName[2].Value.pszValue);
AttName[2].pNextValue = NULL;
Attributes.unAttributes = 3; //# of attributes
Attributes.ulEvalTag = TEXT_VALUE_ARRAY; // Value Type.
Attributes.rgEntryValues = (ATT_VALUE*)&AttName;
AttValue[0].DapiType = DAPI_STRING8;
AttValue[0].Value.pszValue = "Organization";
AttValue[0].size = strlen(AttValue[0].Value.pszValue);
AttValue[0].pNextValue = NULL;
AttValue[1].DapiType = DAPI_STRING8;
AttValue[1].Value.pszValue = "Exch_admin";
AttValue[1].size = strlen(AttValue[1].Value.pszValue);
AttValue[1].pNextValue = NULL;
AttValue[2].DapiType = DAPI_STRING8;
AttValue[2].Value.pszValue = szCN;
AttValue[2].size = strlen(AttValue[2].Value.pszValue);
AttValue[2].pNextValue = NULL;
Values.unAttributes = 3; //# of attributes
Values.ulEvalTag = TEXT_VALUE_ARRAY; // Value Type.
Values.rgEntryValues = (ATT_VALUE*)&AttValue;
pDAPIEvent = DAPIRead(hDAPISession,
0, //DAPI_READ_DEFINED_ATTRIBUTES,
szCN, &Attributes, &ppAttribs, &ppValues);
if(pDAPIEvent) {
// Read FAILED
printf("\nDAPIRead ERROR %08x check app eventlog",
pDAPIEvent->dwDAPIError);
fprintf(ef,"\nDAPIRead ERROR %08x check app eventlog",
pDAPIEvent->dwDAPIError);
ReportDAPIEvent(pDAPIEvent);
} else printf("\nDAPIRead() was successful");
pRelativeSD = (SECURITY_DESCRIPTOR *)malloc(2048);
pAbsoluteSecurityDescriptor = (SECURITY_DESCRIPTOR *)malloc(2048);
pRelativeSD = (SECURITY_DESCRIPTOR *)
(*(ppAttribs)).rgEntryValues[1].Value.lpBinary;
// Change the security descriptor to Absolute.
dwAbs = MakeSDAbsolute(
(PSECURITY_DESCRIPTOR)pRelativeSD,
(PSECURITY_DESCRIPTOR *) &pAbsoluteSecurityDescriptor);
// AddNameToSD()
// **TO DO: Change the domain\user to the user you want as the admin.
if (CreateMySecurityDescriptor(pAbsoluteSecurityDescriptor,MyUser))
{
printf("\nCreateMySecurityDescriptor was successful");
fprintf(ef,"\nCreateMySecurityDescriptor was successful");
}
else
{
printf("\nCreateMySecurityDescriptor Failed for Organization");
fprintf(ef,"\nCreateMySecurityDescriptor Failed for Organization");
}
// Change the security descriptor to SelfRelative.
ulAbsSecLength = GetSecurityDescriptorLength(
pAbsoluteSecurityDescriptor);
pRelativeSD = (SECURITY_DESCRIPTOR *) malloc(ulAbsSecLength);
if (MakeSelfRelativeSD(pAbsoluteSecurityDescriptor,
pRelativeSD,&ulAbsSecLength))
{
printf("\nMakeSelfRelativeSD was successful");
fprintf(ef,"\nMakeSelfRelativeSD was successful");
}
else
{
printf("\nMakeSelfRelativeSD Failed for Organization");
fprintf(ef,"\nMakeSelfRelativeSD Failed for Organization");
}
if (IsValidSecurityDescriptor(pRelativeSD))
{
printf("\nValid SD");
fprintf(ef,"\nValid SD");
}
else
{
printf("\nInvalid SD for Organization");
fprintf(ef,"\nInvalid SD for Organization");
}
GetSecurityDescriptorDacl(pRelativeSD,&present,
&dacl, &systemDefault);
if (IsValidAcl(dacl))
printf("\nValid ACL");
fprintf(ef,"\nValid ACL");
AttValue[1].DapiType = DAPI_BINARY;
AttValue[1].Value.lpBinary = (unsigned char *)pRelativeSD;
AttValue[1].size = GetSecurityDescriptorLength(pRelativeSD);
AttValue[1].pNextValue = NULL;
// Write Security Descriptor Back to Exchange.
pDAPIEvent = DAPIWrite(hDAPISession, DAPI_WRITE_UPDATE,
&Attributes, &Values, NULL, NULL, NULL);
if(pDAPIEvent)
{
// create FAILED.
printf("\nDAPIWrite ERROR %08x check app eventlog",
pDAPIEvent->dwDAPIError);
fprintf(ef,"\nDAPIWrite ERROR %08x check app eventlog", \
pDAPIEvent->dwDAPIError);
ReportDAPIEvent(pDAPIEvent);
// DAPIFreeMemory(pDAPIEvent);
}
else
printf("\nDAPIWrite() for Organization was successful");
fprintf(ef,"\nDAPIWrite() for Organization was successful");
}
void ReportDAPIEvent(DAPI_EVENT* pDAPIEvent)
{
HANDLE hDAPIEventSource = RegisterEventSource(NULL,
TEXT("MSExchangeDSImp"));
ReportEvent( hDAPIEventSource, (WORD)EVENTLOG_ERROR_TYPE,
0xFFFF, pDAPIEvent->dwDAPIError, NULL,
(WORD)pDAPIEvent->unSubst, 0,
(const char**) pDAPIEvent->rgpszSubst, NULL);
DAPIFreeMemory(pDAPIEvent);
DeregisterEventSource(hDAPIEventSource);
}
BOOL CreateMySecurityDescriptor(
PSECURITY_DESCRIPTOR pSecurityDescriptor,
char *Owner )
{
GENERIC_MAPPING GenericMapping = DS_GENERIC_MAPPING;
PSID pOwnerSid;
PACL pAcl;
BOOL Ret=FALSE;
BOOL present;
BOOL systemDefault;
DWORD cbNewAcl;
ACCESS_ALLOWED_ACE * pAce;
ACCESS_MASK AccessMask = NORMAL_ADMIN_RIGHTS |
RIGHT_MAIL_ADMIN_AS | RIGHT_DS_MODIFY_SEC_ATT;
DWORD dwAce;
PACL pNewAcl;
//
// Initialize the Security Descriptor struct.
//
{
//
// Get the SID for the account/Group.
//
DWORD lSD = GetSecurityDescriptorLength(pSecurityDescriptor);
DWORD len1=1024,len2=1024;
char RefDomain[1024];
SID_NAME_USE snu=SidTypeUser; //don't care
if ((pOwnerSid=(PSID)calloc(len1,1))==NULL)
return FALSE;
Ret = LookupAccountName( NULL, Owner, pOwnerSid, &len1,
RefDomain, &len2, &snu );
if (!Ret)
{
free(pOwnerSid);
return FALSE;
}
}
{
//
// Create the access control list with access for
// the preceding SID.
//
MapGenericMask(&AccessMask, &GenericMapping);
if (!GetSecurityDescriptorDacl(
(SECURITY_DESCRIPTOR *)pSecurityDescriptor,
&present, &pAcl, &systemDefault))
return GetLastError();
ACL_SIZE_INFORMATION asiAcl;
if (GetAclInformation(pAcl,&asiAcl,
sizeof(asiAcl),AclSizeInformation))
{
printf("\nAcl Information Succeeded");
fprintf(ef,"\nAcl Information Succeeded");
}
else
return FALSE;
cbNewAcl = asiAcl.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) +
GetLengthSid (pOwnerSid);
pNewAcl = (PACL) malloc(cbNewAcl);
if (!InitializeAcl (pNewAcl, cbNewAcl, ACL_REVISION2))
{
printf("\nInitializeAcl failed");
fprintf(ef,"\nInitializeAcl failed");
return FALSE;
}
else
printf("\nInitializeAcl succeeded");
fprintf(ef,"\nInitializeAcl succeeded");
// pAcl = pNewAcl;
// Move each ACE from the present ACL into the new one.
for (dwAce = 0 ; dwAce < asiAcl.AceCount ; dwAce++)
{
// Get the ACE out of the ACL
if (!GetAce (pAcl, dwAce, (void **)&pAce))
{
printf("\nGetAce failed");
fprintf(ef,"\nGetAce failed");
}
// Place the ACE into the new ACL.
if (!AddAce (pNewAcl, ACL_REVISION2, dwAce, pAce,
((ACE_HEADER *) pAce)->AceSize))
{
printf("\nAddAce failed");
fprintf(ef,"\nAddAce failed");
}
}
Ret = AddAccessAllowedAce( pNewAcl, ACL_REVISION,
AccessMask, pOwnerSid );
if (!Ret)
{
long err = GetLastError();
free(pOwnerSid);
free(pAcl);
return FALSE;
}
}
if (IsValidAcl(pNewAcl))
printf("\nValid ACL");
fprintf(ef,"\nValid ACL");
//
// Add the created ACL to the discreationary control list.
//
Ret = SetSecurityDescriptorDacl(pSecurityDescriptor,
TRUE,pNewAcl,FALSE);
if (!Ret)
{
free(pOwnerSid);
free(pAcl);
return FALSE;
}
if (IsValidSecurityDescriptor(pSecurityDescriptor))
printf("\nValid SD");
fprintf(ef,"\nValid SD");
DWORD lSD = GetSecurityDescriptorLength(pSecurityDescriptor);
return TRUE;
}
DWORD MakeSDAbsolute (
PSECURITY_DESCRIPTOR OldSD,
PSECURITY_DESCRIPTOR *NewSD )
{
PSECURITY_DESCRIPTOR sd = NULL;
DWORD descriptorSize;
DWORD daclSize;
DWORD saclSize;
DWORD ownerSIDSize;
DWORD groupSIDSize;
PACL dacl;
PACL sacl;
PSID ownerSID;
PSID groupSID;
BOOL present;
BOOL systemDefault;
ULONG pAce = NULL;
BOOL bToken = FALSE;
//
// Get SACL
//
if (!GetSecurityDescriptorSacl (OldSD, &present, &sacl,
&systemDefault))
return GetLastError();
if (sacl && present)
{
saclSize = sacl->AclSize;
} else saclSize = 0;
//
// Get DACL
//
if (!GetSecurityDescriptorDacl (OldSD, &present, &dacl,
&systemDefault))
return GetLastError();
if (dacl && present)
{
daclSize = dacl->AclSize;
} else daclSize = 0;
//
// Get Owner.
//
if (!GetSecurityDescriptorOwner (OldSD, &ownerSID, &systemDefault))
return GetLastError();
ownerSIDSize = GetLengthSid (ownerSID);
//
// Get Group.
//
if (!GetSecurityDescriptorGroup (OldSD, &groupSID, &systemDefault))
return GetLastError();
groupSIDSize = GetLengthSid (groupSID);
//
// Do the conversion.
//
descriptorSize = 0;
bToken = MakeAbsoluteSD (OldSD, sd, &descriptorSize, dacl,
&daclSize, sacl, &saclSize, ownerSID,
&ownerSIDSize, groupSID, &groupSIDSize);
sd = (PSECURITY_DESCRIPTOR)
new BYTE [SECURITY_DESCRIPTOR_MIN_LENGTH];
if (!InitializeSecurityDescriptor (sd,
SECURITY_DESCRIPTOR_REVISION))
return GetLastError();
if (!MakeAbsoluteSD (OldSD, sd, &descriptorSize, dacl, &daclSize,
sacl, &saclSize, ownerSID, &ownerSIDSize,
groupSID, &groupSIDSize))
return GetLastError();
*NewSD = sd;
return ERROR_SUCCESS;
}
Keywords : kbADSI kbAPI kbMsg kbEDK550
Version : WINDOWS:5.0,5.5
Platform : WINDOWS
Issue type : kbhowto
Last Reviewed: November 4, 1998