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 (DapiDumpSecApp) uses DAPIRead function to read this information. Let's take a look at the code:

    (*
     * Algorithm:
     *  1. Do DAPIStart.
     *  2. Do DAPIRead to request security descriptor.
     *  3. Do DAPIEnd.
     *)

procedure TfrmMain.btStartClick(Sender: TObject);
function DumpSecurAttributes(pSD:PSID):TStrings;
var
...
begin

    if GetSecurityDescriptorDacl(pSD,pbDaclPresent,pDacl, lpbDaclDefaulted) then
        begin
            wAceCount := pdacl.AceCount;
            pAce := nil;
            
            for W := 0 to wAceCount-1 do
            begin
                b := GetAce(pdacl^, w, pAce);
                dwMask := PACCESS_ALLOWED_ACE(pAce).Mask;
                Result.Add('Mask '+IntToStr(W)+': '+#0+IntToHex(dwMask,8))
            end;
        end;

end;

var
ObjectToRead:Array [0..255] of Char;
TempStr:String;
userprop:TStrings;
iSizeNeeded,
CountAtt,i:Integer;
p:PCHAR;
ppSD:PSID;
begin

ppSD:=nil;

if Assigned(SiteInfo) then SiteInfo.Free;
SiteInfo:=TSiteInfo.Create(Trim(ebESName.Text));

if SiteInfo.GetInfo then
begin
    ZeroMemory(@ObjectToRead,256);


    TempStr:=Trim(ebMailbox.Text);
    if TempStr<>EmptyStr then
        TempStr:='/cn=Recipients/cn='+TempStr
    else
    TempStr:='/cn=Recipients';

TempStr:=SiteInfo.SiteDNString+TempStr;
StrPCopy(@ObjectToRead,TempStr);


// Check for started DAPI Session
if DSession=DAPI_INVALID_HANDLE then
begin
DAPIParms.dwDAPISignature:=DAPI_SIGNATURE;
DAPIParms.dwFlags := DAPI_EVENT_ALL;
DAPIParms.pszDSAName:=PChar(SiteInfo.SrvName);

(*
The DAPIStart function initializes a directory operation session.
*)

pDAPIEvent:=DAPIStart(@DSession,@DAPIParms);

if Assigned(pDAPIEvent) then
begin
    RaiseDAPIError(pDAPIEvent);
    DAPIFreeMemory(pDAPIEvent);
end
else
    begin
        if Assigned(pValues) then
            begin
            DapiFreeMemory(pValues);
            pValues:=nil;
    end;

        if Assigned(pAttributes) then
            begin
                DapiFreeMemory(pAttributes);
                pAttributes:=nil;
        end;


CountAtt:=2;


deAttributes:=DAPIAllocBuffer(SizeOf(DAPI_ENTRY), nil);
ZeroMemory(deAttributes, SizeOf(DAPI_ENTRY));


deAttributes.unAttributes := 1;
deAttributes.ulEvalTag := TEXT_LINE;

deAttributes.rgEntryValues:=DAPIAllocBuffer(SizeOf(ATT_VALUE), deAttributes);
ZeroMemory(deAttributes.rgEntryValues, SizeOf(ATT_VALUE));

PATT_VALUE(deAttributes.rgEntryValues).DapiType := DAPI_TEXT;
PATT_VALUE(deAttributes.rgEntryValues).Value.pszValue:='Object-Class,NT-Security-Descriptor';
PATT_VALUE(deAttributes.rgEntryValues).size := strlen(PATT_VALUE(deAttributes.rgEntryValues).Value.pszValue);


pDAPIEvent:=DAPIRead(
                                    DSession,
                                    0,
                                    @ObjectToRead,
                                    deAttributes,
                                    @pValues,
                                    nil);

if Assigned(pDAPIEvent) then
        RaiseDAPIError(pDAPIEvent)
else
begin
        iSizeNeeded:=PATT_VALUE(ULONG(pValues.rgEntryValues) + ( sizeof(ATT_VALUE))).size;
        ppSD:=nil;
        ListViewProp.Items.Clear;

        If iSizeNeeded>0 then
        begin
        ppSD:=AllocMem(iSizeNeeded);


CopyMemory(ppSD,
                    PATT_VALUE(ULONG(pValues.rgEntryValues) + ( sizeof(ATT_VALUE))).Value.lpBinary,
                    iSizeNeeded);

        userprop:=DumpSecurAttributes(ppSD);

if Assigned(ppSD) then
        FreeMem(ppSD);

ListViewProp.Items.BeginUpdate;
ListViewProp.Items.Clear;
        for i := 0 to userprop.count - 1 do
            with ListViewProp.Items.Add do
                begin
                p := @userprop [i] [1];
                Caption := p;
                inc(p,StrLen(P)+1);
                SubItems.Add(p);
        end;

ListViewProp.Items.EndUpdate;
userprop.Free;
end;
// Deallocate memory

if Assigned(avAttrName) then
begin
DapiFreeMemory(avAttrName);
avAttrName:=nil;
end;


if Assigned(deAttributes) then
begin
DapiFreeMemory(deAttributes);
deAttributes:=nil;
end;



if Assigned(pValues) then
begin
DapiFreeMemory(pValues);
pValues:=nil;
end;

if Assigned(pAttributes) then
begin
DapiFreeMemory(pAttributes);
pAttributes:=nil;
end;

end;

end;
end;
end;
if DSession<>DAPI_INVALID_HANDLE then
// Terminate DAPI session
DAPIEnd(@DSession);
end;

Compiled DELPHI 5 example