The Labs \ Source Viewer \ SSCLI \ System.Security.Policy \ CodeConnectAccess

  1. // ==++==
  2. //
  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. //
  14. // ==--==
  15. // NetCodeGroup.cs
  16. //
  17. // Representation for code groups used for the policy mechanism
  18. //
  19. namespace System.Security.Policy
  20. {
  21.    
  22.     using System;
  23.     using System.Security.Util;
  24.     using System.Security;
  25.     using System.Collections;
  26.     using System.Reflection;
  27.     using System.Globalization;
  28.     using System.Runtime.Serialization;
  29.     using System.Runtime.Versioning;
  30.    
  31.     //
  32.     //This is a simple property bag used to describe connect back access.
  33.     //
  34.     [Serializable()]
  35.     [System.Runtime.InteropServices.ComVisible(true)]
  36.     public class CodeConnectAccess
  37.     {
  38.         private string _LowerCaseScheme;
  39.         private string _LowerCasePort;
  40.         private int _IntPort;
  41.        
  42.         private const string DefaultStr = "$default";
  43.         //must remain in lower case
  44.         private const string OriginStr = "$origin";
  45.         //must remain in lower case
  46.         internal const int NoPort = -1;
  47.         internal const int AnyPort = -2;
  48.         // This safely excludes -1 (if we decide to support "any" port later)
  49.         //
  50.         // public helper fields to deal with special scheme and port values.
  51.         //
  52.         public static readonly int DefaultPort = -3;
  53.         public static readonly int OriginPort = -4;
  54.         public static readonly string OriginScheme = OriginStr;
  55.         public static readonly string AnyScheme = "*";
  56.        
  57.         //
  58.         // A set of public static class factories
  59.         //
  60.         public CodeConnectAccess(string allowScheme, int allowPort)
  61.         {
  62.             if (!IsValidScheme(allowScheme))
  63.                 throw new ArgumentOutOfRangeException("allowScheme");
  64.            
  65.             SetCodeConnectAccess(allowScheme.ToLower(CultureInfo.InvariantCulture), allowPort);
  66.         }
  67.         //
  68.         public static CodeConnectAccess CreateOriginSchemeAccess(int allowPort)
  69.         {
  70.             CodeConnectAccess access = new CodeConnectAccess();
  71.             access.SetCodeConnectAccess(OriginScheme, allowPort);
  72.             return access;
  73.         }
  74.         //
  75.         public static CodeConnectAccess CreateAnySchemeAccess(int allowPort)
  76.         {
  77.             CodeConnectAccess access = new CodeConnectAccess();
  78.             access.SetCodeConnectAccess(AnyScheme, allowPort);
  79.             return access;
  80.         }
  81.         //
  82.         private CodeConnectAccess()
  83.         {
  84.         }
  85.         //
  86.         private void SetCodeConnectAccess(string lowerCaseScheme, int allowPort)
  87.         {
  88.             _LowerCaseScheme = lowerCaseScheme;
  89.            
  90.             if (allowPort == DefaultPort)
  91.                 _LowerCasePort = DefaultStr;
  92.             else if (allowPort == OriginPort)
  93.                 _LowerCasePort = OriginStr;
  94.             else {
  95.                 if (allowPort < 0 || allowPort > 65535)
  96.                     throw new ArgumentOutOfRangeException("allowPort");
  97.                
  98.                 _LowerCasePort = allowPort.ToString(CultureInfo.InvariantCulture);
  99.             }
  100.            
  101.             _IntPort = allowPort;
  102.         }
  103.         //
  104.         public string Scheme {
  105.             get { return _LowerCaseScheme; }
  106.         }
  107.         //
  108.         public int Port {
  109.             get { return _IntPort; }
  110.         }
  111.         //
  112.         public override bool Equals(object o)
  113.         {
  114.             if ((object)this == (object)o)
  115.                 return true;
  116.            
  117.             CodeConnectAccess that = (o as CodeConnectAccess);
  118.            
  119.             if (that == null)
  120.                 return false;
  121.            
  122.             return this.Scheme == that.Scheme && this.Port == that.Port;
  123.         }
  124.         //
  125.         public override int GetHashCode()
  126.         {
  127.             return Scheme.GetHashCode() + Port.GetHashCode();
  128.         }
  129.         //
  130.         // internal stuff
  131.         //
  132.         //
  133.         // The valid scheme values are: "*", "$origin", or a valid Uri scheme
  134.         // The valid port valies are "$origin" "$default" or a valid Uri port
  135.         //
  136.         internal CodeConnectAccess(string allowScheme, string allowPort)
  137.         {
  138.             if (allowScheme == null || allowScheme.Length == 0)
  139.                 throw new ArgumentNullException("allowScheme");
  140.            
  141.             if (allowPort == null || allowPort.Length == 0)
  142.                 throw new ArgumentNullException("allowPort");
  143.            
  144.             _LowerCaseScheme = allowScheme.ToLower(CultureInfo.InvariantCulture);
  145.            
  146.             if (_LowerCaseScheme == OriginScheme)
  147.                 _LowerCaseScheme = OriginScheme;
  148.             else if (_LowerCaseScheme == AnyScheme)
  149.                 _LowerCaseScheme = AnyScheme;
  150.             else if (!IsValidScheme(_LowerCaseScheme))
  151.                 throw new ArgumentOutOfRangeException("allowScheme");
  152.            
  153.             _LowerCasePort = allowPort.ToLower(CultureInfo.InvariantCulture);
  154.            
  155.             if (_LowerCasePort == DefaultStr)
  156.                 _IntPort = DefaultPort;
  157.             else if (_LowerCasePort == OriginStr)
  158.                 _IntPort = OriginPort;
  159.             else {
  160.                 _IntPort = Int32.Parse(allowPort, CultureInfo.InvariantCulture);
  161.                
  162.                 if (_IntPort < 0 || _IntPort > 65535)
  163.                     throw new ArgumentOutOfRangeException("allowPort");
  164.                
  165.                 _LowerCasePort = _IntPort.ToString(CultureInfo.InvariantCulture);
  166.             }
  167.         }
  168.         //
  169.         internal bool IsOriginScheme {
  170.             get { return (object)_LowerCaseScheme == (object)OriginScheme; }
  171.         }
  172.         //
  173.         internal bool IsAnyScheme {
  174.             get { return (object)_LowerCaseScheme == (object)AnyScheme; }
  175.         }
  176.         //
  177.         internal bool IsDefaultPort {
  178.             get { return Port == DefaultPort; }
  179.         }
  180.         //
  181.         internal bool IsOriginPort {
  182.             get { return Port == OriginPort; }
  183.         }
  184.         //
  185.         // More Internal stuff
  186.         //
  187.         internal string StrPort {
  188.             get { return _LowerCasePort; }
  189.         }
  190.         //
  191.         static internal bool IsValidScheme(string scheme)
  192.         {
  193.             if (((object)scheme == null) || (scheme.Length == 0) || !IsAsciiLetter(scheme[0]))
  194.                 return false;
  195.            
  196.             for (int i = scheme.Length - 1; i > 0; --i) {
  197.                 if (!(IsAsciiLetterOrDigit(scheme[i]) || (scheme[i] == '+') || (scheme[i] == '-') || (scheme[i] == '.')))
  198.                     return false;
  199.             }
  200.             return true;
  201.         }
  202.         //
  203.         private static bool IsAsciiLetterOrDigit(char character)
  204.         {
  205.             return IsAsciiLetter(character) || (character >= '0' && character <= '9');
  206.         }
  207.         //
  208.         private static bool IsAsciiLetter(char character)
  209.         {
  210.             return (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z');
  211.         }
  212.     }
  213.    
  214.     [Serializable()]
  215.     [System.Runtime.InteropServices.ComVisible(true)]
  216.     public sealed class NetCodeGroup : CodeGroup, IUnionSemanticCodeGroup
  217.     {
  218.         [System.Diagnostics.Conditional("_DEBUG")]
  219.         [ResourceExposure(ResourceScope.None)]
  220.         [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  221.         private static void DEBUG_OUT(string str)
  222.         {
  223.             #if _DEBUG
  224.             if (debug) {
  225.                 if (to_file) {
  226.                     System.Text.StringBuilder sb = new System.Text.StringBuilder();
  227.                     sb.Append(str);
  228.                     sb.Append((char)13);
  229.                     sb.Append((char)10);
  230.                     PolicyManager._DebugOut(file, sb.ToString());
  231.                 }
  232.                 else
  233.                     Console.WriteLine(str);
  234.             }
  235.             #endif
  236.         }
  237.        
  238.         #if _DEBUG
  239.         private static bool debug;
  240.         private static readonly bool to_file;
  241.         private const string file = "c:\\com99\\src\\bcl\\debug.txt";
  242.         #endif
  243.        
  244.         [OptionalField(VersionAdded = 2)]
  245.         private ArrayList m_schemesList;
  246.         [OptionalField(VersionAdded = 2)]
  247.         private ArrayList m_accessList;
  248.        
  249.         [OnDeserializing()]
  250.         private void OnDeserializing(StreamingContext ctx)
  251.         {
  252.             m_schemesList = null;
  253.             m_accessList = null;
  254.            
  255.            
  256.         }
  257.        
  258.        
  259.         private const string c_IgnoreUserInfo = "";
  260.         // don't need anymore since WebPermission will ignore userinfo anyway. was: @"([^\\/?#]*@)?";
  261.         // not exactly correct syntax but should work fine assuming System.Uri will not accept bogus Uri schemes
  262.         private const string c_AnyScheme = "([0-9a-z+\\-\\.]+)://";
  263.        
  264.         private static readonly char[] c_SomeRegexChars = new char[] {'.', '-', '+', '[', ']', '{', '$', '^', '#', ')',
  265.             /* rest are unc-only*/        '(', ' '};
  266.        
  267.         public static readonly string AnyOtherOriginScheme = CodeConnectAccess.AnyScheme;
  268.         public static readonly string AbsentOriginScheme = string.Empty;
  269.        
  270.         internal NetCodeGroup() : base()
  271.         {
  272.             SetDefaults();
  273.         }
  274.        
  275.         public NetCodeGroup(IMembershipCondition membershipCondition) : base(membershipCondition, (PolicyStatement)null)
  276.         {
  277.             SetDefaults();
  278.         }
  279.        
  280.         //
  281.         // Reset the talkback access to nothing.
  282.         // When a new instance of NetCodeGroup is created it's populated with default talkback rules
  283.         //
  284.         public void ResetConnectAccess()
  285.         {
  286.             m_schemesList = null;
  287.             m_accessList = null;
  288.         }
  289.         //
  290.         // Added public stuff for programmatic support of the talkback access
  291.         // The connectAccess can be null means an empty access (no access) is added
  292.         //
  293.         public void AddConnectAccess(string originScheme, CodeConnectAccess connectAccess)
  294.         {
  295.             if (originScheme == null)
  296.                 throw new ArgumentNullException("originScheme");
  297.            
  298.             if (originScheme != AbsentOriginScheme && originScheme != AnyOtherOriginScheme && !CodeConnectAccess.IsValidScheme(originScheme))
  299.                 throw new ArgumentOutOfRangeException("originScheme");
  300.            
  301.             if (originScheme == AbsentOriginScheme && connectAccess.IsOriginScheme)
  302.                 throw new ArgumentOutOfRangeException("connectAccess");
  303.            
  304.             if (m_schemesList == null) {
  305.                 m_schemesList = new ArrayList();
  306.                 m_accessList = new ArrayList();
  307.             }
  308.            
  309.             originScheme = originScheme.ToLower(CultureInfo.InvariantCulture);
  310.            
  311.             for (int i = 0; i < m_schemesList.Count; ++i) {
  312.                 if ((string)m_schemesList[i] == originScheme) {
  313.                     // originScheme entry is found and we may want to add nothing to it.
  314.                     if (connectAccess == null)
  315.                         return;
  316.                    
  317.                     ArrayList list = (ArrayList)m_accessList[i];
  318.                     for (i = 0; i < list.Count; ++i) {
  319.                         if (((CodeConnectAccess)list[i]).Equals(connectAccess))
  320.                             return;
  321.                     }
  322.                     list.Add(connectAccess);
  323.                     return;
  324.                 }
  325.             }
  326.            
  327.             // originScheme entry is not found, create a new one.
  328.             m_schemesList.Add(originScheme);
  329.             ArrayList newOriginSchemeList = new ArrayList();
  330.             m_accessList.Add(newOriginSchemeList);
  331.            
  332.             // we may want to keep it empty.
  333.             if (connectAccess != null)
  334.                 newOriginSchemeList.Add(connectAccess);
  335.            
  336.         }
  337.         //
  338.         // Each DictionaryEntry will contain
  339.         // Key=originScheme and Value=CodeConnectAccess[] array
  340.         //
  341.         public DictionaryEntry[] GetConnectAccessRules()
  342.         {
  343.             if (m_schemesList == null)
  344.                 return null;
  345.            
  346.             DictionaryEntry[] result = new DictionaryEntry[m_schemesList.Count];
  347.             for (int i = 0; i < result.Length; ++i) {
  348.                 result[i].Key = m_schemesList[i];
  349.                 result[i].Value = ((ArrayList)m_accessList[i]).ToArray(typeof(CodeConnectAccess));
  350.             }
  351.             return result;
  352.         }
  353.        
  354.         public override PolicyStatement Resolve(Evidence evidence)
  355.         {
  356.             if (evidence == null)
  357.                 throw new ArgumentNullException("evidence");
  358.            
  359.             if (this.MembershipCondition.Check(evidence)) {
  360.                 PolicyStatement thisPolicy = CalculateAssemblyPolicy(evidence);
  361.                
  362.                 IEnumerator enumerator = this.Children.GetEnumerator();
  363.                 while (enumerator.MoveNext()) {
  364.                     PolicyStatement childPolicy = ((CodeGroup)enumerator.Current).Resolve(evidence);
  365.                    
  366.                     if (childPolicy != null) {
  367.                         if (((thisPolicy.Attributes & childPolicy.Attributes) & PolicyStatementAttribute.Exclusive) == PolicyStatementAttribute.Exclusive) {
  368.                             throw new PolicyException(Environment.GetResourceString("Policy_MultipleExclusive"));
  369.                         }
  370.                        
  371.                         thisPolicy.GetPermissionSetNoCopy().InplaceUnion(childPolicy.GetPermissionSetNoCopy());
  372.                         thisPolicy.Attributes = thisPolicy.Attributes | childPolicy.Attributes;
  373.                     }
  374.                 }
  375.                
  376.                 return thisPolicy;
  377.             }
  378.             else {
  379.                 return null;
  380.             }
  381.         }
  382.        
  383.         /// <internalonly/>
  384.         PolicyStatement IUnionSemanticCodeGroup.InternalResolve(Evidence evidence)
  385.         {
  386.             if (evidence == null)
  387.                 throw new ArgumentNullException("evidence");
  388.            
  389.            
  390.             if (this.MembershipCondition.Check(evidence)) {
  391.                 return CalculateAssemblyPolicy(evidence);
  392.             }
  393.            
  394.             return null;
  395.         }
  396.        
  397.         public override CodeGroup ResolveMatchingCodeGroups(Evidence evidence)
  398.         {
  399.             if (evidence == null)
  400.                 throw new ArgumentNullException("evidence");
  401.            
  402.             if (this.MembershipCondition.Check(evidence)) {
  403.                 CodeGroup retGroup = this.Copy();
  404.                
  405.                 retGroup.Children = new ArrayList();
  406.                
  407.                 IEnumerator enumerator = this.Children.GetEnumerator();
  408.                
  409.                 while (enumerator.MoveNext()) {
  410.                     CodeGroup matchingGroups = ((CodeGroup)enumerator.Current).ResolveMatchingCodeGroups(evidence);
  411.                    
  412.                     // If the child has a policy, we are done.
  413.                    
  414.                     if (matchingGroups != null) {
  415.                         retGroup.AddChild(matchingGroups);
  416.                     }
  417.                 }
  418.                
  419.                 return retGroup;
  420.                
  421.             }
  422.             else {
  423.                 return null;
  424.             }
  425.         }
  426.         //
  427.         private string EscapeStringForRegex(string str)
  428.         {
  429.             int start = 0;
  430.             int idx;
  431.             System.Text.StringBuilder sb = null;
  432.            
  433.             while (start < str.Length && (idx = str.IndexOfAny(c_SomeRegexChars, start)) != -1) {
  434.                 if (sb == null)
  435.                     sb = new System.Text.StringBuilder(str.Length * 2);
  436.                 sb.Append(str, start, idx - start).Append('\\').Append(str[idx]);
  437.                 start = idx + 1;
  438.             }
  439.             if (sb == null)
  440.                 return str;
  441.            
  442.             if (start < str.Length)
  443.                 sb.Append(str, start, str.Length - start);
  444.            
  445.             return sb.ToString();
  446.         }
  447.        
  448.        
  449.         private SecurityElement CreateWebPermission(string host, string scheme, string port)
  450.         {
  451.             if (scheme == null)
  452.                 scheme = string.Empty;
  453.            
  454.             // If there is no OriginScheme host string, no talk back access is possible
  455.             if (host == null || host.Length == 0)
  456.                 return null;
  457.            
  458.             host = host.ToLower(CultureInfo.InvariantCulture);
  459.             scheme = scheme.ToLower(CultureInfo.InvariantCulture);
  460.            
  461.             int intPort = CodeConnectAccess.NoPort;
  462.             if (port != null && port.Length != 0)
  463.                 intPort = Int32.Parse(port, CultureInfo.InvariantCulture);
  464.             else
  465.                 port = string.Empty;
  466.            
  467.             CodeConnectAccess[] access = FindAccessRulesForScheme(scheme);
  468.             if (access == null || access.Length == 0)
  469.                 return null;
  470.            
  471.             SecurityElement root = new SecurityElement("IPermission");
  472.            
  473.             root.AddAttribute("class", "System.Net.WebPermission, System, Version=" + ThisAssembly.Version + ", Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKeyToken);
  474.             root.AddAttribute("version", "1");
  475.            
  476.             SecurityElement connectAccess = new SecurityElement("ConnectAccess");
  477.            
  478.             host = EscapeStringForRegex(host);
  479.             scheme = EscapeStringForRegex(scheme);
  480.             string uriStr = TryPermissionAsOneString(access, scheme, host, intPort);
  481.            
  482.             if (uriStr != null) {
  483.                 SecurityElement uri = new SecurityElement("URI");
  484.                 uri.AddAttribute("uri", uriStr);
  485.                 connectAccess.AddChild(uri);
  486.             }
  487.             else {
  488.                 if (port.Length != 0)
  489.                     port = ":" + port;
  490.                
  491.                 for (int i = 0; i < access.Length; ++i) {
  492.                     uriStr = GetPermissionAccessElementString(access[i], scheme, host, port);
  493.                     SecurityElement uri = new SecurityElement("URI");
  494.                     uri.AddAttribute("uri", uriStr);
  495.                     connectAccess.AddChild(uri);
  496.                 }
  497.             }
  498.            
  499.             root.AddChild(connectAccess);
  500.             return root;
  501.         }
  502.         //
  503.         //
  504.         //
  505.         private CodeConnectAccess[] FindAccessRulesForScheme(string lowerCaseScheme)
  506.         {
  507.             if (m_schemesList == null)
  508.                 return null;
  509.            
  510.             int i = m_schemesList.IndexOf(lowerCaseScheme);
  511.             if (i == -1) {
  512.                 // Trying default rule but only if the passed string is not about "no scheme case"
  513.                 if (lowerCaseScheme == AbsentOriginScheme || (i = m_schemesList.IndexOf(AnyOtherOriginScheme)) == -1)
  514.                     return null;
  515.             }
  516.            
  517.             ArrayList accessList = (ArrayList)m_accessList[i];
  518.             return (CodeConnectAccess[])accessList.ToArray(typeof(CodeConnectAccess));
  519.         }
  520.         //
  521.         // This is an attempt to optimize resulting regex if the rules can be combined into one expression string
  522.         //
  523.         private string TryPermissionAsOneString(CodeConnectAccess[] access, string escapedScheme, string escapedHost, int intPort)
  524.         {
  525.             bool noPort = true;
  526.             bool originPort = true;
  527.             bool anyScheme = false;
  528.             int sameCustomPort = CodeConnectAccess.AnyPort;
  529.            
  530.             //
  531.             // We can compact rules in one regex if the destination port is the same for all granted accesses.
  532.             // We may have three cases (order is significant)
  533.             // - No port (empty) in the resulting rule
  534.             // - Origin server port that is intPort parameter
  535.             // - Some custom port that is the same for all accesses
  536.             //
  537.             for (int i = 0; i < access.Length; ++i) {
  538.                 noPort &= (access[i].IsDefaultPort || (access[i].IsOriginPort && intPort == CodeConnectAccess.NoPort));
  539.                 originPort &= (access[i].IsOriginPort || access[i].Port == intPort);
  540.                
  541.                 if (access[i].Port >= 0) {
  542.                    
  543.                     if (sameCustomPort == CodeConnectAccess.AnyPort) {
  544.                         sameCustomPort = access[i].Port;
  545.                     }
  546.                     else if (access[i].Port != sameCustomPort) {
  547.                         // found conflicting ports
  548.                         sameCustomPort = CodeConnectAccess.NoPort;
  549.                     }
  550.                 }
  551.                 else {
  552.                     // Cannot compress Regex if saw at least one "default port" access rule and another one with exact port.
  553.                     sameCustomPort = CodeConnectAccess.NoPort;
  554.                 }
  555.                
  556.                 if (access[i].IsAnyScheme)
  557.                     anyScheme = true;
  558.             }
  559.            
  560.             if (!noPort && !originPort && sameCustomPort == CodeConnectAccess.NoPort)
  561.                 return null;
  562.            
  563.             // We can produce the resulting expression as one string
  564.             System.Text.StringBuilder sb = new System.Text.StringBuilder(c_AnyScheme.Length * access.Length + c_IgnoreUserInfo.Length * 2 + escapedHost.Length);
  565.             if (anyScheme)
  566.                 sb.Append(c_AnyScheme);
  567.             else {
  568.                 sb.Append('(');
  569.                 int i = 0;
  570.                 for (; i < access.Length; ++i) {
  571.                     // This is to avoid output like (http|http|http)
  572.                     int k = 0;
  573.                     for (; k < i; ++k) {
  574.                         if (access[i].Scheme == access[k].Scheme)
  575.                             break;
  576.                     }
  577.                     if (k == i) {
  578.                         if (i != 0)
  579.                             sb.Append('|');
  580.                         sb.Append(access[i].IsOriginScheme ? escapedScheme : EscapeStringForRegex(access[i].Scheme));
  581.                     }
  582.                 }
  583.                 sb.Append(")://");
  584.                 ;
  585.             }
  586.            
  587.             sb.Append(c_IgnoreUserInfo).Append(escapedHost);
  588.            
  589.             if (noPort) {
  590.                 ;
  591.             }
  592.             else if (originPort)
  593.                 sb.Append(':').Append(intPort);
  594.             else
  595.                 sb.Append(':').Append(sameCustomPort);
  596.            
  597.             sb.Append("/.*");
  598.             return sb.ToString();
  599.         }
  600.         //
  601.         // This tries to return a single element to be added into resulting WebPermission
  602.         // Returns Null if there is nothing to add.
  603.         //
  604.         private string GetPermissionAccessElementString(CodeConnectAccess access, string escapedScheme, string escapedHost, string strPort)
  605.         {
  606.             System.Text.StringBuilder sb = new System.Text.StringBuilder(c_AnyScheme.Length * 2 + c_IgnoreUserInfo.Length + escapedHost.Length);
  607.            
  608.             if (access.IsAnyScheme)
  609.                 sb.Append(c_AnyScheme);
  610.             else if (access.IsOriginScheme)
  611.                 sb.Append(escapedScheme).Append("://");
  612.             else
  613.                 sb.Append(EscapeStringForRegex(access.Scheme)).Append("://");
  614.            
  615.             sb.Append(c_IgnoreUserInfo).Append(escapedHost);
  616.            
  617.             if (access.IsDefaultPort) {
  618.                 ;
  619.             }
  620.             else if (access.IsOriginPort)
  621.                 sb.Append(strPort);
  622.             else
  623.                 sb.Append(':').Append(access.StrPort);
  624.            
  625.             sb.Append("/.*");
  626.             return sb.ToString();
  627.         }
  628.        
  629.         internal PolicyStatement CalculatePolicy(string host, string scheme, string port)
  630.         {
  631.             SecurityElement webPerm = CreateWebPermission(host, scheme, port);
  632.            
  633.             SecurityElement root = new SecurityElement("PolicyStatement");
  634.             SecurityElement permSet = new SecurityElement("PermissionSet");
  635.             permSet.AddAttribute("class", "System.Security.PermissionSet");
  636.             permSet.AddAttribute("version", "1");
  637.            
  638.             if (webPerm != null)
  639.                 permSet.AddChild(webPerm);
  640.            
  641.             root.AddChild(permSet);
  642.            
  643.             PolicyStatement policy = new PolicyStatement();
  644.             policy.FromXml(root);
  645.             return policy;
  646.         }
  647.        
  648.         private PolicyStatement CalculateAssemblyPolicy(Evidence evidence)
  649.         {
  650.             IEnumerator evidenceEnumerator = evidence.GetHostEnumerator();
  651.            
  652.             PolicyStatement thisPolicy = null;
  653.            
  654.             Site site = null;
  655.            
  656.             while (evidenceEnumerator.MoveNext()) {
  657.                 Url url = evidenceEnumerator.Current as Url;
  658.                
  659.                 if (url != null) {
  660.                     thisPolicy = CalculatePolicy(url.GetURLString().Host, url.GetURLString().Scheme, url.GetURLString().Port);
  661.                 }
  662.                 else {
  663.                     if (site == null)
  664.                         site = evidenceEnumerator.Current as Site;
  665.                 }
  666.             }
  667.            
  668.             if (thisPolicy == null && site != null)
  669.                 thisPolicy = CalculatePolicy(site.Name, null, null);
  670.            
  671.             if (thisPolicy == null)
  672.                 thisPolicy = new PolicyStatement(new PermissionSet(false), PolicyStatementAttribute.Nothing);
  673.            
  674.             return thisPolicy;
  675.         }
  676.        
  677.         public override CodeGroup Copy()
  678.         {
  679.             NetCodeGroup group = new NetCodeGroup(this.MembershipCondition);
  680.            
  681.             group.Name = this.Name;
  682.             group.Description = this.Description;
  683.             if (m_schemesList != null) {
  684.                 group.m_schemesList = (ArrayList)this.m_schemesList.Clone();
  685.                 group.m_accessList = new ArrayList(this.m_accessList.Count);
  686.                 for (int i = 0; i < this.m_accessList.Count; ++i)
  687.                     group.m_accessList.Add(((ArrayList)this.m_accessList[i]).Clone());
  688.             }
  689.            
  690.             IEnumerator enumerator = this.Children.GetEnumerator();
  691.            
  692.             while (enumerator.MoveNext()) {
  693.                 group.AddChild((CodeGroup)enumerator.Current);
  694.             }
  695.            
  696.            
  697.             return group;
  698.         }
  699.        
  700.         public override string MergeLogic {
  701.             get { return Environment.GetResourceString("MergeLogic_Union"); }
  702.         }
  703.        
  704.         public override string PermissionSetName {
  705.             get { return Environment.GetResourceString("NetCodeGroup_PermissionSet"); }
  706.         }
  707.        
  708.        
  709.         public override string AttributeString {
  710.             get { return null; }
  711.         }
  712.         //
  713.         public override bool Equals(object o)
  714.         {
  715.             if ((object)this == (object)o)
  716.                 return true;
  717.            
  718.             NetCodeGroup that = (o as NetCodeGroup);
  719.            
  720.             if (that == null || !base.Equals(that))
  721.                 return false;
  722.            
  723.             if ((this.m_schemesList == null) != (that.m_schemesList == null))
  724.                 return false;
  725.            
  726.             if (this.m_schemesList == null)
  727.                 return true;
  728.            
  729.             if (this.m_schemesList.Count != that.m_schemesList.Count)
  730.                 return false;
  731.            
  732.            
  733.             for (int i = 0; i < this.m_schemesList.Count; ++i) {
  734.                 int idx = that.m_schemesList.IndexOf(this.m_schemesList[i]);
  735.                 if (idx == -1)
  736.                     return false;
  737.                
  738.                 ArrayList thisList = (ArrayList)this.m_accessList[i];
  739.                 ArrayList thatList = (ArrayList)that.m_accessList[idx];
  740.                 if (thisList.Count != thatList.Count)
  741.                     return false;
  742.                
  743.                 for (int k = 0; k < thisList.Count; ++k) {
  744.                     if (!thatList.Contains(thisList[k]))
  745.                         return false;
  746.                 }
  747.             }
  748.            
  749.             return true;
  750.         }
  751.         //
  752.         //
  753.         public override int GetHashCode()
  754.         {
  755.             return base.GetHashCode() + GetRulesHashCode();
  756.         }
  757.         private int GetRulesHashCode()
  758.         {
  759.             if (m_schemesList == null)
  760.                 return 0;
  761.            
  762.             int result = 0;
  763.             for (int i = 0; i < m_schemesList.Count; ++i)
  764.                 result += ((string)m_schemesList[i]).GetHashCode();
  765.            
  766.             foreach (ArrayList accessList in m_accessList)
  767.                 for (int i = 0; i < accessList.Count; ++i)
  768.                     result += ((CodeConnectAccess)accessList[i]).GetHashCode();
  769.            
  770.             return result;
  771.         }
  772.         //
  773.         protected override void CreateXml(SecurityElement element, PolicyLevel level)
  774.         {
  775.             DictionaryEntry[] rules = GetConnectAccessRules();
  776.             if (rules == null)
  777.                 return;
  778.            
  779.             SecurityElement rulesElement = new SecurityElement("connectAccessRules");
  780.            
  781.             foreach (DictionaryEntry rule in rules) {
  782.                 SecurityElement codeOriginElement = new SecurityElement("codeOrigin");
  783.                 codeOriginElement.AddAttribute("scheme", (string)rule.Key);
  784.                 foreach (CodeConnectAccess access in (CodeConnectAccess[])rule.Value) {
  785.                     SecurityElement accessElem = new SecurityElement("connectAccess");
  786.                     accessElem.AddAttribute("scheme", access.Scheme);
  787.                     accessElem.AddAttribute("port", access.StrPort);
  788.                     codeOriginElement.AddChild(accessElem);
  789.                 }
  790.                 rulesElement.AddChild(codeOriginElement);
  791.             }
  792.             element.AddChild(rulesElement);
  793.         }
  794.        
  795.         protected override void ParseXml(SecurityElement e, PolicyLevel level)
  796.         {
  797.             //Reset the exiting content
  798.             ResetConnectAccess();
  799.            
  800.             SecurityElement et = e.SearchForChildByTag("connectAccessRules");
  801.            
  802.             if (et == null || et.Children == null) {
  803.                 SetDefaults();
  804.                 return;
  805.             }
  806.            
  807.             foreach (SecurityElement codeOriginElem in et.Children) {
  808.                 if (codeOriginElem.Tag.Equals("codeOrigin")) {
  809.                     string originScheme = codeOriginElem.Attribute("scheme");
  810.                     bool oneAdded = false;
  811.                    
  812.                     if (codeOriginElem.Children != null) {
  813.                         foreach (SecurityElement accessElem in codeOriginElem.Children) {
  814.                             if (accessElem.Tag.Equals("connectAccess")) {
  815.                                 string connectScheme = accessElem.Attribute("scheme");
  816.                                 string connectPort = accessElem.Attribute("port");
  817.                                 AddConnectAccess(originScheme, new CodeConnectAccess(connectScheme, connectPort));
  818.                                 oneAdded = true;
  819.                             }
  820.                             else {
  821.                                 // improper tag found, just ignore
  822.                             }
  823.                         }
  824.                     }
  825.                    
  826.                     if (!oneAdded) {
  827.                         //special case as to no talkback access for a given scheme
  828.                         AddConnectAccess(originScheme, null);
  829.                     }
  830.                    
  831.                 }
  832.                 else {
  833.                     // improper tag found, just ignore
  834.                 }
  835.             }
  836.         }
  837.        
  838.         internal override string GetTypeName()
  839.         {
  840.             return "System.Security.Policy.NetCodeGroup";
  841.         }
  842.         //
  843.         // This method is called at the ctor time to populate default accesses (V1.1 compat)
  844.         //
  845.         private void SetDefaults()
  846.         {
  847.             // No access for file://
  848.             AddConnectAccess("file", null);
  849.            
  850.             // access fot http://
  851.             AddConnectAccess("http", new CodeConnectAccess("http", CodeConnectAccess.OriginPort));
  852.             AddConnectAccess("http", new CodeConnectAccess("https", CodeConnectAccess.OriginPort));
  853.             /* CONSIDER
  854.             AddConnectAccess("http", new CodeConnectAccess("https", CodeConnectAccess.DefaultPort));
  855.             AddConnectAccess("http", new CodeConnectAccess("ftp", CodeConnectAccess.DefaultPort));
  856.             AddConnectAccess("http", new CodeConnectAccess("soap.tcp", CodeConnectAccess.DefaultPort));
  857.             */           
  858.            
  859.             // access fot https://
  860. AddConnectAccess("https", new CodeConnectAccess("https", CodeConnectAccess.OriginPort));
  861.             /* CONSIDER
  862.             AddConnectAccess("https", new CodeConnectAccess("soap.tcp", CodeConnectAccess.DefaultPort));
  863.             */           
  864.            
  865.            
  866.             // access fot ftp://
  867. /* CONSIDER
  868.             AddConnectAccess("ftp", new CodeConnectAccess("ftp", CodeConnectAccess.OriginPort));
  869.             AddConnectAccess("ftp", new CodeConnectAccess("http", CodeConnectAccess.DefaultPort));
  870.             AddConnectAccess("ftp", new CodeConnectAccess("https", CodeConnectAccess.DefaultPort));
  871.             AddConnectAccess("ftp", new CodeConnectAccess("soap.tcp", CodeConnectAccess.DefaultPort));
  872.             */           
  873.            
  874.             // access for no scheme and for any other scheme
  875. AddConnectAccess(NetCodeGroup.AbsentOriginScheme, CodeConnectAccess.CreateAnySchemeAccess(CodeConnectAccess.OriginPort));
  876.             AddConnectAccess(NetCodeGroup.AnyOtherOriginScheme, CodeConnectAccess.CreateOriginSchemeAccess(CodeConnectAccess.OriginPort));
  877.         }
  878.        
  879.     }
  880.    
  881. }

Developer Fusion