Microsoft KB Archive/194809

= How To Add a User with Permissions to Exchange Server Objects =

Article ID: 194809

Article Last Modified on 3/21/2005

-

APPLIES TO


 * Microsoft Exchange Development Kit 5.5
 * Microsoft Exchange Server 5.0 Standard Edition
 * Microsoft Exchange Server 5.5 Standard Edition

-



This article was previously published under Q194809



SUMMARY
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.



MORE INFORMATION
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:

 Parameter 1: Exchange_Server_Name (Exchange server to which you connect) Parameter 2: /O=Organization_Name (DN or the Organization object.) Parameter 3: Exchange_SiteName (Site Name the Exchange Server is in.)  Parameter 4: Domain\NT_account (Account to add with permissions.) #include    #include     #include     #include     #include 

#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; } </li></ul>

Keywords: kbhowto kbapi kbmsg KB194809

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.