简体   繁体   中英

Allow only Admin to delete a file?

I am writing a C# application and I want to set (at application start) the permissions so that only the Administrator can delete a file which the application uses. All other users should not be able to delete it or modify its permissions.

The file should be protected from standard file system usage (so no one, except Admin, can delete it). Only Admin should be able to set back the file permissions. Also, other users should be able to read/write it.

Is this possible? I have found some code examples here, but none of them work. The code I'm trying :

FileSecurity fSecurity = File.GetAccessControl("database.sdf");

        AuthorizationRuleCollection rules = fSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
        foreach (AuthorizationRule rule in rules)
        {
            System.Security.Principal.NTAccount account =
                (System.Security.Principal.NTAccount)rule.IdentityReference.Translate(typeof(System.Security.Principal.NTAccount));
            if (account.Value != "BUILTIN\\Administrators")
            {
                fSecurity.AddAccessRule(new FileSystemAccessRule(account.Value, FileSystemRights.Delete, AccessControlType.Deny));
            }
        }

        File.SetAccessControl("database.sdf", fSecurity);    

Can I configure the file permissions and owner programmatically from the app when running it as a normal user, not admin?

Thank you!

PS The file is a SQL Server Compact database.

Before we get started, let me just say that this:

System.Security.Principal.NTAccount account =
    (System.Security.Principal.NTAccount)rule.IdentityReference.Translate(typeof(System.Security.Principal.NTAccount));
if (account.Value != "BUILTIN\\Administrators")

is entirely unnecessary .

The builtin Administrators group is a well-known security principal , and is guaranteed to always have the same Security Identifier ( S-1-5-32-544 ), easy to compare against.


Your current procedure of explicitly granting Deny Delete for all principals that already happens to have an access rule may also backfire immensely.

Imagine that an access rule with the following characteristics already exist in the ACL:

Identity: Everyone
Access right: Read
Control type: Allow

Congratulations! You've now implicitly denied everyone the right to delete the file, including the Administrators group.

What you want to do is:

  1. Make sure the Administrators group is the Owner of the file
  2. Remove all existing access rules that grants Allow Delete (explicitly or implicitly)
  3. Add a single Access Rule granting Allow FullControl to the Administrators group
  4. Remove all inherited rules and protect the ACL from inheritance

// Way safer than string comparison against "BUILTIN\\Administrators"
IdentityReference BuiltinAdministrators = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);

// Grab ACL from file
FileSecurity FileACL = File.GetAccessControl(TargetFilePath);

// Check if correct owner is set
if (FileACL.GetOwner(typeof(SecurityIdentifier)) != BuiltinAdministrators)
{
    // If not, make it so!
    FileACL.SetOwner(BuiltinAdministrators);
}

foreach (FileSystemAccessRule fsRule in FileACL.GetAccessRules(true, false, typeof(SecurityIdentifier)))
{
    // Check if rule grants delete
    if ((fsRule.FileSystemRights & FileSystemRights.Delete) == FileSystemRights.Delete)
    {
        // If so, nuke it!
        FileACL.RemoveAccessRule(fsRule);
    }
}

// Add a single explicit rule to allow FullControl
FileACL.AddAccessRule(new FileSystemAccessRule(BuiltinAdministrators, FileSystemRights.FullControl, AccessControlType.Allow));

// Enable protection from inheritance, remove existing inherited rules
FileACL.SetAccessRuleProtection(true, false);

// Write ACL back to file
File.SetAccessControl(TargetFilePath, FileACL);

Using Mathias' help, I found the answer to my question:

try
{
       // Way safer than string comparison against "BUILTIN\\Administrators"
       IdentityReference BuiltinAdministrators = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
       IdentityReference AuthenticatedUsers = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);

       FileSecurity FileACL = File.GetAccessControl("database.sdf"); // Grab ACL from file

       if (FileACL.GetOwner(typeof(SecurityIdentifier)) != BuiltinAdministrators) // Check if correct owner is set
       {
             FileACL.SetOwner(BuiltinAdministrators); // If not, make it so!
       }

       foreach (FileSystemAccessRule fsRule in FileACL.GetAccessRules(true, true, typeof(SecurityIdentifier)))
       {
             if ((fsRule.FileSystemRights & FileSystemRights.Delete) == FileSystemRights.Delete ||
                    (fsRule.FileSystemRights & FileSystemRights.ChangePermissions) == FileSystemRights.ChangePermissions) // Check if rule grants delete or change permissions
             {
                  FileACL.RemoveAccessRule(fsRule); // If so, nuke it!
             }
       }

       // Add explicit rules
       FileACL.AddAccessRule(new FileSystemAccessRule(BuiltinAdministrators, FileSystemRights.FullControl, AccessControlType.Allow));
       FileACL.AddAccessRule(new FileSystemAccessRule(AuthenticatedUsers, FileSystemRights.Delete, AccessControlType.Deny));
       FileACL.AddAccessRule(new FileSystemAccessRule(AuthenticatedUsers, FileSystemRights.ChangePermissions, AccessControlType.Deny));
       FileACL.AddAccessRule(new FileSystemAccessRule(AuthenticatedUsers, FileSystemRights.Read, AccessControlType.Allow));
       FileACL.AddAccessRule(new FileSystemAccessRule(AuthenticatedUsers, FileSystemRights.Write, AccessControlType.Allow));

       FileACL.SetAccessRuleProtection(true, false); // Enable protection from inheritance, remove existing inherited rules
       File.SetAccessControl("database.sdf", FileACL); // Write ACL back to file
   }
   catch { }

And in order to work, the application has to be run once as admin.

Setting file permissions programmatically is new to me, so if someone thinks the code may not do what it's intended to do, please correct me. Thank you!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM