Modifying an existing access control entry - c#

I had made a logic error in the FileSystemRights interpretation which was causing it to always applied Read permission no matter what else was entered.
I'm making a ps cmdlet which is meant to be fed a list of username and modify the permissions for a folder of the same name as the user. From my testing this script will create the new special acl entry for the user for an allow or deny entry however it will not modify the entry if it already exists. I.e. if a user has read access already and I attempt to grant write access it does not change the entry. I am not sure how I would go about modifying the existing permission without completely removing the old permissions.
DirectoryInfo diDirInfo = new DirectoryInfo(FolderName);
DirectorySecurity dsDirSecurity = diDirInfo.GetAccessControl();
//These just interpet the objects for the rights and the allow/deny entries from the command line
FileSystemRights FSR = genFSR();
AccessControlType ACT = genAct();
dsDirSecurity.AddAccessRule(new FileSystemAccessRule(UserName, FSR, ACT));
diDirInfo.SetAccessControl(dsDirSecurity);
I tried ModifyAccessRule and got the same behavior.
FileSystemAccessRule fsaRule = new FileSystemAccessRule(UserName, FSR, ACT);
dsDirSecurity.ModifyAccessRule(AccessControlModification.Add, fsaRule, out modified);

Use ModifyAccessRule instead of AddAccessRule.
See http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.objectsecurity.modifyaccessrule.aspx

Related

How to use shared memory between service and User Interface App in c#?

If I write following in service:
mmfKernel = MemoryMappedFile.CreateNew("Global\\myMMF", 1024);
and following in user app:
MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("Global\\myMMF");
I get access denial to global mmf. How to grant access rights to mmfKernel to everyone with all possible rights?
But the other way round,
following in user app after I acquire SeCreateGlobalPrivilege:
mmfKernel = MemoryMappedFile.CreateNew("Global\\myMMF", 1024);
and following in service:
MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("Global\\myMMF");
I get path access denial while creating mmfKernel even though I have already SeCreateGlobalPrivilege.
How to create it as normal user but not admin?
If they run under different user accounts, and you think memory mapped files is a good IPC for your use case, you should use another CreateNew version, which accepts MemoryMappedFileSecurity argument with the permissions.
Here’s how to creates an access control list which gives full control permission to everyone:
var sid = new SecurityIdentifier( WellKnownSidType.WorldSid, null );
var ace = new AccessRule<MemoryMappedFileRights>( sid,
MemoryMappedFileRights.FullControl, AccessControlType.Allow );
var acl = new MemoryMappedFileSecurity();
acl.AddAccessRule( ace );
Then pass that acl object to MemoryMappedFile.CreateNew method.
Consider which permissions you actually need. If your desktop process only needs read access to the shared file, change the access rule accordingly. Also it’s a good idea to use more specific trustee instead of everyone, maybe AuthenticatedUserSid (=“Authenticated users”) in place of WorldSid (=“Everyone”), maybe a specific user account or security group.

How to check whether access permissions have changed for a directory in C#?

Following is the code that I have written,
var prevSecInfo = Directory.GetAccessControl(path);
if (Utilities.ShowChangePermissionsWindow(path)) {
var currSecInfo = Directory.GetAccessControl(path);
if (currSecInfo != prevSecInfo)
Utilities.ApplyPermissionsOnSubdirectories(path);
}
So, currently, I am getting the access control info before displaying the permissions window.
Next, I am displaying the permissions window which is actually the Security tab of the file/folder properties window. Changes can be made in permissions once it opens up.
But, in case no changes are made, I don't want to call my ApplyPermissionsOnSubdirectories() method. Hence, I am getting the access control info again in another variable and comparing the previous and the current info.
But, this isn't working. The comparison returns false even when no permissions are changed.
How can I check whether permissions have changed for the given path?
You cannot compare the contents of two reference type objects this way.
if (currSecInfo != prevSecInfo) will always return false, unless they both reference to the same object.
Unfortunately, DirectorySecurity type also does not provide Equals overriden method.
There is a StackOverflow article with some ready-made solutions for comparing permissions:
compare windows file (or folder) permissions
While working on the problem above, I found another solution which looks less complex and shorter is terms of code.
DirectorySecurity securityInfoBefore = Directory.GetAccessControl(path, AccessControlSections.Access);
string aclStrBefore = securityInfoBefore.GetSecurityDescriptorSddlForm(AccessControlSections.Access).ToString();
Here, path is the absolute path to the file/folder.
The aim to get the DirectorySecurity object before the permissions are changed and getting the SecurityDescriptorSddlForm as a string.
Now you can add your code to change the permissions. After the permissions are changed, add the following code,
DirectorySecurity securityInfoAfter = Directory.GetAccessControl(path, AccessControlSections.Access);
string aclStrAfter = securityInfoAfter.GetSecurityDescriptorSddlForm(AccessControlSections.Access).ToString();
The next step would be to compare the before and after strings.
if (aclStrBefore.Equals(aclStrAfter)) {
// permissions have not changed
} else {
// permissions have changed
}
This has helped me so far. Please feel free to add to my answer or correct it if required.

