GetSecurityInfo always returns Access Denied

2

I am trying to get file owner using GetSecurityInfo, but get GetSecurityInfo is always returning 5, "ACCESS DENIED" even if I have access to get ownership of the file. The .NET method "GetOwner" works, but I need long filename support, and am restricted from using .NET 4.6.2 or 3rd party .NET libraries which adds long filename support.

I want to get file owner, in a way that handles long filenames (longer than 260 characters) and will work in .NET 4.0.

Works but doesn't handle long file paths

var fs = File.GetAccessControl(filename);

    var sid = fs.GetOwner(typeof(SecurityIdentifier));
    Console.WriteLine(sid); // SID

    var ntAccount = sid.Translate(typeof(NTAccount));

Should handle long file paths, but always returns Access Denied:

FileAccess.Read = 1 FileShare.ReadWrite = 3

[Flags]
            public enum FileAttributes : uint
            {
                /// <summary>
                /// A file that is read-only. Applications can read the file, but cannot write to it or delete it. This attribute is not honored on directories. For more information, see "You cannot view or change the Read-only or the System attributes of folders in Windows Server 2003, in Windows XP, or in Windows Vista".
                /// </summary>
                Readonly = 0x00000001,

                /// <summary>
                /// The file or directory is hidden. It is not included in an ordinary directory listing.
                /// </summary>
                Hidden = 0x00000002,

                /// <summary>
                /// A file or directory that the operating system uses a part of, or uses exclusively.
                /// </summary>
                System = 0x00000004,

                /// <summary>
                /// The handle that identifies a directory.
                /// </summary>
                Directory = 0x00000010,

                /// <summary>
                /// A file or directory that is an archive file or directory. Applications typically use this attribute to mark files for backup or removal.
                /// </summary>
                Archive = 0x00000020,

                /// <summary>
                /// This value is reserved for system use.
                /// </summary>
                Device = 0x00000040,

                /// <summary>
                /// A file that does not have other attributes set. This attribute is valid only when used alone.
                /// </summary>
                Normal = 0x00000080,

                /// <summary>
                /// A file that is being used for temporary storage. File systems avoid writing data back to mass storage if sufficient cache memory is available, because typically, an application deletes a temporary file after the handle is closed. In that scenario, the system can entirely avoid writing the data. Otherwise, the data is written after the handle is closed.
                /// </summary>
                Temporary = 0x00000100,

                /// <summary>
                /// A file that is a sparse file.
                /// </summary>
                SparseFile = 0x00000200,

                /// <summary>
                /// A file or directory that has an associated reparse point, or a file that is a symbolic link.
                /// </summary>
                ReparsePoint = 0x00000400,

                /// <summary>
                /// A file or directory that is compressed. For a file, all of the data in the file is compressed. For a directory, compression is the default for newly created files and subdirectories.
                /// </summary>
                Compressed = 0x00000800,

                /// <summary>
                /// The data of a file is not available immediately. This attribute indicates that the file data is physically moved to offline storage. This attribute is used by Remote Storage, which is the hierarchical storage management software. Applications should not arbitrarily change this attribute.
                /// </summary>
                Offline = 0x00001000,

                /// <summary>
                /// The file or directory is not to be indexed by the content indexing service.
                /// </summary>
                NotContentIndexed = 0x00002000,

                /// <summary>
                /// A file or directory that is encrypted. For a file, all data streams in the file are encrypted. For a directory, encryption is the default for newly created files and subdirectories.
                /// </summary>
                Encrypted = 0x00004000,

                /// <summary>
                /// This value is reserved for system use.
                /// </summary>
                Virtual = 0x00010000
            }

    [DllImport("kernel32.dll", SetLastError = true)]
            internal static extern IntPtr LocalFree(
                IntPtr handle
            );

    [DllImport("advapi32.dll", SetLastError = true)]
            static extern int GetSecurityInfo(
            SafeFileHandle handle,
            SE_OBJECT_TYPE objectType,
            SECURITY_INFORMATION securityInfo,
            out IntPtr sidOwner,
            out IntPtr sidGroup,
            out IntPtr dacl,
            out IntPtr sacl,
            out IntPtr securityDescriptor);


            enum SE_OBJECT_TYPE
            {
                SE_UNKNOWN_OBJECT_TYPE,
                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
            }

            enum SECURITY_INFORMATION
            {
                OWNER_SECURITY_INFORMATION = 1,
                GROUP_SECURITY_INFORMATION = 2,
                DACL_SECURITY_INFORMATION = 4,
                SACL_SECURITY_INFORMATION = 8,
            }

    public static string GetOwner(string filename)
            {
                string owner = "";
                var hFile = CreateFile(
                    filename,
                    FileAccess.Read,
                    FileShare.ReadWrite,
                    IntPtr.Zero,
                    FileMode.Open,
                    FileAttributes.Normal, 
                    IntPtr.Zero);

                if (!hFile.IsInvalid)
                {
                    IntPtr ownerSid;
                    IntPtr groupSid = IntPtr.Zero;
                    IntPtr dacl = IntPtr.Zero;
                    IntPtr sacl = IntPtr.Zero;
                    IntPtr securityDescriptor = IntPtr.Zero;

                    int returnValue = GetSecurityInfo(
                        hFile,
                        SE_OBJECT_TYPE.SE_FILE_OBJECT,
                        SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION,
                        out ownerSid,
                        out groupSid,
                        out dacl,
                        out sacl,
                        out securityDescriptor
                        );

                    if (returnValue == ERROR_SUCCESS)
                    {
                        IntPtr sidString = IntPtr.Zero;
                        var sid = new SecurityIdentifier(ownerSid);
                        var ntAccount = sid.Translate(typeof(NTAccount));
                        owner = ntAccount.ToString();
                    }
                    else
                    {
                        Win32Exception exception = new Win32Exception(returnValue);
                        owner = string.Format("Failed to get owner: {0}", exception.Message);
                    }

                    LocalFree(securityDescriptor);
                }
                else
                {
                    Win32Exception exception = new Win32Exception(Marshal.GetLastWin32Error());
                    owner = string.Format("Failed to open file when getting owner: {0}", exception.Message);
                }
                return owner;
            }
c#
winapi
pinvoke
asked on Stack Overflow May 17, 2018 by Malcolm McCaffery • edited May 17, 2018 by Malcolm McCaffery

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0