PInvoke AuthzAccessCheck from c# giving error 87 : invalid parameter

1.3k views Asked by At

I'm trying to a PInvoke of AuthzAccessCheck to work in my c# application and keep running into the error code 87 : invalid parameter. As an initial test I've been trying to follow the basic structure of the GetAccess routine from the example code found here.

I've tried all the variations I can think of to get this working, and at this point I'm pretty much stuck. Can anyone help explain what I might be doing wrong?

Here is the full test code:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.AccessControl;
using System.ComponentModel;
using System.Text;

namespace PinvokeTest
{
    class Program
    {
        public interface IFunctionResult
        {
            bool Error { get; }
            string Message { get; }
        }

        public class FunctionResult : IFunctionResult
        {
            public FunctionResult() { _err = false; _msg = string.Empty; }
            public FunctionResult(string message) { _err = true; _msg = message; }

            private bool _err;
            private string _msg;

            public bool Error { get { return _err; } }
            public string Message { get { return _msg; } }
        }

        static void Main(string[] args)
        {
            string file_name = "C:\\AUTOEXEC.BAT";

            System.IO.FileInfo fi = new System.IO.FileInfo(file_name);
            FileSecurity fs = fi.GetAccessControl();
            byte[] rsd_bytes = fs.GetSecurityDescriptorBinaryForm();

            SecurityIdentifier user_sid;
            using (WindowsIdentity current_user = WindowsIdentity.GetCurrent()) { user_sid = current_user.User; }
            byte[] sid_bytes = new byte[user_sid.BinaryLength];
            user_sid.GetBinaryForm(sid_bytes, 0);

            IFunctionResult res = TestAuthzAccessCheck(rsd_bytes, sid_bytes);
            if (res.Error) { Console.WriteLine(res.Message); }
            else { Console.WriteLine("SUCCESS"); }
        }

        // see : http://msdn.microsoft.com/en-us/library/aa446637%28VS.85%29.aspx
        public static IFunctionResult TestAuthzAccessCheck(byte[] rsd_bytes, byte[] sid_bytes)
        {
            FunctionResult ret = null;

            IntPtr hClientContext = IntPtr.Zero;
            IntPtr hResourceManager = IntPtr.Zero;
            IntPtr reply_ptr = IntPtr.Zero;
            IntPtr request_ptr = IntPtr.Zero;
            IntPtr check_results = IntPtr.Zero;

            LUID unused_id = new LUID();

            AUTHZ_ACCESS_REPLY reply = new AUTHZ_ACCESS_REPLY();
            reply.Error = IntPtr.Zero;
            reply.GrantedAccessMask = IntPtr.Zero;
            reply.ResultListLength = 0;
            reply.SaclEvaluationResults = IntPtr.Zero;

            AUTHZ_ACCESS_REQUEST request = new AUTHZ_ACCESS_REQUEST();
            request.DesiredAccess = MAXIMUM_ALLOWED;
            request.PrincipalSelfSid = null;
            request.ObjectTypeList = null;
            request.ObjectTypeListLength = 0;
            request.OptionalArguments = IntPtr.Zero;

            try
            {
                for (int x = 0; x == 0; x++)
                {
                    if (!AuthzInitializeResourceManager((int)AuthzResourceManagerFlags.NO_AUDIT, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, "", out hResourceManager))
                    {
                        int err = Marshal.GetLastWin32Error();
                        Win32Exception win32Exception = new Win32Exception(err);
                        ret = new FunctionResult("AuthzInitializeResourceManager Error[" + err + "] : " + win32Exception.Message);
                        break;
                    }

                    if (!AuthzInitializeContextFromSid((int)AuthzContextFlags.NONE, sid_bytes, hResourceManager, IntPtr.Zero, unused_id, IntPtr.Zero, out hClientContext))
                    {
                        int err = Marshal.GetLastWin32Error();
                        Win32Exception win32Exception = new Win32Exception(err);
                        ret = new FunctionResult("AuthzInitializeContextFromSid Error[" + err + "] : " + win32Exception.Message);
                        break;
                    }

                    reply.Error = Marshal.AllocHGlobal(1020);
                    reply.GrantedAccessMask = Marshal.AllocHGlobal(sizeof(uint));
                    reply.ResultListLength = 1;

                    request_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(request));
                    Marshal.StructureToPtr(request, request_ptr, false);

                    reply_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(reply));
                    Marshal.StructureToPtr(reply, reply_ptr, false);

                    if (!AuthzAccessCheck((int)AuthzAccessCheckFlags.NONE, hClientContext, request_ptr, IntPtr.Zero, rsd_bytes, null, 0, ref reply_ptr, out check_results))
                    {
                        int err = Marshal.GetLastWin32Error();
                        Win32Exception win32Exception = new Win32Exception(err);
                        ret = new FunctionResult("AuthzAccessCheck Error[" + err + "] : " + win32Exception.Message);
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                ret = new FunctionResult("TestAuthzAccessCheck Exception : " + e.Message);
            }
            finally
            {
                if (reply.GrantedAccessMask != IntPtr.Zero) { Marshal.FreeHGlobal(reply.GrantedAccessMask); }
                if (reply.Error != IntPtr.Zero) { Marshal.FreeHGlobal(reply.Error); }
                if (reply_ptr != IntPtr.Zero) { Marshal.FreeHGlobal(reply_ptr); }
                if (request_ptr != IntPtr.Zero) { Marshal.FreeHGlobal(request_ptr); }
                if (hClientContext != IntPtr.Zero)
                {
                    if (!AuthzFreeContext(hClientContext))
                    {
                        int err = Marshal.GetLastWin32Error();
                        Win32Exception win32Exception = new Win32Exception(err);
                        ret = new FunctionResult((ret == null ? "" : (ret.Message + " ")) + "AuthzFreeContext Error[" + err + "] : " + win32Exception.Message);
                    }
                }
                if (hResourceManager != IntPtr.Zero)
                {
                    if (!AuthzFreeResourceManager(hResourceManager))
                    {
                        int err = Marshal.GetLastWin32Error();
                        Win32Exception win32Exception = new Win32Exception(err);
                        ret = new FunctionResult((ret == null ? "" : (ret.Message + " ")) + "AuthzFreeResourceManager Error[" + err + "] : " + win32Exception.Message);
                    }
                }
            }

            return ret;
        }


