Modifying Access to Directory Objects
| Nik Okuntseff |
MS Exchange Server Programming |
Modifying Access to Directory Objects
How can we modify access rights to a Directory object? Obviously, we need
to change the security descriptor associated with the object or its parent.
Let's suppose that we want to allow everyone access to a mailbox. The program
below (Security/Modify) does it.
#include <afxwin.h>
#include <dapi.h>
#include <edk.h>
int SetDirObjectSD(char * pszServer, char * pszDirectoryName, void *
pSelfRelSD)
{
/*
* Algorithm:
* 1. Do DAPIStart.
* 2. Do DAPIWrite to set security descriptor.
* 3. Do DAPIEnd.
*/
DAPI_PARMS parms = {0};
parms.dwDAPISignature = DAPI_SIGNATURE;
parms.pszDSAName = pszServer;
parms.pszContainer = "Recipients";
PDAPI_EVENT pDAPIEvent = NULL;
DAPI_HANDLE hDAPISession = NULL;
// Initialize DAPI
pDAPIEvent = ::DAPIStart(&hDAPISession, &parms);
if (pDAPIEvent)
{
DAPIFreeMemory(pDAPIEvent);
return -1;
}
// We have DAPI session. Use it now for read.
DAPI_ENTRY * pdeValues = NULL;
DAPI_ENTRY * pdeAttributes = NULL;
ATT_VALUE avAttrName[5];
ATT_VALUE avAttrValue[5];
avAttrName[0].DapiType = DAPI_STRING8;
avAttrName[0].Value.pszA = "Obj-Class";
avAttrName[0].size = 9;
avAttrName[0].pNextValue = NULL;
avAttrName[1].DapiType = DAPI_STRING8;
avAttrName[1].Value.pszA = "Directory Name";
avAttrName[1].size = 14;
avAttrName[1].pNextValue = NULL;
avAttrName[2].DapiType = DAPI_STRING8;
avAttrName[2].Value.pszA = "Home-Server";
avAttrName[2].size = 11;
avAttrName[2].pNextValue = NULL;
avAttrName[3].DapiType = DAPI_STRING8;
avAttrName[3].Value.pszA = "NT-Security-Descriptor";
avAttrName[3].size = 22;
avAttrName[3].pNextValue = NULL;
avAttrValue[0].DapiType = DAPI_STRING8;
avAttrValue[0].Value.pszA = "Mailbox";
avAttrValue[0].size = 8;
avAttrValue[0].pNextValue = NULL;
avAttrValue[1].DapiType = DAPI_STRING8;
avAttrValue[1].Value.pszA = pszDirectoryName;
avAttrValue[1].size = strlen(pszDirectoryName);
avAttrValue[1].pNextValue = NULL;
avAttrValue[2].DapiType = DAPI_STRING8;
avAttrValue[2].Value.pszA = "~SERVER"; // Or use
explicit server name here
avAttrValue[2].size = 7;
avAttrValue[2].pNextValue = NULL;
avAttrValue[3].DapiType = DAPI_BINARY;
avAttrValue[3].Value.lpBinary = (BYTE *) pSelfRelSD;
avAttrValue[3].size = GetSecurityDescriptorLength(pSelfRelSD);
avAttrValue[3].pNextValue = NULL;
// Set terminators
ZeroMemory(&avAttrName[4], sizeof(ATT_VALUE));
ZeroMemory(&avAttrValue[4], sizeof(ATT_VALUE));
DAPI_ENTRY deAttributes;
DAPI_ENTRY deValues;
deAttributes.unAttributes = 4;
deAttributes.ulEvalTag = TEXT_VALUE_ARRAY;
deAttributes.rgEntryValues = &avAttrName[0];
deValues.unAttributes = 4;
deValues.ulEvalTag = VALUE_ARRAY;
deValues.rgEntryValues = &avAttrValue[0];
char * pAccount = NULL;
char * pPassword = NULL;
ULONG ulUSN = 0;
pDAPIEvent = ::DAPIWrite(hDAPISession,
DAPI_WRITE_UPDATE,
&deAttributes,
&deValues,
&ulUSN,
&pAccount, //
Account
&pPassword); // Password
if (pDAPIEvent)
{
DAPIFreeMemory(pDAPIEvent);
return -1;
}
// Terminate DAPI session
DAPIEnd(&hDAPISession);
return 0;
}
int main( void )
{
char * pszServer = "MIG"; // Change
this
char * pszDirectoryName = "NikO"; // Change this
/*
* Algorithm:
* 1. Create a security descriptor that
allows access for everyone.
* 2. Convert it to self-relative format.
* 3. Call the SetDirObjectSD function.
*/
// Start with security descriptor in absolute format
SECURITY_DESCRIPTOR sd;
BOOL b = InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
assert(b);
// This is our SID for group "Everyone"
BYTE sidEveryone[12] = {1,1,0,0,0,0,0,1,0,0,0,0};
// Determine size for DACL, allocate and initialize
it.
DWORD dwSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
+ sizeof(sidEveryone) - sizeof(DWORD);
PACL pDacl = (PACL) malloc(dwSize);
b = InitializeAcl(pDacl, dwSize, ACL_REVISION);
assert(b);
// Allow access for everyone.
// The mask 0x000100FF defines Service Account Admin.
access.
b = AddAccessAllowedAce(pDacl, ACL_REVISION, 0x000100FF,
sidEveryone);
assert(b);
// Insert DACL into security descriptor
b = SetSecurityDescriptorDacl(&sd, TRUE, pDacl,
FALSE);
assert(b);
// Set up owner and group. Exchange needs them.
b = SetSecurityDescriptorOwner(&sd, sidEveryone,
FALSE);
assert(b);
b = SetSecurityDescriptorGroup(&sd, sidEveryone,
FALSE);
assert(b);
// We need to convert it to self-relative format
// Determine size first
BYTE * pSelfRelSD = NULL;
DWORD dwSelfRelSize = 0;
b = MakeSelfRelativeSD(&sd, pSelfRelSD, &dwSelfRelSize);
if (dwSelfRelSize)
pSelfRelSD = (BYTE *) malloc(dwSelfRelSize);
b = MakeSelfRelativeSD(&sd, pSelfRelSD, &dwSelfRelSize);
assert(b);
// Set our security descriptor into the directory
object
int i = SetDirObjectSD(pszServer, pszDirectoryName,
pSelfRelSD);
assert(S_OK == i);
// Deallocate memory
if (pSelfRelSD)
free(pSelfRelSD);
if (pDacl)
free(pDacl);
return 0;
}
A few notes about this code.
-
First, the format of the security descriptor is important - it needs to
be self-relative. Otherwise the DAPIWrite function fails. Also, you need
to set up owner and primary group in the security descriptor. I use the
well-known security identifier assigned to "Everyone" group. This makes
code shorter and more illustrative.
-
Second, notice that I have used the pszContainer member in DAPI_PARMS
structure to make it work properly. If you don't supply it, the DAPIWrite
may create another mailbox object in the site container instead of the
Recipients container.
-
Third, the Directory Name attribute that is set up before the DAPIWrite
call is the last part of mailbox distinguished name. Examine raw properties
of the mailbox to get this value and change accordingly. At first
I was thinking that I could use mailbox DN (similar to the way I used when
retrieving security descriptors). I abandoned further attempts to make
the DN working after a few unsuccessful attempts.
-
You may need to add some error output when pDAPIEvent is not NULL (or GetLastError()
for Win32 API function calls). All error handling is stripped to deliver
readability. The topic "How to Work with
DAPI_EVENT Structure" describes how to handle DAPI_EVENT.
If you modify mailbox access as this code does, then anyone will be able
to use the mailbox. Also, if you examine Application Event Log on a computer
against which you run this code, you should normally see MSExchangeDS service
event ID 1175 recorded there with the following description: "The security
attributes on object Object_Distinguished_Name were modified." User name
who had performed the operation is also listed.
[ Contents |
Home
]
Send comments and suggestions to niko@wrconsulting.com
Copyright © 1997-1998 by Nik Okuntseff
|