Are you a world traveler? ZoneTick is a cool utility that'll help you stay in touch over multiple time zones!
 
Retrieving Security Descriptors from Directory Objects  
Nik Okuntseff  MS Exchange Server Programming 

Retrieving Security Descriptors from Directory Objects

It is convenient to have code that retrieves Windows NT security descriptors from Microsoft Exchange directory objects. You can use DAPI or MAPI to extract them. The sample below (Security/Retrieve) uses DAPIRead function to read this information. Let's take a look at the code:

#include <afxwin.h>
#include <dapi.h>
#include <edk.h>
 

int GetDirObjectSD(char * pszServer, char * pszDN, void ** ppSD)
{
    /*
     * Algorithm:
     *  1. Do DAPIStart.
     *  2. Do DAPIRead to request security descriptor.
     *  3. Do DAPIEnd.
     */

    DAPI_PARMS parms = {0};
    parms.dwDAPISignature = DAPI_SIGNATURE;
    parms.pszDSAName = pszServer;
 
    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[3];

    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 = "NT-Security-Descriptor";
    avAttrName[1].size = 22;
    avAttrName[1].pNextValue = NULL;

    // This terminates our attribute name array
    ZeroMemory( &avAttrName[2], sizeof(ATT_VALUE) );

    DAPI_ENTRY deAttributes;
 
    deAttributes.unAttributes = 2;
    deAttributes.ulEvalTag = TEXT_VALUE_ARRAY;
    deAttributes.rgEntryValues = &avAttrName[0];

    // Now read the security descriptor
    pDAPIEvent = DAPIRead(hDAPISession,
        0,
        pszDN,
        &deAttributes,
        &pdeValues,
        &pdeAttributes);
 
    if (pDAPIEvent)
    {
        DAPIFreeMemory(pDAPIEvent);
        return -1;
    }

    // Allocate new security descriptor
    int iSizeNeeded = pdeValues->rgEntryValues[1].size;
    *ppSD = malloc(iSizeNeeded);

    // Copy data into it
    memcpy(*ppSD, pdeValues->rgEntryValues[1].Value.lpBinary, iSizeNeeded);

    // Deallocate memory
    if (pdeValues)
        DAPIFreeMemory(pdeValues);
    if (pdeAttributes)
        DAPIFreeMemory(pdeAttributes);

    // Terminate DAPI session
    DAPIEnd(&hDAPISession);
    return 0;
}
 

int main( void )
{
    char * pszServer = "MIG";    // Change this
 
    // Get the organization name.
    LPSTR pszOrganizations;
    HRESULT hr = HrEnumOrganizations("", pszServer, &pszOrganizations);
    if (FAILED(hr)) throw -1;

    // Get the first available site.
    LPSTR pszSites;
    hr = HrEnumSites(pszServer, pszOrganizations, &pszSites);
    if (FAILED(hr)) throw -1;
    char * pszSite = pszSites;
    // Note. In case of multiple sites one string is allocated.
    // A single zero separates individual entries, a double zero
    // terminates the list.

    char pszDN[MAX_PATH];
    ZeroMemory(pszDN, MAX_PATH);
    memcpy(pszDN, pszSite, strlen(pszSite));
 
    // Let's do it for the Recipients container
    // Append "/cn=Recipients" to get DN
    memcpy(pszDN + strlen(pszSite), "/cn=Recipients", 15);

    void * pSD = NULL;
    int i = GetDirObjectSD(pszServer, pszDN, &pSD);
    assert(S_OK == i);
    // We have the security descriptor here.

    // Dump DACL masks
    int DaclOffset = (int)((PISECURITY_DESCRIPTOR) pSD)->Dacl;
    PACL dacl = (PACL)((BYTE *) pSD + DaclOffset);
 
    WORD wAceCount = dacl->AceCount;
    void * pAce = NULL;
    for (WORD w = 0; w < wAceCount; w++)
    {
        BOOL b = GetAce(dacl, w, &pAce);
        assert(b);

        DWORD dwMask = ((ACCESS_ALLOWED_ACE *) pAce)->Mask;
        printf("\nMask %d: 0x%08X", w, dwMask);
    }

    if (pSD)
        free(pSD);
    return 0;
}

The function named GetDirObjectSD gets security descriptor for us. It does this by utilizing Directory API (DAPI) functions. We need to provide the object Distinguished Name (DN) and deallocate security descriptor after use.

The main function illustrates a few other things. First, it obtains the Exchange organization name via the HrEnumOrganizations call, then it gets the name for the first available Exchange site in it. If you have just one site - this is all you need to get DN for the site. In case of multiple sites you may need to scan through the list. Notice the comment in the code about the format of the string. Then I append something to the site DN to get the distinguished name for the Recipients container in the site. You may wish to navigate further below to individual mailboxes. In this case you need to append "/cn=MailboxAlias" to the string. Then I call the GetDirObjectSD and dump access masks from the resulting security descriptor.
 

[ Contents | Home ]

Send comments and suggestions to niko@wrconsulting.com
Copyright © 1997-1998 by Nik Okuntseff