Как предотвратить удаление файла любым пользователем - PullRequest
0 голосов
/ 17 апреля 2020

Проблема: необходимо предотвратить удаление отдельных файлов Windows, по крайней мере, без прав администратора. Файлы должны быть доступны для чтения всем пользователям. Каталог Windows, в котором находятся файлы, должен быть доступен для записи и чтения «Все».

Отладка: Пример кода ниже - моя попытка установить правила контроля доступа «Запретить удаление» для файла примера (строка «urlFilePath» содержит полный путь к реальному файлу при выполнении этого кода). Код выполняется без ошибок, но файлы по-прежнему помечены как удаляемые всеми (и другими учетными записями).

Подробно: у меня есть служба C#, которая переносит файлы из списка, который скоро будет списан. Fil eNet 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++;
    }

Выше я следовал (я думал) примеру MS добавления / удаления правил ACL. Я не получаю ошибок, предупреждений или исключений, но файлы остаются полностью удаляемыми всеми. Я явно добавил список учетных записей, думая, что, возможно, уже недостаточно учетных записей, связанных с файлом. Когда он запускается, он сообщает, что удаление / добавление l oop выполняется для 9 учетных записей - 5 добавленных мною плюс 4 уже связанных, поэтому правило удаления / добавления l oop выполняется для всех учетных записей.

Как я могу установить отдельные файлы, которые нельзя удалить? Допустимо разрешить их удаление, если лицо, удаляющее файл, дает право владения отдельным файлом, поскольку это должно быть достаточно безопасно.

Я бы предпочел не разрешать администраторам домена удалять, не вступая во владение файлом. , но Администраторы могут иметь возможность удалять файлы (как локальных, так и администраторов домена), если предотвращение этих групп слишком сложно. Крайне необходимо, чтобы все пользователи, не являющиеся администраторами, не удалили ни один из этих файлов.

Мой вопрос был закрыт как требующий "подробностей отладки", но без упоминания о том, какие данные отсутствовали или запрашивались. ???

1 Ответ

0 голосов
/ 20 апреля 2020

После еще нескольких проб и ошибок, я думаю, что нашел решение. Применение «Запретить» к праву удаления недостаточно. Следующее, кажется, работает. Для удаления набора файлов таким способом требуется, чтобы пользователь с достаточными правами удалил правила запрета.

Я получаю список всех текущих учетных записей с доступом к папке, добавляю несколько «хорошо известных» учетных записей и затем выполняю итерацию. через учетные записи, удалив все права, кроме READ, а затем применив права DENY ко всему, кроме READ.

Получите список учетных записей.

    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);

Я подозреваю, что есть более чистый и простой способ сделать это, но по крайней мере это работает для того, что мне нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...