How can I remove ACL from folder that owned by non-existing user

I am developing a C# application.
I need to change the ACLs on a folder, to do so I am running my program as elevated administrator, and everything works fine.
The problem is that if the user that owns the folder got deleted from the system, then when I try to take ownership on the folder I get unauthorized exception.
This is the code that fails:
using (new PrivilegeEnabler(Process.GetCurrentProcess(), Privilege.TakeOwnership))
{
var directorySecurity = directoryInfo.GetAccessControl();
directorySecurity.SetOwner(WindowsIdentity.GetCurrent().User);
Directory.SetAccessControl(directoryInfo.FullName, directorySecurity);
}
The exception occurs on the line: directoryInfo.GetAccessControl();
PrivilegeEnabler is a class defined in Process Privileges , and it's used to take ownership on the file.
I found a solution.
You need to set the owner, by creating a new access control (without calling to GetAccessControl) and setting the owner to the current process.
and then you can do whatever you want with the file.
using (new PrivilegeEnabler(Process.GetCurrentProcess(), Privilege.TakeOwnership))
{
//create empty directory security
var directorySecurity = new DirectorySecurity();
//set the directory owner to current user
directorySecurity.SetOwner(WindowsIdentity.GetCurrent().User);
//set the access control
Directory.SetAccessControl(directoryInfo.FullName, directorySecurity);
}

read permission denied using NTFS when I denied write permission

Using the below code I denied write permission for a user, even when I checked security tab only write permission is denied, but I'm not able to access the folder for reading.
ADsSecurity objADsSec;
SecurityDescriptor objSecDes;
AccessControlList objDAcl;
AccessControlEntry objAce1;
AccessControlEntry objAce2;
Object objSIdHex;
ADsSID objSId;
objADsSec = new ADsSecurityClass();
objSecDes = (SecurityDescriptor)(objADsSec.GetSecurityDescriptor("FILE://" + vPath));
objDAcl = (AccessControlList)objSecDes.DiscretionaryAcl;
objSId = new ADsSIDClass();
objSId.SetAs((int)ADSSECURITYLib.ADS_SID_FORMAT.ADS_SID_SAM, UserName.ToString());
objSIdHex = objSId.GetAs((int)ADSSECURITYLib.ADS_SID_FORMAT.ADS_SID_SDDL);
objAce2 = new AccessControlEntryClass();
objAce2.Trustee = (objSIdHex).ToString();
objAce2.AccessMask = (int)ActiveDs.ADS_RIGHTS_ENUM.ADS_RIGHT_GENERIC_WRITE;
objAce2.AceType = (int)ActiveDs.ADS_ACETYPE_ENUM.ADS_ACETYPE_ACCESS_DENIED;
objAce2.AceFlags = (int)ActiveDs.ADS_ACEFLAG_ENUM.ADS_ACEFLAG_INHERIT_ACE | 1;
objDAcl.AddAce(objAce2);
objSecDes.DiscretionaryAcl = objDAcl;
// Set permissions on the NTFS file system folder.
objADsSec.SetSecurityDescriptor(objSecDes, "FILE://" + vPath);
You're not showing objAce1
You need to order Deny ACE entries before Grant ACE entries.
Try swapping the order of entries in the ACL.
Thus, the DACL's list of ACEs should be appropriately ordered. The standard (canonical) ordering is to first place explicit denies, then explicit allows, general (group) denies, and group allows. If the canonical ordering isn't used, unanticipated allows or denies may occur
From Understanding Windows File And Registry Permissions

