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);
}
}
I figured out the problem, turns out it was a marshalling issue. The correct signature for AuthzAccessCheck is
and the proper way to use it is to not manually marshal the structures. Here's the snippet which works for me...