The Labs \ Source Viewer \ SSCLI \ System.Net \ SocketPermissionAttribute

  1. //------------------------------------------------------------------------------
  2. // <copyright file="SocketPermission.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.Net
  16. {
  17.    
  18.     using System.Collections;
  19.     using System.Security;
  20.     using System.Security.Permissions;
  21.     using System.Globalization;
  22.     using System.Threading;
  23.    
  24.     //NOTE: While SocketPermissionAttribute resides in System.DLL,
  25.     // no classes from that DLL are able to make declarative usage of SocketPermission.
  26.    
  27.    
  28.     // THE syntax of this attribute is as followed
  29.     // [SocketPermsion(SecurityAction.Assert, Access=Connect, Host=hostname, Transport=Tcp/Udp/All, port=portN/All)]
  30.     // [SocketPermsion(SecurityAction.Assert, Access=Accept, Host=localname, Transport=Tcp/Udp/All, port=portN/All)]
  31.     //
  32.     // WHERE:
  33.     //=======
  34.     // - hostname is either a DNS hostname OR an IP address 1.2.3.4 or an IP wildcard 1.2.*.*
  35.     // - protocol is either Tcp, Udp or All
  36.     // - port is a numeric value or -1 that means "All Ports"
  37.     //
  38.     // All the properites Host, Protocol and Port must be specified.
  39.     // "localIP" means that you put here a valid address or DNS name or the localhost
  40.     //
  41.     // NetworkAccess specifies the scope of permission, i.e. for connecting to remote peer,
  42.     // or for accepting data on the local resources.
  43.     //
  44.    
  45.     [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
  46.    
  47.     [Serializable()]
  48.     public sealed class SocketPermissionAttribute : CodeAccessSecurityAttribute
  49.     {
  50.         private string m_access = null;
  51.         private string m_host = null;
  52.         private string m_port = null;
  53.         private string m_transport = null;
  54.        
  55.         private const string strAccess = "Access";
  56.         private const string strConnect = "Connect";
  57.         private const string strAccept = "Accept";
  58.         private const string strHost = "Host";
  59.         private const string strTransport = "Transport";
  60.         private const string strPort = "Port";
  61.        
  62.         public SocketPermissionAttribute(SecurityAction action) : base(action)
  63.         {
  64.         }
  65.        
  66.         public string Access {
  67.             get { return m_access; }
  68.             set {
  69.                 if (m_access != null) {
  70.                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, strAccess, value), "value");
  71.                 }
  72.                 m_access = value;
  73.             }
  74.         }
  75.        
  76.         public string Host {
  77.             get { return m_host; }
  78.             set {
  79.                 if (m_host != null) {
  80.                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, strHost, value), "value");
  81.                 }
  82.                 m_host = value;
  83.             }
  84.         }
  85.        
  86.         public string Transport {
  87.             get { return m_transport; }
  88.             set {
  89.                 if (m_transport != null) {
  90.                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, strTransport, value), "value");
  91.                 }
  92.                 m_transport = value;
  93.             }
  94.         }
  95.        
  96.         public string Port {
  97.             get { return m_port; }
  98.             set {
  99.                 if (m_port != null) {
  100.                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_multi, strPort, value), "value");
  101.                 }
  102.                 m_port = value;
  103.             }
  104.         }
  105.        
  106.         public override IPermission CreatePermission()
  107.         {
  108.             SocketPermission perm = null;
  109.             if (Unrestricted) {
  110.                 perm = new SocketPermission(PermissionState.Unrestricted);
  111.             }
  112.             else {
  113.                 perm = new SocketPermission(PermissionState.None);
  114.                 if (m_access == null) {
  115.                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_count, strAccess));
  116.                 }
  117.                 if (m_host == null) {
  118.                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_count, strHost));
  119.                 }
  120.                 if (m_transport == null) {
  121.                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_count, strTransport));
  122.                 }
  123.                 if (m_port == null) {
  124.                     throw new ArgumentException(SR.GetString(SR.net_perm_attrib_count, strPort));
  125.                 }
  126.                 ParseAddPermissions(perm);
  127.             }
  128.             return perm;
  129.         }
  130.        
  131.        
  132.         private void ParseAddPermissions(SocketPermission perm)
  133.         {
  134.            
  135.             NetworkAccess access;
  136.             if (0 == string.Compare(m_access, strConnect, StringComparison.OrdinalIgnoreCase)) {
  137.                 access = NetworkAccess.Connect;
  138.             }
  139.             else if (0 == string.Compare(m_access, strAccept, StringComparison.OrdinalIgnoreCase)) {
  140.                 access = NetworkAccess.Accept;
  141.             }
  142.             else {
  143.                 throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val, strAccess, m_access));
  144.             }
  145.            
  146.             TransportType transport;
  147.             try {
  148.                 transport = (TransportType)Enum.Parse(typeof(TransportType), m_transport, true);
  149.             }
  150.             catch (Exception e) {
  151.                 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
  152.                     throw;
  153.                 }
  154.                 throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val, strTransport, m_transport), e);
  155.             }
  156.             catch {
  157.                 throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val, strTransport, m_transport), new Exception(SR.GetString(SR.net_nonClsCompliantException)));
  158.             }
  159.            
  160.             int port;
  161.             if (string.Compare(m_port, "All", StringComparison.OrdinalIgnoreCase) == 0) {
  162.                 m_port = "-1";
  163.             }
  164.             try {
  165.                 port = Int32.Parse(m_port, NumberFormatInfo.InvariantInfo);
  166.             }
  167.             catch (Exception e) {
  168.                 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
  169.                     throw;
  170.                 }
  171.                 throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val, strPort, m_port), e);
  172.             }
  173.             catch {
  174.                 throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val, strPort, m_port), new Exception(SR.GetString(SR.net_nonClsCompliantException)));
  175.             }
  176.            
  177.             if (!ValidationHelper.ValidateTcpPort(port) && port != SocketPermission.AllPorts) {
  178.                 throw new ArgumentOutOfRangeException(SR.GetString(SR.net_perm_invalid_val, strPort, m_port));
  179.             }
  180.             perm.AddPermission(access, transport, m_host, port);
  181.         }
  182.        
  183.     }
  184.    
  185.    
  186.     /// <devdoc>
  187.     /// <para>
  188.     /// Controls rights to make or accept connections on a transport address.
  189.     /// </para>
  190.     /// </devdoc>
  191.     [Serializable()]
  192.     public sealed class SocketPermission : CodeAccessPermission, IUnrestrictedPermission
  193.     {
  194.        
  195.         private ArrayList m_connectList;
  196.         private ArrayList m_acceptList;
  197.         private bool m_noRestriction;
  198.        
  199.        
  200.         /// <devdoc>
  201.         /// <para>
  202.         /// Returns the enumeration of permissions to connect a remote peer.
  203.         /// </para>
  204.         /// </devdoc>
  205.         public IEnumerator ConnectList {
  206.             get { return m_connectList.GetEnumerator(); }
  207.         }
  208.        
  209.         /// <devdoc>
  210.         /// <para>
  211.         /// Returns the enumeration of permissions to accept incoming connections.
  212.         /// </para>
  213.         /// </devdoc>
  214.         public IEnumerator AcceptList {
  215.             get { return m_acceptList.GetEnumerator(); }
  216.         }
  217.        
  218.        
  219.         /// <devdoc>
  220.         /// <para>
  221.         /// Defines a constant representing all ports.
  222.         /// </para>
  223.         /// </devdoc>
  224.         public const int AllPorts = unchecked((int)4294967295u);
  225.        
  226.         internal const int AnyPort = unchecked((int)0);
  227.        
  228.         /// <devdoc>
  229.         /// <para>
  230.         /// Creates a new instance of the <see cref='System.Net.SocketPermission'/>
  231.         /// class that passes all demands
  232.         /// or that fails all demands.
  233.         /// </para>
  234.         /// </devdoc>
  235.         public SocketPermission(PermissionState state)
  236.         {
  237.             initialize();
  238.             m_noRestriction = (state == PermissionState.Unrestricted);
  239.         }
  240.        
  241.         internal SocketPermission(bool free)
  242.         {
  243.             initialize();
  244.             m_noRestriction = free;
  245.         }
  246.        
  247.        
  248.         /// <devdoc>
  249.         /// <para>
  250.         /// Creates a new instance of the SocketPermissions class for the given transport address with the specified permission.
  251.         /// </para>
  252.         /// </devdoc>
  253.         public SocketPermission(NetworkAccess access, TransportType transport, string hostName, int portNumber)
  254.         {
  255.             initialize();
  256.             m_noRestriction = false;
  257.             AddPermission(access, transport, hostName, portNumber);
  258.         }
  259.        
  260.         /// <devdoc>
  261.         /// <para>
  262.         /// Adds a permission to the set of permissions for a transport address.
  263.         /// </para>
  264.         /// </devdoc>
  265.         public void AddPermission(NetworkAccess access, TransportType transport, string hostName, int portNumber)
  266.         {
  267.             if (hostName == null) {
  268.                 throw new ArgumentNullException("hostName");
  269.             }
  270.            
  271.             EndpointPermission endPoint = new EndpointPermission(hostName, portNumber, transport);
  272.            
  273.             AddPermission(access, endPoint);
  274.         }
  275.        
  276.         internal void AddPermission(NetworkAccess access, EndpointPermission endPoint)
  277.         {
  278.             if (m_noRestriction) {
  279.                 // Is the permission unrestricted?
  280.                 return;
  281.                 // YES-- then additional endpoints have no effect
  282.             }
  283.             if ((access & NetworkAccess.Connect) != 0)
  284.                 m_connectList.Add(endPoint);
  285.             if ((access & NetworkAccess.Accept) != 0)
  286.                 m_acceptList.Add(endPoint);
  287.         }
  288.        
  289.         // IUnrestrictedPermission interface methods
  290.         /// <devdoc>
  291.         /// <para>
  292.         /// Checks the overall permission state of the object.
  293.         /// </para>
  294.         /// </devdoc>
  295.         public bool IsUnrestricted()
  296.         {
  297.             return m_noRestriction;
  298.         }
  299.        
  300.         // IPermission interface methods
  301.         /// <devdoc>
  302.         /// <para>
  303.         /// Creates
  304.         /// a copy of a <see cref='System.Net.SocketPermission'/> instance.
  305.         /// </para>
  306.         /// </devdoc>
  307.         public override IPermission Copy()
  308.         {
  309.            
  310.             SocketPermission sp = new SocketPermission(m_noRestriction);
  311.            
  312.             sp.m_connectList = (ArrayList)m_connectList.Clone();
  313.             sp.m_acceptList = (ArrayList)m_acceptList.Clone();
  314.             return sp;
  315.         }
  316.        
  317.         private bool FindSubset(ArrayList source, ArrayList target)
  318.         {
  319.             foreach (EndpointPermission e in source) {
  320.                
  321.                 bool found = false;
  322.                
  323.                 foreach (EndpointPermission ee in target) {
  324.                     if (e.SubsetMatch(ee)) {
  325.                         found = true;
  326.                         break;
  327.                     }
  328.                 }
  329.                 if (!found) {
  330.                     return false;
  331.                 }
  332.             }
  333.             return true;
  334.         }
  335.        
  336.         /// <devdoc>
  337.         /// <para>Returns the logical union between two <see cref='System.Net.SocketPermission'/> instances.</para>
  338.         /// </devdoc>
  339.         public override IPermission Union(IPermission target)
  340.         {
  341.             // Pattern suggested by Security engine
  342.             if (target == null) {
  343.                 return this.Copy();
  344.             }
  345.             SocketPermission other = target as SocketPermission;
  346.             if (other == null) {
  347.                 throw new ArgumentException(SR.GetString(SR.net_perm_target), "target");
  348.             }
  349.             if (m_noRestriction || other.m_noRestriction) {
  350.                 return new SocketPermission(true);
  351.             }
  352.             SocketPermission result = (SocketPermission)other.Copy();
  353.            
  354.             for (int i = 0; i < m_connectList.Count; i++) {
  355.                 result.AddPermission(NetworkAccess.Connect, (EndpointPermission)m_connectList[i]);
  356.             }
  357.             for (int i = 0; i < m_acceptList.Count; i++) {
  358.                 result.AddPermission(NetworkAccess.Accept, (EndpointPermission)m_acceptList[i]);
  359.             }
  360.             return result;
  361.         }
  362.        
  363.         /// <devdoc>
  364.         /// <para>
  365.         /// Returns the logical intersection between two <see cref='System.Net.SocketPermission'/> instances.
  366.         /// </para>
  367.         /// </devdoc>
  368.         public override IPermission Intersect(IPermission target)
  369.         {
  370.             // Pattern suggested by Security engine
  371.             if (target == null) {
  372.                 return null;
  373.             }
  374.            
  375.             SocketPermission other = target as SocketPermission;
  376.             if (other == null) {
  377.                 throw new ArgumentException(SR.GetString(SR.net_perm_target), "target");
  378.             }
  379.            
  380.             SocketPermission result;
  381.             if (m_noRestriction) {
  382.                 result = (SocketPermission)(other.Copy());
  383.             }
  384.             else if (other.m_noRestriction) {
  385.                 result = (SocketPermission)(this.Copy());
  386.             }
  387.             else {
  388.                 result = new SocketPermission(false);
  389.                 intersectLists(m_connectList, other.m_connectList, result.m_connectList);
  390.                 intersectLists(m_acceptList, other.m_acceptList, result.m_acceptList);
  391.             }
  392.            
  393.             // return null if resulting permission is restricted and empty
  394.             if (!result.m_noRestriction && result.m_connectList.Count == 0 && result.m_acceptList.Count == 0) {
  395.                 return null;
  396.             }
  397.             return result;
  398.         }
  399.        
  400.         /// <devdoc>
  401.         /// <para>Compares two <see cref='System.Net.SocketPermission'/> instances.</para>
  402.         /// </devdoc>
  403.         public override bool IsSubsetOf(IPermission target)
  404.         {
  405.             // Pattern suggested by security engine
  406.             if (target == null) {
  407.                 return (m_noRestriction == false && m_connectList.Count == 0 && m_acceptList.Count == 0);
  408.             }
  409.            
  410.             SocketPermission other = target as SocketPermission;
  411.             if (other == null) {
  412.                 throw new ArgumentException(SR.GetString(SR.net_perm_target), "target");
  413.             }
  414.            
  415.             if (other.IsUnrestricted()) {
  416.                 return true;
  417.             }
  418.             else if (this.IsUnrestricted()) {
  419.                 return false;
  420.             }
  421.             else if (this.m_acceptList.Count + this.m_connectList.Count == 0) {
  422.                 return true;
  423.             }
  424.             else if (other.m_acceptList.Count + other.m_connectList.Count == 0) {
  425.                 return false;
  426.             }
  427.            
  428.             bool result = false;
  429.             try {
  430.                 if (FindSubset(m_connectList, other.m_connectList) && FindSubset(m_acceptList, other.m_acceptList)) {
  431.                     result = true;
  432.                 }
  433.             }
  434.             finally {
  435.                 // This is around a back door into DNS
  436.                 // Security engine will call isSubsetOf and probably have
  437.                 // DNS permission asserted. We call DNS resolve.
  438.                 // Before return do cleanup of DNS results.
  439.                
  440.                 // Only "this" needs cleanup, the policy object is not available for
  441.                 // an application to look at.
  442.                 this.CleanupDNS();
  443.             }
  444.            
  445.             return result;
  446.         }
  447.        
  448.         //
  449.         //This is to cleanup DNS resolution results
  450.         //
  451.         private void CleanupDNS()
  452.         {
  453.             foreach (EndpointPermission e in m_connectList) {
  454.                 //DNS hostnames never produce 'cached=true'
  455.                 if (e.cached) {
  456.                     continue;
  457.                 }
  458.                 e.address = null;
  459.             }
  460.            
  461.             foreach (EndpointPermission e in m_acceptList) {
  462.                 //DNS hostnames never produce 'cached=true'
  463.                 if (e.cached) {
  464.                     continue;
  465.                 }
  466.                 e.address = null;
  467.             }
  468.         }
  469.        
  470.         /// <devdoc>
  471.         /// </devdoc>
  472.         public override void FromXml(SecurityElement securityElement)
  473.         {
  474.             if (securityElement == null) {
  475.                
  476.                 //
  477.                 // null SecurityElement
  478.                 //
  479.                
  480.                 throw new ArgumentNullException("securityElement");
  481.             }
  482.             if (!securityElement.Tag.Equals("IPermission")) {
  483.                
  484.                 //
  485.                 // SecurityElement must be a permission element
  486.                 //
  487.                
  488.                 throw new ArgumentException(SR.GetString(SR.net_not_ipermission), "securityElement");
  489.             }
  490.            
  491.             string className = securityElement.Attribute("class");
  492.            
  493.             if (className == null) {
  494.                
  495.                 //
  496.                 // SecurityElement must be a permission element for this type
  497.                 //
  498.                
  499.                 throw new ArgumentException(SR.GetString(SR.net_no_classname), "securityElement");
  500.             }
  501.             if (className.IndexOf(this.GetType().FullName) < 0) {
  502.                
  503.                 //
  504.                 // SecurityElement must be a permission element for this type
  505.                 //
  506.                
  507.                 throw new ArgumentException(SR.GetString(SR.net_no_typename), "securityElement");
  508.             }
  509.            
  510.             //
  511.             // Start recovering the state from XML encoding
  512.             //
  513.            
  514.             initialize();
  515.            
  516.            
  517.             string str = securityElement.Attribute("Unrestricted");
  518.            
  519.             if (str != null) {
  520.                 m_noRestriction = (0 == string.Compare(str, "true", StringComparison.OrdinalIgnoreCase));
  521.                 if (m_noRestriction)
  522.                     return;
  523.             }
  524.            
  525.             m_noRestriction = false;
  526.             m_connectList = new ArrayList();
  527.             m_acceptList = new ArrayList();
  528.            
  529.             SecurityElement et = securityElement.SearchForChildByTag("ConnectAccess");
  530.             if (et != null) {
  531.                 ParseAddXmlElement(et, m_connectList, "ConnectAccess, ");
  532.             }
  533.             et = securityElement.SearchForChildByTag("AcceptAccess");
  534.             if (et != null) {
  535.                 ParseAddXmlElement(et, m_acceptList, "AcceptAccess, ");
  536.             }
  537.         }
  538.        
  539.         private static void ParseAddXmlElement(SecurityElement et, ArrayList listToAdd, string accessStr)
  540.         {
  541.            
  542.             foreach (SecurityElement uriElem in et.Children) {
  543.                 if (uriElem.Tag.Equals("ENDPOINT")) {
  544.                     Hashtable attributes = uriElem.Attributes;
  545.                     string tmpStr;
  546.                    
  547.                     try {
  548.                         tmpStr = attributes["host"] as string;
  549.                     }
  550.                     catch {
  551.                         tmpStr = null;
  552.                     }
  553.                    
  554.                     if (tmpStr == null) {
  555.                         throw new ArgumentNullException(accessStr + "host");
  556.                     }
  557.                     string host = tmpStr;
  558.                    
  559.                     try {
  560.                         tmpStr = attributes["transport"] as string;
  561.                     }
  562.                     catch {
  563.                         tmpStr = null;
  564.                     }
  565.                     if (tmpStr == null) {
  566.                         throw new ArgumentNullException(accessStr + "transport");
  567.                     }
  568.                     TransportType transport;
  569.                     try {
  570.                         transport = (TransportType)Enum.Parse(typeof(TransportType), tmpStr, true);
  571.                     }
  572.                     catch (Exception exception) {
  573.                         if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
  574.                             throw;
  575.                         }
  576.                         throw new ArgumentException(accessStr + "transport", exception);
  577.                     }
  578.                     catch {
  579.                         throw new ArgumentException(accessStr + "transport", new Exception(SR.GetString(SR.net_nonClsCompliantException)));
  580.                     }
  581.                    
  582.                     try {
  583.                         tmpStr = attributes["port"] as string;
  584.                     }
  585.                     catch {
  586.                         tmpStr = null;
  587.                     }
  588.                     if (tmpStr == null) {
  589.                         throw new ArgumentNullException(accessStr + "port");
  590.                     }
  591.                     if (string.Compare(tmpStr, "All", StringComparison.OrdinalIgnoreCase) == 0) {
  592.                         tmpStr = "-1";
  593.                     }
  594.                     int port;
  595.                     try {
  596.                         port = Int32.Parse(tmpStr, NumberFormatInfo.InvariantInfo);
  597.                     }
  598.                     catch (Exception exception) {
  599.                         if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
  600.                             throw;
  601.                         }
  602.                         throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val, accessStr + "port", tmpStr), exception);
  603.                     }
  604.                     catch {
  605.                         throw new ArgumentException(SR.GetString(SR.net_perm_invalid_val, accessStr + "port", tmpStr), new Exception(SR.GetString(SR.net_nonClsCompliantException)));
  606.                     }
  607.                    
  608.                     if (!ValidationHelper.ValidateTcpPort(port) && port != SocketPermission.AllPorts) {
  609.                         throw new ArgumentOutOfRangeException(SR.GetString(SR.net_perm_invalid_val, accessStr + "port", tmpStr));
  610.                     }
  611.                    
  612.                    
  613.                     listToAdd.Add(new EndpointPermission(host, port, transport));
  614.                 }
  615.                 else {
  616.                     // improper tag found, just ignore
  617.                 }
  618.             }
  619.         }
  620.        
  621.         /// <devdoc>
  622.         /// <para>[To be supplied.]</para>
  623.         /// </devdoc>
  624.         public override SecurityElement ToXml()
  625.         {
  626.            
  627.             SecurityElement securityElement = new SecurityElement("IPermission");
  628.            
  629.             securityElement.AddAttribute("class", this.GetType().FullName + ", " + this.GetType().Module.Assembly.FullName.Replace('"', '\''));
  630.             securityElement.AddAttribute("version", "1");
  631.            
  632.             if (!IsUnrestricted()) {
  633.                 if (m_connectList.Count > 0) {
  634.                    
  635.                     SecurityElement permList = new SecurityElement("ConnectAccess");
  636.                     foreach (EndpointPermission permission in m_connectList) {
  637.                         SecurityElement endpoint = new SecurityElement("ENDPOINT");
  638.                         endpoint.AddAttribute("host", permission.Hostname);
  639.                         endpoint.AddAttribute("transport", permission.Transport.ToString());
  640.                         endpoint.AddAttribute("port", permission.Port != AllPorts ? permission.Port.ToString(NumberFormatInfo.InvariantInfo) : "All");
  641.                         permList.AddChild(endpoint);
  642.                     }
  643.                     securityElement.AddChild(permList);
  644.                 }
  645.                
  646.                 if (m_acceptList.Count > 0) {
  647.                    
  648.                     SecurityElement permList = new SecurityElement("AcceptAccess");
  649.                     foreach (EndpointPermission permission in m_acceptList) {
  650.                         SecurityElement endpoint = new SecurityElement("ENDPOINT");
  651.                         endpoint.AddAttribute("host", permission.Hostname);
  652.                         endpoint.AddAttribute("transport", permission.Transport.ToString());
  653.                         endpoint.AddAttribute("port", permission.Port != AllPorts ? permission.Port.ToString(NumberFormatInfo.InvariantInfo) : "All");
  654.                         permList.AddChild(endpoint);
  655.                     }
  656.                     securityElement.AddChild(permList);
  657.                 }
  658.             }
  659.             else {
  660.                 securityElement.AddAttribute("Unrestricted", "true");
  661.             }
  662.             return securityElement;
  663.         }
  664.        
  665.         private void initialize()
  666.         {
  667.             m_noRestriction = false;
  668.             m_connectList = new ArrayList();
  669.             m_acceptList = new ArrayList();
  670.         }
  671.        
  672.         private static void intersectLists(ArrayList A, ArrayList B, ArrayList result)
  673.         {
  674.             // The optimization is done according to the following truth
  675.             // (A|B|C) intersect (B|C|E|D)) == B|C|(A inter E)|(A inter D)
  676.             //
  677.             // We also check on any duplicates in the result
  678.            
  679.            
  680.             bool[] aDone = new bool[A.Count];
  681.             //used to avoid duplicates in result
  682.             bool[] bDone = new bool[B.Count];
  683.             int ia = 0;
  684.             int ib = 0;
  685.             // Round 1st
  686.             // Getting rid of same permissons in the input arrays (assuming X /\ X = X)
  687.             foreach (EndpointPermission a in A) {
  688.                 ib = 0;
  689.                 foreach (EndpointPermission b in B) {
  690.                     // check to see if b is in the result already
  691.                     if (!bDone[ib]) {
  692.                         //if both elements are the same, copy it into result
  693.                         if (a.Equals(b)) {
  694.                             result.Add(a);
  695.                             aDone[ia] = bDone[ib] = true;
  696.                             //since permissions are ORed we can break and go to the next A
  697.                             break;
  698.                         }
  699.                     }
  700.                     ++ib;
  701.                 }
  702.                 //foreach b in B
  703.                 ++ia;
  704.             }
  705.             //foreach a in A
  706.             ia = 0;
  707.             // Round second
  708.             // Grab only intersections of objects not found in both A and B
  709.             foreach (EndpointPermission a in A) {
  710.                
  711.                 if (!aDone[ia]) {
  712.                     ib = 0;
  713.                     foreach (EndpointPermission b in B) {
  714.                         if (!bDone[ib]) {
  715.                             EndpointPermission intesection = a.Intersect(b);
  716.                             if (intesection != null) {
  717.                                 bool found = false;
  718.                                 // check to see if we already have the same result
  719.                                 foreach (EndpointPermission res in result) {
  720.                                     if (res.Equals(intesection)) {
  721.                                         found = true;
  722.                                         break;
  723.                                     }
  724.                                 }
  725.                                 if (!found) {
  726.                                     result.Add(intesection);
  727.                                 }
  728.                             }
  729.                         }
  730.                         //!Done[ib]
  731.                         ++ib;
  732.                     }
  733.                     //foreach b in B
  734.                 }
  735.                 //!Done[ia]
  736.                 ++ia;
  737.             }
  738.             //foreach a in A
  739.         }
  740.        
  741.     }
  742.     // class SocketPermission
  743.    
  744.     /// <devdoc>
  745.     /// Represents an element of SocketPermission object contents.
  746.     /// </devdoc>
  747.     [Serializable()]
  748.     public class EndpointPermission
  749.     {
  750.        
  751.        
  752.         internal string hostname;
  753.         internal int port;
  754.         internal TransportType transport;
  755.         internal bool wildcard;
  756.         internal IPAddress[] address;
  757.         internal bool cached = false;
  758.        
  759.         private static char[] DotSeparator = new char[] {'.'};
  760.         private const string encSeperator = "#";
  761.        
  762.         /// <devdoc>
  763.         /// <para>
  764.         /// Returns the hostname part of EndpointPermission object
  765.         /// </para>
  766.         /// </devdoc>
  767.         public string Hostname {
  768.             get { return hostname; }
  769.         }
  770.        
  771.         /// <devdoc>
  772.         /// <para>
  773.         /// Returns the transport of EndpointPermission object
  774.         /// </para>
  775.         /// </devdoc>
  776.         public TransportType Transport {
  777.             get { return transport; }
  778.         }
  779.        
  780.         /// <devdoc>
  781.         /// <para>
  782.         /// Returns the Port part of EndpointPermission object
  783.         /// </para>
  784.         /// </devdoc>
  785.         public int Port {
  786.             get { return port; }
  787.         }
  788.        
  789.         internal EndpointPermission(string epname, int port, TransportType trtype)
  790.         {
  791.            
  792.             if (CheckEndPointName(epname) == EndPointType.Invalid) {
  793.                 throw new ArgumentException(SR.GetString(SR.net_perm_epname, epname), "epname");
  794.             }
  795.             if (!ValidationHelper.ValidateTcpPort(port) && port != SocketPermission.AllPorts) {
  796.                 throw new ArgumentOutOfRangeException(SR.GetString(SR.net_perm_invalid_val, "Port", port.ToString(NumberFormatInfo.InvariantInfo)));
  797.             }
  798.            
  799.             hostname = epname;
  800.             this.port = port;
  801.             transport = trtype;
  802.             wildcard = false;
  803.         }
  804.        
  805.         //
  806.         // This is ONLY a syntatic check on equality, hostnames are compared as strings!
  807.         //
  808.         public override bool Equals(object obj)
  809.         {
  810.            
  811.             EndpointPermission ep = (EndpointPermission)obj;
  812.            
  813.             if (String.Compare(hostname, ep.hostname, StringComparison.OrdinalIgnoreCase) != 0) {
  814.                 return false;
  815.             }
  816.             if (port != ep.port) {
  817.                 return false;
  818.             }
  819.             if (transport != ep.transport) {
  820.                 return false;
  821.             }
  822.             return true;
  823.         }
  824.        
  825.         public override int GetHashCode()
  826.         {
  827.             return ToString().GetHashCode();
  828.         }
  829.        
  830.        
  831.         internal bool IsDns {
  832.             get {
  833.                 if (IsValidWildcard) {
  834.                     return false;
  835.                 }
  836.                 return CheckEndPointName(hostname) == EndPointType.DnsOrWildcard;
  837.             }
  838.         }
  839.        
  840.        
  841.         //
  842.         // In this version wildcards are only allowed over IP ranges
  843.         // not DNS names. For example "*.microsoft.com" is not allowed
  844.         // A valid wildcard will have exactly three periods
  845.         //IPv6 wildcards are NOT supported
  846.         //
  847.         private bool IsValidWildcard {
  848.             get {
  849.                
  850.                 int len = hostname.Length;
  851.                
  852.                 //
  853.                 // Check minimum length
  854.                 //
  855.                
  856.                 if (len < 3) {
  857.                     return false;
  858.                 }
  859.                
  860.                 //
  861.                 // First and last characters cannot be periods
  862.                 //
  863.                
  864.                 if ((hostname[0] == '.') || (hostname[len - 1] == '.')) {
  865.                     return false;
  866.                 }
  867.                
  868.                 int dotCount = 0;
  869.                 int anyCount = 0;
  870.                
  871.                 for (int i = 0; i < hostname.Length; i++) {
  872.                     if (hostname[i] == '.') {
  873.                         dotCount++;
  874.                     }
  875.                     else if (hostname[i] == '*') {
  876.                         ++anyCount;
  877.                     }
  878.                     else if (!Char.IsDigit(hostname[i])) {
  879.                         // Not a digit?
  880.                         return false;
  881.                         // Reject wildcard
  882.                     }
  883.                 }
  884.                 return (dotCount == 3) && (anyCount > 0);
  885.             }
  886.         }
  887.        
  888.         internal bool MatchAddress(EndpointPermission e)
  889.         {
  890.            
  891.             // For Asp.Net config we made it valid empty string in a hostname,
  892.             // but it will match to nothing.
  893.             if (this.Hostname.Length == 0 || e.Hostname.Length == 0) {
  894.                 return false;
  895.             }
  896.            
  897.             //
  898.             // This is a fix for INADDR_ANY in Bind()
  899.             // if this.Hostname == "0.0.0.0" then it matches only to e.Hostname="*.*.*.*"
  900.             //
  901.             // The reason is to not pass "0.0.0.0" into Resolve()
  902.             if (this.Hostname.Equals("0.0.0.0")) {
  903.                 if (e.Hostname.Equals("*.*.*.*") || e.Hostname.Equals("0.0.0.0"))
  904.                     return true;
  905.                 return false;
  906.             }
  907.            
  908.             if (IsDns && e.IsDns) {
  909.                
  910.                
  911.                 return (String.Compare(hostname, e.hostname, StringComparison.OrdinalIgnoreCase) == 0);
  912.             }
  913.             Resolve();
  914.             e.Resolve();
  915.            
  916.            
  917.             if (((address == null) && !wildcard) || ((e.address == null) && !e.wildcard)) {
  918.                 return false;
  919.             }
  920.            
  921.             //
  922.             // try matching IP addresses against other wildcard address(es) or
  923.             // wildcard
  924.             //
  925.            
  926.             if (this.wildcard && !e.wildcard) {
  927.                 return false;
  928.                 // as a wildcard I cannot be subset of a host.
  929.             }
  930.             else if (e.wildcard) {
  931.                 if (this.wildcard) {
  932.                     // check against my _wildcard_
  933.                     if (MatchWildcard(e.hostname)) {
  934.                         return true;
  935.                     }
  936.                 }
  937.                 else {
  938.                     // check against my _addresses_
  939.                     for (int i = 0; i < address.Length; ++i) {
  940.                         if (e.MatchWildcard(address[i].ToString())) {
  941.                             return true;
  942.                         }
  943.                     }
  944.                 }
  945.             }
  946.             else {
  947.                 //both are _not_ wildcards
  948.                 for (int i = 0; i < address.Length; ++i) {
  949.                     for (int j = 0; j < e.address.Length; ++j) {
  950.                         if (address[i].Equals(e.address[j])) {
  951.                             return true;
  952.                         }
  953.                     }
  954.                 }
  955.             }
  956.             return false;
  957.         }
  958.        
  959.         internal bool MatchWildcard(string str)
  960.         {
  961.            
  962.             string[] wcPieces = hostname.Split(DotSeparator);
  963.             string[] strPieces = str.Split(DotSeparator);
  964.            
  965.             if ((strPieces.Length != 4) || (wcPieces.Length != 4)) {
  966.                 return false;
  967.             }
  968.             for (int i = 0; i < 4; i++) {
  969.                 if ((strPieces[i] != wcPieces[i]) && (wcPieces[i] != "*")) {
  970.                     return false;
  971.                 }
  972.             }
  973.             return true;
  974.         }
  975.        
  976.         internal void Resolve()
  977.         {
  978.            
  979.             //
  980.             // if we already resolved this name then don't do it again
  981.             //
  982.            
  983.             if (cached) {
  984.                 return;
  985.             }
  986.            
  987.             //
  988.             // IP wildcards are not resolved
  989.             //
  990.            
  991.             if (wildcard) {
  992.                 return;
  993.             }
  994.            
  995.             //
  996.             // IP addresses with wildcards are allowed in permissions
  997.             //
  998.            
  999.             if (IsValidWildcard) {
  1000.                 wildcard = true;
  1001.                 cached = true;
  1002.                 return;
  1003.             }
  1004.            
  1005.             //
  1006.             // Check if the permission was specified as numeric IP.
  1007.             //
  1008.             IPAddress ipaddr;
  1009.             if (IPAddress.TryParse(hostname, out ipaddr)) {
  1010.                 address = new IPAddress[1];
  1011.                 address[0] = ipaddr;
  1012.                 cached = true;
  1013.                 return;
  1014.             }
  1015.            
  1016.             //
  1017.             // Not numeric: use GetHostByName to determine addresses
  1018.             //
  1019.             try {
  1020.                 bool timedOut;
  1021.                 IPHostEntry ipHostEntry = Dns.InternalResolveFast(hostname, Timeout.Infinite, out timedOut);
  1022.                 if (ipHostEntry != null) {
  1023.                     address = ipHostEntry.AddressList;
  1024.                 }
  1025.                
  1026.                 // NB: It never caches DNS responses
  1027.                 //
  1028.                
  1029.             }
  1030.             catch (SecurityException) {
  1031.                 throw;
  1032.             }
  1033.             catch {
  1034.                 // ignore second exception
  1035.             }
  1036.         }
  1037.        
  1038.         internal bool SubsetMatch(EndpointPermission e)
  1039.         {
  1040.             return ((transport == e.transport) || (e.transport == TransportType.All)) && ((port == e.port) || (e.port == SocketPermission.AllPorts) || port == SocketPermission.AnyPort) && MatchAddress(e);
  1041.         }
  1042.        
  1043.         public override string ToString()
  1044.         {
  1045.             return hostname + encSeperator + port + encSeperator + ((int)transport).ToString(NumberFormatInfo.InvariantInfo);
  1046.         }
  1047.        
  1048.         internal EndpointPermission Intersect(EndpointPermission E)
  1049.         {
  1050.            
  1051.             string commonName = null;
  1052.             TransportType commonTransport;
  1053.             int commonPort;
  1054.            
  1055.             //
  1056.             // Look at the transport
  1057.             //
  1058.            
  1059.             if (transport == E.transport) {
  1060.                 // same transport
  1061.                 commonTransport = transport;
  1062.             }
  1063.             // NO: check if one of the permissions authorize all transports
  1064.             else if (transport == TransportType.All) {
  1065.                 commonTransport = E.transport;
  1066.             }
  1067.             else if (E.transport == TransportType.All) {
  1068.                 commonTransport = transport;
  1069.             }
  1070.             else {
  1071.                 // transport dont match-- intersection is empty
  1072.                 return null;
  1073.             }
  1074.            
  1075.             //
  1076.             // Determine common port
  1077.             //
  1078.            
  1079.             if (port == E.port) {
  1080.                 commonPort = port;
  1081.             }
  1082.             else if (port == SocketPermission.AllPorts) {
  1083.                 commonPort = E.port;
  1084.             }
  1085.             else if (E.port == SocketPermission.AllPorts) {
  1086.                 commonPort = port;
  1087.             }
  1088.             else {
  1089.                 return null;
  1090.             }
  1091.            
  1092.             //Work out common hostname part
  1093.             //
  1094.             // This is a fix for INADDR_ANY in Bind()
  1095.             // if this.Hostname == "0.0.0.0" then it matches only to e.Hostname="*.*.*.*"
  1096.             //
  1097.             // The reason is to not pass "0.0.0.0" into Resolve()
  1098.             if (this.Hostname.Equals("0.0.0.0")) {
  1099.                 if (E.Hostname.Equals("*.*.*.*") || E.Hostname.Equals("0.0.0.0"))
  1100.                     commonName = this.Hostname;
  1101.                 else
  1102.                     //i.e. 0.0.0.0
  1103.                     return null;
  1104.             }
  1105.             else if (E.Hostname.Equals("0.0.0.0")) {
  1106.                 if (this.Hostname.Equals("*.*.*.*") || this.Hostname.Equals("0.0.0.0"))
  1107.                     commonName = E.Hostname;
  1108.                 else
  1109.                     //i.e. 0.0.0.0
  1110.                     return null;
  1111.             }
  1112.             else if (IsDns && E.IsDns) {
  1113.                 //
  1114.                 // If both are DNS names we compare names as strings
  1115.                 //
  1116.                 if (String.Compare(hostname, E.hostname, StringComparison.OrdinalIgnoreCase) != 0) {
  1117.                     return null;
  1118.                 }
  1119.                 else {
  1120.                     commonName = hostname;
  1121.                 }
  1122.             }
  1123.             else {
  1124.                 Resolve();
  1125.                 E.Resolve();
  1126.                
  1127.                 //
  1128.                
  1129.                 if (((address == null) && !wildcard) || ((E.address == null) && !E.wildcard)) {
  1130.                     return null;
  1131.                 }
  1132.                
  1133.                
  1134.                 //
  1135.                 // Find intersection of address lists
  1136.                 if (wildcard && E.wildcard) {
  1137.                     string[] wcPieces = hostname.Split(DotSeparator);
  1138.                     string[] strPieces = E.hostname.Split(DotSeparator);
  1139.                     string result = "";
  1140.                    
  1141.                     if ((strPieces.Length != 4) || (wcPieces.Length != 4)) {
  1142.                         return null;
  1143.                     }
  1144.                     for (int i = 0; i < 4; i++) {
  1145.                         if (i != 0) {
  1146.                             result += ".";
  1147.                         }
  1148.                         if (strPieces[i] == wcPieces[i]) {
  1149.                             result += strPieces[i];
  1150.                         }
  1151.                         else if (strPieces[i] == "*") {
  1152.                             result += wcPieces[i];
  1153.                         }
  1154.                         else if (wcPieces[i] == "*") {
  1155.                             result += strPieces[i];
  1156.                         }
  1157.                         else
  1158.                             return null;
  1159.                     }
  1160.                     commonName = result;
  1161.                 }
  1162.                 else if (wildcard) {
  1163.                     //if ME is a wildcard
  1164.                     //
  1165.                     //
  1166.                     // Check for wildcard IP matching
  1167.                     //
  1168.                     for (int i = 0; i < E.address.Length; ++i) {
  1169.                         if (MatchWildcard(E.address[i].ToString())) {
  1170.                             commonName = E.hostname;
  1171.                             //SHE fits into my wildcard
  1172.                             break;
  1173.                         }
  1174.                     }
  1175.                 }
  1176.                 else if (E.wildcard) {
  1177.                     //if SHE is a wildcard
  1178.                     for (int i = 0; i < address.Length; ++i) {
  1179.                         if (E.MatchWildcard(address[i].ToString())) {
  1180.                             commonName = hostname;
  1181.                             //ME fit into her wildcard
  1182.                             break;
  1183.                         }
  1184.                     }
  1185.                 }
  1186.                 else {
  1187.                     //
  1188.                     // Not wildcard: check aginst IP addresses list
  1189.                     //
  1190.                    
  1191.                     if (address == E.address) {
  1192.                         // they both are NOT null (already checked)
  1193.                         commonName = hostname;
  1194.                     }
  1195.                    
  1196.                     //
  1197.                     // Search the IP addresses for match
  1198.                     //
  1199.                     for (int i = 0; commonName == null && i < address.Length; i++) {
  1200.                         for (int k = 0; k < E.address.Length; k++) {
  1201.                             if (address[i].Equals(E.address[k])) {
  1202.                                 commonName = hostname;
  1203.                                 break;
  1204.                             }
  1205.                         }
  1206.                     }
  1207.                 }
  1208.                 if (commonName == null) {
  1209.                     return null;
  1210.                 }
  1211.             }
  1212.            
  1213.             return new EndpointPermission(commonName, commonPort, commonTransport);
  1214.         }
  1215. /*
  1216. FROM RFC 952
  1217. ------------
  1218. ASSUMPTIONS
  1219. 1  A "name" (Net, Host, Gateway, or Domain name) is a text string up
  1220.     to 24 characters drawn from the alphabet (A-Z), digits (0-9), minus sign (-), and period (.).
  1221.     Note that periods are only allowed when they serve to delimit components of "domain style names".
  1222.     (See RFC-921, "Domain Name System Implementation Schedule", for background).
  1223.     No blank or space characters are permitted as part of a name.
  1224.     No distinction is made between upper and lower case.
  1225.     The first character must be an alpha character.
  1226.     The last character must not be a minus sign or period.
  1227.     Single character names or nicknames are not allowed.
  1228.     Implementaion below is relaxed in terms of:
  1229.     - Hostname may start with a digit (as per RFC1123 )
  1230.     - Hostname may contain '_' character (historical Inet issue)
  1231.     - Hostname may be a single-character string (historical Inet issue)
  1232.     - Hostname may contain '*' as a wildcard for an EndPointPermission
  1233.     - Hostname may be empty (to support config templates)
  1234.     - Hostname may be an IPv6 string comprised of A-F, 0-9, '.', ':', and '%' chars
  1235. */       
  1236.         private enum EndPointType
  1237.         {
  1238.             Invalid,
  1239.             IPv6,
  1240.             DnsOrWildcard,
  1241.             IPv4
  1242.         }
  1243.        
  1244.         private static EndPointType CheckEndPointName(string name)
  1245.         {
  1246.             if (name == null) {
  1247.                 return EndPointType.Invalid;
  1248.             }
  1249.             bool isIPv6 = false;
  1250.             bool isDnsOrWC = false;
  1251.             bool isHexLetter = false;
  1252.             for (int i = 0; i < name.Length; ++i) {
  1253.                 char ch = name[i];
  1254.                 switch (ch) {
  1255.                     case '.':
  1256.                         //note _all_ dots name is an error
  1257.                         continue;
  1258.                     case '-':
  1259.                     case '_':
  1260.                     case '*':
  1261.                         //if _all_ chars are those we call Dns (to confirm error)
  1262.                         isDnsOrWC = true;
  1263.                         continue;
  1264.                     case ':':
  1265.                     case '%':
  1266.                         isIPv6 = true;
  1267.                         continue;
  1268.                     default:
  1269.                         break;
  1270.                 }
  1271.                
  1272.                 //Check on letters but NOT hex digits
  1273.                 if ((ch > 'f' && ch <= 'z') || (ch > 'F' && ch <= 'Z')) {
  1274.                     isDnsOrWC = true;
  1275.                     continue;
  1276.                 }
  1277.                 //Check on HEX letters
  1278.                 if ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
  1279.                     isHexLetter = true;
  1280.                     continue;
  1281.                 }
  1282.                 //Here only digits left (others are invalid)
  1283.                 if (!(ch >= '0' && ch <= '9'))
  1284.                     return EndPointType.Invalid;
  1285.             }
  1286.            
  1287.             // The logic is (solely for the purpose of SocketPermssion class)
  1288.             // isIPv6 && isDnsOrWC = EndPointType.Invalid
  1289.             // isIPv6 && !isDnsOrWC = EndPointType.IPv6
  1290.             // !isIPv6 && isDnsOrWC = EndPointType.DnsOrWildcard
  1291.             // !isIPv6 && !isDnsOrWC && isHexLetter = EndPointType.DnsOrWildcard;
  1292.             // else = EndPointType.IPv4
  1293.             return isIPv6 ? (isDnsOrWC ? EndPointType.Invalid : EndPointType.IPv6) : (isDnsOrWC ? EndPointType.DnsOrWildcard : isHexLetter ? EndPointType.DnsOrWildcard : EndPointType.IPv4);
  1294.         }
  1295.        
  1296.        
  1297.     }
  1298.     // class EndpointPermission
  1299.    
  1300. }
  1301. // namespace System.Net

Developer Fusion