0

I was trying to write a C# equivalent for ACCESS_DENIED_ACE struct as defined in MSDN:

typedef struct _ACCESS_DENIED_ACE {
  ACE_HEADER  Header;
  ACCESS_MASK Mask;
  DWORD       SidStart;
} ACCESS_DENIED_ACE, *PACCESS_DENIED_ACE;

Where SidStart is the first DWORD of a trustee's SID. The remaining bytes of the SID are stored in contiguous memory after the SidStart member.

I have seen examples where its used like (PSID) &accessAllowedAce->SidStart as in,

if ( EqualSid (pSid, (PSID) &accessDeniedAce->SidStart) )
{
   //
}

Now how can I write the C# StructLayout for this and how can I use it in EqualSid function, also explain how your solution works.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
sri
  • 1,005
  • 1
  • 12
  • 26

2 Answers2

2

Start with the sub structs.

[StructLayout(LayoutKind.Sequential)]
struct ACE_HEADER
{
    byte AceType;
    byte AceFlags;
    uint AceSize;
}

DWORD = uint

[Flags]
enum ACCESS_MASK : uint
{
    // ...
}

Its a flag based enum struct to be represented as 32 bits (i.e. multiple states can be toggled). You'll need to define the bits as documented.

[StructLayout(LayoutKind.Sequential)]
struct ACCESS_DENIED_ACE
{
    ACE_HEADER Header;
    ACCESS_MASK Mask;
    uint SidStart;
}

Simple structure now.

M Afifi
  • 4,645
  • 2
  • 28
  • 48
  • How can I use SidStart in c#, if in C++ its used like (PSID) &accessAllowedAce->SidStart. Will marshalling uint (SidStart) to IntPtr work? – sri Jul 25 '12 at 10:57
  • @sri: I think you can use like this : `var sid1 = new IntPtr((long)ace.SidStart); if ( EqualSid(sid1, sid2) ) { .... }`. Try and let me know if it works. – Nawaz Jul 25 '12 at 11:18
  • I haven't seen the **typedef** for PSID, but it's most likely just a **DWORD** and its added for readability. For your question, well as @Nawaz said, var sid = new ACCESS_DENIED_ACE(...); sid.SidStart will give you the value of SidStart no need for an IntPtr based on the definition of that structure in MSDN. – M Afifi Jul 25 '12 at 11:42
  • @Nawaz: My ace was created using Marshal.PtrToStructure, so it creates a new copy. Now my question is, will it copy all the bites in the SID to the new struct created, or only the first byte of the SID as SidStart is an uint. If it copies all the bites as a contiguous memory after the SidStart member in the marshalled object how is it knowing that information while marshalling. – sri Jul 25 '12 at 12:01
  • SidStart is a DWORD, so it will copy all of it into the uint. It doesn't have to be a uint in the C# definition. Everything in the "native" structure will get copied across. – M Afifi Jul 25 '12 at 12:14
  • 1
    @sri: I don't think that it will copy the rest of the bits which lies beyond the struct. It is one reason why this hack is considered to be bad, by C++ programmers who care about compliancy.But then I think if you know the number of bytes used for SID, then you can change the definition of `ACCESS_DENIED_ACE` as follows : `uint[] SidStart;` , i.e, make it an array so the marshalling will know how many bytes it needs to copy. – Nawaz Jul 25 '12 at 12:15
1

When I get the IntPtr for ACCESS_DENIED_ACE (assume deniedAceIntPtr), I can get the IntPtr for SID in the ACCESS_DENIED_ACE by adding the offset of the SidStart

IntPtr tempSid = IntPtr.Add(deniedAceIntPtr, 8);

sri
  • 1,005
  • 1
  • 12
  • 26