DirectorySecurity.AddAccessRule Appears to work, but really doesn't - c#

I have an application that is intended to add read/execute permissions for a user. It appears to work, but really doesn't.
I have the following code:
string folderName = #"\\ShareDrive\MyDepartment\someFolder";
DirectorySecurity ds = new DirectoryInfo(folderName).GetAccessControl(AccessControlSections.Access);
AuthorizationRuleCollection rules = ds.GetAccessRules(true, true, typeof(NTAccount));
ds.AddAccessRule(
new FileSystemAccessRule(
"SomeValidUser#myCompany.com",
FileSystemRights.ReadAndExecute,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.None,
AccessControlType.Allow));
rules = ds.GetAccessRules(true, true, typeof(NTAccount));
//when I examine the value of 'rules' after executing the above statement, it appears the person has been added with
//the correct identity reference (successfully translated the email address)
After executing this code, if I check permissions in Windows File Explorer, the person has NOT been added. This is actually expected since if I try to add the person in File Explorer, I get an access denied error. I was expecting AddAccessRule to throw an exception.
My question is: How can I in C# check to see if the operation actually succeeded?

You need to call SetAccessControl() passing in your modified DirectorySecurity object to actually apply your changes.

Related

Remove Users group permission for folder inside ProgramData

When I create a folder inside ProgramData folder say Test then I'm seeing below permission for the folder by default for the Users group,
Question, can I remove all the permission for Users group?
I tried below code, but nothing no permission removed,
// This gets the "Authenticated Users" group, no matter what it's called
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
// Create the rules
FileSystemAccessRule fullControlRule = new FileSystemAccessRule(sid, FileSystemRights.FullControl, AccessControlType.Allow);
if (Directory.Exists("C:\\ProgramData\\Test"))
{
// Get your file's ACL
DirectorySecurity fsecurity = Directory.GetAccessControl("C:\\ProgramData\\Test");
// remove the rule to the ACL
fsecurity.RemoveAccessRuleAll(fullControlRule);
// Set the ACL back to the file
Directory.SetAccessControl("C:\\ProgramData\\Test", fsecurity);
}
First, code which should work for your requirement (just tested it myself):
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;
...
...
var directoryInfo = new DirectoryInfo(#"C:\ProgramData\Test");
// get the ACL of the directory
var dirSec = directoryInfo.GetAccessControl();
// remove inheritance, copying all entries so that they are direct ACEs
dirSec.SetAccessRuleProtection(true, true);
// do the operation on the directory
directoryInfo.SetAccessControl(dirSec);
// reread the ACL
dirSec = directoryInfo.GetAccessControl();
// get the well known SID for "Users"
var sid = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);
// loop through every ACE in the ACL
foreach (FileSystemAccessRule rule in dirSec.GetAccessRules(true, false, typeof(SecurityIdentifier)))
{
// if the current entry is one with the identity of "Users", remove it
if (rule.IdentityReference == sid)
dirSec.RemoveAccessRule(rule);
}
// do the operation on the directory
directoryInfo.SetAccessControl(dirSec);
And now to the details:
First, your idea was good to use a well-known SID and not directly the string. But the Users group is NOT Authenticated Users, so we have to use BuiltinUsersSid
Then, we have to remove the inheritance. In your above screen shot, the entries are grayed out, so not directly changeable. We first have to migrate the inherited entries to direct ones, preserving old entries (if not, the ACL would be empty afterwards).
Then, there can be more than one entry for Users (in fact, there are two). We have to loop through all entries and check if it is one which has the Users sid. Then we remove it.
Some final words:
The ACL / permissioning logic is very complex, and escpecially the inheritance can lead to many problems. But it's getting better now.
I remember the first years after the introduction of inheritance (NT4 => Windows 2000), when many tools (even MS own ones) did not handle it correctly, which produced all sort of problems with invalid / damaged ACLs.

How do I add ACL rules without replacing existing ones?

