0
votes

Is there api in .net for getting effective folder permissions for user? I know how get permissions by using `DirectorySecurity.GetAccessRules(). But in this case I should manually analyze all permissions for user: permissions for groups, that include the user, inherited permissions and user permission for folder.

Is there a function in the Windows API that can return these permissions via platform invoke?

1
The solution is described in this topic doesn't work. The function GetEffectiveRightsFromAcl is sensetive to order of access rules. - SullenMan
And that's a problem why? Regular access checks are also sensitive to the order of access rules. Can you show an example where GetEffectiveRightsFromAcl doesn't do what you want it to do, and what you're expecting to happen instead? - Jeroen Mostert

1 Answers

-1
votes

class Program { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] public struct LUID { public uint LowPart; public int HighPart; }

    [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 OBJECT_TYPE_LIST
    {
        OBJECT_TYPE_LEVEL Level;
        int Sbz;
        IntPtr ObjectType;
    };

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

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


    enum AUTHZ_RM_FLAG : uint
    {
        AUTHZ_RM_FLAG_NO_AUDIT = 1,
        AUTHZ_RM_FLAG_INITIALIZE_UNDER_IMPERSONATION = 2,
        AUTHZ_RM_FLAG_NO_CENTRAL_ACCESS_POLICIES = 4,
    }



    [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
    static extern uint GetNamedSecurityInfo(
        string pObjectName,
        SE_OBJECT_TYPE ObjectType,
        SECURITY_INFORMATION SecurityInfo,
        out IntPtr pSidOwner,
        out IntPtr pSidGroup,
        out IntPtr pDacl,
        out IntPtr pSacl,
        out IntPtr pSecurityDescriptor);
    [DllImport("authz.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, EntryPoint = "AuthzInitializeContextFromSid", CharSet = CharSet.Unicode)]
    static extern public bool AuthzInitializeContextFromSid(
                                           int Flags,
                                           IntPtr UserSid ,
                                           IntPtr AuthzResourceManager,
                                           IntPtr pExpirationTime,
                                           LUID Identitifier,
                                           IntPtr DynamicGroupArgs,
                                           out IntPtr pAuthzClientContext
                                           );



    [DllImport("authz.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall, EntryPoint = "AuthzInitializeResourceManager", CharSet = CharSet.Unicode)]
    static extern public bool AuthzInitializeResourceManager(
                                    int flags,
                                    IntPtr pfnAccessCheck,
                                    IntPtr pfnComputeDynamicGroups,
                                    IntPtr pfnFreeDynamicGroups,
                                    string name,
                                    out IntPtr rm
                                    );
    [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,
                                                 IntPtr pSecurityDescriptor, 
                                                byte[] OptionalSecurityDescriptorArray,
                                                int OptionalSecurityDescriptorCount, 
                                                ref AUTHZ_ACCESS_REPLY pReply,
                                                out IntPtr phAccessCheckResults);

    enum ACCESS_MASK : uint
    {
        FILE_TRAVERSE = 0x20,FILE_LIST_DIRECTORY = 0x1,FILE_READ_DATA = 0x1,FILE_READ_ATTRIBUTES = 0x80,FILE_READ_EA = 0x8,FILE_ADD_FILE = 0x2,FILE_WRITE_DATA = 0x2,FILE_ADD_SUBDIRECTORY = 0x4,FILE_APPEND_DATA = 0x4,FILE_WRITE_ATTRIBUTES = 0x100,FILE_WRITE_EA = 0x10,FILE_DELETE_CHILD = 0x40,DELETE = 0x10000,READ_CONTROL = 0x20000,WRITE_DAC = 0x40000,
        WRITE_OWNER = 0x80000,
    }

    [Flags]
    enum SECURITY_INFORMATION : uint
    {
        OWNER_SECURITY_INFORMATION = 0x00000001,
        GROUP_SECURITY_INFORMATION = 0x00000002,
        DACL_SECURITY_INFORMATION = 0x00000004,
        SACL_SECURITY_INFORMATION = 0x00000008,
        UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000,
        UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000,
        PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000,
        PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
    }

    enum SE_OBJECT_TYPE
    {
        SE_UNKNOWN_OBJECT_TYPE = 0,
        SE_FILE_OBJECT,
    }



    static void Main(string[] args)
    {
        //String UserName = "NT Authority\\Authenticated Users";
        do {
            Console.WriteLine("UserName:");
            String UserName = Console.ReadLine();
            SecurityIdentifier sid = null;
            NTAccount ac = new NTAccount(UserName);
            try
            {
                sid = (SecurityIdentifier)ac.Translate(typeof(SecurityIdentifier));
            }
            catch (Exception e)
            {
                Console.WriteLine("Not a group or user");
                continue;
            }
            Console.WriteLine("Path:");
            String Path = Console.ReadLine();

            if (!(File.Exists(Path) || Directory.Exists(Path)))
            {
                Console.WriteLine("Invalid Path");
                continue;
            }


            IntPtr pSidOwner, pSidGroup, pDacl, pSacl, pSecurityDescriptor;
            ACCESS_MASK mask = new ACCESS_MASK();
            uint ret = GetNamedSecurityInfo(Path,
                                            SE_OBJECT_TYPE.SE_FILE_OBJECT,
                                            SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION | SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION,
                                            out pSidOwner,
                                            out pSidGroup, 
                                            out pDacl, 
                                            out pSacl,
                                            out pSecurityDescriptor);

            IntPtr hManager = IntPtr.Zero;
            bool f = AuthzInitializeResourceManager(1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, null, out hManager);

            byte[] bytes = new byte[sid.BinaryLength];
            sid.GetBinaryForm(bytes, 0);
            String _psUserSid = "";
            foreach (byte si in bytes)
            {
                _psUserSid += si;
            }

            LUID unusedSid = new LUID();
            IntPtr UserSid = Marshal.AllocHGlobal(bytes.Length);
            Marshal.Copy(bytes, 0, UserSid, bytes.Length);
            IntPtr pClientContext = IntPtr.Zero;

            if (f)
            {
                f = AuthzInitializeContextFromSid(0, UserSid, hManager, IntPtr.Zero, unusedSid, IntPtr.Zero, out pClientContext);


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

                AUTHZ_ACCESS_REPLY reply = new AUTHZ_ACCESS_REPLY();
                reply.GrantedAccessMask = IntPtr.Zero;
                reply.ResultListLength = 0;
                reply.SaclEvaluationResults = IntPtr.Zero;
                IntPtr AccessReply = IntPtr.Zero;
                reply.Error = Marshal.AllocHGlobal(1020);
                reply.GrantedAccessMask = Marshal.AllocHGlobal(sizeof(uint));
                reply.ResultListLength = 1;
                int i = 0;
                Dictionary<String, String> rightsmap = new Dictionary<String, String>();
                List<string> effectivePermissionList = new List<string>();
                string[] rights = new string[14] { "Full Control", "Traverse Folder / execute file", "List folder / read data", "Read attributes", "Read extended attributes", "Create files / write files", "Create folders / append data", "Write attributes", "Write extended attributes", "Delete subfolders and files", "Delete", "Read permission", "Change permission", "Take ownership" };
                rightsmap.Add("FILE_TRAVERSE", "Traverse Folder / execute file");
                rightsmap.Add("FILE_LIST_DIRECTORY", "List folder / read data");
                rightsmap.Add("FILE_READ_DATA", "List folder / read data");
                rightsmap.Add("FILE_READ_ATTRIBUTES", "Read attributes");
                rightsmap.Add("FILE_READ_EA", "Read extended attributes");
                rightsmap.Add("FILE_ADD_FILE", "Create files / write files");
                rightsmap.Add("FILE_WRITE_DATA", "Create files /  write files");
                rightsmap.Add("FILE_ADD_SUBDIRECTORY", "Create folders / append data");
                rightsmap.Add("FILE_APPEND_DATA", "Create folders / append data");
                rightsmap.Add("FILE_WRITE_ATTRIBUTES", "Write attributes");
                rightsmap.Add("FILE_WRITE_EA", "Write extended attributes");
                rightsmap.Add("FILE_DELETE_CHILD", "Delete subfolders and files");
                rightsmap.Add("DELETE", "Delete");
                rightsmap.Add("READ_CONTROL", "Read permission");
                rightsmap.Add("WRITE_DAC", "Change permission");
                rightsmap.Add("WRITE_OWNER", "Take ownership");


                f = AuthzAccessCheck(0, pClientContext, ref request, IntPtr.Zero, pSecurityDescriptor, null, 0, ref reply, out AccessReply);
                if (f)
                {
                    int granted_access = Marshal.ReadInt32(reply.GrantedAccessMask);

                     mask = (ACCESS_MASK)granted_access;

                    foreach (ACCESS_MASK item in Enum.GetValues(typeof(ACCESS_MASK)))
                    {
                        if ((mask & item) == item)
                        {
                            effectivePermissionList.Add(rightsmap[item.ToString()]);
                            i++;
                        }

                    }
                }
                Marshal.FreeHGlobal(reply.GrantedAccessMask);




                if (i == 16)
                {
                    effectivePermissionList.Insert(0, "Full Control");
                }
                Console.WriteLine(".......................");
                foreach (string r in rights)
                {
                    if (effectivePermissionList.Contains(r))
                    {
                        Console.WriteLine(r);
                    }
                }

            }
            Console.WriteLine("_________________________________________________\n");
        } while (true);

       // Console.ReadLine();
    }

}