The Labs \ Source Viewer \ SSCLI \ System.Security.Permissions \ ResourcePermissionBase

  1. //------------------------------------------------------------------------------
  2. // <copyright file="ResourcePermissionBase.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Security.Permissions
  16. {
  17.     using System;
  18.     using System.Text;
  19.     using System.Reflection;
  20.     using System.Security;
  21.     using System.Security.Permissions;
  22.     using System.Collections;
  23.     using System.Collections.Specialized;
  24.     using System.Runtime.InteropServices;
  25.     using System.Globalization;
  26.     using System.Diagnostics;
  27.    
  28.     /// <devdoc>
  29.     /// <para>[To be supplied.]</para>
  30.     /// </devdoc>
  31.     [Serializable(), SecurityPermissionAttribute(SecurityAction.InheritanceDemand, ControlEvidence = true, ControlPolicy = true)]
  32.     public abstract class ResourcePermissionBase : CodeAccessPermission, IUnrestrictedPermission
  33.     {
  34.         private static string computerName;
  35.         private string[] tagNames;
  36.         private Type permissionAccessType;
  37.         private bool isUnrestricted;
  38.         private Hashtable rootTable = CreateHashtable();
  39.        
  40.         public const string Any = "*";
  41.         public const string Local = ".";
  42.        
  43.         /// <devdoc>
  44.         /// <para>[To be supplied.]</para>
  45.         /// </devdoc>
  46.         protected ResourcePermissionBase()
  47.         {
  48.         }
  49.        
  50.         /// <devdoc>
  51.         /// <para>[To be supplied.]</para>
  52.         /// </devdoc>
  53.         protected ResourcePermissionBase(PermissionState state)
  54.         {
  55.             if (state == PermissionState.Unrestricted)
  56.                 this.isUnrestricted = true;
  57.             else if (state == PermissionState.None)
  58.                 this.isUnrestricted = false;
  59.             else
  60.                 throw new ArgumentException(SR.GetString(SR.InvalidPermissionState), "state");
  61.         }
  62.        
  63.         private static Hashtable CreateHashtable()
  64.         {
  65.             #pragma warning disable 618
  66.             // Most subclasses should be using an OSCasing string comparer,
  67.             // and this is our best current match.
  68.             // We're using the obsolete classes so we can deserialize on v1.1.
  69.             return new Hashtable(StringComparer.OrdinalIgnoreCase);
  70.             #pragma warning restore 618
  71.         }
  72.        
  73.         private string ComputerName {
  74.             get {
  75.                 if (computerName == null) {
  76.                     lock (typeof(ResourcePermissionBase)) {
  77.                         if (computerName == null) {
  78.                             StringBuilder sb = new StringBuilder(256);
  79.                             int len = sb.Capacity;
  80.                             UnsafeNativeMethods.GetComputerName(sb, ref len);
  81.                             computerName = sb.ToString();
  82.                         }
  83.                     }
  84.                 }
  85.                
  86.                 return computerName;
  87.             }
  88.         }
  89.        
  90.         private bool IsEmpty {
  91.             get { return (!isUnrestricted && rootTable.Count == 0); }
  92.         }
  93.        
  94.         /// <devdoc>
  95.         /// <para>[To be supplied.]</para>
  96.         /// </devdoc>
  97.         protected Type PermissionAccessType {
  98.             get { return this.permissionAccessType; }
  99.            
  100.             set {
  101.                 if (value == null)
  102.                     throw new ArgumentNullException("value");
  103.                
  104.                 if (!value.IsEnum)
  105.                     throw new ArgumentException(SR.GetString(SR.PermissionBadParameterEnum), "value");
  106.                
  107.                 this.permissionAccessType = value;
  108.             }
  109.         }
  110.        
  111.         /// <devdoc>
  112.         /// <para>[To be supplied.]</para>
  113.         /// </devdoc>
  114.         protected string[] TagNames {
  115.             get { return this.tagNames; }
  116.            
  117.             set {
  118.                 if (value == null)
  119.                     throw new ArgumentNullException("value");
  120.                
  121.                 if (value.Length == 0)
  122.                     throw new ArgumentException(SR.GetString(SR.PermissionInvalidLength, "0"), "value");
  123.                
  124.                 this.tagNames = value;
  125.             }
  126.         }
  127.        
  128.         /// <devdoc>
  129.         /// <para>[To be supplied.]</para>
  130.         /// </devdoc>
  131.         protected void AddPermissionAccess(ResourcePermissionBaseEntry entry)
  132.         {
  133.             if (entry == null)
  134.                 throw new ArgumentNullException("entry");
  135.            
  136.             if (entry.PermissionAccessPath.Length != this.TagNames.Length)
  137.                 throw new InvalidOperationException(SR.GetString(SR.PermissionNumberOfElements));
  138.            
  139.             Hashtable currentTable = this.rootTable;
  140.             string[] accessPath = entry.PermissionAccessPath;
  141.             for (int index = 0; index < accessPath.Length - 1; ++index) {
  142.                 if (currentTable.ContainsKey(accessPath[index]))
  143.                     currentTable = (Hashtable)currentTable[accessPath[index]];
  144.                 else {
  145.                     Hashtable newHashTable = CreateHashtable();
  146.                     currentTable[accessPath[index]] = newHashTable;
  147.                     currentTable = newHashTable;
  148.                 }
  149.             }
  150.            
  151.             if (currentTable.ContainsKey(accessPath[accessPath.Length - 1]))
  152.                 throw new InvalidOperationException(SR.GetString(SR.PermissionItemExists));
  153.            
  154.             currentTable[accessPath[accessPath.Length - 1]] = entry.PermissionAccess;
  155.         }
  156.        
  157.         protected void Clear()
  158.         {
  159.             this.rootTable.Clear();
  160.         }
  161.        
  162.         /// <devdoc>
  163.         /// <para>[To be supplied.]</para>
  164.         /// </devdoc>
  165.         public override IPermission Copy()
  166.         {
  167.             ResourcePermissionBase permission = CreateInstance();
  168.             permission.tagNames = this.tagNames;
  169.             permission.permissionAccessType = this.permissionAccessType;
  170.             permission.isUnrestricted = this.isUnrestricted;
  171.             permission.rootTable = CopyChildren(this.rootTable, 0);
  172.             return permission;
  173.         }
  174.        
  175.         private Hashtable CopyChildren(object currentContent, int tagIndex)
  176.         {
  177.             IDictionaryEnumerator contentEnumerator = ((Hashtable)currentContent).GetEnumerator();
  178.             Hashtable newTable = CreateHashtable();
  179.             while (contentEnumerator.MoveNext()) {
  180.                 if (tagIndex < (this.TagNames.Length - 1))
  181.                     newTable[contentEnumerator.Key] = CopyChildren(contentEnumerator.Value, tagIndex + 1);
  182.                 else
  183.                     newTable[contentEnumerator.Key] = contentEnumerator.Value;
  184.             }
  185.            
  186.             return newTable;
  187.         }
  188.        
  189.         private ResourcePermissionBase CreateInstance()
  190.         {
  191.             new PermissionSet(PermissionState.Unrestricted).Assert();
  192.             return (ResourcePermissionBase)Activator.CreateInstance(this.GetType(), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null);
  193.         }
  194.        
  195.         /// <devdoc>
  196.         /// <para>[To be supplied.]</para>
  197.         /// </devdoc>
  198.         protected ResourcePermissionBaseEntry[] GetPermissionEntries()
  199.         {
  200.             return GetChildrenAccess(this.rootTable, 0);
  201.         }
  202.        
  203.         private ResourcePermissionBaseEntry[] GetChildrenAccess(object currentContent, int tagIndex)
  204.         {
  205.             IDictionaryEnumerator contentEnumerator = ((Hashtable)currentContent).GetEnumerator();
  206.             ArrayList list = new ArrayList();
  207.             while (contentEnumerator.MoveNext()) {
  208.                 if (tagIndex < (this.TagNames.Length - 1)) {
  209.                     ResourcePermissionBaseEntry[] currentEntries = GetChildrenAccess(contentEnumerator.Value, tagIndex + 1);
  210.                     for (int index = 0; index < currentEntries.Length; ++index)
  211.                         currentEntries[index].PermissionAccessPath[tagIndex] = (string)contentEnumerator.Key;
  212.                    
  213.                     list.AddRange(currentEntries);
  214.                 }
  215.                 else {
  216.                     ResourcePermissionBaseEntry entry = new ResourcePermissionBaseEntry((int)contentEnumerator.Value, new string[this.TagNames.Length]);
  217.                     entry.PermissionAccessPath[tagIndex] = (string)contentEnumerator.Key;
  218.                    
  219.                     list.Add(entry);
  220.                 }
  221.             }
  222.            
  223.             return (ResourcePermissionBaseEntry[])list.ToArray(typeof(ResourcePermissionBaseEntry));
  224.         }
  225.        
  226.         /// <devdoc>
  227.         /// <para>[To be supplied.]</para>
  228.         /// </devdoc>
  229.         public override void FromXml(SecurityElement securityElement)
  230.         {
  231.             if (securityElement == null)
  232.                 throw new ArgumentNullException("securityElement");
  233.            
  234.             if (!securityElement.Tag.Equals("Permission") && !securityElement.Tag.Equals("IPermission"))
  235.                 throw new ArgumentException(SR.GetString(SR.Argument_NotAPermissionElement));
  236.            
  237.             string version = securityElement.Attribute("version");
  238.             if (version != null && !version.Equals("1"))
  239.                 throw new ArgumentException(SR.GetString(SR.Argument_InvalidXMLBadVersion));
  240.            
  241.             string unrestrictedValue = securityElement.Attribute("Unrestricted");
  242.             if (unrestrictedValue != null && (string.Compare(unrestrictedValue, "true", StringComparison.OrdinalIgnoreCase) == 0)) {
  243.                 this.isUnrestricted = true;
  244.                 return;
  245.             }
  246.             else
  247.                 isUnrestricted = false;
  248.            
  249.            
  250.             this.rootTable = (Hashtable)ReadChildren(securityElement, 0);
  251.         }
  252.        
  253.         /// <devdoc>
  254.         /// <para>[To be supplied.]</para>
  255.         /// </devdoc>
  256.         public override IPermission Intersect(IPermission target)
  257.         {
  258.             if (target == null)
  259.                 return null;
  260.            
  261.             if (target.GetType() != this.GetType())
  262.                 throw new ArgumentException(SR.GetString(SR.PermissionTypeMismatch), "target");
  263.            
  264.             ResourcePermissionBase targetPermission = (ResourcePermissionBase)target;
  265.             if (this.IsUnrestricted())
  266.                 return targetPermission.Copy();
  267.            
  268.             if (targetPermission.IsUnrestricted())
  269.                 return this.Copy();
  270.            
  271.             ResourcePermissionBase newPermission = null;
  272.             Hashtable newPermissionRootTable = (Hashtable)IntersectContents(this.rootTable, targetPermission.rootTable);
  273.             if (newPermissionRootTable != null) {
  274.                 newPermission = CreateInstance();
  275.                 newPermission.rootTable = newPermissionRootTable;
  276.             }
  277.             return newPermission;
  278.         }
  279.        
  280.         private object IntersectContents(object currentContent, object targetContent)
  281.         {
  282.             if (currentContent is int) {
  283.                 int currentAccess = (int)currentContent;
  284.                 int targetAccess = (int)targetContent;
  285.                 return (currentAccess & targetAccess);
  286.             }
  287.             else {
  288.                 Hashtable newContents = CreateHashtable();
  289.                
  290.                 //Before executing the intersect operation, need to
  291.                 //resolve the "." entries
  292.                 object currentLocalContent = ((Hashtable)currentContent)[Local];
  293.                 object currentComputerNameContent = ((Hashtable)currentContent)[ComputerName];
  294.                 if (currentLocalContent != null || currentComputerNameContent != null) {
  295.                     object targetLocalContent = ((Hashtable)targetContent)[Local];
  296.                     object targetComputerNameContent = ((Hashtable)targetContent)[ComputerName];
  297.                     if (targetLocalContent != null || targetComputerNameContent != null) {
  298.                         object currentLocalMergedContent = currentLocalContent;
  299.                         if (currentLocalContent != null && currentComputerNameContent != null)
  300.                             currentLocalMergedContent = UnionOfContents(currentLocalContent, currentComputerNameContent);
  301.                         else if (currentComputerNameContent != null)
  302.                             currentLocalMergedContent = currentComputerNameContent;
  303.                        
  304.                         object targetLocalMergedContent = targetLocalContent;
  305.                         if (targetLocalContent != null && targetComputerNameContent != null)
  306.                             targetLocalMergedContent = UnionOfContents(targetLocalContent, targetComputerNameContent);
  307.                         else if (targetComputerNameContent != null)
  308.                             targetLocalMergedContent = targetComputerNameContent;
  309.                        
  310.                         object computerNameValue = IntersectContents(currentLocalMergedContent, targetLocalMergedContent);
  311.                         if (HasContent(computerNameValue)) {
  312.                             // There should be no computer name key added if the information
  313.                             // was not specified in one of the targets
  314.                             if (currentComputerNameContent != null || targetComputerNameContent != null) {
  315.                                 newContents[ComputerName] = computerNameValue;
  316.                             }
  317.                             else {
  318.                                 newContents[Local] = computerNameValue;
  319.                             }
  320.                         }
  321.                     }
  322.                 }
  323.                
  324.                 IDictionaryEnumerator contentEnumerator;
  325.                 Hashtable contentsTable;
  326.                 if (((Hashtable)currentContent).Count < ((Hashtable)targetContent).Count) {
  327.                     contentEnumerator = ((Hashtable)currentContent).GetEnumerator();
  328.                     contentsTable = ((Hashtable)targetContent);
  329.                 }
  330.                 else {
  331.                     contentEnumerator = ((Hashtable)targetContent).GetEnumerator();
  332.                     contentsTable = ((Hashtable)currentContent);
  333.                 }
  334.                
  335.                 //The wildcard entries intersection should be treated
  336.                 //as any other entry.
  337.                 while (contentEnumerator.MoveNext()) {
  338.                     string currentKey = (string)contentEnumerator.Key;
  339.                     if (contentsTable.ContainsKey(currentKey) && currentKey != Local && currentKey != ComputerName) {
  340.                        
  341.                         object currentValue = contentEnumerator.Value;
  342.                         object targetValue = contentsTable[currentKey];
  343.                         object newValue = IntersectContents(currentValue, targetValue);
  344.                         if (HasContent(newValue))
  345.                             newContents[currentKey] = newValue;
  346.                     }
  347.                 }
  348.                
  349.                 return (newContents.Count > 0) ? newContents : null;
  350.             }
  351.         }
  352.        
  353.         // This is used from IntersectContents. IntersectContents can return either a hashtable or
  354.         // an int. If the hashtable is null or the int is 0, we don't want to save those values -
  355.         // ie the intersection was empty. This checks for null and a zero int value.
  356.         private bool HasContent(object value)
  357.         {
  358.             if (value == null)
  359.                 return false;
  360.            
  361.             if (value is int) {
  362.                 int intValue = (int)value;
  363.                 if (intValue == 0)
  364.                     return false;
  365.             }
  366.            
  367.             return true;
  368.            
  369.         }
  370.        
  371.         private bool IsContentSubset(object currentContent, object targetContent)
  372.         {
  373.             //
  374.             if (currentContent is int) {
  375.                 int currentAccess = (int)currentContent;
  376.                 int targetAccess = (int)targetContent;
  377.                 if ((currentAccess & targetAccess) != currentAccess)
  378.                     return false;
  379.                
  380.                 return true;
  381.             }
  382.             else {
  383.                 Hashtable currentContentTable = (Hashtable)currentContent;
  384.                 Hashtable targetContentTable = (Hashtable)targetContent;
  385.                
  386.                 //If the target table contains a wild card, all the current entries need to be
  387.                 //a subset of the target.
  388.                 object targetAnyContent = targetContentTable[Any];
  389.                 if (targetAnyContent != null) {
  390.                     foreach (DictionaryEntry currentEntry in currentContentTable) {
  391.                         if (!IsContentSubset(currentEntry.Value, targetAnyContent)) {
  392.                             return false;
  393.                         }
  394.                     }
  395.                     return true;
  396.                 }
  397.                
  398.                 //Check the entries for remote machines first
  399.                 foreach (DictionaryEntry currentEntry in currentContentTable) {
  400.                     string currentContentKey = (string)currentEntry.Key;
  401.                     if (currentContentKey != Local && currentContentKey != ComputerName) {
  402.                         if (!targetContentTable.ContainsKey(currentContentKey)) {
  403.                             return false;
  404.                         }
  405.                         else if (!IsContentSubset(currentEntry.Value, targetContentTable[currentContentKey])) {
  406.                             return false;
  407.                         }
  408.                     }
  409.                 }
  410.                
  411.                 // Entries for "." and local machine name apply to the same target.
  412.                 // Merge them before further processing.
  413.                 object currentLocalMergedContent = MergeContents(currentContentTable[Local], currentContentTable[ComputerName]);
  414.                 if (currentLocalMergedContent != null) {
  415.                     object targetLocalMergedContent = MergeContents(targetContentTable[Local], targetContentTable[ComputerName]);
  416.                     if (targetLocalMergedContent != null) {
  417.                         return IsContentSubset(currentLocalMergedContent, targetLocalMergedContent);
  418.                     }
  419.                     else if (!IsEmpty) {
  420.                         return false;
  421.                     }
  422.                 }
  423.                 return true;
  424.             }
  425.         }
  426.        
  427.         private object MergeContents(object content1, object content2)
  428.         {
  429.             if (content1 == null) {
  430.                 if (content2 == null) {
  431.                     return null;
  432.                 }
  433.                 else {
  434.                     return content2;
  435.                 }
  436.             }
  437.             else {
  438.                 if (content2 == null) {
  439.                     return content1;
  440.                 }
  441.                 else {
  442.                     return UnionOfContents(content1, content2);
  443.                 }
  444.             }
  445.         }
  446.        
  447.         /// <devdoc>
  448.         /// <para>[To be supplied.]</para>
  449.         /// </devdoc>
  450.         public override bool IsSubsetOf(IPermission target)
  451.         {
  452.             if (target == null) {
  453.                 return (IsEmpty);
  454.             }
  455.            
  456.             if (target.GetType() != this.GetType())
  457.                 return false;
  458.            
  459.             ResourcePermissionBase targetPermission = (ResourcePermissionBase)target;
  460.             if (targetPermission.IsUnrestricted())
  461.                 return true;
  462.             else if (this.IsUnrestricted())
  463.                 return false;
  464.            
  465.             return IsContentSubset(this.rootTable, targetPermission.rootTable);
  466.            
  467.         }
  468.        
  469.         /// <devdoc>
  470.         /// <para>[To be supplied.]</para>
  471.         /// </devdoc>
  472.         public bool IsUnrestricted()
  473.         {
  474.             return this.isUnrestricted;
  475.         }
  476.        
  477.         private object ReadChildren(SecurityElement securityElement, int tagIndex)
  478.         {
  479.             Hashtable newTable = CreateHashtable();
  480.             if (securityElement.Children != null) {
  481.                 for (int index = 0; index < securityElement.Children.Count; ++index) {
  482.                     SecurityElement currentElement = (SecurityElement)securityElement.Children[index];
  483.                     if (currentElement.Tag == this.TagNames[tagIndex]) {
  484.                         string contentName = currentElement.Attribute("name");
  485.                        
  486.                         if (tagIndex < (this.TagNames.Length - 1))
  487.                             newTable[contentName] = ReadChildren(currentElement, tagIndex + 1);
  488.                         else {
  489.                             string accessString = currentElement.Attribute("access");
  490.                             int permissionAccess = 0;
  491.                             if (accessString != null) {
  492.                                 permissionAccess = (int)Enum.Parse(PermissionAccessType, accessString);
  493.                             }
  494.                             newTable[contentName] = permissionAccess;
  495.                         }
  496.                     }
  497.                 }
  498.             }
  499.             return newTable;
  500.         }
  501.        
  502.         /// <devdoc>
  503.         /// <para>[To be supplied.]</para>
  504.         /// </devdoc>
  505.         protected void RemovePermissionAccess(ResourcePermissionBaseEntry entry)
  506.         {
  507.             if (entry == null)
  508.                 throw new ArgumentNullException("entry");
  509.            
  510.             if (entry.PermissionAccessPath.Length != this.TagNames.Length)
  511.                 throw new InvalidOperationException(SR.GetString(SR.PermissionNumberOfElements));
  512.            
  513.             Hashtable currentTable = this.rootTable;
  514.             string[] accessPath = entry.PermissionAccessPath;
  515.             for (int index = 0; index < accessPath.Length; ++index) {
  516.                 if (currentTable == null || !currentTable.ContainsKey(accessPath[index]))
  517.                     throw new InvalidOperationException(SR.GetString(SR.PermissionItemDoesntExist));
  518.                 else {
  519.                     Hashtable oldTable = currentTable;
  520.                     if (index < accessPath.Length - 1) {
  521.                         currentTable = (Hashtable)currentTable[accessPath[index]];
  522.                         if (currentTable.Count == 1)
  523.                             oldTable.Remove(accessPath[index]);
  524.                     }
  525.                     else {
  526.                         currentTable = null;
  527.                         oldTable.Remove(accessPath[index]);
  528.                     }
  529.                 }
  530.             }
  531.         }
  532.        
  533.         /// <devdoc>
  534.         /// <para>[To be supplied.]</para>
  535.         /// </devdoc>
  536.         public override SecurityElement ToXml()
  537.         {
  538.             SecurityElement root = new SecurityElement("IPermission");
  539.             Type type = this.GetType();
  540.             root.AddAttribute("class", type.FullName + ", " + type.Module.Assembly.FullName.Replace('"', '\''));
  541.             root.AddAttribute("version", "1");
  542.            
  543.             if (this.isUnrestricted) {
  544.                 root.AddAttribute("Unrestricted", "true");
  545.                 return root;
  546.             }
  547.            
  548.             WriteChildren(root, this.rootTable, 0);
  549.             return root;
  550.         }
  551.        
  552.         /// <devdoc>
  553.         /// <para>[To be supplied.]</para>
  554.         /// </devdoc>
  555.         public override IPermission Union(IPermission target)
  556.         {
  557.             if (target == null)
  558.                 return this.Copy();
  559.            
  560.             if (target.GetType() != this.GetType())
  561.                 throw new ArgumentException(SR.GetString(SR.PermissionTypeMismatch), "target");
  562.            
  563.             ResourcePermissionBase targetPermission = (ResourcePermissionBase)target;
  564.             ResourcePermissionBase newPermission = null;
  565.             if (this.IsUnrestricted() || targetPermission.IsUnrestricted()) {
  566.                 newPermission = CreateInstance();
  567.                 newPermission.isUnrestricted = true;
  568.             }
  569.             else {
  570.                 Hashtable newPermissionRootTable = (Hashtable)UnionOfContents(this.rootTable, targetPermission.rootTable);
  571.                 if (newPermissionRootTable != null) {
  572.                     newPermission = CreateInstance();
  573.                     newPermission.rootTable = newPermissionRootTable;
  574.                 }
  575.             }
  576.             return newPermission;
  577.         }
  578.        
  579.         private object UnionOfContents(object currentContent, object targetContent)
  580.         {
  581.             if (currentContent is int) {
  582.                 int currentAccess = (int)currentContent;
  583.                 int targetAccess = (int)targetContent;
  584.                 return (currentAccess | targetAccess);
  585.             }
  586.             else {
  587.                 //The wildcard and "." entries can be merged as
  588.                 //any other entry.
  589.                 Hashtable newContents = CreateHashtable();
  590.                 IDictionaryEnumerator contentEnumerator = ((Hashtable)currentContent).GetEnumerator();
  591.                 IDictionaryEnumerator targetContentEnumerator = ((Hashtable)targetContent).GetEnumerator();
  592.                 while (contentEnumerator.MoveNext())
  593.                     newContents[(string)contentEnumerator.Key] = contentEnumerator.Value;
  594.                
  595.                 while (targetContentEnumerator.MoveNext()) {
  596.                     if (!newContents.ContainsKey(targetContentEnumerator.Key))
  597.                         newContents[targetContentEnumerator.Key] = targetContentEnumerator.Value;
  598.                     else {
  599.                         object currentValue = newContents[targetContentEnumerator.Key];
  600.                         object targetValue = targetContentEnumerator.Value;
  601.                         newContents[targetContentEnumerator.Key] = UnionOfContents(currentValue, targetValue);
  602.                     }
  603.                 }
  604.                
  605.                 return (newContents.Count > 0) ? newContents : null;
  606.             }
  607.         }
  608.        
  609.         private void WriteChildren(SecurityElement currentElement, object currentContent, int tagIndex)
  610.         {
  611.             IDictionaryEnumerator contentEnumerator = ((Hashtable)currentContent).GetEnumerator();
  612.             while (contentEnumerator.MoveNext()) {
  613.                 SecurityElement contentElement = new SecurityElement(this.TagNames[tagIndex]);
  614.                 currentElement.AddChild(contentElement);
  615.                 contentElement.AddAttribute("name", (string)contentEnumerator.Key);
  616.                
  617.                 if (tagIndex < (this.TagNames.Length - 1))
  618.                     WriteChildren(contentElement, contentEnumerator.Value, tagIndex + 1);
  619.                 else {
  620.                     string accessString = null;
  621.                     int currentAccess = (int)contentEnumerator.Value;
  622.                     if (this.PermissionAccessType != null && currentAccess != 0) {
  623.                         accessString = Enum.Format(PermissionAccessType, currentAccess, "g");
  624.                         contentElement.AddAttribute("access", accessString);
  625.                     }
  626.                 }
  627.             }
  628.         }
  629.        
  630.         [SuppressUnmanagedCodeSecurity()]
  631.         private static class UnsafeNativeMethods
  632.         {
  633.             [DllImport(ExternDll.Kernel32, CharSet = CharSet.Auto, BestFitMapping = false)]
  634.             static internal extern bool GetComputerName(StringBuilder lpBuffer, ref int nSize);
  635.         }
  636.     }
  637. }

Developer Fusion