it-swarm.com.de

Überprüfen auf Verzeichnis- und Dateischreibberechtigungen in .NET

In meiner .NET 2.0-Anwendung muss ich überprüfen, ob ausreichende Berechtigungen zum Erstellen und Schreiben von Dateien in einem Verzeichnis vorhanden sind. Zu diesem Zweck habe ich die folgende Funktion, die versucht, eine Datei zu erstellen und ein einzelnes Byte in die Datei zu schreiben. Anschließend lösche ich mich selbst, um zu testen, ob Berechtigungen vorhanden sind.

Ich dachte mir, der beste Weg zu überprüfen war, es tatsächlich zu versuchen und alle möglichen Ausnahmen zu erkennen. Ich bin nicht besonders glücklich über die allgemeine Ausnahme, also gibt es einen besseren oder vielleicht akzeptierteren Weg, dies zu tun?

private const string TEMP_FILE = "\\tempFile.tmp";

/// <summary>
/// Checks the ability to create and write to a file in the supplied directory.
/// </summary>
/// <param name="directory">String representing the directory path to check.</param>
/// <returns>True if successful; otherwise false.</returns>
private static bool CheckDirectoryAccess(string directory)
{
    bool success = false;
    string fullPath = directory + TEMP_FILE;

    if (Directory.Exists(directory))
    {
        try
        {
            using (FileStream fs = new FileStream(fullPath, FileMode.CreateNew, 
                                                            FileAccess.Write))
            {
                fs.WriteByte(0xff);
            }

            if (File.Exists(fullPath))
            {
                File.Delete(fullPath);
                success = true;
            }
        }
        catch (Exception)
        {
            success = false;
        }
    }
74
Andy

Die Antworten von Richard und Jason sind in die richtige Richtung. Was Sie jedoch tun sollten, ist die effektiven Berechtigungen berechnen für die Benutzeridentität, die Ihren Code ausführt. Keines der Beispiele oben berücksichtigt beispielsweise die Gruppenzugehörigkeit.

Ich bin mir ziemlich sicher Keith Brown hatte etwas Code, um dies in seiner Wiki-Version zu tun (derzeit offline) von The .NET Developers Guide to Windows Security . Dies wird auch in seinem Programmieren von Windows-Sicherheit Buch ausführlich erörtert.

Die Berechnung effektiver Berechtigungen ist nichts für schwache Nerven, und Ihr Code, der versucht, eine Datei zu erstellen und die ausgelöste Sicherheitsausnahme abzufangen, ist wahrscheinlich der Pfad des geringsten Widerstands. 

21
Kev

Directory.GetAcessControl(path) macht das, wonach Sie fragen.

public static bool HasWritePermissionOnDir(string path)
{
    var writeAllow = false;
    var writeDeny = false;
    var accessControlList = Directory.GetAccessControl(path);
    if (accessControlList == null)
        return false;
    var accessRules = accessControlList.GetAccessRules(true, true, 
                                typeof(System.Security.Principal.SecurityIdentifier));
    if (accessRules ==null)
        return false;

    foreach (FileSystemAccessRule rule in accessRules)
    {
        if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write) 
            continue;

        if (rule.AccessControlType == AccessControlType.Allow)
            writeAllow = true;
        else if (rule.AccessControlType == AccessControlType.Deny)
            writeDeny = true;
    }

    return writeAllow && !writeDeny;
}

(FileSystemRights.Write & rights) == FileSystemRights.Write verwendet etwas namens "Flags". Wenn Sie nicht wissen, was es ist, sollten Sie sich wirklich darüber informieren :)

46
richardwiden

Deny hat Vorrang vor Allow. Lokale Regeln haben Vorrang vor ererbten Regeln. Ich habe viele Lösungen gesehen (einschließlich einiger Antworten, die hier gezeigt werden), aber keine davon berücksichtigt, ob Regeln vererbt sind oder nicht. Daher empfehle ich den folgenden Ansatz, der die Regelvererbung berücksichtigt (ordentlich in eine Klasse eingeschlossen):

public class CurrentUserSecurity
{
    WindowsIdentity _currentUser;
    WindowsPrincipal _currentPrincipal;

    public CurrentUserSecurity()
    {
        _currentUser = WindowsIdentity.GetCurrent();
        _currentPrincipal = new WindowsPrincipal(_currentUser);
    }

    public bool HasAccess(DirectoryInfo directory, FileSystemRights right)
    {
        // Get the collection of authorization rules that apply to the directory.
        AuthorizationRuleCollection acl = directory.GetAccessControl()
            .GetAccessRules(true, true, typeof(SecurityIdentifier));
        return HasFileOrDirectoryAccess(right, acl);
    }

    public bool HasAccess(FileInfo file, FileSystemRights right)
    {
        // Get the collection of authorization rules that apply to the file.
        AuthorizationRuleCollection acl = file.GetAccessControl()
            .GetAccessRules(true, true, typeof(SecurityIdentifier));
        return HasFileOrDirectoryAccess(right, acl);
    }