        public const int MAXIMUM_ALLOWED = 0x02000000;

        [Flags]
        public enum AuthzResourceManagerFlags : int
        {
            NONE = 0,
            NO_AUDIT = 0x1,
            INITIALIZE_UNDER_IMPERSONATION = 0x2,
            VALID_INIT_FLAGS = (NO_AUDIT | INITIALIZE_UNDER_IMPERSONATION),
        };

        [Flags]
        public enum AuthzContextFlags : int
        {
            NONE = 0,
            SKIP_TOKEN_GROUPS = 0x2,
            REQUIRE_S4U_LOGON = 0x4,
            COMPUTE_PRIVILEGES = 0x8
        };

        [Flags]
        public enum AuthzAccessCheckFlags : int
        {
            NONE = 0,
            NO_DEEP_COPY_SD = 0x00000001
        };

        [Flags]
        public enum AuthzGenerateFlags : int
        {
            NONE = 0,
            SUCCESS_AUDIT = 0x00000001,
            FAILURE_AUDIT = 0x00000002,
        };

        public enum OBJECT_TYPE_LEVEL : int
        {
            ACCESS_OBJECT_GUID = 0,
            ACCESS_PROPERTY_SET_GUID = 1,
            ACCESS_PROPERTY_GUID = 2,
            ACCESS_MAX_LEVEL = 4
        };

        [StructLayout(LayoutKind.Sequential)]
        public struct LUID
        {
            public uint LowPart;
            public int HighPart;
        };

        [StructLayout(LayoutKind.Sequential)]
        public struct OBJECT_TYPE_LIST
        {
            OBJECT_TYPE_LEVEL Level;
            int Sbz;
            IntPtr ObjectType;
        };

        [StructLayout(LayoutKind.Sequential)]
        public struct AUTHZ_ACCESS_REQUEST
        {
            public int DesiredAccess;
            public byte[] PrincipalSelfSid;
            public OBJECT_TYPE_LIST[] ObjectTypeList;
            public int ObjectTypeListLength;
            public IntPtr OptionalArguments;
        };

        [StructLayout(LayoutKind.Sequential)]
        public struct AUTHZ_ACCESS_REPLY
        {
            public int ResultListLength;
            public IntPtr GrantedAccessMask;
            public IntPtr SaclEvaluationResults;
            public IntPtr Error;
        };