I would like to add some new ACL rules alongside existing ones. I am currently using SetAccessRule, with the expectation that adding new rules also keeps the old ones. According to the documentation for SetAccessRule,
The SetAccessRule method adds the specified access control list (ACL) rule or overwrites any identical ACL rules that match the FileSystemRights value of the rule parameter. For example, if the rule parameter specifies a Read value and the SetAccessRule method finds an identical ACL rule that specifies the Read value, the identical rule will be overwritten. If the SetAccessRule method finds an identical ACL rule that specifies the Write value, the identical rule will not be overwritten.
However, in practice, I've found that adding a new rule actually overwrites any previous rules (belonging to the same user/SID?). This seems to contradict what the documentation says.
My current intention is to assign both read and write permissions, but in separate calls. Unfortunately, the latter permissions overwrite the first. In the example code below, the result is only the read permissions are assigned. If I comment out that block, then only the write permissions are assigned. This could be fixed with an additional if condition to assign both permissions, but it still overwrites any existing permissions on the directory, which is undesired.
DirectoryInfo directory = new DirectoryInfo(abspath);
DirectorySecurity security = directory.GetAccessControl();
security.SetAccessRuleProtection(false, true);
if (perm.Contains("write"))
{
security.SetAccessRule(new FileSystemAccessRule(user, FileSystemRights.Write, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow));
}
if (perm.Contains("read"))
{
security.SetAccessRule(new FileSystemAccessRule(user, FileSystemRights.ReadAndExecute | FileSystemRights.Traverse, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow));
}
directory.SetAccessControl(security);
How should I handle adding new rules while keeping existing ones? And, is the documentation incorrect, am I misinterpreting it, or is my code incorrect?
Try using DirectorySecurity.AddAccessRule method instead to append/add permissions instead or replacing, see this MSDN link for more info
security.AddAccessRule(new FileSystemAccessRule(user, FileSystemRights.Write, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow));

C# code to set a remote share to inherit permissions from its parent directory

I have two machines, call them client and server, in a Windows domain. The server has a shared directory which can be accessed from the client machine. I want to run a C# application on the client which sets the permission on this share to inherit the permissions of the share's parent directory on the server. How do I do this?
I have tried code along the following lines, but I don't think it has the right effect:
DirectoryInfo shareDirectoryInfo = new DirectoryInfo("\\server\share");
DirectorySecurity directorySecurity = shareDirectoryInfo.GetAccessControl();
directorySecurity.SetAccessRuleProtection(false, false);
InheritanceFlags iFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
FileSystemAccessRule accessRule = new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, iFlags, PropagationFlags.InheritOnly, AccessControlType.Allow);
bool modified;
directorySecurity.ModifyAccessRule(AccessControlModification.Set, accessRule, out modified);
if (modified)
{
Directory.SetAccessControl(name, directorySecurity);
}
I guess I don't understand why I have to create a FileSystemAccessRule for the directory - how can I just say inherit from parent?
Thanks for any help! Martin
You can set the folder to inherit from parent by using SetAccessRuleProtection
DirectoryInfo targetFolder = new DirectoryInfo(#"\\server\share");
DirectorySecurity folderSecurity = targetFolder.GetAccessControl(); // Existing security
folderSecurity.SetAccessRuleProtection(false, true); // This sets the folder to inherit
targetFolder.SetAccessControl(folderSecurity);
EDIT: The msdn document explains that if false is sent as the first argument, then the second argument is ignored.

DirectorySecurity not setting permissions correctly

I have a C# code which creates a folder and sets some permissions on it. Here is the code sample:
static void Main(string[] args){
Directory.CreateDirectory("C:\\vk07");
DirectorySecurity dirSec = Directory.GetAccessControl("C:\\vk07");
dirSec.AddAccessRule(new FileSystemAccessRule("INTRANET\\fGLBChorusUsers", FileSystemRights.ReadAndExecute, AccessControlType.Allow));
Directory.SetAccessControl("C:\\vk07", dirSec);
}
When I check the permissions set on the folder created above, instead of having Read and Modify (which is what I have set in the code), it shows only "Special Permissions" as checked.
Please can some one help me with this? I am new to ACL, so don't understand it very well.
I was having this same problem, The actual reason is if you look at that network service picture from the other post, it is applying to files only. The basic permissions will only show up on the first picture if they say "This folder, subfolders, and files" To do this, you need to set the two flags -InheritanceFlags.ContainerInherit + InheritanceFlags.ObjectInherit.
Try
'If destination directory does not exist, create it first.
If Not Directory.Exists(path) Then Directory.CreateDirectory(path)
Dim dir As New DirectoryInfo(path)
Dim dirsec As DirectorySecurity = dir.GetAccessControl()
'Remove inherited permissions
dirsec.SetAccessRuleProtection(True, False)
'create rights, include subfolder and files to be inherited by this
Dim Modify As New FileSystemAccessRule(username, FileSystemRights.Modify, InheritanceFlags.ContainerInherit + InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)
Dim Full As New FileSystemAccessRule(admingroup, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit + InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)
dirsec.AddAccessRule(Modify)
dirsec.AddAccessRule(Full)
'Set
dir.SetAccessControl(dirsec)
Catch ex As Exception
MsgBox(ex.Message)
End Try
This code works for me:
security.AddAccessRule(
new FileSystemAccessRule(
"domain\\login",
FileSystemRights.Modify,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.None,
AccessControlType.Allow
));
I also had this problem. After executing the following code:
var security = Directory.GetAccessControl(folderPath);
security.AddAccessRule(
new FileSystemAccessRule(
new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null),
FileSystemRights.Modify,
InheritanceFlags.ObjectInherit,
PropagationFlags.InheritOnly,
AccessControlType.Allow
)
);
Directory.SetAccessControl(folderPath, security);
...then the Properties Dialog for folderPath would appear as follows:
As you mentioned, only 'Special Permissions' is checked, but if you click Advanced, then you see:
Notice that in this dialog NETWORK SERVICE has the modify permission.
It seems as though when you set permissions programmatically Windows does not show these permissions within the folder properties dialog, but they still exist under advanced security settings. I also confirmed that my Window service (running as NETWORK SERVICE) was then able to access files within folderPath.
FileSystemRights.ReadAndExecute doesn't allow you to modify. This is for read-only.
You would need FileSystemRights.Modify for the full range.
You may want to check out for the options available.
here is an example of the above:
String dir = #"C:\vk07";
Directory.CreateDirectory(dir);
DirectoryInfo dirInfo = new DirectoryInfo(dir);
DirectorySecurity dirSec = dirInfo.GetAccessControl();
dirSec.AddAccessRule(new FileSystemAccessRule("INTRANET\\fGLBChorusUsers",FileSystemRights.Modify,AccessCo‌ntrolType.Allow));
dirInfo.SetAccessControl(dirSec);
I got the same code to work in VB, setting FileSystemRights.FullControl.
Dim fsRule As FileSystemAccessRule = New FileSystemAccessRule(sid, FileSystemRights.FullControl, (InheritanceFlags.ContainerInherit + InheritanceFlags.ObjectInherit), PropagationFlags.None, AccessControlType.Allow)

