home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / net / SocketPermission.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  28.2 KB  |  1,069 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)SocketPermission.java    1.22 98/12/01
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.net;
  16.  
  17. import java.util.Enumeration;
  18. import java.util.Vector;
  19. import java.util.Hashtable;
  20. import java.util.StringTokenizer;
  21. import java.net.InetAddress;
  22. import java.security.Permission;
  23. import java.security.PermissionCollection;
  24. import java.io.Serializable;
  25. import java.io.IOException;
  26.  
  27. /**
  28.  * This class represents access to a network via sockets.
  29.  * A SocketPermission consists of a 
  30.  * host specification and a set of "actions" specifying ways to
  31.  * connect to that host. The host is specified as
  32.  * <pre>
  33.  *    host = (hostname | IPaddress)[:portrange]
  34.  *    portrange = portnumber | -portnumber | portnumber-[portnumber]
  35.  * </pre>
  36.  * The host is expressed as a DNS name, as a numerical IP address,
  37.  * or as "localhost" (for the local machine).
  38.  * The wildcard "*" may be included once in a DNS name host
  39.  * specification. If it is included, it must be in the leftmost 
  40.  * position, as in "*.sun.com".
  41.  * <p>
  42.  * The port or portrange is optional. A port specification of the 
  43.  * form "N-", where <i>N</i> is a port number, signifies all ports
  44.  * numbered <i>N</i> and above, while a specification of the
  45.  * form "-N" indicates all ports numbered <i>N</i> and below.
  46.  * <p>
  47.  * The possible ways to connect to the host are 
  48.  * <pre>
  49.  * accept
  50.  * connect
  51.  * listen
  52.  * resolve
  53.  * </pre>
  54.  * The "listen" action is only meaningful when used with "localhost". 
  55.  * The "resolve" (resolve host/ip name service lookups) action is implied
  56.  * when any of the other actions are present.
  57.  * 
  58.  * <p>As an example of the creation and meaning of SocketPermissions,  
  59.  * note that if the following permission:
  60.  * 
  61.  * <pre>
  62.  *   p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept");
  63.  * </pre>
  64.  * 
  65.  * is granted to some code, it allows that code to connect to port 7777 on
  66.  * <code>puffin.eng.sun.com</code>, and to accept connections on that port.
  67.  * 
  68.  * <p>Similarly, if the following permission:
  69.  * 
  70.  * <pre>
  71.  *   p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept");
  72.  *   p2 = new SocketPermission("localhost:1024-", "accept,connect,listen");
  73.  * </pre>
  74.  * 
  75.  * is granted to some code, it allows that code to 
  76.  * accept connections on, connect to, or listen on any port between
  77.  * 1024 and 65535 on the local host.
  78.  *
  79.  * <p>Note: Granting code permission to accept or make connections to remote
  80.  * hosts may be dangerous because malevolent code can then more easily
  81.  * transfer and share confidential data among parties who may not
  82.  * otherwise have access to the data.
  83.  * 
  84.  * @see Permissions
  85.  * @see SocketPermissions
  86.  *
  87.  * @version 1.22 99/03/26
  88.  *
  89.  * @author Marianne Mueller
  90.  * @author Roland Schemers 
  91.  */
  92.  
  93. public final class SocketPermission extends Permission 
  94. implements java.io.Serializable 
  95. {
  96.  
  97.     /**
  98.      * Connect to host:port
  99.      */
  100.     private final static int CONNECT    = 0x1;
  101.  
  102.     /**
  103.      * Listen on host:port
  104.      */
  105.     private final static int LISTEN    = 0x2;
  106.  
  107.     /**
  108.      * Accept a connection from host:port
  109.      */
  110.     private final static int ACCEPT    = 0x4;
  111.  
  112.     /**
  113.      * Resolve DNS queries
  114.      */
  115.     private final static int RESOLVE    = 0x8;
  116.  
  117.     /**
  118.      * No actions
  119.      */
  120.     private final static int NONE        = 0x0;
  121.  
  122.     /**
  123.      * All actions
  124.      */ 
  125.     private final static int ALL    = CONNECT|LISTEN|ACCEPT|RESOLVE;
  126.  
  127.     // various port constants
  128.     private static final int PORT_MIN = 0;
  129.     private static final int PORT_MAX = 65535;
  130.     private static final int PRIV_PORT_MAX = 1023;
  131.  
  132.     // the actions mask
  133.     private transient int mask;
  134.  
  135.     /**
  136.      * the actions string. 
  137.      *
  138.      * @serial
  139.      */
  140.  
  141.     private String actions; // Left null as long as possible, then
  142.                             // created and re-used in the getAction function.
  143.  
  144.     // the canonical name of the host
  145.     // in the case of "*.foo.com", cname is ".foo.com".
  146.  
  147.     private transient String cname;
  148.  
  149.     // all the IP addresses of the host 
  150.     private transient InetAddress[] addresses;
  151.  
  152.     // true if the hostname is a wildcard (e.g. "*.sun.com")
  153.     private transient boolean wildcard;
  154.  
  155.     // true if we were initialized with a single numeric IP address
  156.     private transient boolean init_with_ip;
  157.  
  158.     // true if this SocketPermission represents an invalid/unknown host
  159.     // used for implies when the delayed lookup has already failed
  160.     private transient boolean invalid;
  161.  
  162.     // port range on host
  163.     private transient int[] portrange; 
  164.  
  165.     // true if the trustProxy system property is set
  166.     private static boolean trustProxy;
  167.  
  168.     static {
  169.     Boolean tmp = (Boolean) java.security.AccessController.doPrivileged(
  170.                 new sun.security.action.GetBooleanAction("trustProxy"));
  171.     trustProxy = tmp.booleanValue();
  172.     }
  173.  
  174.     /**
  175.      * Creates a new SocketPermission object with the specified actions.
  176.      * The host is expressed as a DNS name, or as a numerical IP address.
  177.      * Optionally, a port or a portrange may be supplied (separated
  178.      * from the DNS name or IP address by a colon).
  179.      * <p>
  180.      * To specify the local machine, use "localhost" as the <i>host</i>.
  181.      * Also note: An empty <i>host</i> String ("") is equivalent to "localhost".
  182.      * <p>
  183.      * The <i>actions</i> parameter contains a comma-separated list of the
  184.      * actions granted for the specified host (and port(s)). Possible actions are
  185.      * "connect", "listen", "accept", "resolve", or 
  186.      * any combination of those. "resolve" is automatically added
  187.      * when any of the other three are specified.
  188.      * <p>
  189.      * Examples of SocketPermission instantiation are the following: 
  190.      * <pre>
  191.      *    nr = new SocketPermission("www.catalog.com", "connect");
  192.      *    nr = new SocketPermission("www.sun.com:80", "connect");
  193.      *    nr = new SocketPermission("*.sun.com", "connect");
  194.      *    nr = new SocketPermission("*.edu", "resolve");
  195.      *    nr = new SocketPermission("204.160.241.0", "connect");
  196.      *    nr = new SocketPermission("localhost:1024-65535", "listen");
  197.      *    nr = new SocketPermission("204.160.241.0:1024-65535", "connect");
  198.      * </pre>
  199.      * 
  200.      * @param host the hostname or IPaddress of the computer, optionally
  201.      * including a colon followed by a port or port range. 
  202.      * @param action the action string.
  203.      */
  204.     public SocketPermission(String host, String action) {
  205.     super(getHost(host));
  206.     init(host, getMask(action));
  207.     }
  208.  
  209.  
  210.     SocketPermission(String host, int mask) {
  211.     super(getHost(host));
  212.     init(host, mask);
  213.     }
  214.  
  215.     private static String getHost(String host)
  216.     {
  217.     if (host.equals(""))
  218.         return "localhost";
  219.     else 
  220.         return host;
  221.     }
  222.  
  223.     private boolean isDottedIP(String host) 
  224.     {
  225.     char[] h = host.toCharArray();
  226.     int n = h.length - 1;
  227.     int components = 0;
  228.  
  229.     if (n > -1 && h[0] == '.')
  230.         return false;
  231.  
  232.     while (n != -1) {
  233.         char c0, c1, c2;
  234.         c0 = h[n];
  235.         if (n < 2) {
  236.         c2 = '.';
  237.         if (n == 1) {
  238.             c1 = h[0];
  239.         } else {
  240.             c1 = '.';
  241.         }
  242.         n = -1;
  243.         } else {
  244.         c1 = h[n-1];
  245.         if (c1 == '.') {
  246.             c2 = '.';
  247.             n -= 2;
  248.         } else {
  249.             c2 = h[n-2];
  250.             if (c2 == '.') {
  251.             n -= 3;
  252.             } else {
  253.             if ((n-3) != -1) {
  254.                 if (h[n-3] != '.')
  255.                 return false;
  256.                 n -= 4;
  257.             } else
  258.                 n -= 3;
  259.             }
  260.         }
  261.         }
  262.         if (c0 < '0' || c0 > '9' ||
  263.             (c1 < '0' && c1 != '.') || c1 > '9' ||
  264.             (c2 < '0' && c2 != '.') || c2 > '2' ||
  265.             (c2 == '2' && (c1 > '5' || (c1 == '5' && c0 > '5'))))
  266.         return false;
  267.         components++;
  268.     }
  269.  
  270.     return (components == 4);
  271.     }
  272.  
  273.     private int[] parsePort(String port) 
  274.     throws Exception
  275.     {
  276.  
  277.     if (port == null || port.equals("") || port.equals("*")) {
  278.         return new int[] {PORT_MIN, PORT_MAX};
  279.     }
  280.  
  281.     int dash = port.indexOf('-');
  282.  
  283.     if (dash == -1) {
  284.         int p = Integer.parseInt(port);
  285.         return new int[] {p, p};
  286.     } else {
  287.         String low = port.substring(0, dash);
  288.         String high = port.substring(dash+1);
  289.         int l,h;
  290.  
  291.         if (low.equals("")) {
  292.         l = PORT_MIN;
  293.         } else {
  294.         l = Integer.parseInt(low);
  295.         }
  296.  
  297.         if (high.equals("")) {
  298.         h = PORT_MAX;
  299.         } else {
  300.         h = Integer.parseInt(high);
  301.         }
  302.         if (h<l) 
  303.         throw new IllegalArgumentException("invalid port range");
  304.  
  305.         return new int[] {l, h};
  306.     }
  307.     }
  308.  
  309.     /**
  310.      * Initialize the SocketPermission object. We don't do any DNS lookups
  311.      * as this point, instead we hold off until the implies method is
  312.      * called.
  313.      */
  314.     private void init(String host, int mask) {
  315.  
  316.     host = getHost(host);
  317.  
  318.     // Set the integer mask that represents the actions
  319.  
  320.     if ((mask & ALL) != mask) 
  321.         throw new IllegalArgumentException("invalid actions mask");
  322.  
  323.     // always OR in RESOLVE if we allow any of the others
  324.     this.mask = mask | RESOLVE;
  325.  
  326.     // Parse the host name.  A name has up to three components, the
  327.     // hostname, a port number, or two numbers representing a port
  328.     // range.   "www.sun.com:8080-9090" is a valid host name.  
  329.  
  330.     int sep = host.indexOf(':');
  331.  
  332.     if (sep != -1) {
  333.         String port = host.substring(sep+1);
  334.         host = host.substring(0, sep);
  335.         try {
  336.         portrange = parsePort(port);
  337.         } catch (Exception e) {
  338.         throw new 
  339.             IllegalArgumentException("invalid port range: "+port);
  340.         }
  341.     } else {
  342.         portrange = new int[] { PORT_MIN, PORT_MAX };
  343.     }
  344.         
  345.     // is this a domain wildcard specification
  346.  
  347.     if (host.startsWith("*")) {
  348.         wildcard = true;
  349.         if (host.equals("*")) {
  350.         cname = "";
  351.         } else if (host.startsWith("*.")) {
  352.         cname = host.substring(1).toLowerCase();
  353.         } else {
  354.           throw new 
  355.            IllegalArgumentException("invalid host wildcard specification");
  356.         }
  357.         return;
  358.     } else {
  359.         // see if we are being initialized with an IP address.
  360.         if (isDottedIP(host)) {
  361.         try {
  362.             addresses = 
  363.             new InetAddress[] {InetAddress.getByName(host) };
  364.             init_with_ip = true;
  365.         } catch (UnknownHostException uhe) {
  366.             // this shouldn't happen
  367.             invalid = true;
  368.         }
  369.         }
  370.     }
  371.     }
  372.  
  373.     /**
  374.      * Convert an action string to an integer actions mask. 
  375.      *
  376.      * @param action the action string
  377.      * @return the action mask
  378.      */
  379.     private static int getMask(String action) {
  380.  
  381.     int mask = NONE;
  382.  
  383.     if (action == null) {
  384.         return mask;
  385.     }
  386.  
  387.     char[] a = action.toCharArray();
  388.  
  389.     int i = a.length - 1;
  390.     if (i < 0)
  391.         return mask;
  392.  
  393.     while (i != -1) {
  394.         char c;
  395.  
  396.         // skip whitespace
  397.         while ((i!=-1) && ((c = a[i]) == ' ' ||
  398.                    c == '\r' ||
  399.                    c == '\n' ||
  400.                    c == '\f' ||
  401.                    c == '\t'))
  402.         i--;
  403.  
  404.         // check for the known strings
  405.         int matchlen;
  406.  
  407.         if (i >= 6 && (a[i-6] == 'c' || a[i-6] == 'C') &&
  408.               (a[i-5] == 'o' || a[i-5] == 'O') &&
  409.               (a[i-4] == 'n' || a[i-4] == 'N') &&
  410.               (a[i-3] == 'n' || a[i-3] == 'N') &&
  411.               (a[i-2] == 'e' || a[i-2] == 'E') &&
  412.               (a[i-1] == 'c' || a[i-1] == 'C') &&
  413.               (a[i] == 't' || a[i] == 'T'))
  414.         {
  415.         matchlen = 7;
  416.         mask |= CONNECT;
  417.  
  418.         } else if (i >= 6 && (a[i-6] == 'r' || a[i-6] == 'R') &&
  419.                  (a[i-5] == 'e' || a[i-5] == 'E') &&
  420.                  (a[i-4] == 's' || a[i-4] == 'S') &&
  421.                  (a[i-3] == 'o' || a[i-3] == 'O') &&
  422.                  (a[i-2] == 'l' || a[i-2] == 'L') &&
  423.                  (a[i-1] == 'v' || a[i-1] == 'V') &&
  424.                  (a[i] == 'e' || a[i] == 'E'))
  425.         {
  426.         matchlen = 7;
  427.         mask |= RESOLVE;
  428.  
  429.         } else if (i >= 5 && (a[i-5] == 'l' || a[i-5] == 'L') &&
  430.                  (a[i-4] == 'i' || a[i-4] == 'I') &&
  431.                  (a[i-3] == 's' || a[i-3] == 'S') &&
  432.                  (a[i-2] == 't' || a[i-2] == 'T') &&
  433.                  (a[i-1] == 'e' || a[i-1] == 'E') &&
  434.                  (a[i] == 'n' || a[i] == 'N'))
  435.         {
  436.         matchlen = 6;
  437.         mask |= LISTEN;
  438.  
  439.         } else if (i >= 5 && (a[i-5] == 'a' || a[i-5] == 'A') &&
  440.                  (a[i-4] == 'c' || a[i-4] == 'C') &&
  441.                  (a[i-3] == 'c' || a[i-3] == 'C') &&
  442.                  (a[i-2] == 'e' || a[i-2] == 'E') &&
  443.                  (a[i-1] == 'p' || a[i-1] == 'P') &&
  444.                  (a[i] == 't' || a[i] == 'T'))
  445.         {
  446.         matchlen = 6;
  447.         mask |= ACCEPT;
  448.  
  449.         } else {
  450.         // parse error
  451.         throw new IllegalArgumentException(
  452.             "invalid permission: " + action);
  453.         }
  454.  
  455.         // make sure we didn't just match the tail of a word
  456.         // like "ackbarfaccept".  Also, skip to the comma.
  457.         boolean seencomma = false;
  458.         while (i >= matchlen && !seencomma) {
  459.         switch(a[i-matchlen]) {
  460.         case ',':
  461.             seencomma = true;
  462.             /*FALLTHROUGH*/
  463.         case ' ': case '\r': case '\n':
  464.         case '\f': case '\t':
  465.             break;
  466.         default:
  467.             throw new IllegalArgumentException(
  468.                 "invalid permission: " + action);
  469.         }
  470.         i--;
  471.         }
  472.  
  473.         // point i at the location of the comma minus one (or -1).
  474.         i -= matchlen;
  475.     }
  476.  
  477.     return mask;
  478.     }
  479.  
  480.     /**
  481.      * attempt to get the fully qualified domain name
  482.      *
  483.      */
  484.     void getCanonName()
  485.     throws UnknownHostException
  486.     {
  487.     if (cname != null || invalid) return;
  488.  
  489.     // attempt to get the canonical name
  490.  
  491.     try { 
  492.         // first get the IP addresses if we don't have them yet
  493.         // this is because we need the IP address to then get 
  494.         // FQDN.
  495.         if (addresses == null) {
  496.         getIP();
  497.         }
  498.  
  499.         // we have to do this check, otherwise we might not
  500.         // get the fully qualified domain name
  501.         if (init_with_ip) {
  502.         cname = addresses[0].getHostName(false).toLowerCase();
  503.         } else {
  504.          cname = InetAddress.getByName(addresses[0].getHostAddress()).
  505.                                               getHostName(false).toLowerCase();
  506.         }
  507.     } catch (UnknownHostException uhe) {
  508.         invalid = true;
  509.         throw uhe;
  510.     }
  511.     }
  512.  
  513.     /**
  514.      * get IP addresses. Sets invalid to true if we can't get them.
  515.      *
  516.      */
  517.     void getIP()
  518.     throws UnknownHostException 
  519.     {
  520.     if (addresses != null || wildcard || invalid) return;
  521.  
  522.     try { 
  523.         // now get all the IP addresses
  524.         String host;
  525.         int i = getName().indexOf(":");
  526.         if (i == -1)
  527.         host = getName();
  528.         else {
  529.         host = getName().substring(0,i);
  530.         }
  531.  
  532.         addresses = 
  533.         new InetAddress[] {InetAddress.getAllByName0(host, false)[0]};
  534.  
  535.     } catch (UnknownHostException uhe) {
  536.         invalid = true;
  537.         throw uhe;
  538.     }
  539.     }
  540.  
  541.     /**
  542.      * Checks if this socket permission object "implies" the 
  543.      * specified permission.
  544.      * <P>
  545.      * More specifically, this method first ensures that all of the following
  546.      * are true (and returns false if any of them are not):<p>
  547.      * <ul>
  548.      * <li> <i>p</i> is an instanceof SocketPermission,<p>
  549.      * <li> <i>p</i>'s actions are a proper subset of this
  550.      * object's actions, and<p>
  551.      * <li> <i>p</i>'s port range is included in this port range.<p>
  552.      * </ul>
  553.      * 
  554.      * Then <code>implies</code> checks each of the following, in order,
  555.      * and for each returns true if the stated condition is true:<p>
  556.      * <ul>
  557.      * <li> If this object was initialized with a single IP address and one of <i>p</i>'s 
  558.      * IP addresses is equal to this object's IP address.<p>
  559.      * <li>If this object is a wildcard domain (such as *.sun.com), and
  560.      * <i>p</i>'s canonical name (the name without any preceding *)
  561.      * ends with this object's canonical host name. For example, *.sun.com
  562.      * implies *.eng.sun.com..<p>
  563.      * <li>If this object was not initialized with a single IP address, and one of this
  564.      * object's IP addresses equals one of <i>p</i>'s IP addresses.<p>
  565.      * <li>If this canonical name equals <i>p</i>'s canonical name.<p>
  566.      * </ul>
  567.      * 
  568.      * If none of the above are true, <code>implies</code> returns false.
  569.      * @param p the permission to check against.
  570.      *
  571.      * @return true if the specified permission is implied by this object,
  572.      * false if not.  
  573.      */
  574.  
  575.     public boolean implies(Permission p) {
  576.     int i,j;
  577.  
  578.     if (!(p instanceof SocketPermission))
  579.         return false;
  580.  
  581.     SocketPermission that = (SocketPermission) p;
  582.  
  583.     return ((this.mask & that.mask) == that.mask) && 
  584.                                     impliesIgnoreMask(that);
  585.     }
  586.  
  587.     /**
  588.      * Checks if the incoming Permission's action are a proper subset of
  589.      * the this object's actions.
  590.      * <P>
  591.      * Check, in the following order:
  592.      * <ul>
  593.      * <li> Checks that "p" is an instanceof a SocketPermission
  594.      * <li> Checks that "p"'s actions are a proper subset of the
  595.      * current object's actions.
  596.      * <li> Checks that "p"'s port range is included in this port range
  597.      * <li> If this object was initialized with an IP address, checks that 
  598.      *      one of "p"'s IP addresses is equal to this object's IP address.
  599.      * <li> If either object is a wildcard domain (i.e., "*.sun.com"),
  600.      *      attempt to match based on the wildcard.
  601.      * <li> If this object was not initialized with an IP address, attempt
  602.      *      to find a match based on the IP addresses in both objects.
  603.      * <li> Attempt to match on the canonical hostnames of both objects.
  604.      * </ul>
  605.      * @param p the incoming permission request
  606.      *
  607.      * @return true if "permission" is a proper subset of the current object,
  608.      * false if not.  
  609.      */
  610.  
  611.     boolean impliesIgnoreMask(SocketPermission that) {
  612.     int i,j;
  613.  
  614.     if ((that.mask & RESOLVE) != that.mask) {
  615.         // check port range
  616.         if ((that.portrange[0] < this.portrange[0]) ||
  617.             (that.portrange[1] > this.portrange[1])) {
  618.             return false;
  619.         }
  620.     }
  621.  
  622.     // allow a "*" wildcard to always match anything
  623.     if (this.wildcard && this.getName().equals("*"))
  624.         return true;
  625.  
  626.     // return if either one of these NetPerm objects are invalid...
  627.     if (this.invalid || that.invalid) {
  628.         if (!trustProxy)
  629.         return false;
  630.  
  631.         // if we trust the proxy, we see if the original names/IPs passed
  632.         // in were equal.
  633.  
  634.         String thisHost = getName();
  635.         String thatHost = that.getName();
  636.  
  637.         int sep = thisHost.indexOf(':');
  638.         if (sep != -1)
  639.         thisHost = thisHost.substring(0, sep);
  640.  
  641.         sep = thatHost.indexOf(':');
  642.         if (sep != -1)
  643.         thatHost = thatHost.substring(0, sep);
  644.  
  645.         if (thisHost == null) 
  646.         return false;
  647.         else 
  648.         return thisHost.equalsIgnoreCase(thatHost);
  649.     }
  650.  
  651.  
  652.     try {
  653.         if (this.init_with_ip) { // we only check IP addresses
  654.         if (that.wildcard) 
  655.             return false;
  656.  
  657.         if (that.init_with_ip) {
  658.             return (this.addresses[0].equals(that.addresses[0]));
  659.         } else {
  660.             if (that.addresses == null) {
  661.             that.getIP();
  662.             }
  663.             for (i=0; i < that.addresses.length; i++) {
  664.             if (this.addresses[0].equals(that.addresses[i]))
  665.                 return true;
  666.             }
  667.         }
  668.         // since "this" was initialized with an IP address, we
  669.         // don't check any other cases
  670.         return false;
  671.         }
  672.  
  673.         // check and see if we have any wildcards...
  674.         if (this.wildcard || that.wildcard) {
  675.         // if they are both wildcards, return true iff
  676.         // that's cname ends with this cname (i.e., *.sun.com
  677.         // implies *.eng.sun.com)
  678.         if (this.wildcard && that.wildcard)
  679.             return (that.cname.endsWith(this.cname));
  680.  
  681.         // a non-wildcard can't imply a wildcard
  682.         if (that.wildcard)
  683.             return false;
  684.  
  685.         // this is a wildcard, lets see if that's cname ends with
  686.         // it...
  687.         if (that.cname == null) {
  688.             that.getCanonName();
  689.         }
  690.         return (that.cname.endsWith(this.cname));
  691.         }
  692.  
  693.         // comapare IP addresses
  694.         if (this.addresses == null) {
  695.         this.getIP();
  696.         }
  697.  
  698.         if (that.addresses == null) {
  699.         that.getIP();
  700.         }
  701.  
  702.         for (j = 0; j < this.addresses.length; j++) {
  703.         for (i=0; i < that.addresses.length; i++) {
  704.             if (this.addresses[j].equals(that.addresses[i]))
  705.             return true;
  706.         }
  707.         }
  708.  
  709.         // XXX: if all else fails, compare hostnames?
  710.         // Do we really want this?
  711.         if (this.cname == null) {
  712.         this.getCanonName();
  713.         }
  714.  
  715.         if (that.cname == null) {
  716.         that.getCanonName();
  717.         }
  718.  
  719.         return (this.cname.equalsIgnoreCase(that.cname));
  720.  
  721.     } catch (UnknownHostException uhe) {
  722.         // commented out, otherwise the last return is
  723.         // flagged as unreachable by the compiler.
  724.         // return false;
  725.     }
  726.  
  727.     // make sure the first thing that is done here is to return
  728.     // false. If not, uncomment the return false in the above catch.
  729.  
  730.     return false; 
  731.     }
  732.  
  733.     /**
  734.      * Checks two SocketPermission objects for equality. 
  735.      * <P>
  736.      * @param obj the object to test for equality with this object.
  737.      * 
  738.      * @return true if <i>obj</i> is a SocketPermission, and has the same hostname,
  739.      *  port range, and
  740.      *  actions as this SocketPermission object.
  741.      */
  742.     public boolean equals(Object obj) {
  743.     if (obj == this)
  744.         return true;
  745.  
  746.     if (! (obj instanceof SocketPermission))
  747.         return false;
  748.  
  749.     SocketPermission that = (SocketPermission) obj;
  750.  
  751.     //this is (overly?) complex!!!
  752.  
  753.     // check the mask first
  754.     if (this.mask != that.mask) return false;
  755.  
  756.     // now check the port range...
  757.     if ((this.portrange[0] != that.portrange[0]) ||
  758.         (this.portrange[1] != that.portrange[1])) {
  759.         return false;
  760.     }
  761.  
  762.     // short cut. This catches:
  763.     //  "crypto" equal to "crypto", or
  764.     // "1.2.3.4" equal to "1.2.3.4.", or 
  765.     //  "*.edu" equal to "*.edu", but it 
  766.     //  does not catch "crypto" equal to
  767.     // "crypto.eng.sun.com".
  768.  
  769.     if (this.getName().equalsIgnoreCase(that.getName())) {
  770.         return true;
  771.     }
  772.  
  773.     // we now attempt to get the Canonical (FQDN) name and
  774.     // compare that. If this fails, about all we can do is return
  775.     // false.
  776.  
  777.     try {
  778.         this.getCanonName();
  779.         that.getCanonName();
  780.     } catch (UnknownHostException uhe) {
  781.         return false;
  782.     }
  783.  
  784.     if (this.invalid || that.invalid) 
  785.         return false;
  786.  
  787.     if (this.cname != null) {
  788.         return this.cname.equalsIgnoreCase(that.cname);
  789.     }
  790.  
  791.     return false;
  792.     }
  793.  
  794.     /**
  795.      * Returns the hash code value for this object.
  796.      *
  797.      * @return a hash code value for this object.
  798.      */
  799.  
  800.     public int hashCode() {
  801.     /*
  802.      * If this SocketPermission was initialized with an IP address
  803.      * or a wildcard, use getName().hashCode(), otherwise use
  804.      * the hashCode() of the host name returned from 
  805.      * java.net.InetAddress.getHostName method.
  806.      */
  807.  
  808.     if (init_with_ip || wildcard) {
  809.         return this.getName().hashCode();
  810.     }
  811.  
  812.     try {
  813.         getCanonName();
  814.     } catch (UnknownHostException uhe) {        
  815.  
  816.     }
  817.  
  818.     if (invalid || cname == null)
  819.         return this.getName().hashCode();
  820.     else
  821.         return this.cname.hashCode();
  822.     }
  823.  
  824.     /**
  825.      * Return the current action mask.
  826.      *
  827.      * @return the actions mask.
  828.      */
  829.  
  830.     int getMask() {
  831.     return mask;
  832.     }
  833.  
  834.     /**
  835.      * Returns the "canonical string representation" of the actions in the
  836.      * specified mask.
  837.      * Always returns present actions in the following order: 
  838.      * connect, listen, accept, resolve.  
  839.      *
  840.      * @param mask a specific integer action mask to translate into a string
  841.      * @return the canonical string representation of the actions
  842.      */
  843.     private static String getActions(int mask)
  844.     {
  845.     StringBuffer sb = new StringBuffer();
  846.         boolean comma = false;
  847.  
  848.     if ((mask & CONNECT) == CONNECT) {
  849.         comma = true;
  850.         sb.append("connect");
  851.     }
  852.  
  853.     if ((mask & LISTEN) == LISTEN) {
  854.         if (comma) sb.append(',');
  855.             else comma = true;
  856.         sb.append("listen");
  857.     }
  858.  
  859.     if ((mask & ACCEPT) == ACCEPT) {
  860.         if (comma) sb.append(',');
  861.             else comma = true;
  862.         sb.append("accept");
  863.     }
  864.  
  865.  
  866.     if ((mask & RESOLVE) == RESOLVE) {
  867.         if (comma) sb.append(',');
  868.             else comma = true;
  869.         sb.append("resolve");
  870.     }
  871.  
  872.     return sb.toString();
  873.     }
  874.  
  875.     /**
  876.      * Returns the canonical string representation of the actions.
  877.      * Always returns present actions in the following order: 
  878.      * connect, listen, accept, resolve.  
  879.      *
  880.      * @return the canonical string representation of the actions.
  881.      */
  882.     public String getActions()
  883.     {
  884.     if (actions == null)
  885.         actions = getActions(this.mask);
  886.  
  887.     return actions;
  888.     }
  889.  
  890.     /**
  891.      * Returns a new PermissionCollection object for storing SocketPermission 
  892.      * objects.
  893.      * <p>
  894.      * SocketPermission objects must be stored in a manner that allows them 
  895.      * to be inserted into the collection in any order, but that also enables the 
  896.      * PermissionCollection <code>implies</code>
  897.      * method to be implemented in an efficient (and consistent) manner.
  898.      *
  899.      * @return a new PermissionCollection object suitable for storing SocketPermissions.
  900.      */
  901.  
  902.     public PermissionCollection newPermissionCollection() {
  903.     return new SocketPermissionCollection();
  904.     }
  905.  
  906.     /**
  907.      * WriteObject is called to save the state of the SocketPermission 
  908.      * to a stream. The actions are serialized, and the superclass
  909.      * takes care of the name.
  910.      */
  911.     private synchronized void writeObject(java.io.ObjectOutputStream s)
  912.         throws IOException
  913.     {
  914.     // Write out the actions. The superclass takes care of the name
  915.     // call getActions to make sure actions field is initialized
  916.     if (actions == null)
  917.         getActions();
  918.     s.defaultWriteObject();
  919.     }
  920.  
  921.     /**
  922.      * readObject is called to restore the state of the SocketPermission from
  923.      * a stream.
  924.      */
  925.     private synchronized void readObject(java.io.ObjectInputStream s)
  926.          throws IOException, ClassNotFoundException
  927.     {
  928.     // Read in the action, then initialize the rest
  929.     s.defaultReadObject();
  930.     init(getName(),getMask(actions));
  931.     }
  932.  
  933.     /*
  934.     public String toString() 
  935.     {
  936.     StringBuffer s = new StringBuffer(super.toString() + "\n" +
  937.         "cname = " + cname + "\n" +
  938.         "wildcard = " + wildcard + "\n" +
  939.         "invalid = " + invalid + "\n" +
  940.             "portrange = " + portrange[0] + "," + portrange[1] + "\n");
  941.     if (addresses != null) for (int i=0; i<addresses.length; i++) {
  942.         s.append( addresses[i].getHostAddress());
  943.         s.append("\n");
  944.     } else {
  945.         s.append("(no addresses)\n");
  946.     }
  947.  
  948.     return s.toString();
  949.     }
  950.  
  951.     public static void main(String args[]) throws Exception {
  952.     SocketPermission this_ = new SocketPermission(args[0], "connect");
  953.     SocketPermission that_ = new SocketPermission(args[1], "connect");
  954.     System.out.println("-----\n");
  955.     System.out.println("this.implies(that) = " + this_.implies(that_));
  956.     System.out.println("-----\n");
  957.     System.out.println("this = "+this_);
  958.     System.out.println("-----\n");
  959.     System.out.println("that = "+that_);
  960.     System.out.println("-----\n");
  961.  
  962.     SocketPermissionCollection nps = new SocketPermissionCollection();
  963.     nps.add(this_);
  964.     nps.add(new SocketPermission("www-leland.stanford.edu","connect"));
  965.     nps.add(new SocketPermission("www-sun.com","connect"));
  966.     System.out.println("nps.implies(that) = " + nps.implies(that_));
  967.     System.out.println("-----\n");
  968.     }
  969.     */
  970. }
  971.  
  972. /**
  973.  
  974. if (init'd with IP, key is IP as string)
  975. if wildcard, its the wild card
  976. else its the cname?
  977.  
  978.  *
  979.  * @see java.security.Permission
  980.  * @see java.security.Permissions
  981.  * @see java.security.PermissionCollection
  982.  *
  983.  * @version 1.22 99/03/26
  984.  *
  985.  * @author Roland Schemers
  986.  */
  987.  
  988. final class SocketPermissionCollection extends PermissionCollection 
  989. implements Serializable
  990. {
  991.     /**
  992.      * The SocketPermissions for this set.
  993.      */
  994.  
  995.     private Vector permissions;
  996.  
  997.     /**
  998.      * Create an empty SocketPermissions object.
  999.      *
  1000.      */
  1001.  
  1002.     public SocketPermissionCollection() {
  1003.     permissions = new Vector();
  1004.     }
  1005.  
  1006.     /**
  1007.      * Adds a permission to the SocketPermissions. The key for the hash is
  1008.      * the name in the case of wildcards, or all the IP addresses.
  1009.      *
  1010.      * @param permission the Permission object to add.
  1011.      */
  1012.  
  1013.     public void add(Permission permission)
  1014.     {
  1015.     if (! (permission instanceof SocketPermission))
  1016.         throw new IllegalArgumentException("invalid permission: "+
  1017.                            permission);
  1018.     permissions.addElement(permission);
  1019.     }
  1020.  
  1021.     /**
  1022.      * Check and see if this collection of permissions implies the permissions 
  1023.      * expressed in "permission".
  1024.      *
  1025.      * @param p the Permission object to compare
  1026.      *
  1027.      * @return true if "permission" is a proper subset of a permission in 
  1028.      * the collection, false if not.
  1029.      */
  1030.  
  1031.     public boolean implies(Permission permission) 
  1032.     {
  1033.     if (! (permission instanceof SocketPermission))
  1034.            return false;
  1035.  
  1036.     SocketPermission np = (SocketPermission) permission;
  1037.  
  1038.     int desired = np.getMask();
  1039.     int effective = 0;
  1040.     int needed = desired;
  1041.  
  1042.     Enumeration e = permissions.elements();
  1043.     //System.out.println("implies "+np);
  1044.     while (e.hasMoreElements()) {
  1045.         SocketPermission x = (SocketPermission) e.nextElement();
  1046.         //System.out.println("  trying "+x);
  1047.         if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(np)) {
  1048.         effective |=  x.getMask();
  1049.         if ((effective & desired) == desired)
  1050.             return true;
  1051.         needed = (desired ^ effective);
  1052.         }
  1053.     }
  1054.     return false;
  1055.     }
  1056.  
  1057.     /**
  1058.      * Returns an enumeration of all the SocketPermission objects in the 
  1059.      * container.
  1060.      *
  1061.      * @return an enumeration of all the SocketPermission objects.
  1062.      */
  1063.  
  1064.     public Enumeration elements()
  1065.     {
  1066.     return permissions.elements();
  1067.     }
  1068. }
  1069.