问题:至少在没有管理员权限的情况下,需要防止单个Windows文件被删除。文件必须可由“所有人”读取。文件所在的Windows目录必须是“所有人”可读写的。
调试:下面的示例代码是我尝试在示例文件上设置“拒绝删除”访问控制规则(执行此代码时,字符串“ urlFilePath”包含实际文件的完整路径)。该代码运行没有错误,但是文件仍然被所有人(和其他帐户)标记为可删除。
详细信息:我有一个C#服务,可将文件从即将停用的FileNet WORM存储系统迁移到Windows文件系统存储。
这些文件必须可供许多用户访问(实际上是“每个人”),但必须保留以防删除-意外或有意的。文件将驻留在其中的文件夹必须是可写的(必须允许某些用户添加将来的文件),因此我不能将文件夹设为只读。
我以为可以将ACL规则添加到“拒绝”删除中,但是以下代码不起作用。我犯了一个简单的错误,还是缺少一些技巧?
string urlFilePath = @"\\server\directory\anotherdir\myfile.pdf";
List<string> fileAccounts = new List<string>();
FileInfo fi = new FileInfo(urlFilePath);
FileSecurity fsec = fi.GetAccessControl();
AuthorizationRuleCollection acl = fsec.GetAccessRules(includeExplicit: true, includeInherited: true, targetType: typeof(System.Security.Principal.NTAccount));
foreach (FileSystemAccessRule acr in acl)
{
if (!fileAccounts.Contains(acr.IdentityReference.Value))
fileAccounts.Add(acr.IdentityReference.Value);
}
// populate standard accounts
foreach (string s in new string[] { "GUEST", "USERS", "DOMAIN USERS", "NETWORK", "AUTHENTICATED USERS"})
{
if (!fileAccounts.Contains(s))
fileAccounts.Add(s);
}
FileSecurity fileSecurity = File.GetAccessControl(urlFilePath);
int numAccounts = 0;
foreach (string account in fileAccounts)
{
fileSecurity.RemoveAccessRule(new FileSystemAccessRule(account, FileSystemRights.Delete, AccessControlType.Allow));
fileSecurity.AddAccessRule(new FileSystemAccessRule(account, FileSystemRights.Delete, AccessControlType.Deny));
numAccounts++;
}
在上面,我遵循(我认为)添加/删除ACL规则的MS示例。我没有收到任何错误,警告或异常,但是文件仍然可以被所有人完全删除。我明确地添加了帐户列表,以为可能已经与该文件关联的帐户还不够。运行此命令时,它将报告针对9个帐户运行删除/添加循环-我添加的5个帐户,再加上已关联的4个帐户,因此删除规则/添加规则循环正在针对所有帐户执行。
如何将单个文件设置为不可删除?如果删除的人将自己的所有权授予了单个文件,则允许删除它们,这是可以接受的,因为这样做应该足够安全。
我希望不允许域管理员在不取得文件所有权的情况下进行删除,但如果阻止这些组太困难,则允许管理员[[可以删除文件(本地和域管理员)。迫切需要防止任何非管理员删除其中任何一个文件。
我的问题已关闭,因为需要“调试详细信息”,但没有提及缺少或请求了哪些详细信息。 ???我获得了具有该文件夹访问权限的所有当前帐户的列表,添加了几个“知名”帐户,然后遍历这些帐户,删除了除READ以外的所有权限,然后对除READ以外的所有内容应用DENY权限。 >
获取帐户列表。
DirectoryInfo dInfo = new DirectoryInfo(dir);
DirectorySecurity dSec = dInfo.GetAccessControl();
AuthorizationRuleCollection arc = dSec.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
List<string> fileAccounts = new List<string>();
foreach (FileSystemAccessRule fsar in arc)
{
if (!fileAccounts.Contains(fsar.IdentityReference.Value))
fileAccounts.Add(fsar.IdentityReference.Value);
}
foreach (string s in new string[] { "GUEST", "USERS", "DOMAIN USERS", "NETWORK", "Authenticated Users", "SYSTEM", "Everyone" })
{
if (!fileAccounts.Contains(s))
fileAccounts.Add(s);
}
循环访问帐户,删除/添加权限。请注意,并非在所有情况下都可能存在所有帐户(例如,域/非域帐户),因此我会捕获并丢弃错误。
FileInfo fi = new FileInfo(fname);
FileSecurity fsec = fi.GetAccessControl();
int numSet = 0;
foreach (string account in fileAccounts)
{
try
{
fsec.RemoveAccessRule(new FileSystemAccessRule(account, FileSystemRights.Delete, AccessControlType.Allow));
fsec.RemoveAccessRule(new FileSystemAccessRule(account, FileSystemRights.FullControl, AccessControlType.Allow));
fsec.RemoveAccessRule(new FileSystemAccessRule(account, FileSystemRights.Modify, AccessControlType.Allow));
fsec.RemoveAccessRule(new FileSystemAccessRule(account, FileSystemRights.ReadAndExecute, AccessControlType.Allow));
fsec.RemoveAccessRule(new FileSystemAccessRule(account, FileSystemRights.Write, AccessControlType.Allow));
fsec.AddAccessRule(new FileSystemAccessRule(account, FileSystemRights.Delete, AccessControlType.Deny));
fsec.AddAccessRule(new FileSystemAccessRule(account, FileSystemRights.FullControl, AccessControlType.Deny));
fsec.AddAccessRule(new FileSystemAccessRule(account, FileSystemRights.Modify, AccessControlType.Deny));
fsec.AddAccessRule(new FileSystemAccessRule(account, FileSystemRights.ReadAndExecute, AccessControlType.Deny));
fsec.AddAccessRule(new FileSystemAccessRule(account, FileSystemRights.Write, AccessControlType.Deny));
}
catch (Exception ex)
{
// log error and continue if necessare - Console.WriteLine(account + ": " + ex.Message);
}
numSet++;
}
fi.SetAccessControl(fsec);
我怀疑有更干净,更简单的方法来执行此操作,但是至少这可以满足我的需要。