How would I deleted a sub directory of a directory that has deny for "List folder contents"? The description for the "List Folder/Read Data" permission can be found here but I could not find Microsoft documentation on it.
Here is how the directory structure and how the permissions are setup.
C:\Temp\A\B\test.txt
Here is the code I have tried with results in the comments for the code. Also above each method I have included a comment stating what values for path I have tried. I never attempted to delete a directory that had children for all these examples. I am either attempting to delete a file or a empty directory.
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool RemoveDirectory(string lpPathName);
//C:\Temp\A - Success
//C:\Temp\A\B - Fail
private void RemoveDirectoryImpl(string path)
{
if (!RemoveDirectory(path))
//Returns error code 5 "access denied"
Debug.WriteLine(Marshal.GetLastWin32Error());
}
//C:\Temp\A - Success
//C:\Temp\A\B - Fail
private void DirectoryInfoDeleteImpl(string path)
{
DirectoryInfo directoryInfo = new DirectoryInfo(path);
//this throws an UnauthorizedAccessException but the directory is empty so it has no read-only files and the directory itself is not read-only.
directoryInfo.Delete();
}
//C:\Temp\A - Success
//C:\Temp\A\B - Fail
private void DirectoryDeleteImpl(string path)
{
//this throws an UnauthorizedAccessException but the directory is empty so it has no read-only files and the directory itself is not read-only.
Directory.Delete(path);
}
I can add and delete file in B for some reason. Also I can delete the root directory with the deny "List folder contents" as long as it is empty.
//C:\Temp\A\B\test.txt - Success
private void FileDeleteImpl(string path)
{
//this is successful and does not throw an error.
File.Delete(path);
}
I did find Bypass Traverse Checking which was interesting. I confirmed that our group policy settings still have the Everyone group as part of it.
Here is a screen shot of my security tab for the directory too.
EDIT 1:
Using the information @rbmm gave me in the comments I was able to put together this code but it still will not delete the directory. I tried this code after giving myself "List folder contents" and it worked. Nothing errors in this code.
private void BackupPrivilegeDeleteImpl(string path)
{
TOKEN_PRIVILEGES tokenPrivileges = new TOKEN_PRIVILEGES();
tokenPrivileges.Privileges = new LUID_AND_ATTRIBUTES[40];
IntPtr token = IntPtr.Zero;
try
{
bool success = OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_ADJUST_PRIVILEGES, ref token);
if (!success)
throw new Win32Exception(Marshal.GetLastWin32Error());
success = LookupPrivilegeValue(null, SE_BACKUP_NAME, ref tokenPrivileges.Privileges[0].Luid);
if (!success)
throw new Win32Exception(Marshal.GetLastWin32Error());
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
success = AdjustTokenPrivileges(token, false, ref tokenPrivileges, (uint)Marshal.SizeOf(tokenPrivileges), IntPtr.Zero, IntPtr.Zero);
if (!success)
throw new Win32Exception(Marshal.GetLastWin32Error());
//Directory always comes back as the value 0xffffffff
IntPtr directory = CreateFile(path, EFileAccessMasks.Delete, EFileShare.Delete, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.DeleteOnClose | EFileAttributes.ReparsePoint | EFileAttributes.BackupSemantics, IntPtr.Zero);
CloseHandle(directory);
Debug.WriteLine(success.ToString());
}
catch (Win32Exception e)
{
tbLastError.Text = e.NativeErrorCode.ToString();
Debug.WriteLine(e.ToString());
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
finally
{
CloseHandle(token);
}
}
EDIT2:
As per @eryksun request added output from accessschk.
C:\Temp\A
DESCRIPTOR FLAGS:
[SE_DACL_PRESENT]
[SE_DACL_PROTECTED]
OWNER: REDACTED
[0] ACCESS_DENIED_ACE_TYPE: NT AUTHORITY\Authenticated Users
[CONTAINER_INHERIT_ACE]
FILE_LIST_DIRECTORY
FILE_READ_ATTRIBUTES
FILE_READ_EA
FILE_TRAVERSE
READ_CONTROL
[1] ACCESS_ALLOWED_ACE_TYPE: NT AUTHORITY\Authenticated Users
[OBJECT_INHERIT_ACE]
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_ADD_FILE
FILE_ADD_SUBDIRECTORY
FILE_LIST_DIRECTORY
FILE_READ_ATTRIBUTES
FILE_READ_EA
FILE_TRAVERSE
FILE_WRITE_ATTRIBUTES
FILE_WRITE_EA
SYNCHRONIZE
READ_CONTROL
[2] ACCESS_ALLOWED_ACE_TYPE: NT AUTHORITY\SYSTEM
[OBJECT_INHERIT_ACE]
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_ALL_ACCESS
[3] ACCESS_ALLOWED_ACE_TYPE: REDACTED
[OBJECT_INHERIT_ACE]
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_ALL_ACCESS
[4] ACCESS_ALLOWED_ACE_TYPE: BUILTIN\Administrators
[OBJECT_INHERIT_ACE]
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_ALL_ACCESS
[5] ACCESS_ALLOWED_ACE_TYPE: BUILTIN\Users
[OBJECT_INHERIT_ACE]
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_ALL_ACCESS
Accesschk v6.12 - Reports effective permissions for securable objects Copyright (C) 2006-2017 Mark Russinovich Sysinternals - www.sysinternals.com
C:\Temp\A\B
DESCRIPTOR FLAGS:
[SE_DACL_PRESENT]
[SE_DACL_PROTECTED]
OWNER: REDACTED
[0] ACCESS_DENIED_ACE_TYPE: NT AUTHORITY\Authenticated Users
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_LIST_DIRECTORY
FILE_READ_ATTRIBUTES
FILE_READ_EA
FILE_TRAVERSE
READ_CONTROL
[1] ACCESS_ALLOWED_ACE_TYPE: NT AUTHORITY\Authenticated Users
[OBJECT_INHERIT_ACE]
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_ADD_FILE
FILE_ADD_SUBDIRECTORY
FILE_LIST_DIRECTORY
FILE_READ_ATTRIBUTES
FILE_READ_EA
FILE_TRAVERSE
FILE_WRITE_ATTRIBUTES
FILE_WRITE_EA
SYNCHRONIZE
READ_CONTROL
[2] ACCESS_ALLOWED_ACE_TYPE: NT AUTHORITY\SYSTEM
[OBJECT_INHERIT_ACE]
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_ALL_ACCESS
[3] ACCESS_ALLOWED_ACE_TYPE: REDACTED
[OBJECT_INHERIT_ACE]
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_ALL_ACCESS
[4] ACCESS_ALLOWED_ACE_TYPE: BUILTIN\Administrators
[OBJECT_INHERIT_ACE]
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_ALL_ACCESS
[5] ACCESS_ALLOWED_ACE_TYPE: BUILTIN\Users
[OBJECT_INHERIT_ACE]
[CONTAINER_INHERIT_ACE]
[INHERITED_ACE]
FILE_ALL_ACCESS
Here is the final code for getting the delete to work. Thank you to @eryksun and @rbmm for their help on getting this to work and giving me the correct win32 api calls I needed to make. My biggest issue here was that I was marshaling the LUID on this line LookupPrivilegeValue(null, "SeBackupPrivilege", ref tokenPrivileges.Privileges[0].Luid)
as a uint and not as a LUID struct. After setting my privileges on the token I was able to use the managed C# delete method for directory since under the hood it is just calling RemoveDirectory
. Also I started checking if AdjustPrivileges
was successful based on the bool it returned as well as always using Marshal.GetLastWin32Error() != 0
which really helped debug this.
private void BackupPrivilegeDeleteImpl(string path)
{
TOKEN_PRIVILEGES tokenPrivileges = new TOKEN_PRIVILEGES();
tokenPrivileges.Privileges = new LUID_AND_ATTRIBUTES[1];
IntPtr token = IntPtr.Zero;
try
{
bool success = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, ref token);
if (!success)
throw new Win32Exception(Marshal.GetLastWin32Error());
success = LookupPrivilegeValue(null, "SeBackupPrivilege", ref tokenPrivileges.Privileges[0].Luid);
if (!success)
throw new Win32Exception(Marshal.GetLastWin32Error());
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
success = AdjustTokenPrivileges(token, false, ref tokenPrivileges, (uint)Marshal.SizeOf(tokenPrivileges), IntPtr.Zero, IntPtr.Zero);
if (!success || Marshal.GetLastWin32Error() != 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!RemoveDirectory(path))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
catch (Win32Exception e)
{
tbLastError.Text = e.NativeErrorCode.ToString();
Debug.WriteLine(e.ToString());
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
finally
{
CloseHandle(token);
}
}
Use SetAccessControl()
of DirectoryInfo
to provide access on directory if your application running with admin privilege.
User contributions licensed under CC BY-SA 3.0