20
Dec
Off

On filesystem permission

When manipulating the file System you can give it a “try/catch”
This is rather inelegant.

If you only want to check weather a certain user would have the necessary rights it becomes more nasty:
You will have to use impersonation, will run the risk that the user can write but not delete the random testfile afterwards.

Nominal vs. effective permissions

Nominal permissions

checks whether a user or group is permitted via Access Control ACL.
Only the explicit or intherited (from folders above) permissions of the user or group are checked.

If you want to check the effective permissions you have to iterate through all groups the user/group is assigned to.

 

Effective permissions

Often this is what you want. This tells you what can be done without iterating through all Groups the user is assigned to.

 

Nominal permissions can be handled by managed code:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
 
namespace CheckDirPermission
{
    public class FileSystemNominalPermission
    {
        /// <summary>
        /// Resolve weather a user or group has a defined permission in the filesystem (file or folder)
        /// </summary>
        /// <param name="identity">user or group name</param>
        /// <param name="path">full path to folder or file</param>
        /// <param name="right">single enum or flag combination of FileSystemRights</param>
        /// <returns>true if permission is granted</returns>
        /// <example>bool hasPermission = IdentityHasPerimission(@"NT-AUTORITÄT\SYSTEM", @"c:\", FileSystemRights.Read);</example>
        public static bool IdentityHasPerimission(string identity, string path, FileSystemRights right)
        {
            var rules = AuthRules(path, explicitDefinition: true, implicitDefinition: true)
                .Where(rule => rule.FileSystemRights.HasFlag(right) && string.Equals(rule.IdentityReference.ToString(), identity, StringComparison.InvariantCultureIgnoreCase))
                .ToArray();
            //check that the right is somewhere allowed and nowhere denied
            return rules.Any(rule => rule.AccessControlType == AccessControlType.Allow)
                && !rules.Any(rule => rule.AccessControlType == AccessControlType.Deny);
        }
 
        /// <summary>
        /// returns FileSystemAccessRules for a given folder or file
        /// </summary>
        /// <param name="path">full path to folder or file</param>
        /// <param name="explicitDefinition">use definitions explicitly defined for the folder/file defined</param>
        /// <param name="implicitDefinition">use definitions </param>
        /// <returns></returns>
        /// <exception cref="FileNotFoundException">Path is invalid</exception>
        /// <exception cref="UnauthorizedAccessException">The current user may have no right to query access control for the path given</exception>
        public static IEnumerable<FileSystemAccessRule> AuthRules(string path, bool explicitDefinition, bool implicitDefinition)
        {
            var isDirectory = DirectoryHelper.PathIsDirectoryManaged(path);
            if (!isDirectory.HasValue)
            {
                throw new FileNotFoundException("Path is invalid");
            }
                
 
            FileSystemSecurity accessControlList = null;
            Func<stringAccessControlSectionsFileSystemSecurity> GetAccessControlDelegate;
            if (isDirectory.Value)
                GetAccessControlDelegate = Directory.GetAccessControl;
            else
                GetAccessControlDelegate = File.GetAccessControl;
 
            try
            {
                accessControlList = GetAccessControlDelegate.Invoke(path, AccessControlSections.Access);
            }
            catch (Exception)
            {
                throw new UnauthorizedAccessException("The current user may have no right to query access control for the path given");
            }
            if (accessControlList == null)
                yield break;
            var accessRules = accessControlList.GetAccessRules(
                includeExplicit: explicitDefinition,
                includeInherited: implicitDefinition,
                targetType: typeof(System.Security.Principal.NTAccount));
            if (accessRules == null)
                yield break;
            foreach (var rule in accessRules)
            {
                yield return rule as FileSystemAccessRule;
            }
        }
 
    }
}

For effective permissions unmanaged win32 DLL access is required:

using System;
using System.Runtime.InteropServices;
 
namespace CheckDirPermission
{
    public class FileSystemEffectivePermission
    {
        public static bool EffectivePermissionInDirectory(TRUSTEE trustee, string path, ACCESS_MASK permissionMask)
        {
            IntPtr pSidOwner, pSidGroup, pDacl, pSacl, pSecurityDescriptor;
            uint ret = GetNamedSecurityInfo(path,
                SE_OBJECT_TYPE.SE_FILE_OBJECT,
                SECURITY_INFORMATION.DACL_SECURITY_INFORMATION,
                out pSidOwner, out pSidGroup, out pDacl, out pSacl, out pSecurityDescriptor);
 
            var mask = new ACCESS_MASK();
            ret = GetEffectiveRightsFromAcl(pDacl, ref trustee, ref mask);
 
            return mask.HasFlag(permissionMask);
        }
 
        public static bool EffectivePermissionInDirectory(string name, TRUSTEE_FORM form, TRUSTEE_TYPE type, string path, ACCESS_MASK permissionMask)
        {
            var trustee = new TRUSTEE();
            trustee.TrusteeForm = form;
            trustee.TrusteeType = type;
            trustee.ptstrName = name;
 
            return EffectivePermissionInDirectory(trustee,path,permissionMask);
        }
 
