开发者

Convert SDDL to readable text in .NET [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
开发者_StackOverflow中文版

Want to improve this question? Update the question so it focuses on one problem only by editing this post.

Closed 6 years ago.

Improve this question

Is there a good way to convert the SDDL permission codes to readable text in .NET?

For example to convert GR to Generic Read etc.

Thanks


Below is a class that I put together to Parse SDDL and generate Human Readable output:

class SDDLParser
{
    static private Dictionary<string, string> ACE_Types = null;
    static private Dictionary<string, string> ACE_Flags = null;
    static private Dictionary<string, string> Permissions = null;
    static private Dictionary<string, string> Trustee = null;

    private static void Initialize()
    {
        ACE_Types = new Dictionary<string, string>();
        ACE_Flags = new Dictionary<string, string>();
        Permissions = new Dictionary<string, string>();
        Trustee = new Dictionary<string, string>();
        #region Add ACE_Types
        ACE_Types.Add("A", "Access Allowed");
        ACE_Types.Add("D", "Access Denied");
        ACE_Types.Add("OA", "Object Access Allowed");
        ACE_Types.Add("OD", "Object Access Denied");
        ACE_Types.Add("AU", "System Audit");
        ACE_Types.Add("AL", "System Alarm");
        ACE_Types.Add("OU", "Object System Audit");
        ACE_Types.Add("OL", "Object System Alarm");
        #endregion
        #region Add ACE_Flags
        ACE_Flags.Add("CI", "Container Inherit");
        ACE_Flags.Add("OI", "Object Inherit");
        ACE_Flags.Add("NP", "No Propagate");
        ACE_Flags.Add("IO", "Inheritance Only");
        ACE_Flags.Add("ID", "Inherited");
        ACE_Flags.Add("SA", "Successful Access Audit");
        ACE_Flags.Add("FA", "Failed Access Audit");
        #endregion
        #region Add Permissions
        #region Generic Access Rights
        Permissions.Add("GA", "Generic All");
        Permissions.Add("GR", "Generic Read");
        Permissions.Add("GW", "Generic Write");
        Permissions.Add("GX", "Generic Execute");
        #endregion
        #region Directory Access Rights
        Permissions.Add("RC", "Read Permissions");
        Permissions.Add("SD", "Delete");
        Permissions.Add("WD", "Modify Permissions");
        Permissions.Add("WO", "Modify Owner");
        Permissions.Add("RP", "Read All Properties");
        Permissions.Add("WP", "Write All Properties");
        Permissions.Add("CC", "Create All Child Objects");
        Permissions.Add("DC", "Delete All Child Objects");
        Permissions.Add("LC", "List Contents");
        Permissions.Add("SW", "All Validated Writes");
        Permissions.Add("LO", "List Object");
        Permissions.Add("DT", "Delete Subtree");
        Permissions.Add("CR", "All Extended Rights");
        #endregion
        #region File Access Rights
        Permissions.Add("FA", "File All Access");
        Permissions.Add("FR", "File Generic Read");
        Permissions.Add("FW", "File Generic Write");
        Permissions.Add("FX", "File Generic Execute");
        #endregion
        #region Registry Key Access Rights
        Permissions.Add("KA", "Key All Access");
        Permissions.Add("KR", "Key Read");
        Permissions.Add("KW", "Key Write");
        Permissions.Add("KX", "Key Execute");
        #endregion
        #endregion
        #region Add Trustee's
        Trustee.Add("AO", "Account Operators");
        Trustee.Add("RU", "Alias to allow previous Windows 2000");
        Trustee.Add("AN", "Anonymous Logon");
        Trustee.Add("AU", "Authenticated Users");
        Trustee.Add("BA", "Built-in Administrators");
        Trustee.Add("BG", "Built in Guests");
        Trustee.Add("BO", "Backup Operators");
        Trustee.Add("BU", "Built-in Users");
        Trustee.Add("CA", "Certificate Server Administrators");
        Trustee.Add("CG", "Creator Group");
        Trustee.Add("CO", "Creator Owner");
        Trustee.Add("DA", "Domain Administrators");
        Trustee.Add("DC", "Domain Computers");
        Trustee.Add("DD", "Domain Controllers");
        Trustee.Add("DG", "Domain Guests");
        Trustee.Add("DU", "Domain Users");
        Trustee.Add("EA", "Enterprise Administrators");
        Trustee.Add("ED", "Enterprise Domain Controllers");
        Trustee.Add("WD", "Everyone");
        Trustee.Add("PA", "Group Policy Administrators");
        Trustee.Add("IU", "Interactively logged-on user");
        Trustee.Add("LA", "Local Administrator");
        Trustee.Add("LG", "Local Guest");
        Trustee.Add("LS", "Local Service Account");
        Trustee.Add("SY", "Local System");
        Trustee.Add("NU", "Network Logon User");
        Trustee.Add("NO", "Network Configuration Operators");
        Trustee.Add("NS", "Network Service Account");
        Trustee.Add("PO", "Printer Operators");
        Trustee.Add("PS", "Self");
        Trustee.Add("PU", "Power Users");
        Trustee.Add("RS", "RAS Servers group");
        Trustee.Add("RD", "Terminal Server Users");
        Trustee.Add("RE", "Replicator");
        Trustee.Add("RC", "Restricted Code");
        Trustee.Add("SA", "Schema Administrators");
        Trustee.Add("SO", "Server Operators");
        Trustee.Add("SU", "Service Logon User");
        #endregion
    }

    private static string friendlyTrusteeName(string trustee)
    {
        if (Trustee.Keys.Contains(trustee))
        {
            return Trustee[trustee];
        }
        else
        {
            try
            {
                System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(trustee);
                return sid.Translate(typeof(System.Security.Principal.NTAccount)).ToString();
            }
            catch (Exception)
            {
                return trustee;
            }
        }
    }

    private static string doParse(string subSDDL, string Separator, string Separator2)
    {
        string retval = "";
        char type = subSDDL.ToCharArray()[0];
        if (type == 'O')
        {
            string owner = subSDDL.Substring(2);
            return "Owner: " + friendlyTrusteeName(owner) + Separator;
        }
        else if (type == 'G')
        {
            string group = subSDDL.Substring(2);
            return "Group: " + friendlyTrusteeName(group) + Separator;
        }
        else if ((type == 'D') || (type == 'S'))
        {
            if (type == 'D')
            {
                retval += "DACL" + Separator;
            }
            else
            {
                retval += "SACL" + Separator;
            }
            string[] sections = subSDDL.Split('(');
            for (int count = 1; count < sections.Length; count++)
            {
                retval += "# " + count.ToString() + " of " + (sections.Length - 1).ToString() + Separator;
                string[] parts = sections[count].TrimEnd(')').Split(';');
                retval += "";
                if (ACE_Types.Keys.Contains(parts[0]))
                {
                    retval += Separator2 + "Type: " + ACE_Types[parts[0]] + Separator;
                }
                if (ACE_Flags.Keys.Contains(parts[1]))
                {
                    retval += Separator2 + "Inheritance: " + ACE_Flags[parts[1]] + Separator;
                }
                for (int count2 = 0; count2 < parts[2].Length; count2 += 2)
                {
                    string perm = parts[2].Substring(count2, 2);
                    if (Permissions.Keys.Contains(perm))
                    {
                        if (count2 == 0)
                        {
                            retval += Separator2 + "Permissions: " + Permissions[perm];
                        }
                        else
                        {
                            retval += "|" + Permissions[perm];
                        }
                    }
                }
                retval += Separator;
                retval += Separator2 + "Trustee: " + friendlyTrusteeName(parts[5]) + Separator;
            }
        }
        return retval;
    }

    public static string Parse(string SDDL)
    {
        return Parse(SDDL, "\r\n", "\t");
    }

    public static string Parse(string SDDL, string Separator, string Separator2)
    {
        string retval = "";
        if (ACE_Types == null)
        {
            Initialize();
        }
        int startindex = 0;
        int nextindex = 0;
        int first = 0;
        string section;
        while (true)
        {
            first = SDDL.IndexOf(':', nextindex) - 1;
            startindex = nextindex;
            if (first < 0)
            {
                break;
            }
            if (first != 0)
            {
                section = SDDL.Substring(startindex - 2, first - startindex + 2);
                retval += doParse(section, Separator, Separator2);
            }
            nextindex = first + 2;
        }
        section = SDDL.Substring(startindex - 2);
        retval += doParse(section, Separator, Separator2);
        return retval;
    }
}

You are free to use this code, and adapt it to your needs.


Just because I also needed a similar function earlier and the accepted answer (while excellent) broke on permissions that weren't represented by two-character strings, I knocked up a similar human-readable parser.

Since the permission bits are dependent on the object to which they apply, you have to pass both the string and a suitable Flags enum of the permission bits. In most cases these are predefined in System.Security.AccessControl but, for more esoteric objects (like Terminal Services sessions), the enum may need to be manually defined.

(The type parameter and enum hackery is nasty -- I just didn't want to have to pass another lookup into the method when most of the common ones exist as enums.)

Anyway...

void Main()
{
    var sddl = "O:SYG:SYD:(A;CI;0xf03bf;;;SY)(A;;CCLO;;;LS)(A;;CCLO;;;NS)(A;;0xf03bf;;;BA)(A;;CC;;;IU)S:NO_ACCESS_CONTROL";

    SddlDecoder.DecodeString<FileSystemRights>(sddl).Dump("FileSystem");
    SddlDecoder.DecodeString<RegistryRights>(sddl).Dump("Registry");
    SddlDecoder.DecodeString<SemaphoreRights>(sddl).Dump("Semaphore");
}

// Define other methods and classes here
public static class SddlDecoder
{
    private static readonly ConcurrentDictionary<Type, Dictionary<uint, string>> _rights
        = new ConcurrentDictionary<Type, Dictionary<uint, string>>();

    public static string DecodeString<TRightsEnum>(string sddl) where TRightsEnum : struct
    {
        var rightsEnumType = typeof(TRightsEnum);
        if (!rightsEnumType.IsEnum ||
            Marshal.SizeOf(Enum.GetUnderlyingType(rightsEnumType)) != 4 ||
            !rightsEnumType.GetCustomAttributes(typeof(FlagsAttribute), true).Any())
        {
            throw new ArgumentException("TRightsEnum must be a 32-bit integer System.Enum with Flags attribute", "TRightsEnum");
        }
        else if (string.IsNullOrWhiteSpace(sddl))
            throw new ArgumentNullException("sddl");

        var descriptor = new RawSecurityDescriptor(sddl);

        var rights = _rights.GetOrAdd(rightsEnumType, 
                                      t => Enum.GetValues(rightsEnumType)
                                               .Cast<uint>()
                                               .Where(n => n != 0 && (n & (n - 1)) == 0)
                                               .Distinct()
                                               .OrderBy(n => n)
                                               .Select(v => new { v, n = Enum.GetName(rightsEnumType, v) })
                                               .ToDictionary(x => x.v, x => x.n));

        var builder = new StringBuilder();

        builder.Append("Owner: ").AppendLine(SidToAccountName(descriptor.Owner));
        builder.Append("Group: ").AppendLine(SidToAccountName(descriptor.Group));

        if (descriptor.SystemAcl != null)
        {
            builder.AppendLine("System ACL:");
            DecodeAclEntries(builder, descriptor.SystemAcl, rights);
        }

        if (descriptor.DiscretionaryAcl != null)
        {
            builder.AppendLine("Discretionary ACL:");
            DecodeAclEntries(builder, descriptor.DiscretionaryAcl, rights);
        }

        return builder.ToString();
    }

    private static string SidToAccountName(SecurityIdentifier sid)
    {
        return (sid.IsValidTargetType(typeof(NTAccount)))
             ? ((NTAccount)sid.Translate(typeof(NTAccount))).Value
             : sid.Value;
    }

    private static void DecodeAclEntries(StringBuilder builder, RawAcl acl, Dictionary<uint, string> rights)
    {
        var counter = 0;
        foreach (var ace in acl)
        {
            builder.Append("  #")
                   .Append(++counter)
                   .Append(": ");

            var knownAce = ace as KnownAce;
            if (knownAce != null)
            {
                builder.Append(knownAce.AceType > AceType.MaxDefinedAceType
                                ? "Custom Access"
                                : knownAce.AceType.ToString())
                       .Append(" for ")
                       .Append(SidToAccountName(knownAce.SecurityIdentifier));

                if (knownAce.AceFlags != AceFlags.None)
                {
                    builder.Append(" (")
                           .Append(knownAce.AceFlags)
                           .Append(')');
                }

                builder.AppendLine();

                var mask = unchecked((uint)knownAce.AccessMask);

                foreach (var r in rights.Keys)
                {
                    if ((mask & r) == r)
                    {
                        builder.Append("    - ")
                               .AppendLine(rights[r]);
                    }
                }
            }
            else builder.AppendLine("Unknown ACE");
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