locked
RegGetKeySecurity returns negative pointer. RRS feed

  • Question

  • I am trying to get the current SECURITY_DESCRIPTOR so that I can add to it and use RegSetKeySecurity to set the new security with the desired changes.
    Every time I use RegGetKeySecurity it returns a negative pointer to a security descriptor and when I use IsValidSecurityDescriptor it is not valid.
    Is there any other way I could get the SECURITY_DESCRIPTOR or is there something I am doing wrong?

    It works perfectly if I create a SECURITY_DESCRIPTOR from scratch and use RegSetKeySecurity to set the security, however it overwrites the current descriptor. I need to keep the current settings and simply add to them.

    The code for my RegGetKeySecurity call is as follows:

    [DllImport("advapi32.dll", SetLastError=true)]
    private static extern int RegGetKeySecurity(IntPtr hKey, SECURITY_INFORMATION SecurityInformation,ref IntPtr pSecurityDescriptor, ref int lpcbSecurityDescriptor);


    uint error=(uint)RegGetKeySecurity(_key,SECURITY_INFORMATION.DACL_SECURITY_INFORMATION|SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION| SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION| SECURITY_INFORMATION.PROTECTED_DACL_SECURITY_INFORMATION| SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION, ref descriptorPtr, ref buffer); // first call is to get the proper buffer size for the second call.

    error = (uint)RegGetKeySecurity(_key, SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION | SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION | SECURITY_INFORMATION.PROTECTED_DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION, ref descriptorPtr, ref buffer);

    bool success = IsValidSecurityDescriptor(descriptorPtr);

    when debugging descriptorPtr shows up as - value.

    Thanks for your help.

    Ian
    Tuesday, August 4, 2009 5:33 PM

Answers

  • Using "ref" for the 3rd argument is wrong.  You have to pass an IntPtr to the buffer which the API will then fill.  Use Marshal.AllocHGlobal to allocate it.

    Hans Passant.
    • Marked as answer by Ian_Rintoul Wednesday, August 5, 2009 3:53 PM
    Tuesday, August 4, 2009 8:59 PM

All replies

  • What do you need that RegistryKey.GetAccessControl doesn't return?

    Post the code that pins the descriptorPtr and defines the buffer.  You naming isn't clear.  descriptorPtr should be an IntPtr to a pinned array and buffer should be an unsigned integer.  You should pin the array after the first call with the value returned in buffer.
    Tuesday, August 4, 2009 8:28 PM
  • Using "ref" for the 3rd argument is wrong.  You have to pass an IntPtr to the buffer which the API will then fill.  Use Marshal.AllocHGlobal to allocate it.

    Hans Passant.
    • Marked as answer by Ian_Rintoul Wednesday, August 5, 2009 3:53 PM
    Tuesday, August 4, 2009 8:59 PM
  • I need to be able to access a 64 bit registry from a 32 bit application hence the P/Invoke.

    Here is the requested code. It works now that I removed the ref and changed it to use a uint instead of int, however when I marshal it to a SECURITY_DESCRIPTOR Structure it has a negative control value and thus does not retrieve the string security descriptor correctly.

    [StructLayout(LayoutKind.Sequential)]
            public class SECURITY_DESCRIPTOR
            {
                public byte revision;
                public byte size;
                public short control;
                public IntPtr owner;
                public IntPtr group;
                public IntPtr sacl;
                public IntPtr dacl;
            }


    IntPtr descriptorPtr = IntPtr.Zero
    uint buffer =(uint) Marshal.SizeOf(typeof(SECURITY_DESCRIPTOR));

    error =(uint) RegGetKeySecurity(_key, SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION | SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION | SECURITY_INFORMATION.PROTECTED_DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION, tempPtr, ref buffer);
    descriptorPtr = Marshal.AllocHGlobal((int)buffer);
    error = (uint)RegGetKeySecurity(_key, SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION | SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION | SECURITY_INFORMATION.PROTECTED_DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION, descriptorPtr, ref buffer);

    SECURITY_DESCRIPTOR descriptor = new SECURITY_DESCRIPTOR();
    Marshal.PtrToStructure(descriptorPtr, descriptor);
    Wednesday, August 5, 2009 12:32 PM
  • Thanks, changing the ref worked well, now I get a valid SECURITY_DESCRIPTOR pointer, however when I marshal it to a SECURITY_DESCRIPTOR it has a negative control value. Do you know why this is happening?


    [StructLayout(LayoutKind.Sequential)]
            public class SECURITY_DESCRIPTOR
            {
                public byte revision;
                public byte size;
                public short control;
                public IntPtr owner;
                public IntPtr group;
                public IntPtr sacl;
                public IntPtr dacl;
            }


    SECURITY_DESCRIPTOR descriptor = new SECURITY_DESCRIPTOR();
    Marshal.PtrToStructure(descriptorPtr, descriptor);
    Wednesday, August 5, 2009 12:39 PM
  • That field is declared as unsigned short in the SDK.  It will be negative here when the SE_SELF_RELATIVE bit is on.

    Hans Passant.
    Wednesday, August 5, 2009 12:46 PM
  • Getting the security descriptor is working now, however when I use the ConvertSecurityDescriptorToStringSecurityDescriptor method and marshal it to a string it gives unreadable characters(boxes) and I am unable to add to it then convert it back to a valid security descriptor. Is there any reason why this would happen?


    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool ConvertSecurityDescriptorToStringSecurityDescriptor (IntPtr SecurityDescriptor , byte RequestedStringSDRevision,SECURITY_INFORMATION SecurityInformation,out IntPtr StringSecurityDescriptor,out byte StringSecurityDescriptorLen);


    Marshal.PtrToStructure(descriptorPtr, descriptor);

    if (ConvertSecurityDescriptorToStringSecurityDescriptor(descriptorPtr, descriptor.revision, SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION | SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION | SECURITY_INFORMATION.SACL_SECURITY_INFORMATION, out descriptorStringPtr, out size))
                        sddlStr = Marshal.PtrToStringAuto(descriptorStringPtr);
    Wednesday, August 5, 2009 2:53 PM
  • You forgot to specify the CharSet attribute for [DllImport].  You are getting the Ansi string.  Please close this thread, your additional questions have little to do with the original topic.  Start a new thread whenever you have a new question.

    Hans Passant.
    Wednesday, August 5, 2009 3:48 PM