Mid*_*das 3 c# impersonation file-io file-exists
基于对MSDN文档中File.Exists,该File.Exists方法应该返回false的任何错误,包括没有获得主叫用户读取文件.
我希望它false在文件被设置为FullControl拒绝给用户时返回,并FullControl拒绝用户拒绝该文件所在的目录.
我所看到的是当用户访问目录而不是文件时,File.Exists返回true; 但是,如果用户无权访问该目录,则File.Exists返回false.
我写了一个小程序来演示我在说什么:
using System;
using System.DirectoryServices;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
namespace ConsoleApplication1
{
internal class Program
{
private const string DirName = "TestDir";
private const string FileName = "File.txt";
private const string Password = "Password1";
private const string UserName = "PermissionTestUser";
private static WindowsImpersonationContext Identity = null;
private static IntPtr LogonToken = IntPtr.Zero;
public enum LogonProvider
{
LOGON32_PROVIDER_DEFAULT = 0,
LOGON32_PROVIDER_WINNT35 = 1,
LOGON32_PROVIDER_WINNT40 = 2,
LOGON32_PROVIDER_WINNT50 = 3
};
public enum LogonType
{
LOGON32_LOGON_INTERACTIVE = 2,
LOGON32_LOGON_NETWORK = 3,
LOGON32_LOGON_BATCH = 4,
LOGON32_LOGON_SERVICE = 5,
LOGON32_LOGON_UNLOCK = 7,
LOGON32_LOGON_NETWORK_CLEARTEXT = 8, // Win2K or higher
LOGON32_LOGON_NEW_CREDENTIALS = 9 // Win2K or higher
};
public static void Main(string[] args)
{
string filePath = Path.Combine(DirName, FileName);
try
{
CreateUser();
CreateDir();
CreateFile(filePath);
// grant user full control to the dir
SetAccess(DirName, AccessControlType.Allow);
// deny user full control to the file
SetAccess(filePath, AccessControlType.Deny);
// impersonate user
Impersonate();
Console.WriteLine("File.Exists (with dir permissions): {0}", File.Exists(filePath));
UndoImpersonate();
// deny access to dir
SetAccess(DirName, AccessControlType.Deny);
// impersonate user
Impersonate();
Console.WriteLine("File.Exists (without dir permissions): {0}", File.Exists(filePath));
UndoImpersonate();
}
finally
{
UndoImpersonate();
DeleteDir();
DeleteUser();
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr handle);
private static void CreateDir()
{
Directory.CreateDirectory(DirName);
}
private static void CreateFile(string path)
{
File.Create(path).Dispose();
}
private static void CreateUser()
{
DirectoryEntry ad = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
DirectoryEntry newUser = ad.Children.Add(UserName, "user");
newUser.Invoke("SetPassword", new object[] { Password });
newUser.Invoke("Put", new object[] { "Description", "Test user" });
newUser.CommitChanges();
}
private static void DeleteDir()
{
Directory.Delete(DirName, true);
}
private static void DeleteUser()
{
DirectoryEntry ad = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
DirectoryEntries users = ad.Children;
DirectoryEntry user = users.Find(UserName, "user");
if (user != null)
{
users.Remove(user);
}
}
private static void Impersonate()
{
if (LogonUser(UserName, ".", Password, (int)LogonType.LOGON32_LOGON_INTERACTIVE, (int)LogonProvider.LOGON32_PROVIDER_DEFAULT, ref LogonToken))
{
Identity = WindowsIdentity.Impersonate(LogonToken);
return;
}
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool LogonUser(string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
private static void SetAccess(string path, AccessControlType type)
{
FileSecurity fs = File.GetAccessControl(path);
FileSystemAccessRule far = new FileSystemAccessRule(UserName, FileSystemRights.FullControl, type);
fs.AddAccessRule(far);
File.SetAccessControl(path, fs);
}
private static void UndoImpersonate()
{
if (Identity != null)
{
Identity.Undo();
Identity = null;
}
if (LogonToken != IntPtr.Zero)
{
CloseHandle(LogonToken);
LogonToken = IntPtr.Zero;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行此程序的结果是:
File.Exists (with dir permissions): True
File.Exists (without dir permissions): False
Run Code Online (Sandbox Code Playgroud)
谁能解释为什么他们不同?在这两种情况下,用户都没有对该文件的读访问权.
这是默认行为File.Exist.根据MSDN:
File.Exist返回值类型:
System.Boolean如果调用者具有所需权限并且path包含现有文件的名称,则为true;否则为false.否则,错误.如果path为null,无效路径或零长度字符串,则此方法也返回false.如果调用者没有足够的权限来读取指定的文件,则不会抛出异常,并且无论路径是否存在,该方法都返回false.
另外
该
Exists方法不应用于路径验证,此方法仅检查路径中指定的文件是否存在.将无效路径传递给Exists将返回false.
换句话说,将所需的权限在这里,是要知道所需的权限,该文件的存在(如法顾名思义,File.Exist).这意味着只要用户有权访问该目录,就可以知道该文件是否存在.
在给定目录权限的情况下,用户是否具有文件访问权限不会影响用户对文件存在的了解.但是没有目录权限,用户就无法知道文件的存在,从而File.Exist返回false
编辑(在评论反馈后):
可能相当令人困惑的部分将是最后一句话:
如果调用者没有足够的权限来读取指定的文件,则不会抛出异常,并且无论路径是否存在,该方法都返回false.
读取指定文件的足够权限取决于父目录的读访问权限,而不是指定文件的读访问权限.(Rob先生补充评论).单词"足够"可能会提示某些行为,它只依赖于对父目录的读访问,而不是对指定文件的读访问.
但我承认,解释和单词的选择可能听起来相当直观,因为人们可能直观地将"读取指定文件的足够权限"解释为对指定文件的读访问而不是父目录.