home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / net / SocketPermission.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  22.8 KB  |  873 lines

  1. /*
  2.  * @(#)SocketPermission.java    1.10 98/03/18
  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]
  35.  * </pre>
  36.  * The possible ways to connect to the host are 
  37.  * <pre>
  38.  * accept
  39.  * connect
  40.  * listen
  41.  * resolve
  42.  * </pre>
  43.  * The "listen" action is only meaningful when used with "localhost". 
  44.  * The "resolve" (resolve host/ip name service lookups) action is implied
  45.  * when any of the other actions are present.
  46.  * 
  47.  * <p>As an example of the creation and meaning of SocketPermissions, if the 
  48.  * following permissions are created for classes
  49.  * signed by mrm:
  50.  * 
  51.  * <pre>
  52.  *   p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept");
  53.  *   p2 = new SocketPermission("localhost:1024-", "accept,connect,listen");
  54.  * </pre>
  55.  * 
  56.  * then classes signedBy mrm can connect to port 7777 on
  57.  * <code>puffin.eng.sun.com</code>, or accept connections on that port.
  58.  * Classes signedBy mrm may also listen on any port between 1024 and
  59.  * 65535, as well as port 0.
  60.  *
  61.  * @see Permissions
  62.  * @see SocketPermissions
  63.  *
  64.  * @version 1.10 98/03/18
  65.  *
  66.  * @author Marianne Mueller
  67.  * @author Roland Schemers 
  68.  */
  69.  
  70. public final class SocketPermission extends Permission 
  71. implements java.io.Serializable 
  72. {
  73.  
  74.     /** use serialVersionUID from JDK 1.2 for interoperability */
  75.     private static final long serialVersionUID = -323680778045894697L;
  76.  
  77.     /**
  78.      * Connect to host:port
  79.      */
  80.     private final static int CONNECT    = 0x1;
  81.  
  82.     /**
  83.      * Listen on host:port
  84.      */
  85.     private final static int LISTEN    = 0x2;
  86.  
  87.     /**
  88.      * Accept a connection from host:port
  89.      */
  90.     private final static int ACCEPT    = 0x4;
  91.  
  92.     /**
  93.      * Resolve DNS queries
  94.      */
  95.     private final static int RESOLVE    = 0x8;
  96.  
  97.     /**
  98.      * No actions
  99.      */
  100.     private final static int NONE        = 0x0;
  101.  
  102.     /**
  103.      * All actions
  104.      */ 
  105.     private final static int ALL    = CONNECT|LISTEN|ACCEPT|RESOLVE;
  106.  
  107.     // various port constants
  108.     private static final int PORT_MIN = 0;
  109.     private static final int PORT_MAX = 65535;
  110.     private static final int PRIV_PORT_MAX = 1023;
  111.  
  112.     // the actions mask
  113.     private int mask;
  114.  
  115.     // the actions string. Left null as long as possible, then
  116.     // created and re-used in the getAction function.
  117.     private String actions;
  118.  
  119.     // the canonical name of the host
  120.     // in the case of "*.foo.com", cname is ".foo.com".
  121.  
  122.     private String cname;
  123.  
  124.     // all the IP addresses of the host 
  125.     private InetAddress[] addresses;
  126.  
  127.     // true if the hostname is a wildcard (e.g. "*.sun.com")
  128.     private boolean wildcard;
  129.  
  130.     // true if we were initialized with a single numeric IP address
  131.     private boolean init_with_ip;
  132.  
  133.     // true if this SocketPermission represents an invalid/unknown host
  134.     // used for implies when the delayed lookup has already failed
  135.     private boolean invalid;
  136.  
  137.     // port range on host
  138.     private int[] portrange; 
  139.  
  140.     /**
  141.      * Creates a new SocketPermission object with the specified actions.
  142.      * The host is expressed as a DNS name, or as a numerical IP address.
  143.      * Optionally, a port or a portrange may be supplied (separated
  144.      * from the DNS name or IP address by a colon).
  145.      * <p>
  146.      * The <i>actions</i> parameter contains a comma-separated list of the
  147.      * actions granted for the specified host (and port(s)). Possible actions are
  148.      * "connect", "listen", "accept", "resolve", or 
  149.      * any combination of those. "resolve" is automatically added
  150.      * when any of the other three are specified.
  151.      * <p>
  152.      * Examples of SocketPermission instantiation are the following: 
  153.      * <pre>
  154.      *    nr = new SocketPermission("www.catalog.com", "connect");
  155.      *    nr = new SocketPermission("www.sun.com:80", "connect");
  156.      *    nr = new SocketPermission("*.sun.com", "connect");
  157.      *    nr = new SocketPermission("*.edu", "resolve");
  158.      *    nr = new SocketPermission("204.160.241.0", "connect");
  159.      *    nr = new SocketPermission("localhost:1024-65535", "listen");
  160.      *    nr = new SocketPermission("204.160.241.0:1024-65535", "connect");
  161.      * </pre>
  162.      * 
  163.      * @param host the hostname or IPaddress of the computer, optionally
  164.      * including a colon followed by a port or port range. 
  165.      * @param action the action string.
  166.      */
  167.     public SocketPermission(String host, String action) {
  168.     super(host);
  169.     init(host, getMask(action));
  170.     }
  171.  
  172.  
  173.     SocketPermission(String host, int mask) {
  174.     super(host);
  175.     init(host, mask);
  176.     }
  177.  
  178.     private boolean isDottedIP(String host) 
  179.     {
  180.     int n = 0;
  181.  
  182.     for(int i = 0; i < host.length(); i++) {
  183.  
  184.         char c = host.charAt(i);
  185.         if (!Character.isDigit(c)) { // !digit
  186.             return false;
  187.         }
  188.         int b = 0;
  189.         while(c != '.') {
  190.             if (!Character.isDigit(c)) {
  191.             return false;
  192.             }
  193.             b = b*10 + c - '0';
  194.             if (++i >= host.length()) {
  195.             break;
  196.             }
  197.             c = host.charAt(i);
  198.         } 
  199.         if (b > 0xFF) { /* bogus - bigger than a byte */
  200.             return false;
  201.         }
  202.         n++;
  203.     }
  204.  
  205.     if (n != 4) {
  206.         return false;
  207.     } else {
  208.         return true;
  209.     }
  210.     }
  211.  
  212.     private int[] parsePort(String port) 
  213.     throws Exception
  214.     {
  215.  
  216.     if (port == null || port.equals("") || port.equals("*")) {
  217.         return new int[] {PORT_MIN, PORT_MAX};
  218.     }
  219.  
  220.     int dash = port.indexOf('-');
  221.  
  222.     if (dash == -1) {
  223.         int p = Integer.parseInt(port);
  224.         return new int[] {p, p};
  225.     } else {
  226.         String low = port.substring(0, dash);
  227.         String high = port.substring(dash+1);
  228.         int l,h;
  229.  
  230.         if (low.equals("")) {
  231.         l = PORT_MIN;
  232.         } else {
  233.         l = Integer.parseInt(low);
  234.         }
  235.  
  236.         if (high.equals("")) {
  237.         h = PORT_MAX;
  238.         } else {
  239.         h = Integer.parseInt(high);
  240.         }
  241.         if (h<l) 
  242.         throw new IllegalArgumentException("invalid port range");
  243.  
  244.         return new int[] {l, h};
  245.     }
  246.     }
  247.  
  248.     /**
  249.      * Initialize the SocketPermission object. We don't do any DNS lookups
  250.      * as this point, instead we hold off until the implies method is
  251.      * called.
  252.      */
  253.     private void init(String host, int mask) {
  254.  
  255.     // Set the integer mask that represents the actions
  256.  
  257.     if ((mask & ALL) != mask) 
  258.         throw new IllegalArgumentException("invalid actions mask");
  259.  
  260.     // always OR in RESOLVE if we allow any of the others
  261.     this.mask = mask | RESOLVE;
  262.  
  263.     // Parse the host name.  A name has up to three components, the
  264.     // hostname, a port number, or two numbers representing a port
  265.     // range.   "www.sun.com:8080-9090" is a valid host name.  
  266.  
  267.     int sep = host.indexOf(':');
  268.  
  269.     if (sep != -1) {
  270.         String port = host.substring(sep+1);
  271.         host = host.substring(0, sep);
  272.         try {
  273.         portrange = parsePort(port);
  274.         } catch (Exception e) {
  275.         throw new 
  276.             IllegalArgumentException("invalid port range: "+port);
  277.         }
  278.     } else {
  279.         portrange = new int[] { PORT_MIN, PORT_MAX };
  280.     }
  281.         
  282.     // is this a domain wildcard specification
  283.  
  284.     if (host.startsWith("*")) {
  285.         wildcard = true;
  286.         if (host.equals("*")) {
  287.         cname = "";
  288.         } else if (host.startsWith("*.")) {
  289.         cname = host.substring(1).toLowerCase();
  290.         } else {
  291.           throw new 
  292.            IllegalArgumentException("invalid host wildcard specification");
  293.         }
  294.         return;
  295.     } else {
  296.         // see if we are being initialized with an IP address.
  297.         if (isDottedIP(host)) {
  298.         try {
  299.             addresses = 
  300.             new InetAddress[] {InetAddress.getByName(host) };
  301.             init_with_ip = true;
  302.         } catch (UnknownHostException uhe) {
  303.             // this shouldn't happen
  304.             invalid = true;
  305.         }
  306.         }
  307.     }
  308.     }
  309.  
  310.     /**
  311.      * Convert an action string to an integer actions mask. 
  312.      *
  313.      * @param action the action string
  314.      * @return the action mask
  315.      */
  316.     private static int getMask(String action) {
  317.  
  318.     int mask = NONE;
  319.  
  320.     if (action == null) {
  321.         return mask;
  322.     }
  323.  
  324.     action = action.toLowerCase();
  325.     StringTokenizer st = new StringTokenizer(action, ",");
  326.     while (st.hasMoreTokens()) {
  327.         String token = st.nextToken().trim();
  328.         if (token.equals("connect"))
  329.         mask |= CONNECT;
  330.         else if (token.equals("listen"))
  331.         mask |= LISTEN;
  332.         else if (token.equals("accept"))
  333.         mask |= ACCEPT;
  334.         else if (token.equals("resolve"))
  335.         mask |= RESOLVE;
  336.         else
  337.         throw new 
  338.           IllegalArgumentException("invalid net permission: "+token);
  339.     }
  340.     return mask;
  341.     }
  342.  
  343.  
  344.     /**
  345.      * attempt to get the fully qualified domain name
  346.      *
  347.      */
  348.     void getCanonName()
  349.     throws UnknownHostException
  350.     {
  351.     if (cname != null || invalid) return;
  352.  
  353.     // attempt to get the canonical name
  354.  
  355.     try { 
  356.         // first get the IP addresses if we don't have them yet
  357.         // this is because we need the IP address to then get 
  358.         // FQDN.
  359.         if (addresses == null) {
  360.         getIP();
  361.         }
  362.  
  363.         // we have to do this check, otherwise we might not
  364.         // get the fully qualified domain name
  365.         if (init_with_ip) {
  366.         cname = addresses[0].getHostName(false).toLowerCase();
  367.         } else {
  368.          cname = InetAddress.getByName(addresses[0].getHostAddress()).
  369.                                               getHostName(false).toLowerCase();
  370.         }
  371.     } catch (UnknownHostException uhe) {
  372.         invalid = true;
  373.         throw uhe;
  374.     }
  375.     }
  376.  
  377.     /**
  378.      * get IP addresses. Sets invalid to true if we can't get them.
  379.      *
  380.      */
  381.     void getIP()
  382.     throws UnknownHostException 
  383.     {
  384.     if (addresses != null || wildcard || invalid) return;
  385.  
  386.     try { 
  387.         // now get all the IP addresses
  388.         String host;
  389.         int i = getName().indexOf(":");
  390.         if (i == -1)
  391.         host = getName();
  392.         else {
  393.         host = getName().substring(0,i);
  394.         }
  395.  
  396.         addresses = 
  397.         InetAddress.getAllByName0(host, false);
  398.  
  399.     } catch (UnknownHostException uhe) {
  400.         invalid = true;
  401.         throw uhe;
  402.     }
  403.     }
  404.  
  405.     /**
  406.      * Checks if this socket permission object "implies" the 
  407.      * specified permission.
  408.      * <P>
  409.      * More specifically, this method first ensures that all of the following
  410.      * are true (and returns false if any of them are not):<p>
  411.      * <ul>
  412.      * <li> <i>p</i> is an instanceof SocketPermission,<p>
  413.      * <li> <i>p</i>'s actions are a proper subset of this
  414.      * object's actions, and<p>
  415.      * <li> <i>p</i>'s port range is included in this port range.<p>
  416.      * </ul>
  417.      * 
  418.      * Then <code>implies</code> checks each of the following, in order,
  419.      * and for each returns true if the stated condition is true:<p>
  420.      * <ul>
  421.      * <li> If this object was initialized with a single IP address and one of <i>p</i>'s 
  422.      * IP addresses is equal to this object's IP address.<p>
  423.      * <li>If this object is a wildcard domain (such as *.sun.com), and
  424.      * <i>p</i>'s canonical name (the name without any preceding *)
  425.      * ends with this object's canonical host name. For example, *.sun.com
  426.      * implies *.eng.sun.com..<p>
  427.      * <li>If this object was not initialized with a single IP address, and one of this
  428.      * object's IP addresses equals one of <i>p</i>'s IP addresses.<p>
  429.      * <li>If this canonical name equals <i>p</i>'s canonical name.<p>
  430.      * </ul>
  431.      * 
  432.      * If none of the above are true, <code>implies</code> returns false.
  433.      * @param p the permission to check against.
  434.      *
  435.      * @return true if the specified permission is implied by this object,
  436.      * false if not.  
  437.      */
  438.  
  439.     public boolean implies(Permission p) {
  440.     int i,j;
  441.  
  442.     if (!(p instanceof SocketPermission))
  443.         return false;
  444.  
  445.     SocketPermission that = (SocketPermission) p;
  446.  
  447.     return ((this.mask & that.mask) == that.mask) && 
  448.                                     impliesIgnoreMask(that);
  449.     }
  450.  
  451.     /**
  452.      * Checks if the incoming Permission's action are a proper subset of
  453.      * the this object's actions.
  454.      * <P>
  455.      * Check, in the following order:
  456.      * <ul>
  457.      * <li> Checks that "p" is an instanceof a SocketPermission
  458.      * <li> Checks that "p"'s actions are a proper subset of the
  459.      * current object's actions.
  460.      * <li> Checks that "p"'s port range is included in this port range
  461.      * <li> If this object was initialized with an IP address, checks that 
  462.      *      one of "p"'s IP addresses is equal to this object's IP address.
  463.      * <li> If either object is a wildcard domain (i.e., "*.sun.com"),
  464.      *      attempt to match based on the wildcard.
  465.      * <li> If this object was not initialized with an IP address, attempt
  466.      *      to find a match based on the IP addresses in both objects.
  467.      * <li> Attempt to match on the canonical hostnames of both objects.
  468.      * </ul>
  469.      * @param p the incoming permission request
  470.      *
  471.      * @return true if "permission" is a proper subset of the current object,
  472.      * false if not.  
  473.      */
  474.  
  475.     boolean impliesIgnoreMask(SocketPermission that) {
  476.     int i,j;
  477.  
  478.     if ((that.mask & RESOLVE) != that.mask) {
  479.         // check port range
  480.         if ((that.portrange[0] < this.portrange[0]) ||
  481.             (that.portrange[1] > this.portrange[1])) {
  482.             return false;
  483.         }
  484.     }
  485.  
  486.     // allow a "*" wildcard to always match anything
  487.     if (this.wildcard && this.getName().equals("*"))
  488.         return true;
  489.  
  490.     // return if either one of these NetPerm objects are invalid...
  491.     if (this.invalid || that.invalid)
  492.         return false;
  493.  
  494.  
  495.     try {
  496.         if (this.init_with_ip) { // we only check IP addresses
  497.         if (that.wildcard) 
  498.             return false;
  499.  
  500.         if (that.init_with_ip) {
  501.             return (this.addresses[0].equals(that.addresses[0]));
  502.         } else {
  503.             if (that.addresses == null) {
  504.             that.getIP();
  505.             }
  506.             for (i=0; i < that.addresses.length; i++) {
  507.             if (this.addresses[0].equals(that.addresses[i]))
  508.                 return true;
  509.             }
  510.         }
  511.         // since "this" was initialized with an IP address, we
  512.         // don't check any other cases
  513.         return false;
  514.         }
  515.  
  516.         // check and see if we have any wildcards...
  517.         if (this.wildcard || that.wildcard) {
  518.         // if they are both wildcards, return true iff
  519.         // that's cname ends with this cname (i.e., *.sun.com
  520.         // implies *.eng.sun.com)
  521.         if (this.wildcard && that.wildcard)
  522.             return (that.cname.endsWith(this.cname));
  523.  
  524.         // a non-wildcard can't imply a wildcard
  525.         if (that.wildcard)
  526.             return false;
  527.  
  528.         // this is a wildcard, lets see if that's cname ends with
  529.         // it...
  530.         if (that.cname == null) {
  531.             that.getCanonName();
  532.         }
  533.         return (that.cname.endsWith(this.cname));
  534.         }
  535.  
  536.         // comapare IP addresses
  537.         if (this.addresses == null) {
  538.         this.getIP();
  539.         }
  540.  
  541.         if (that.addresses == null) {
  542.         that.getIP();
  543.         }
  544.  
  545.         for (j = 0; j < this.addresses.length; j++) {
  546.         for (i=0; i < that.addresses.length; i++) {
  547.             if (this.addresses[j].equals(that.addresses[i]))
  548.             return true;
  549.         }
  550.         }
  551.  
  552.         // XXX: if all else fails, compare hostnames?
  553.         // Do we really want this?
  554.         if (this.cname == null) {
  555.         this.getCanonName();
  556.         }
  557.  
  558.         if (that.cname == null) {
  559.         that.getCanonName();
  560.         }
  561.  
  562.         return (this.cname.equals(that.cname));
  563.  
  564.     } catch (UnknownHostException uhe) {
  565.         // commented out, otherwise the last return is
  566.         // flagged as unreachable by the compiler.
  567.         // return false;
  568.     }
  569.  
  570.     // make sure the first thing that is done here is to return
  571.     // false. If not, uncomment the return false in the above catch.
  572.  
  573.     return false; 
  574.     }
  575.  
  576.     /**
  577.      * Checks two SocketPermission objects for equality. 
  578.      * <P>
  579.      * @param obj the object to test for equality with this object.
  580.      * 
  581.      * @return true if <i>obj</i> is a SocketPermission, and has the same hostname and
  582.      *  actions as this SocketPermission object.
  583.      */
  584.     public boolean equals(Object obj) {
  585.     if (obj == this)
  586.         return true;
  587.  
  588.     if (! (obj instanceof SocketPermission))
  589.         return false;
  590.  
  591.     SocketPermission that = (SocketPermission) obj;
  592.  
  593.     //this is (overly?) complex!!!
  594.  
  595.     // check the mask first
  596.     if (this.mask != that.mask) return false;
  597.  
  598.     // now check the port range...
  599.     if ((this.portrange[0] != that.portrange[0]) ||
  600.         (this.portrange[1] != that.portrange[1])) {
  601.         return false;
  602.     }
  603.  
  604.     // short cut. This catches:
  605.     //  "crypto" equal to "crypto", or
  606.     // "1.2.3.4" equal to "1.2.3.4.", or 
  607.     //  "*.edu" equal to "*.edu", but it 
  608.     //  does not catch "crypto" equal to
  609.     // "crypto.eng.sun.com".
  610.  
  611.     if (this.getName().equals(that.getName())) {
  612.         return true;
  613.     }
  614.  
  615.     // we now attempt to get the Canonical (FQDN) name and
  616.     // compare that. If this fails, about all we can do is return
  617.     // false.
  618.  
  619.     try {
  620.         this.getCanonName();
  621.         that.getCanonName();
  622.     } catch (UnknownHostException uhe) {
  623.         return false;
  624.     }
  625.  
  626.     if (this.invalid || that.invalid) 
  627.         return false;
  628.  
  629.     if (this.cname != null) {
  630.         return this.cname.equals(that.cname);
  631.     }
  632.  
  633.     return false;
  634.     }
  635.  
  636.     /**
  637.      * Returns the hash code value for this object.
  638.      *
  639.      * @return a hash code value for this object.
  640.      */
  641.  
  642.     public int hashCode() {
  643.     /*
  644.      * If this SocketPermission was initialized with an IP address
  645.      * or a wildcard, use getName().hashCode(), otherwise use
  646.      * the hashCode() of the host name returned from 
  647.      * java.net.InetAddress.getHostName method.
  648.      */
  649.  
  650.     if (init_with_ip || wildcard) {
  651.         return this.getName().hashCode();
  652.     }
  653.  
  654.     try {
  655.         getCanonName();
  656.     } catch (UnknownHostException uhe) {        
  657.  
  658.     }
  659.  
  660.     if (invalid || cname == null)
  661.         return this.getName().hashCode();
  662.     else
  663.         return this.cname.hashCode();
  664.     }
  665.  
  666.     /**
  667.      * Return the current action mask.
  668.      *
  669.      * @return the actions mask.
  670.      */
  671.  
  672.     int getMask() {
  673.     return mask;
  674.     }
  675.  
  676.     /**
  677.      * Returns the "canonical string representation" of the actions in the
  678.      * specified mask.
  679.      * Always returns present actions in the following order: 
  680.      * connect, listen, accept, resolve.  
  681.      *
  682.      * @param mask a specific integer action mask to translate into a string
  683.      * @return the canonical string representation of the actions
  684.      */
  685.     private static String getActions(int mask)
  686.     {
  687.     StringBuffer sb = new StringBuffer();
  688.         boolean comma = false;
  689.  
  690.     if ((mask & CONNECT) == CONNECT) {
  691.         comma = true;
  692.         sb.append("connect");
  693.     }
  694.  
  695.     if ((mask & LISTEN) == LISTEN) {
  696.         if (comma) sb.append(',');
  697.             else comma = true;
  698.         sb.append("listen");
  699.     }
  700.  
  701.     if ((mask & ACCEPT) == ACCEPT) {
  702.         if (comma) sb.append(',');
  703.             else comma = true;
  704.         sb.append("accept");
  705.     }
  706.  
  707.  
  708.     if ((mask & RESOLVE) == RESOLVE) {
  709.         if (comma) sb.append(',');
  710.             else comma = true;
  711.         sb.append("resolve");
  712.     }
  713.  
  714.     return sb.toString();
  715.     }
  716.  
  717.     /**
  718.      * Returns the canonical string representation of the actions.
  719.      * Always returns present actions in the following order: 
  720.      * connect, listen, accept, resolve.  
  721.      *
  722.      * @return the canonical string representation of the actions.
  723.      */
  724.     public String getActions()
  725.     {
  726.     if (actions == null)
  727.         actions = getActions(this.mask);
  728.  
  729.     return actions;
  730.     }
  731.  
  732.     /**
  733.      * Returns a new PermissionCollection object for storing SocketPermission 
  734.      * objects.
  735.      * <p>
  736.      * SocketPermission objects must be stored in a manner that allows them 
  737.      * to be inserted into the collection in any order, but that also enables the 
  738.      * PermissionCollection <code>implies</code>
  739.      * method to be implemented in an efficient (and consistent) manner.
  740.      *
  741.      * @return a new PermissionCollection object suitable for storing SocketPermissions.
  742.      */
  743.  
  744.     public PermissionCollection newPermissionCollection() {
  745.     return new SocketPermissionCollection();
  746.     }
  747.  
  748.     /**
  749.      * WriteObject is called to save the state of the SocketPermission 
  750.      * to a stream. Only the mask is serialized since we want to
  751.      * recalculate the other values when the contents are restored.
  752.      */
  753.     private synchronized void writeObject(java.io.ObjectOutputStream s)
  754.         throws IOException
  755.     {
  756.     // Write out the mask. The superclass takes care of the name
  757.     s.writeInt(mask);
  758.     }
  759.  
  760.     /**
  761.      * readObject is called to restore the state of the FilePermission from
  762.      * a stream. init is called to initialize the rest of the values.
  763.      */
  764.     private synchronized void readObject(java.io.ObjectInputStream s)
  765.          throws IOException, ClassNotFoundException
  766.     {
  767.     // Read in the mask, then initialize the rest
  768.     mask = s.readInt();
  769.     init(getName(),mask);
  770.     }
  771. }
  772.  
  773. /**
  774.  
  775. if (init'd with IP, key is IP as string)
  776. if wildcard, its the wild card
  777. else its the cname?
  778.  
  779.  *
  780.  * @see java.security.Permission
  781.  * @see java.security.Permissions
  782.  * @see java.security.PermissionCollection
  783.  *
  784.  * @version 1.10 98/03/18
  785.  *
  786.  * @author Roland Schemers
  787.  */
  788.  
  789. final class SocketPermissionCollection extends PermissionCollection 
  790. implements Serializable
  791. {
  792.     /** use serialVersionUID from JDK 1.2 for interoperability */
  793.     private static final long serialVersionUID = 2787186408602843674L;
  794.  
  795.     /**
  796.      * The SocketPermissions for this set.
  797.      */
  798.  
  799.     private Vector permissions;
  800.  
  801.     /**
  802.      * Create an empty SocketPermissions object.
  803.      *
  804.      */
  805.  
  806.     public SocketPermissionCollection() {
  807.     permissions = new Vector();
  808.     }
  809.  
  810.     /**
  811.      * Adds a permission to the SocketPermissions. The key for the hash is
  812.      * the name in the case of wildcards, or all the IP addresses.
  813.      *
  814.      * @param permission the Permission object to add.
  815.      */
  816.  
  817.     public void add(Permission permission)
  818.     {
  819.     if (! (permission instanceof SocketPermission))
  820.         throw new IllegalArgumentException("invalid permission: "+
  821.                            permission);
  822.     permissions.addElement(permission);
  823.     }
  824.  
  825.     /**
  826.      * Check and see if this collection of permissions implies the permissions 
  827.      * expressed in "permission".
  828.      *
  829.      * @param p the Permission object to compare
  830.      *
  831.      * @return true if "permission" is a proper subset of a permission in 
  832.      * the collection, false if not.
  833.      */
  834.  
  835.     public boolean implies(Permission permission) 
  836.     {
  837.     if (! (permission instanceof SocketPermission))
  838.            return false;
  839.  
  840.     SocketPermission np = (SocketPermission) permission;
  841.  
  842.     int desired = np.getMask();
  843.     int effective = 0;
  844.     int needed = desired;
  845.  
  846.     Enumeration e = permissions.elements();
  847.     //System.out.println("implies "+np);
  848.     while (e.hasMoreElements()) {
  849.         SocketPermission x = (SocketPermission) e.nextElement();
  850.         //System.out.println("  trying "+x);
  851.         if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(np)) {
  852.         effective |=  x.getMask();
  853.         if ((effective & desired) == desired)
  854.             return true;
  855.         needed = (desired ^ effective);
  856.         }
  857.     }
  858.     return false;
  859.     }
  860.  
  861.     /**
  862.      * Returns an enumeration of all the SocketPermission objects in the 
  863.      * container.
  864.      *
  865.      * @return an enumeration of all the SocketPermission objects.
  866.      */
  867.  
  868.     public Enumeration elements()
  869.     {
  870.     return permissions.elements();
  871.     }
  872. }
  873.