HOWTO: Add a User with Permissions to Exchange Server Objects

ID: Q194809


The information in this article applies to:
  • Exchange Development Kit (EDK), version 5.0
  • Microsoft Exchange Server, versions 5.0, 5.5


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 <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 *) &amp;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(&amp;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; 
    }


Additional query words:

Keywords : kbADSI kbAPI kbMsg kbEDK550 kbDSupport
Version : WINDOWS:5.0; winnt:5.0,5.5
Platform : WINDOWS winnt
Issue type : kbhowto


Last Reviewed: October 1, 1999
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.