API calls claim a user has folder permissions when they don't - c#

Having an issue with a Windows service that needs to monitor/have access to a set of folders, and move files around between those folders.
There's have a bit of boilerplate code that's been used in the past, which will check a given folder for the specific granular permissions for the given user. The odd thing is that I discovered through testing that if I manually deny all permissions on that folder for the account the service is running under, and then run the code, it reports that all is well and the user does in fact have those permissions, even though it's obvious (and demonstrable) that he doesn't.
At first I thought this might be because the service was running under the local System account, but the same issue crops up if it is run with NetworkService as well as with a local user account. This is on Windows 7/2008 R2.
Boilerplate method:
public static void ValidateFolderPermissions(WindowsIdentity userId, string folder, FileSystemRights[] requiredAccessRights)
{
SecurityIdentifier secId;
StringBuilder sb = new StringBuilder();
bool permissionsAreSufficient = false;
bool notAuthorized = false;
String errorMsg = String.Empty;
IdentityReferenceCollection irc = userId.Groups;
foreach (IdentityReference ir in irc)
{
secId = ir.Translate(typeof(SecurityIdentifier)) as SecurityIdentifier;
try
{
DirectoryInfo dInfo = new DirectoryInfo(folder);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
AuthorizationRuleCollection rules = dSecurity.GetAccessRules(true, true, typeof(SecurityIdentifier));
foreach (FileSystemAccessRule ar in rules)
{
if (secId.CompareTo(ar.IdentityReference as SecurityIdentifier) == 0)
{
sb.AppendLine(ar.FileSystemRights.ToString());
foreach (FileSystemRights right in requiredAccessRights)
{
if (right == ar.FileSystemRights)
{
permissionsAreSufficient = true;
break;
}
}
}
}
}
catch (UnauthorizedAccessException)
{
notAuthorized = true;
errorMsg = "user not authorized";
}
catch (SecurityException)
{
// If we failed authorization do not update error
if (!notAuthorized)
errorMsg = "security error";
}
catch (Exception)
{
// If we failed authorization do not update error
if (!notAuthorized)
errorMsg = "invalid folder or folder not accessible";
}
}
if (!permissionsAreSufficient)
{
if (!String.IsNullOrEmpty(errorMsg))
throw new Exception(String.Format("User {0} does not have required access to folder {1}. The error is {2}.", userId.Name, folder, errorMsg));
else
throw new Exception(String.Format("User {0} does not have required access rights to folder {1}.", userId.Name, folder));
}
}
And the calling snippet:
FileSystemRights[] requireAccessRights =
{
FileSystemRights.Delete,
FileSystemRights.Read,
FileSystemRights.FullControl
};
try
{
FolderPermissionValidator.ValidateFolderPermissions(WindowsIdentity.GetCurrent(), inputFolder, requireAccessRights);
Log.Debug("In ServiceConfigurationValidator: {0}, {1}", WindowsIdentity.GetCurrent().Name, inputFolder);
}
catch (Exception ex)
{
Log.Debug("Throwing exception {0}", ex.Message);
}

I don't see anything in ValidateFolderPermissions to check for denials before checking for allowed permissions. If a deny entry prevents access then no amount of allow entries can override it.

