This should be a fairly simple problem, but for some reason I can't seem to get this to work. All I'd like to do is set the permissions on a given directory to allow full access to all users. Here's the code I have so far:
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(destinationDirectory);
FileSystemAccessRule fsar = new FileSystemAccessRule("Users", FileSystemRights.FullControl, AccessControlType.Allow);
DirectorySecurity ds = null;
if (!di.Exists)
{
System.IO.Directory.CreateDirectory(destinationDirectory);
}
ds = di.GetAccessControl();
ds.AddAccessRule(fsar);
No exceptions get thrown, but nothing happens, either. When I check the directory permissions after the code has been run, I see no changes.
Any ideas?
You also need to call SetAccessControl to apply the changes.
ds = di.GetAccessControl();
ds.AddAccessRule(fsar);
di.SetAccessControl(ds); // nothing happens until you do this
It seems that the examples on MSDN are sorely lacking in detail, as discussed here. I hacked the code from this article to get the following which behaves well:
static bool SetAcl()
{
FileSystemRights Rights = (FileSystemRights)0;
Rights = FileSystemRights.FullControl;
// *** Add Access Rule to the actual directory itself
FileSystemAccessRule AccessRule = new FileSystemAccessRule("Users", Rights,
InheritanceFlags.None,
PropagationFlags.NoPropagateInherit,
AccessControlType.Allow);
DirectoryInfo Info = new DirectoryInfo(destinationDirectory);
DirectorySecurity Security = Info.GetAccessControl(AccessControlSections.Access);
bool Result = false;
Security.ModifyAccessRule(AccessControlModification.Set, AccessRule, out Result);
if (!Result)
return false;
// *** Always allow objects to inherit on a directory
InheritanceFlags iFlags = InheritanceFlags.ObjectInherit;
iFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
// *** Add Access rule for the inheritance
AccessRule = new FileSystemAccessRule("Users", Rights,
iFlags,
PropagationFlags.InheritOnly,
AccessControlType.Allow);
Result = false;
Security.ModifyAccessRule(AccessControlModification.Add, AccessRule, out Result);
if (!Result)
return false;
Info.SetAccessControl(Security);
return true;
}
David Heffernan answer does not work on a non-English machine, where trying to set the permissions on "Users" fails with an IdentityNotMapped exception. The following code will work everywhere, by using WellKnownSidType.BuiltinUsersSid instead:
static void SetFullControlPermissionsToEveryone(string path)
{
const FileSystemRights rights = FileSystemRights.FullControl;
var allUsers = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);
// Add Access Rule to the actual directory itself
var accessRule = new FileSystemAccessRule(
allUsers,
rights,
InheritanceFlags.None,
PropagationFlags.NoPropagateInherit,
AccessControlType.Allow);
var info = new DirectoryInfo(path);
var security = info.GetAccessControl(AccessControlSections.Access);
bool result;
security.ModifyAccessRule(AccessControlModification.Set, accessRule, out result);
if (!result)
{
throw new InvalidOperationException("Failed to give full-control permission to all users for path " + path);
}
// add inheritance
var inheritedAccessRule = new FileSystemAccessRule(
allUsers,
rights,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.InheritOnly,
AccessControlType.Allow);
bool inheritedResult;
security.ModifyAccessRule(AccessControlModification.Add, inheritedAccessRule, out inheritedResult);
if (!inheritedResult)
{
throw new InvalidOperationException("Failed to give full-control permission inheritance to all users for " + path);
}
info.SetAccessControl(security);
}
Related
I'm developing a UWP software in which i need to write into "input.txt" file located in the Temp directory. however, when giving permission to this directory in release mode i have problem and it seen like the permission is not set:
string str = inputmessage.Text;
string path = #"input.txt";
try
{
SetAccess(WindowsIdentity.GetCurrent().Name,
Path.GetTempPath());// Path.GetFullPath("."));
// FileStream.SetAccessControl();
File.WriteAllText(Path.GetTempPath()+path,str);
}
and set access is defined as:
private static bool SetAccess(string user, string folder)
{
const FileSystemRights Rights = FileSystemRights.FullControl;
// *** Add Access Rule to the actual directory itself
var AccessRule = new FileSystemAccessRule(user, Rights,
InheritanceFlags.None,
PropagationFlags.NoPropagateInherit,
AccessControlType.Allow);
var Info = new DirectoryInfo(folder);
var Security = Info.GetAccessControl(AccessControlSections.Access);
bool Result;
Security.ModifyAccessRule(AccessControlModification.Set, AccessRule, out Result);
if (!Result) return false;
// *** Always allow objects to inherit on a directory
const InheritanceFlags iFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
// *** Add Access rule for the inheritance
AccessRule = new FileSystemAccessRule(user, Rights,
iFlags,
PropagationFlags.InheritOnly,
AccessControlType.Allow);
Security.ModifyAccessRule(AccessControlModification.Add, AccessRule, out Result);
if (!Result) return false;
Info.SetAccessControl(Security);
return true;
}
FileSystemAccessRule is belong to System.Security.AccessControl Namespace, and it is not compatible with uwp. You could not use it to access TemporaryFolder.
If you want to write into "input.txt" file located in the Temp directory. Please refer the following process.
private async void writeTextToTem(string info)
{
var file = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("info.text", CreationCollisionOption.OpenIfExists);
if (file != null)
{
await Windows.Storage.FileIO.WriteTextAsync(file, info);
}
}
And Path.GetTempPath() also work in uwp, and the matching folder is
C:\Users\Administrator\AppData\Local\Packages\497f6a93-9de3-4985-b27e-c2215ebabe72_75crXXXXXXX\AC\Temp\, it is contained in the app's sandbox you could access it directly.
var path = Path.GetTempPath();
var folder = await StorageFolder.GetFolderFromPathAsync(path);
var file = await folder.CreateFileAsync("info.text", CreationCollisionOption.OpenIfExists);
if (file != null)
{
await Windows.Storage.FileIO.WriteTextAsync(file, str);
}
For more detail you could refer File access permissions.
I'm trying to change the permissions for a directory. To do this I am running an elevated process that actually performs the SetAccessControl.
static void Main(string[] args)
{
var options = new Options();
if (!CommandLine.Parser.Default.ParseArguments(args, options)) return;
var myDirectoryInfo = new DirectoryInfo(options.folder);
var myDirectorySecurity = myDirectoryInfo.GetAccessControl();
var usr = options.user;
myDirectorySecurity.AddAccessRule(new FileSystemAccessRule(usr, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly, AccessControlType.Allow));
try
{
myDirectoryInfo.SetAccessControl(myDirectorySecurity);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
When I run this as administrator there are no errors, but the folder access permissions remain unchanged. Any ideas what is wrong?
The answer that worked for me was using ModifyAccessRule to first grant permissions to the directory. Then to add the inheritance rules.
Also I found that the windows explorer is not always showing the current permissions, not sure what causes it to refresh, but I noticed that at times the permissions were set properly, and my program could access the files in directory,even though explorer showed no permission.
private static bool SetAccess(string user, string folder)
{
const FileSystemRights Rights = FileSystemRights.FullControl;
// *** Add Access Rule to the actual directory itself
var AccessRule = new FileSystemAccessRule(user, Rights,
InheritanceFlags.None,
PropagationFlags.NoPropagateInherit,
AccessControlType.Allow);
var Info = new DirectoryInfo(folder);
var Security = Info.GetAccessControl(AccessControlSections.Access);
bool Result;
Security.ModifyAccessRule(AccessControlModification.Set, AccessRule, out Result);
if (!Result) return false;
// *** Always allow objects to inherit on a directory
const InheritanceFlags iFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
// *** Add Access rule for the inheritance
AccessRule = new FileSystemAccessRule(user, Rights,
iFlags,
PropagationFlags.InheritOnly,
AccessControlType.Allow);
Security.ModifyAccessRule(AccessControlModification.Add, AccessRule, out Result);
if (!Result) return false;
Info.SetAccessControl(Security);
return true;
}
Use the following instead of myDirectoryInfo.SetAccessControl(myDirectorySecurity);
try
{
Directory.SetAccessControl(options.folder,myDirectorySecurity);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I add group in ACL for my folder, but I can't check/unchek options for it.
String account = #"HYPROSTROY\Все сотрудники";
FileSystemRights rights = FileSystemRights.FullControl;
// I have tried and it too:
// FileSystemRights rights = FileSystemRights.Read | FileSystemRights.Write | FileSystemRights.Modify;
AccessControlType controlType = AccessControlType.Allow;
DirectorySecurity security = local_commonDir.Parent.GetAccessControl(AccessControlSections.Access);
FileSystemAccessRule rule = new FileSystemAccessRule(account, rights, controlType);
security.AddAccessRule(rule);
// local_commonDir - экземпляр DirectoryInfo
local_commonDir.Parent.SetAccessControl(security);
Group was added, but all options are unchecked:
UPD ===
I have try other method:
// String account = Path.Combine(Environment.MachineName, "Пользователи");
String account = #"HYPROSTROY\Все сотрудники";
FileSystemRights rights = FileSystemRights.FullControl;
AccessControlType controlType = AccessControlType.Allow;
DirectorySecurity security = local_commonDir.Parent.GetAccessControl(AccessControlSections.All);
FileSystemAccessRule rule = new FileSystemAccessRule(account, rights, controlType);
//security.AddAccessRule(rule);
Boolean result;
security.ModifyAccessRule(AccessControlModification.Add, rule, out result);
local_commonDir.Parent.SetAccessControl(security);
But options is unchecked :(
Where is my mistake?
This works for me:
dir = "C:\test";
DirectorySecurity security = Directory.GetAccessControl(dir);
FileSystemAccessRule rule = new FileSystemAccessRule("Account", FileSystemRights.FullControl, AccessControlType.Allow);
security.AddAccessRule(rule);
Directory.SetAccessControl(dir,security);
I found solution:
WindowsIdentity id = WindowsIdentity.GetCurrent();
var sid = new SecurityIdentifier(WellKnownSidType.AccountDomainUsersSid, id.User.AccountDomainSid);
var security = dir.GetAccessControl();
var rule = new FileSystemAccessRule(sid,
FileSystemRights.FullControl,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.None,
AccessControlType.Allow);
security.AddAccessRule(rule);
dir.SetAccessControl(security);
we have created an application which provides the ability to set a recursive "Deny" on a windows folder for a certain Active Directory group. Basically the same as going into the properties dialog in windows explorer and clicking on security and the adding an AD group with the permission of Deny.
We are using this code:
public void DenyAccessInherited(string DomainAndSamAccountName)
{
SetPermissionAndInherit(this.FolderPath,
NTFSPermission.PropagationFlags.CONTAINER_AND_OBJECT_INHERIT_ACE,
NTFSPermission.NTFSPermission_FULL_CONTROL, NTFSPermission.ACETypes.ADS_ACETYPE_ACCESS_DENIED,
DomainAndSamAccountName);
}
public static void SetPermissionAndInherit(string FolderPath, PropagationFlags Inheritance, int Permission, ACETypes ACETypeAccessAllowedDenied, string DomainAndUsername)
{
AccessControlList dacl = new AccessControlList();
SecurityDescriptor sd = new SecurityDescriptor();
AccessControlEntry newAce = new AccessControlEntry();
ADsSecurityUtility sdUtil = new ADsSecurityUtility();
OnProgress(DomainAndUsername, FolderPath);
sd = sdUtil.GetSecurityDescriptor(FolderPath, ADS_PATH_FILE, ADS_SD_FORMAT_IID);
dacl = sd.DiscretionaryAcl;
RemoveTrusteeFromDACL(dacl, DomainAndUsername);
newAce.Trustee = DomainAndUsername;
newAce.AccessMask = Permission;
newAce.AceFlags = (int)Inheritance;
newAce.AceType = (int)ACETypeAccessAllowedDenied;
dacl.AddAce(newAce);
sdUtil.SetSecurityDescriptor(FolderPath, ADS_PATH_FILE, sd, ADS_SD_FORMAT_IID);
foreach (string File in Directory.GetFiles(FolderPath))
{
SetACE(File, DomainAndUsername, Permission, PropagationFlags.INHERITED_ACE, ACETypeAccessAllowedDenied);
}
foreach (string SubFolderPath in Directory.GetDirectories(FolderPath))
{
SetInheritedPermission(SubFolderPath, DomainAndUsername, Permission, ACETypeAccessAllowedDenied);
}
}
private static void SetInheritedPermission(string FolderPath, string DomainAndUsername, int PermissionFlags, ACETypes AccessFlags)
{
AccessControlList dacl = new AccessControlList();
SecurityDescriptor sd = new SecurityDescriptor();
AccessControlEntry newAce = new AccessControlEntry();
ADsSecurityUtility sdUtil = new ADsSecurityUtility();
SetACE(FolderPath, DomainAndUsername, PermissionFlags, (PropagationFlags)(PropagationFlags.CONTAINER_AND_OBJECT_INHERIT_ACE | PropagationFlags.INHERITED_ACE), AccessFlags);
foreach (string File in Directory.GetFiles(FolderPath))
{
SetACE(File, DomainAndUsername, PermissionFlags, PropagationFlags.INHERITED_ACE, AccessFlags);
}
foreach (string SubFolderPath in Directory.GetDirectories(FolderPath))
{
SetInheritedPermission(SubFolderPath, DomainAndUsername, PermissionFlags, AccessFlags);
}
}
private static void SetACE(string FileOrFolder, string DomainAndUsername, int PermissionFlags, PropagationFlags InheritanceFlags, ACETypes AccessFlags)
{
AccessControlList dacl = new AccessControlList();
SecurityDescriptor sd = new SecurityDescriptor();
AccessControlEntry newAce = new AccessControlEntry();
ADsSecurityUtility sdUtil = new ADsSecurityUtility(); sd = sdUtil.GetSecurityDescriptor(FileOrFolder, ADS_PATH_FILE, ADS_SD_FORMAT_IID);
sd.Control = sd.Control;
OnProgress(DomainAndUsername, FileOrFolder);
dacl = sd.DiscretionaryAcl;
RemoveTrusteeFromDACL(dacl, DomainAndUsername);
newAce.Trustee = DomainAndUsername;
newAce.AccessMask = PermissionFlags;
newAce.AceFlags = (int)InheritanceFlags;
newAce.AceType = (int)AccessFlags;
dacl.AddAce(newAce);
sdUtil.SetSecurityDescriptor(FileOrFolder, ADS_PATH_FILE, sd, ADS_SD_FORMAT_IID);
}
Now we have encountered a large folder with lots of html documents, about 12000 files, and the method above is very slow. It takes about 7 minutes to process the file security. However, when managing security through windows explorer/security it only takes about 20 seconds so there must be some way to optimize this in C#.
Edit: When I leave out the recursion and only set the SecurityDescriptor on the top folder, none of the files below it have the deny for the AD group, only the top folder.
I solved it. I completely dumped the above code and went another way:
public override void DenyAccessInherited(string FolderPath,string DomainAndSamAccountName)
{
using (Impersonator imp = new Impersonator(this.connection.GetSamAccountName(), this.connection.GetDomain(), this.connection.Password))
{
FileSystemAccessRule rule = new FileSystemAccessRule(DomainAndSamAccountName, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, System.Security.AccessControl.PropagationFlags.InheritOnly, AccessControlType.Deny);
DirectoryInfo di = new DirectoryInfo(FolderPath);
DirectorySecurity security = di.GetAccessControl(AccessControlSections.All);
bool modified;
security.ModifyAccessRule(AccessControlModification.Add, rule, out modified);
if (modified)
di.SetAccessControl(security);
}
}
This is very slim and very fast.
Nested folders and files should inherit parent's security settings so you don't need to set it recursively for all. Try to set it only for root folder.
I have a program that's creating a secure directory for user output. This is working correctly, but the files I create in it (or copy to it) are ending up with only administrator access.
DirectoryInfo outputDirectory =
baseOutputDirectory.CreateSubdirectory(outputDirectoryName,
GetDirectorySecurity(searchHits.Request.UserId));
...
private DirectorySecurity GetDirectorySecurity(string owner)
{
const string LOG_SOURCE = "GetDirectorySecurity";
DirectorySecurity ds = new DirectorySecurity();
System.Security.Principal.NTAccount ownerAccount =
new System.Security.Principal.NTAccount(owner);
ds.SetOwner(ownerAccount);
ds.AddAccessRule(
new FileSystemAccessRule(owner,
FileSystemRights.FullControl,
AccessControlType.Allow));
//AdminUsers is a List<string> that contains a list from configuration
// That represents the admins who should be allowed
foreach (string adminUser in AdminUsers)
{
ds.AddAccessRule(
new FileSystemAccessRule(adminUser,
FileSystemRights.FullControl,
AccessControlType.Allow));
}
return ds;
}
/// <summary>
/// This method copies any static supporting files, such as javascripts
/// </summary>
/// <param name="outputDirectory"></param>
private void CopySupportingFiles(DirectoryInfo outputDirectory)
{
foreach (FileInfo file in SupportingFiles)
{
file.CopyTo(
Path.Combine(outputDirectory.FullName, file.Name));
}
}
etc, etc, etc.
What am I doing wrong? Why aren't the permissions cascading?
It looks like you should be setting the InheritanceFlags and PropagationFlags when setting the DirectorySecurity (I believe it overwrite whatever you've manually set).
private DirectorySecurity GetDirectorySecurity(string owner)
{
const string LOG_SOURCE = "GetDirectorySecurity";
DirectorySecurity ds = new DirectorySecurity();
System.Security.Principal.NTAccount ownerAccount =
new System.Security.Principal.NTAccount(owner);
ds.SetOwner(ownerAccount);
ds.AddAccessRule(
new FileSystemAccessRule(owner,
FileSystemRights.FullControl,
InheritanceFlags.ObjectInherit,
PropagationFlags.InheritOnly,
AccessControlType.Allow));
//AdminUsers is a List<string> that contains a list from configuration
// That represents the admins who should be allowed
foreach (string adminUser in AdminUsers)
{
ds.AddAccessRule(
new FileSystemAccessRule(adminUser,
FileSystemRights.FullControl,
InheritanceFlags.ObjectInherit,
PropagationFlags.InheritOnly,
AccessControlType.Allow));
}
return ds;
}