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.
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'm using below code to give permission to a directory
static void SetPermission(string path)
{
if (Directory.Exists(path))
{
var directoryInfo = new DirectoryInfo(path);
// get the ACL of the directory
var directorySecurity = directoryInfo.GetAccessControl();
// remove inheritance, copying all entries so that they are direct ACEs
directorySecurity.SetAccessRuleProtection(true, true);
// do the operation on the directory
directoryInfo.SetAccessControl(directorySecurity);
// re-read the ACL
directorySecurity = 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 directorySecurity.GetAccessRules(true, false, typeof(SecurityIdentifier)))
{
// if the current entry is one with the identity of "Users", remove it
if (rule.IdentityReference == sid)
directorySecurity.RemoveAccessRule(rule);
}
var ntVirtaulUserName = #"NT Service\ServiceName";
// Add the FileSystemAccessRule to the security settings. give full control for user 'NT Service\ServiceName'
directorySecurity.AddAccessRule(new FileSystemAccessRule(ntVirtaulUserName.Replace(#".\", ""), FileSystemRights.FullControl, AccessControlType.Allow));
// do the operation on the directory
directoryInfo.SetAccessControl(directorySecurity);
}
}
This is working when giving permission to a directory (Test),
SetPermission(#"C:\Test");
Now I would like to give permission a file under the Test directory (log.txt), how to do that?
You can use FileInfo Class to handle permission on files. It's usage is like DirectoryInfo. Here is Microsoft document.
public static void AddFileSecurity(string FileName, string Account, FileSystemRights Rights, AccessControlType ControlType)
{
FileInfo fInfo = new FileInfo(FileName);
FileSecurity fSecurity = fInfo.GetAccessControl();
fSecurity.AddAccessRule(newFileSystemAccessRule(Account,Rights,ControlType));
fInfo.SetAccessControl(fSecurity);
}
Is below code is fine?
var ntVirtaulUserName = #"NT Service\ServiceName";
// Get a FileSecurity object that represents the
// current security settings.
FileSecurity fSecurity = File.GetAccessControl(#"C:\Test\log.txt");
// Add the FileSystemAccessRule to the security settings.
fSecurity.AddAccessRule(new FileSystemAccessRule(ntVirtaulUserName.Replace(#".\", ""), FileSystemRights.FullControl, AccessControlType.Allow));
// Set the new access settings.
File.SetAccessControl(#"C:\Test\log.txt", fSecurity);
I want to grant full access / revoke access to network share folders (I could work with it as a mapped drive as well) using active directory admin account.
How can I File.GetAccessControl, .RemoveAccessRule and .AddAccessRule as active directory admin service account who is at the same time an admin of the network share folders?
Here is a snippet I used to do this.
private void EditAccess(List<string> userlist, string folder)
{
foreach (string user in userlist)
{
var AccessRule = new FileSystemAccessRule(user, FileSystemRights.FullControl,
InheritanceFlags.None,
PropagationFlags.NoPropagateInherit,
AccessControlType.Allow);
DirectoryInfo rootFolder = new DirectoryInfo(folder);
DirectorySecurity rootSec = rootFolder.GetAccessControl(AccessControlSections.Access);
bool Result;
rootSec.ModifyAccessRule(AccessControlModification.Set, AccessRule, out Result);
InheritanceFlags iFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
AccessRule = new FileSystemAccessRule(user, FileSystemRights.FullControl, iFlags, PropagationFlags.InheritOnly, AccessControlType.Allow);
rootSec.ModifyAccessRule(AccessControlModification.Add, AccessRule, out Result);
rootFolder.SetAccessControl(rootSec);
}
}
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);
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());
}
}