This code enumerates the entries in the ACL as FileSystemAccessRule objects, but doesn't bother to check whether AccessControlType is allow or deny.
I also note that the logic returns true if any ACE exactly matches any of the elements of the requiredAccessRights array; I suspect the intended behaviour is that it return true if all of the specified rights are present. This could cause false positives if only some of the requested rights are present, but because it only looks for exact matches it could also cause a false negative, e.g., if the ACE actually gives more rights than are being requested. (Not such a problem in the example given, though, because you're asking for Full Control.)
Another flaw is that it only checks for access entries matching groups the user belongs to; access entries for the user account itself will be ignored. (I'm not sure what the behaviour of WindowsIdentity.Groups is for security primitives such as SYSTEM and NetworkService that are not actual user accounts, although it sounds like that part was working as desired.)
Note that because it is very hard to cope properly with all the possible situations (consider, e.g., an access control entry for Everyone, or for SERVICE) it would be wise to allow the administrator to override the check if it is mistakenly reporting that the account doesn't have the necessary access.

Related

Check if can create folder/file in specific path

I need to check if the current user has write permissions inside the path. Here an example:
string save_path = #"C:\Windows\somefolder";
string my_dir = Path.DirectorySeparatorChar + "foobar";
//check if specific path are valid
if (!Directory.Exists(save_path)) { return; }
if (Directory.Exists(save_path + my_dir)) { return; }
if (canWriteOnPath(save_path)) {
Directory.CreateDirectory(save_path + my_dir);
} else {
//You are not allowed to save here OR not are launching this application as "administrator"
Directory.CreateDirectory(#"C:\Users\contoso\Documents\foobar");
}
solved in this question:
CurrentUserSecurity cus = new CurrentUserSecurity();
bool flag = cus.HasAccess(new DirectoryInfo(#"C:\Windows"), FileSystemRights.Write);
if (flag) {
//yes create that folder
Directory.CreateDirectory(Path.Combine(save_path, my_dir));
} else {
//NO YOU CANT
Directory.CreateDirectory(#"C:\Users\contoso\Documents\foobar");
}
The robust method would be to Try to create the directory and Catch any resulting exception.
The documentation for Directory.CreateDirectory lists the possible exceptions: IOException, UnauthorizedAccessException, ArgumentException, ArgumentNullException, PathTooLongException, DirectoryNotFoundException.
Although unlikely, it is possible that the permissions changed between your code checking that access is allowed and actually trying to create the directory.

what is the best way to check in C# .NET if a directory has access to list files or a unauthorized access exception would rise

how would I check in the best way in .NET 2.0 C# if I have access to a specified directory
for listing top directory files e.g. a system directory or system volume information folder etc.
My code for it looks now like this, but I think it is not the best way to check for it since it produces an exception each time which is handled by the check function and returning based on it a result.
I would like to use a function which doesn't throw an error to check if in the specified directory is access to list files or maybe my code can be improved or optimized. I might have to check through a thousand directories if exists an access or not. Raising thousand exceptions might cause a problem, but I don't know.
//here my code using System.IO;
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show(DirectoryCanListFiles("C:\\Windows\\Prefetch").ToString());
}
public static bool DirectoryCanListFiles(string DirectoryPath)
{
try
{
Directory.GetFiles(DirectoryPath, "*", SearchOption.TopDirectoryOnly);
}
catch { return false; }
return true;
}
The best way to check the permission, is try to access the direcoty (read/write/list) & catch the UnauthorizedAccessException.
However for some reason out there, if you want to check permissions, following code should satisfy your need.
You need to read Access Rules for the directory.
private bool DirectoryCanListFiles(string folder)
{
bool hasAccess = false;
//Step 1. Get the userName for which, this app domain code has been executing
string executingUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
NTAccount acc = new NTAccount(executingUser);
SecurityIdentifier secId = acc.Translate(typeof(SecurityIdentifier)) as SecurityIdentifier;
DirectorySecurity dirSec = Directory.GetAccessControl(folder);
//Step 2. Get directory permission details for each user/group
AuthorizationRuleCollection authRules = dirSec.GetAccessRules(true, true, typeof(SecurityIdentifier));
foreach (FileSystemAccessRule ar in authRules)
{
if (secId.CompareTo(ar.IdentityReference as SecurityIdentifier) == 0)
{
var fileSystemRights = ar.FileSystemRights;
Console.WriteLine(fileSystemRights);
//Step 3. Check file system rights here, read / write as required
if (fileSystemRights == FileSystemRights.Read ||
fileSystemRights == FileSystemRights.ReadAndExecute ||
fileSystemRights == FileSystemRights.ReadData ||
fileSystemRights == FileSystemRights.ListDirectory)
{
hasAccess = true;
}
}
}
return hasAccess;
}

Checking for shared folder write access for current user

I have following method to check current user have write access to given network location
DirectorySecurity shareSecurity = new DirectoryInfo(this.GetFileServerRootPath).GetAccessControl();
foreach (FileSystemAccessRule fsRule in shareSecurity.GetAccessRules(true, true, typeof(NTAccount)))
{
// check write permission for current user
if (AccessControlType.Allow == fsRule.AccessControlType &&
FileSystemRights.Write == (fsRule.FileSystemRights & FileSystemRights.Write))
{
if (null != fsRule.IdentityReference &&
fsRule.IdentityReference.Value == WindowsIdentity.GetCurrent().Name)
{
return true;
}
}
}
return false;
but problem is when folder permission given to user group, above method is failed.
I don't want to check the permissions by writing a file and decide the write access permissions.
is there any way to find current user in the IdentityReference.Value? or suggestions to overcome this issue?
This may work for you:
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, this.GetFileServerRootPath);
try
{
writePermission.Demand();
return true;
}
catch (SecurityException s)
{
return false;
}
Just curious - why not just try/catch your write operation?
May be you should use DirectoryInfo on that directory to get its security policies.

Adding User to AD Security Group fails after user creation

I am using a WCF service to expose certain Active Directory management functions to our help desk staff without giving them the group membership required to manipulate AD directly. Adding users to and removing users from groups is working like a champ with existing users, but every time I create a new user it throws back this fun code:
The server is unwilling to process the request. (Exception from HRESULT: 0x80072035)
The code I use to add the user to the group is
public bool AddGroupToUser(string userDn, string groupDn)
{
try
{
DirectoryEntry groupEntry = LdapTools.GetDirectoryEntry(groupDn);
groupEntry.Properties["member"].Add(userDn);
groupEntry.CommitChanges();
groupEntry.Close();
return true;
}
catch (DirectoryServicesCOMException)
{
return false;
}
}
Everything I've read on the subject is rather vague and I can't seem to find out WHY the exception is being triggered. Any ideas?
UPDATE
This is the code I use to create the user in AD:
try
{
DirectoryEntry container = GetDirectoryEntry(storageOu);
DirectoryEntry newUser = container.Children.Add("CN=" + employee.FullName, "user");
newUser.Properties["sAMAccountName"].Value = employee.Username;
newUser.Properties["displayName"].Value = employee.FullName;
newUser.Properties["givenName"].Value = employee.FirstName;
newUser.Properties["sn"].Value = employee.LastName;
newUser.Properties["department"].Value = departmentName;
newUser.Properties["userPrincipalName"].Value = employee.Username + "#APEX.Local";
newUser.CommitChanges();
newUser.Invoke("SetPassword", new object[] { employee.Password });
newUser.CommitChanges();
AdsUserFlags userSettings = AdsUserFlags.NormalAccount;
newUser.Properties["userAccountControl"].Value = userSettings;
newUser.CommitChanges();
ldapPath = newUser.Path;
newUser.Close();
container.Close();
}
catch (DirectoryServicesCOMException e)
{
// Something went wrong... what???
}
catch (Exception e)
{
// Something else went wrong
}
The new user can login, and can be manipulated using the standard MS tools.
Apparently, unless I'm missing an important step here, the issue is time. When forcing the system to sleep for 8 seconds before attempting to add groups to the new user the process works. If I do it any sooner than the 8 second mark it fails.
I'm marking this answer as correct unless anybody can provide me a better solution.
Try:
public bool AddUserToGroup(string userName, string groupName)
{
bool done = false;
GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupName);
if (group == null)
{
group = new GroupPrincipal(context, groupName);
}
UserPrincipal user = UserPrincipal.FindByIdentity(context, userName);
if (user != null & group != null)
{
group.Members.Add(user);
group.Save();
done = (user.IsMemberOf(group));
}
return done;
}
Reference:
http://www.c-sharpcorner.com/UploadFile/dhananjaycoder/activedirectoryoperations11132009113015AM/activedirectoryoperations.aspx
As it mentioned in here, can you tell us that you set the password of the newly created users? In the reference, it says that you should SetPassword of the user before doing anything with it.
Time issue could occur from a Active Directory replication issue.
Once, I gave a product to my customer which creates user over Active Directory, which has over 10.000 records in it, with the given informations on a SharePoint form and then program adds the user to a SharePoint group. The problem was, SharePoint throws an error about the newly created user, it says user does not exist in AD.
So, one of out system engineer told us about the replication opearation on the Active Directory that it could be the source of the problem and it was true.
For the solution, program tries to do the job for 10 times with 1 second sleeps. No problem occurred so far. So as a solution, I would suggest you to check out the AD for the existence of replication method.
P.S: When I asked questions to my customers system engineers about the replication operation, they all rejected the existence of AD replication operation and told me that the program has the problem. They believed me when we created a new user in AD from a computer, we couldn't see the user for 5 seconds on an another computer.

Getting / setting file owner in C#

I have a requirement to read and display the owner of a file (for audit purposes), and potentially changing it as well (this is secondary requirement). Are there any nice C# wrappers?
After a quick google, I found only the WMI solution and a suggestion to PInvoke GetSecurityInfo
No need to P/Invoke. System.IO.File.GetAccessControl will return a FileSecurity object, which has a GetOwner method.
Edit: Reading the owner is pretty simple, though it's a bit of a cumbersome API:
const string FILE = #"C:\test.txt";
var fs = File.GetAccessControl(FILE);
var sid = fs.GetOwner(typeof(SecurityIdentifier));
Console.WriteLine(sid); // SID
var ntAccount = sid.Translate(typeof(NTAccount));
Console.WriteLine(ntAccount); // DOMAIN\username
Setting the owner requires a call to SetAccessControl to save the changes. Also, you're still bound by the Windows rules of ownership - you can't assign ownership to another account. You can give take ownership perms, and they have to take ownership.
var ntAccount = new NTAccount("DOMAIN", "username");
fs.SetOwner(ntAccount);
try {
File.SetAccessControl(FILE, fs);
} catch (InvalidOperationException ex) {
Console.WriteLine("You cannot assign ownership to that user." +
"Either you don't have TakeOwnership permissions, or it is not your user account."
);
throw;
}
FileInfo fi = new FileInfo(#"C:\test.txt");
string user = fi.GetAccessControl().GetOwner(typeof(System.Security.Principal.NTAccount)).ToString();

Categories