        public static bool EffectiveUserPermissionInDirectory(string user, string path, ACCESS_MASK permissionMask)
        {
            var trustee = new TRUSTEE();
            trustee.TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_NAME;
            trustee.TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_USER;
            trustee.ptstrName = user;
 
            return EffectivePermissionInDirectory(trustee, path, permissionMask);
        }
 
        public static bool EffectiveGroupPermissionInDirectory(string group, string path, ACCESS_MASK permissionMask)
        {
            var trustee = new TRUSTEE();
            trustee.TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_NAME;
            trustee.TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_GROUP;
            trustee.ptstrName = group;
 
            return EffectivePermissionInDirectory(trustee, path, permissionMask);
        }
 
 
        public enum ACCESS_MASK : uint
        {   //https://msdn.microsoft.com/de-de/library/windows/desktop/aa374892(v=vs.85).aspx
            //https://blogs.msdn.microsoft.com/openspecification/2010/04/01/about-the-access_mask-structure/
            DELETE = 0x00010000,
            READ_CONTROL = 0x00020000,
            WRITE_DAC = 0x00040000,
            WRITE_OWNER = 0x00080000,
            SYNCHRONIZE = 0x00100000,
 
            STANDARD_RIGHTS_REQUIRED = 0x000f0000,
 
            STANDARD_RIGHTS_READ = 0x00020000,
            STANDARD_RIGHTS_WRITE = 0x00020000,
            STANDARD_RIGHTS_EXECUTE = 0x00020000,
 
            STANDARD_RIGHTS_ALL = 0x001f0000,
 
            SPECIFIC_RIGHTS_ALL = 0x0000ffff,
 
            ACCESS_SYSTEM_SECURITY = 0x01000000,
 
            MAXIMUM_ALLOWED = 0x02000000,
 
            //GENERIC_READ = 0x80000000,
            //GENERIC_WRITE = 0x40000000,
            //GENERIC_EXECUTE = 0x20000000,
            //GENERIC_ALL = 0x10000000,
 
            //DESKTOP_READOBJECTS = 0x00000001,
            //DESKTOP_CREATEWINDOW = 0x00000002,
            //DESKTOP_CREATEMENU = 0x00000004,
            //DESKTOP_HOOKCONTROL = 0x00000008,
            //DESKTOP_JOURNALRECORD = 0x00000010,
            //DESKTOP_JOURNALPLAYBACK = 0x00000020,
            //DESKTOP_ENUMERATE = 0x00000040,
            //DESKTOP_WRITEOBJECTS = 0x00000080,
            //DESKTOP_SWITCHDESKTOP = 0x00000100,
 
            //WINSTA_ENUMDESKTOPS = 0x00000001,
            //WINSTA_READATTRIBUTES = 0x00000002,
            //WINSTA_ACCESSCLIPBOARD = 0x00000004,
            //WINSTA_CREATEDESKTOP = 0x00000008,
            //WINSTA_WRITEATTRIBUTES = 0x00000010,
            //WINSTA_ACCESSGLOBALATOMS = 0x00000020,
            //WINSTA_EXITWINDOWS = 0x00000040,
            //WINSTA_ENUMERATE = 0x00000100,
            //WINSTA_READSCREEN = 0x00000200,
 
            //WINSTA_ALL_ACCESS = 0x0000037f
        }
 
        public enum TRUSTEE_FORM
        {
            TRUSTEE_IS_SID,
            TRUSTEE_IS_NAME,
            TRUSTEE_BAD_FORM,
            TRUSTEE_IS_OBJECTS_AND_SID,
            TRUSTEE_IS_OBJECTS_AND_NAME
        }
        public enum TRUSTEE_TYPE
        {
            TRUSTEE_IS_UNKNOWN,
            TRUSTEE_IS_USER,
            TRUSTEE_IS_GROUP,
            TRUSTEE_IS_DOMAIN,
            TRUSTEE_IS_ALIAS,
            TRUSTEE_IS_WELL_KNOWN_GROUP,
            TRUSTEE_IS_DELETED,
            TRUSTEE_IS_INVALID,
            TRUSTEE_IS_COMPUTER
        }
 
 
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
        public struct TRUSTEE
        {
            IntPtr pMultipleTrustee; // must be null
            public int MultipleTrusteeOperation;
            public TRUSTEE_FORM TrusteeForm;
            public TRUSTEE_TYPE TrusteeType;
            [MarshalAs(UnmanagedType.LPStr)]
            public string ptstrName;
        }
 
        
        [DllImport("advapi32.dll", SetLastError = true)]
        static extern uint GetEffectiveRightsFromAcl(IntPtr pDacl, ref TRUSTEE pTrustee, ref ACCESS_MASK pAccessRights);
 
 
 
        [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);
 
 
        [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,
            SE_SERVICE,
            SE_PRINTER,
            SE_REGISTRY_KEY,
            SE_LMSHARE,
            SE_KERNEL_OBJECT,
            SE_WINDOW_OBJECT,
            SE_DS_OBJECT,
            SE_DS_OBJECT_ALL,
            SE_PROVIDER_DEFINED_OBJECT,
            SE_WMIGUID_OBJECT,
            SE_REGISTRY_WOW64_32KEY
        }
    }
}