C# - Windows ACL - Applying Inherited Permissions

I've been having problems programatically assigning permissions to Folders / Registry entries. I have managed to assign inheriting permissions using the following code:
FileSystemAccessRule rule = new FileSystemAccessRule(LOGON_USER_NAME,
FileSystemRights.FullControl, InheritanceFlags.ContainerInherit |
InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly,
AccessControlType.Allow);
DirectorySecurity security = new DirectorySecurity();
security.SetAccessRule(rule);
Directory.CreateDirectory(dir);
Directory.SetAccessControl(dir, security);
This correctly sets my file permissions on all the child folders i create as an administrator. However, it does not set the permissions on the dir folder itself. I've played around with a fair few permutations for inheritance and propogation, but not had any joy.
For example, I have:
dir = %programfiles%\Test
If i have created a folder in test (%programfiles%\Test\SubFolder), I have full permissions assigned to it for my user, but I do not have full permissions on %programfiles%\Test. This is really annoying, as I would like to give my user full permissions to do whatever with the Test directory as well.
I am having similar problems with registry permissions, but I believe that if i can solve one, i can solve both of the outstanding issues.
Does anyone know how this can be resolved?
Regards
Tris
For the folder:
FileSystemAccessRule rule = new FileSystemAccessRule(LOGON_USER_NAME,
FileSystemRights.FullControl, AccessControlType.Allow);
For subfolders and files:
FileSystemAccessRule rule = new FileSystemAccessRule(LOGON_USER_NAME,
FileSystemRights.FullControl, InheritanceFlags.ContainerInherit |
InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly,
AccessControlType.Allow);
both lines need to be in your project. then you get acls that apply to this folder, subfolders and files
I'm hardly an expert here, but after having to figure this out for my own purposes, I believe that Dave's answer, although functional, is overly complicated. You should be able to achieve this with just one rule:
FileSystemAccessRule rule = new FileSystemAccessRule(LOGON_USER_NAME,
FileSystemRights.FullControl,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.None,
AccessControlType.Allow);
The PropagationFlags.InheritOnly parameter used by the OP in their original code is what prevents the access rule from applying to the object itself.
Also, you might as well set the directory's security as you're creating it, since .NET provides an overload for just that purpose:
Directory.CreateDirectory(dir, security);

Categories