I am trying to set program's installation folder permissions restricted only to Administrators.
There are two scenarios: the folder needs creation and folder already exists.
Here is my code:
public static void CreatePrivateFolder(string path)
{
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
DirectorySecurity securityRules = new DirectorySecurity();
FileSystemAccessRule fsRule =
new FileSystemAccessRule(sid, FileSystemRights.FullControl,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.None, AccessControlType.Allow);
securityRules.SetAccessRule(fsRule);
if (Directory.Exists(path))
{
Directory.SetAccessControl(path, securityRules);
}
else
{
Directory.CreateDirectory(path, securityRules);
}
}
When the folder needs creation, the CreateDirectory works fine, the folder's permissions restricted only to Administrators.
The strange thing is when I am re-run this code and flow to SetAccessControl - the folder's permissions being reset to regular folder with no restricted access.
What do I'm doing wrong?
Folder security results (for path c:\\folderCheck) :
Update
anrei solution answering my question.
However, it seem to be the same problem in a different way:
If the folder already exists with unrestricted permissions, anrei's code don't seem to be work.
The folder's permissions remain unrestricted.
Thanks!
Use this instead of your if (Directory.Exists(path)) block.
// what is
var existingACL = Directory.GetAccessControl(path);
// remove everything from what is
foreach (FileSystemAccessRule rule in existingACL.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)))
existingACL.RemoveAccessRuleAll(rule);
// add yours to what is
existingACL.AddAccessRule (fsRule);
// set again
Directory.SetAccessControl(path, existingACL);
Related
Quick question if anyone happens to know. I'm working on a Worker app in dotnet6 that is intended to be made into a service and I need to store a json file somewhere. Doing some research it seems like CommonApplicationData(ex: "C:/ProgramData") is the place to go. My question is, I can't seem to write a file to that folder. I am able to create a directory just fine. But my access is denied to creating an actual file.
This service will be used on servers in the field right now and cannot answer UAC prompts. I'm unsure what else to do. I can have the file created manually and access, edit it. That seems to work fine. But I'd like to have a logs files dynamically created and more.
Heres the code("its pretty basic")
var dirPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MyServerService");
var path = dirPath + "\\service.json";
var doesDirExist = Directory.Exists(dirPath);
var doesFileExist = File.Exists(path);
if (!doesDirExist || !doesFileExist)
{
Directory.CreateDirectory(dirPath); //<- directory is created just fine
using var file = File.Create(dirPath); // <- fails here (access is denied)
//do stuff
}
This bit of code worked for me. It was indeed a permission issue with the directory being created.
public static bool CreateDirWithAccess(string fullPath, bool readOnly)
{
var dInfo = Directory.CreateDirectory(fullPath);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), readOnly ? FileSystemRights.Read : FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
dInfo.SetAccessControl(dSecurity);
return true;
}
I want to block the option to delete a specific folder.
I am using AccessControl:
if (Directory.Exists("D:\\folder"))
{
currentUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
DirectoryInfo dInfo = new DirectoryInfo("D:\\folder");
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule(currentUser, FileSystemRights.Delete, AccessControlType.Deny));
dInfo.SetAccessControl(dSecurity);
}
But when I try to delete D:\\folder, it is deleted.
I checked the current user in the delete event, and it was the same as the currentUser that got the access rule.
What is the problem here?
It looks like you'll need to call dInfo.SetAccessControl(dSecurity); to persist the change.
http://msdn.microsoft.com/en-us/library/d49cww7f(v=vs.110).aspx
(See: "Remarks")
I was trying to give NTFS permissions on a UNC path for a specific user, but I see different behavior depending on the UNC path. Below is the code (from MSDN) which I am using to give permissions and the result in each scenario,
static void GiveNTFSPermissions(string folderPath,
string ntAccountName,
FileSystemRights accessRights)
{
DirectorySecurity dirSecurity = Directory.GetAccessControl(folderPath);
FileSystemAccessRule newAccessRule =
new FileSystemAccessRule(
ntAccountName,
accessRights,
AccessControlType.Allow);
dirSecurity.AddAccessRule(newAccessRule);
Directory.SetAccessControl(folderPath, dirSecurity);
}
Suppose I have a share named “RootShare” on my local machine, and another folder “InsideRootShare” inside it.
Scenario1:
When I call,
GiveNTFSPermissions(#"\\sri-devpc\RootShare",
#"domain\username",
FileSystemRights.Write);
Inherited permissions were lost on the shared path,
Scenario2:
When I call,
GiveNTFSPermissions(#"\\sri-devpc\RootShare\InsideRootShare",
#"domain\username",
FileSystemRights.Write);
Inherited permissions were intact.
I have tried with different constructors of FileSystemAccessRule but no luck.
What is the reason behind this behavior, and any workaround for this?
We ran into similar issues working with file system permission while working on Dropkick's security module. The solution we came up with is as follows. This will successfully set permissions on any folder without changing the inheritance rules on the folder.
public void SetFileSystemRights(string target, string group, FileSystemRights permission)
{
if (!IsDirectory(target) && !IsFile(target))
return;
var oldSecurity = Directory.GetAccessControl(target);
var newSecurity = new DirectorySecurity();
newSecurity.SetSecurityDescriptorBinaryForm(oldSecurity.GetSecurityDescriptorBinaryForm());
var accessRule = new FileSystemAccessRule(group,
permission,
InheritanceFlags.None,
PropagationFlags.NoPropagateInherit,
AccessControlType.Allow);
bool result;
newSecurity.ModifyAccessRule(AccessControlModification.Set, accessRule, out result);
if (!result) Log.AddError("Something wrong happened");
accessRule = new FileSystemAccessRule(group,
permission,
InheritanceFlags.ContainerInherit |
InheritanceFlags.ObjectInherit,
PropagationFlags.InheritOnly,
AccessControlType.Allow);
result = false;
newSecurity.ModifyAccessRule(AccessControlModification.Add, accessRule, out result);
if (!result) Log.AddError("Something wrong happened");
Directory.SetAccessControl(target, newSecurity);
if (result) Log.AddGood("Permissions set for '{0}' on folder '{1}'", group, target);
if (!result) Log.AddError("Something wrong happened");
}
Found the link that I originally used to figure this out.
I am creating an XML file in the common application folder using C#:
%ALLUSERSPROFILE%\Application Data\
File will be created when application is installed. This file is something that is common to all the users of the local machine.(i.e it contains some setting information)
But my problem is when the file is created by an admin user(i.e application is installed by an admin user) the other users don't have write access to the file. When I checked the attributes of the file, it has given only 'read and execute' is given to other users.
I am using below code to save the file
XDocument.Save(filePath);
Is it possible to create file with write access given to all users? Any help much appreciated!
You can't pass information about ACL into XDocument.Save method, but you can modify permissions of file after saving your xml document. You can use the following code to perform it (don't forget to add reference to System.Security.dll):
using System.Security.AccessControl;
using System.Security.Principal;
using System.IO;
public class FileAccessRulesHelper
{
public void AddWriteRightsToEveryone(string filename)
{
// get sid of everyone group
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
// create rule
FileSystemAccessRule rule = new FileSystemAccessRule(sid, FileSystemRights.Write, AccessControlType.Allow);
// get ACL of file
FileSecurity fsecurity = File.GetAccessControl(filename);
// modify ACL of file
fsecurity.AddAccessRule(rule);
// apply modified ACL to file
File.SetAccessControl(filename, fsecurity);
}
}
I don't think you can pass a parameter to XDocument.Save to control the permissions but you should be able to set them after the save. Something like the following should do:
System.Security.AccessControl.FileSecurity fsec = System.IO.File.GetAccessControl(fileName);
fsec.AddAccessRule( new System.Security.AccessControl.FileSystemAccessRule("Everyone", System.Security.AccessControl.FileSystemRights.Modify, System.Security.AccessControl.AccessControlType.Allow));
System.IO.File.SetAccessControl(fileName, fsec);
I had a similar problem with a service install. You can use the following code to give a folder different permissions.
public static void CreateWithFullAccess(string targetDirectory)
{
try
{
if (!Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
DirectoryInfo info = new DirectoryInfo(targetDirectory);
SecurityIdentifier allUsersSid =
new SecurityIdentifier(WellKnownSidType.LocalServiceSid,
null);
DirectorySecurity security = info.GetAccessControl();
security.AddAccessRule(
new FileSystemAccessRule(allUsersSid,
FileSystemRights.FullControl,
AccessControlType.Allow));
info.SetAccessControl(security);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
}
I have used the code below to allow Everyone access to a folder:
System.Security.AccessControl.DirectorySecurity sec =
System.IO.Directory.GetAccessControl(directory, AccessControlSections.All);
FileSystemAccessRule accRule = new FileSystemAccessRule("Everyone",
FileSystemRights.Modify,
AccessControlType.Allow);
sec.AddAccessRule(accRule); // setACL
sec.ResetAccessRule(accRule);
Now, the Everyone user is added to the folder, but not with any rights assigned. All the read, write, execute etc. checkboxes are not checked.
First thing I want to tell you is how I found this solution. This is probably more important than the answer because file permissions are hard to get correct.
First thing I did was set the permissions I wanted using the Windows dialogs and checkboxes. I added a rule for "Everyone" and ticked all boxes except "Full Control".
Then I wrote this C# code to tell me exactly what parameters I need to duplicate the Windows settings:
string path = #"C:\Users\you\Desktop\perms"; // path to directory whose settings you have already correctly configured
DirectorySecurity sec = Directory.GetAccessControl(path);
foreach (FileSystemAccessRule acr in sec.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount))) {
Console.WriteLine("{0} | {1} | {2} | {3} | {4}", acr.IdentityReference.Value, acr.FileSystemRights, acr.InheritanceFlags, acr.PropagationFlags, acr.AccessControlType);
}
This gave me this line of output:
Everyone | Modify, Synchronize | ContainerInherit, ObjectInherit | None | Allow
So the solution is simple (yet hard to get right if you don't know what to look for!):
DirectorySecurity sec = Directory.GetAccessControl(path);
// Using this instead of the "Everyone" string means we work on non-English systems.
SecurityIdentifier everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
sec.AddAccessRule(new FileSystemAccessRule(everyone, FileSystemRights.Modify | FileSystemRights.Synchronize, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow));
Directory.SetAccessControl(path, sec);
This will make the checkboxes on the Windows security dialog match what you have already set for your test directory.
The below code checks for the folder existence, if not created, creates one. And then sets every user- permission of that folder with full permission (read & write).
string file = #"D:\Richi";
private static void GrantAccess(string file)
{
bool exists = System.IO.Directory.Exists(file);
if (!exists)
{
DirectoryInfo di = System.IO.Directory.CreateDirectory(file);
Console.WriteLine("The Folder is created Sucessfully");
}
else
{
Console.WriteLine("The Folder already exists");
}
DirectoryInfo dInfo = new DirectoryInfo(file);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
dInfo.SetAccessControl(dSecurity);
}
use FileSystemRights.FullControl instead of FileSystemRights.Modify if you want to allow all actions (ACL).