I have a file repository service that for the most part works. The issue is, once I started to implement DirectorySecurity into the methods I ran into issues. The directories create just fine, the assigned accounts to directories are given access, but all permissions end up under "special permissions". That, however, is not the problem. The problem arises when I try to write a new file. I get the following error message:
System.ServiceModel.FaultException'1 ... Access to the path ... is denied.
As I said, the directory structure is created to save the file. The file, however, does not make it into the folder. I do see all my allowed users, and I can place files in there. Again, however, doing so manually in windows I can run .exe files from the directory despite the fact I denied the permission in the AccessControls. Below is an example of the 'Put' method and another method I use to build the DirectorySecurity object.
Questions I have:
Any thoughts on what is going wrong, or advice on security to prevent executable?
Does Visual Studio 2012 need to use a specific "Account" (e.g. NETWORK SERVICES") when running in Debug mode? I did not add that to the permission set.
Is there a timing issue when creating a directory? If so would hit help to Thread.Sleep for a bit to allow Windows to catch up?
Any other advice / things I am missing or did wrong here?
Note on Environment: Windows 7 Ultimate, Visual Studio 2012 (running Windows Form test client via Debug start). The Service is currently installed locally via WAS (running in Services.msc). This is a net.Tcp service with endpoints exposed to client and proxy built manually using ChannelFactory. Get methods seem to work fine. Put methods fail to put the final file into the created directory, and I have concerns that the permissions are actually working correctly.
//----------------------------
//WCF Service - PutText Method
//----------------------------
//NOTE: dir = virtual directory
public bool PutTextFile(string dir, string fileName, string data)
{
string path;
string fExt;
DirectoryInfo d;
#region Null / value checks
//...
#endregion
//check & enforce file extension
fExt = Path.GetExtension(fileName).ToLower();
if (fExt != ".txt" && fExt != ".xml" && fExt != ".csv")
{
fileName = Path.GetFileNameWithoutExtension(fileName) + ".txt";
}
//check directory exists
d = new DirectoryInfo(Path.Combine(this._fileRepositoryRoot, dir));//_fileRepositoryRoot is taken from .config
if (!d.Exists)
{
try
{
DirectorySecurity ds = this.CreateDirSecurityObj(); //<-- See method below
d.Create(ds);
}
catch (Exception e)
{
//...
}
}
//complete path
path = Path.Combine(this._fileRepositoryRoot, dir, fileName);
try
{
using (StreamWriter sw = File.CreateText(path))
{
sw.Write(data);
}
return true;
}
catch (Exception e)
{
//...
}
}
//-------------------------
//Directory Security Method
//-------------------------
//NOTE:
//"private string _myDomain" and "private string _myUserAccount" are pulled from an app.config file
private DirectorySecurity CreateDirSecurityObj()
{
System.Security.AccessControl.DirectorySecurity ds = new System.Security.AccessControl.DirectorySecurity();
//define User rights
FileSystemRights grantUserRights = FileSystemRights.AppendData;
grantUserRights |= FileSystemRights.Synchronize;
grantUserRights |= FileSystemRights.CreateDirectories;
grantUserRights |= FileSystemRights.CreateFiles;
grantUserRights |= FileSystemRights.ListDirectory;
grantUserRights |= FileSystemRights.Read;
grantUserRights |= FileSystemRights.Write;
grantUserRights |= FileSystemRights.Delete;
FileSystemRights denyUserRights = FileSystemRights.ExecuteFile;
denyUserRights |= FileSystemRights.ChangePermissions;
//define access rule
FileSystemAccessRule grantRule_User = new FileSystemAccessRule(Path.Combine(this._myDomain, this._myUserAccount), grantUserRights, AccessControlType.Allow);
FileSystemAccessRule denyRule_User = new FileSystemAccessRule(Path.Combine(this._myDomain, this._myUserAccount), denyUserRights, AccessControlType.Deny);
//add access rule
ds.AddAccessRule(grantRule_User);
ds.AddAccessRule(denyRule_User);
ds.AddAccessRule(grantRule_Admin);
return ds;
}
UPDATE: I tried adding permissions for "NT AUTHORITY\NETWORK SERVICES" (limited access) and "NT AUTHORITY\SYSTEM" (full access). I still get the same denial message. Turning off the DirectorySecurity practices works fine. This must be a problem with the 'mix' or rules. Repeat attempts fail even when directory is in place.