    private bool HasFileOrDirectoryAccess(FileSystemRights right,
                                          AuthorizationRuleCollection acl)
    {
        bool allow = false;
        bool inheritedAllow = false;
        bool inheritedDeny = false;

        for (int i = 0; i < acl.Count; i++) {
            var currentRule = (FileSystemAccessRule)acl[i];
            // If the current rule applies to the current user.
            if (_currentUser.User.Equals(currentRule.IdentityReference) ||
                _currentPrincipal.IsInRole(
                                (SecurityIdentifier)currentRule.IdentityReference)) {

                if (currentRule.AccessControlType.Equals(AccessControlType.Deny)) {
                    if ((currentRule.FileSystemRights & right) == right) {
                        if (currentRule.IsInherited) {
                            inheritedDeny = true;
                        } else { // Non inherited "deny" takes overall precedence.
                            return false;
                        }
                    }
                } else if (currentRule.AccessControlType
                                                  .Equals(AccessControlType.Allow)) {
                    if ((currentRule.FileSystemRights & right) == right) {
                        if (currentRule.IsInherited) {
                            inheritedAllow = true;
                        } else {
                            allow = true;
                        }
                    }
                }
            }
        }

        if (allow) { // Non inherited "allow" takes precedence over inherited rules.
            return true;
        }
        return inheritedAllow && !inheritedDeny;
    }
}

Ich habe jedoch die Erfahrung gemacht, dass dies auf Remotecomputern nicht immer funktioniert, da Sie dort nicht immer das Recht haben, die Dateizugriffsrechte abzufragen. Die Lösung in diesem Fall ist zu versuchen; Möglicherweise sogar, indem Sie einfach versuchen, eine temporäre Datei zu erstellen, wenn Sie den Zugriff wissen müssen, bevor Sie mit den "echten" Dateien arbeiten.

Die akzeptierte Antwort von Kev auf diese Frage gibt eigentlich keinen Code an, sondern verweist auf andere Ressourcen, auf die ich keinen Zugriff habe. Also hier ist mein bester Versuch der Funktion. Es prüft tatsächlich, ob die Berechtigung, die es betrachtet, eine Berechtigung "Schreiben" ist und dass der aktuelle Benutzer der entsprechenden Gruppe angehört.

Es ist vielleicht nicht vollständig in Bezug auf Netzwerkpfade oder was auch immer, aber es ist gut genug für meinen Zweck, lokale Konfigurationsdateien unter "Programme" auf Schreibbarkeit zu prüfen:

using System.Security.Principal;
using System.Security.AccessControl;

private static bool HasWritePermission(string FilePath)
{
    try
    {
        FileSystemSecurity security;
        if (File.Exists(FilePath))
        {
            security = File.GetAccessControl(FilePath);
        }
        else
        {
            security = Directory.GetAccessControl(Path.GetDirectoryName(FilePath));
        }
        var rules = security.GetAccessRules(true, true, typeof(NTAccount));

        var currentuser = new WindowsPrincipal(WindowsIdentity.GetCurrent());
        bool result = false;
        foreach (FileSystemAccessRule rule in rules)
        {
            if (0 == (rule.FileSystemRights &
                (FileSystemRights.WriteData | FileSystemRights.Write)))
            {
                continue;
            }

            if (rule.IdentityReference.Value.StartsWith("S-1-"))
            {
                var sid = new SecurityIdentifier(rule.IdentityReference.Value);
                if (!currentuser.IsInRole(sid))
                {
                    continue;
                }
            }
            else
            {
                if (!currentuser.IsInRole(rule.IdentityReference.Value))
                {
                    continue;
                }
            }

            if (rule.AccessControlType == AccessControlType.Deny)
                return false;
            if (rule.AccessControlType == AccessControlType.Allow)
                result = true;
        }
        return result;
    }
    catch
    {
        return false;
    }
}
18
Bryce Wagner

IMO: Sie müssen wie üblich mit solchen Verzeichnissen arbeiten. Statt Berechtigungen vor der Verwendung zu prüfen, geben Sie jedoch die richtige Methode für die Behandlung von UnauthorizedAccessException an und reagieren Sie entsprechend. Diese Methode ist einfacher und weniger fehleranfällig.

5
arbiter

Versuchen Sie, mit diesem C # -Schnipsel zu arbeiten, das ich gerade erstellt habe:

using System;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string directory = @"C:\downloads";

            DirectoryInfo di = new DirectoryInfo(directory);

            DirectorySecurity ds = di.GetAccessControl();

            foreach (AccessRule rule in ds.GetAccessRules(true, true, typeof(NTAccount)))
            {
                Console.WriteLine("Identity = {0}; Access = {1}", 
                              rule.IdentityReference.Value, rule.AccessControlType);
            }
        }
    }
}

Und hier ist eine Referenz, die Sie auch anschauen könnten. Mein Code gibt Ihnen möglicherweise eine Vorstellung davon, wie Sie vor dem Schreiben in ein Verzeichnis nach Berechtigungen suchen können.

3
Jason Evans

gemäß diesem Link: http://www.authorcode.com/how-to-check-file-permission-to-write-in-c/

es ist einfacher, die vorhandene Klasse SecurityManager zu verwenden

string FileLocation = @"C:\test.txt";
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, FileLocation);
if (SecurityManager.IsGranted(writePermission))
{
  // you have permission
}
else
{
 // permission is required!
}

es scheint jedoch veraltet zu sein, es wird empfohlen, stattdessen PermissionSet zu verwenden.

[Obsolete("IsGranted is obsolete and will be removed in a future release of the .NET Framework.  Please use the PermissionSet property of either AppDomain or Assembly instead.")]
0
Mulder2008