        /*
         * __in       DWORD flags,
         * __in       AUHZ_CLIENT_CONTEXT_HANDLE hAuthzClientContext,
         * __in       PAUTHZ_ACCESS_REQUEST pRequest,
         * __in_opt   AUTHZ_AUDIT_EVENT_HANDLE AuditEvent,
         * __in       PSECURITY_DESCRIPTOR pSecurityDescriptor,
         * __in_opt   PSECURITY_DESCRIPTOR *OptionalSecurityDescriptorArray,
         * __in_opt   DWORD OptionalSecurityDescriptorCount,
         * __inout    PAUTHZ_ACCESS_REPLY pReply,
         * __out_opt  PAUTHZ_ACCESS_CHECK_RESULTS_HANDLE phAccessCheckResults
         */
        [DllImport("authz.dll", EntryPoint = "AuthzAccessCheck", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
        private static extern bool AuthzAccessCheck(int flags, IntPtr hAuthzClientContext,
            IntPtr pRequest, IntPtr AuditEvent,
            [MarshalAs(UnmanagedType.LPArray)] byte[] pSecurityDescriptor, [MarshalAs(UnmanagedType.LPArray)] byte[] OptionalSecurityDescriptorArray,
            int OptionalSecurityDescriptorCount, ref IntPtr pReply, out IntPtr phAccessCheckResults);


        /*
         * BOOL WINAPI AuthzInitializeResourceManager(
         * __in      DWORD flags,
         * __in_opt  PFN_AUTHZ_DYNAMIC_ACCESS_CHECK pfnAccessCheck,
         * __in_opt  PFN_AUTHZ_COMPUTE_DYNAMIC_GROUPS pfnComputeDynamicGroups,
         * __in_opt  PFN_AUTHZ_FREE_DYNAMIC_GROUPS pfnFreeDynamicGroups,
         * __in      PCWSTR szResourceManagerName,
         * __out     PAUTHZ_RESOURCE_MANAGER_HANDLE phAuthzResourceManager
         */
        [DllImport("authz.dll", EntryPoint = "AuthzInitializeResourceManager", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
        private static extern bool AuthzInitializeResourceManager(int flags, IntPtr pfnAccessCheck, IntPtr pfnComputeDynamicGroups,
            IntPtr pfnFreeDynamicGroups, string szResourceManagerName, out IntPtr phAuthzResourceManager);


        /*
         * BOOL WINAPI AuthzInitializeContextFromSid(
         * __in      DWORD Flags,
         * __in      PSID UserSid,
         * __in_opt  AUTHZ_RESOURCE_MANAGER_HANDLE hAuthzResourceManager,
         * __in      PLARGE_INTEGER pExpirationTime,
         * __in      LUID Identifier,
         * __in_opt  PVOID DynamicGroupArgs,
         * __out     PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
         */
        [DllImport("authz.dll", EntryPoint = "AuthzInitializeContextFromSid", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
        private static extern bool AuthzInitializeContextFromSid(int flags, byte[] UserSid, IntPtr hAuthzResourceManager, IntPtr pExpirationTime,
            LUID Identifier, IntPtr DynamicGroupArgs, out IntPtr pAuthzClientContext);


        [DllImport("authz.dll", EntryPoint = "AuthzFreeContext", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
        private static extern bool AuthzFreeContext(IntPtr hAuthzCLientContext);


        [DllImport("authz.dll", EntryPoint = "AuthzFreeResourceManager", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
        private static extern bool AuthzFreeResourceManager(IntPtr hAuthzResourceManager);
    }
}
1

There are 1 answers

0
mark On BEST ANSWER

I figured out the problem, turns out it was a marshalling issue. The correct signature for AuthzAccessCheck is

[DllImport("authz.dll", EntryPoint = "AuthzAccessCheck", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
private static extern bool AuthzAccessCheck(int flags, IntPtr hAuthzClientContext,
    ref AUTHZ_ACCESS_REQUEST pRequest, IntPtr AuditEvent,
    byte[] pSecurityDescriptor, byte[] OptionalSecurityDescriptorArray,
    int OptionalSecurityDescriptorCount, ref AUTHZ_ACCESS_REPLY pReply, out IntPtr phAccessCheckResults);

and the proper way to use it is to not manually marshal the structures. Here's the snippet which works for me...

reply.Error = Marshal.AllocHGlobal(1020);
reply.GrantedAccessMask = Marshal.AllocHGlobal(sizeof(uint));
reply.ResultListLength = 1;

if (!AuthzAccessCheck((int)AuthzAccessCheckFlags.NONE, hClientContext, ref request, IntPtr.Zero, dacl_bytes, null, 0, ref reply, out check_results))
{
    int err = Marshal.GetLastWin32Error();
    ret = new FunctionResult<int>("AuthzAccessCheck Error[" + err + "] : " + ResultWin32.GetErrorName(err));
    break;
}
int granted_access = Marshal.ReadInt32(reply.GrantedAccessMask);