Directory Permission Watcher in c#

I have created the program which is monitoring a directory (e.g. \\server\share\folderXYZ) for changed events (like created, deleted, renamed and permission changes). I also got the notification if anything changed but I can't get exact details what has changed.
For example I have changed the permission for above directory from folder properties (Properties -> Security -> Edit ->Add new user or group or change permission for user and groups). File system watcher give notification if something changed but I can't get other details like:
For which user permission has changed?
Who changed the user permissions?
If any new group has been added(need to get all users in the group if new group added)?
If any new user is added to group and who added and need to get added user details?
If any user or group is removed than removed group or user details?
If any permission is added or changed for user than what permission are added or changed?
If any permission are changed for group than what permission changed?
Example Scenarios:
Action: At 11am, the Admin added User A to Trainees (Existing group)
Expected Result:
Access to \\server\share\folderXYZ changed: User A now has Read access, given by Admin at 11am, because he is now member of Trainees, which has Read Access.
Hope question is clear. I have done lots of search and couldn't find the solution. Please let me know if any API or Service available or any alternatives available?
-Thanks
The way to get the information you want is to use Windows Security Auditing, esp. since you want to know who made a change, not just what the change was.
The following code (and settings), produce output like this:
11-07-2011 17:43:10: 'Fujitsu\Grynn' changed security descriptor on file 'C:\Users\Grynn\Documents\ExcelTools\test.txt' from
'D:AI(A;;0x1200a9;;;BU)(A;ID;FA;;;S-1-5-21-559386011-2179397067-1987725642-1000)(A;ID;FA;;;SY)(A;ID;FA;;;BA)'
to
'D:ARAI(A;ID;FA;;;S-1-5-21-559386011-2179397067-1987725642-1000)(A;ID;FA;;;SY)(A;ID;FA;;;BA)'
using 'C:\Windows\explorer.exe'
12-07-2011 17:55:10: 'Fujitsu\Grynn' changed security descriptor on file 'C:\Users\Grynn\Documents\ExcelTools\test.txt' from
'D:AI(A;ID;FA;;;S-1-5-21-559386011-2179397067-1987725642-1000)(A;ID;FA;;;SY)(A;ID;FA;;;BA)'
to
'D:ARAI(D;;FA;;;S-1-5-21-559386011-2179397067-1987725642-1001)(A;ID;FA;;;S-1-5-21-559386011-2179397067-1987725642-1000)(A;ID;FA;;;SY)(A;ID;FA;;;BA)'
using 'C:\Windows\explorer.exe'
Turning on Auditing has 2 steps:
1. Use gpedit.msc to turn on "Audit Object access"
2. Modify "Auditing" for the folder you want to watch
Now whenever a File System Change event occurs (or via polling) query the security event log.
Code to query 'Security' event log:
var props = new EventLogPropertySelector(new string[] {
"Event/System/TimeCreated/#SystemTime",
"Event/EventData/Data[#Name='SubjectDomainName']",
"Event/EventData/Data[#Name='SubjectUserName']",
"Event/EventData/Data[#Name='ObjectName']",
"Event/EventData/Data[#Name='OldSd']",
"Event/EventData/Data[#Name='NewSd']",
"Event/EventData/Data[#Name='ProcessName']" });
using (var session = new System.Diagnostics.Eventing.Reader.EventLogSession())
{
//4670 == Permissions on an object were changed
var q = new EventLogQuery("Security", PathType.LogName, "*[System[(EventID=4670)]]");
q.Session = session;
EventLogReader rdr = new EventLogReader(q);
for (EventRecord eventInstance = rdr.ReadEvent();
null != eventInstance; eventInstance = rdr.ReadEvent())
{
var elr = ((EventLogRecord)eventInstance);
Console.WriteLine(
"{0}: '{1}\\{2}' changed security descriptor on file '{3}' from \n'{4}' \nto \n'{5}' \nusing '{6}'\n----\n",
elr.GetPropertyValues(props).ToArray());
}
}
From what i know/been reading, FileSystemWatcher can only tell you the file that was affected along with the change type only.
One way to go is for you to maintain a cache of the file attributes you're interested in, an in the presence of an event notifying a change, you query the cache to get the changes made and update it as necessary.

Categories

Resources