| /* SocketPermission.java -- Class modeling permissions for socket operations | |
| Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
| 02111-1307 USA. | |
| As a special exception, if you link this library with other files to | |
| produce an executable, this library does not by itself cause the | |
| resulting executable to be covered by the GNU General Public License. | |
| This exception does not however invalidate any other reasons why the | |
| executable file might be covered by the GNU General Public License. */ | |
| package java.net; | |
| import java.security.Permission; | |
| import java.security.PermissionCollection; | |
| /** | |
| * This class models a specific set of permssions for connecting to a | |
| * host. There are two elements to this, the host/port combination and | |
| * the permission list. | |
| * <p> | |
| * The host/port combination is specified as followed | |
| * <p> | |
| * <pre> | |
| * hostname[:[-]port[-[port]]] | |
| * </pre> | |
| * <p> | |
| * The hostname portion can be either a hostname or IP address. If it is | |
| * a hostname, a wildcard is allowed in hostnames. This wildcard is a "*" | |
| * and matches one or more characters. Only one "*" may appear in the | |
| * host and it must be the leftmost character. For example, | |
| * "*.urbanophile.com" matches all hosts in the "urbanophile.com" domain. | |
| * <p> | |
| * The port portion can be either a single value, or a range of values | |
| * treated as inclusive. The first or the last port value in the range | |
| * can be omitted in which case either the minimum or maximum legal | |
| * value for a port (respectively) is used by default. Here are some | |
| * examples: | |
| * <p><ul> | |
| * <li>8080 - Represents port 8080 only | |
| * <li>2000-3000 - Represents ports 2000 through 3000 inclusive | |
| * <li>-4000 - Represents ports 0 through 4000 inclusive | |
| * <li>1024- - Represents ports 1024 through 65535 inclusive | |
| * </ul><p> | |
| * The permission list is a comma separated list of individual permissions. | |
| * These individual permissions are: | |
| * <p> | |
| * accept<br> | |
| * connect<br> | |
| * listen<br> | |
| * resolve<br> | |
| * <p> | |
| * The "listen" permission is only relevant if the host is localhost. If | |
| * any permission at all is specified, then resolve permission is implied to | |
| * exist. | |
| * <p> | |
| * Here are a variety of examples of how to create SocketPermission's | |
| * <p><pre> | |
| * SocketPermission("www.urbanophile.com", "connect"); | |
| * Can connect to any port on www.urbanophile.com | |
| * SocketPermission("www.urbanophile.com:80", "connect,accept"); | |
| * Can connect to or accept connections from www.urbanophile.com on port 80 | |
| * SocketPermission("localhost:1024-", "listen,accept,connect"); | |
| * Can connect to, accept from, an listen on any local port number 1024 and up. | |
| * SocketPermission("*.edu", "connect"); | |
| * Can connect to any host in the edu domain | |
| * SocketPermission("197.197.20.1", "accept"); | |
| * Can accept connections from 197.197.20.1 | |
| * </pre><p> | |
| * | |
| * @since 1.2 | |
| * | |
| * @author Aaron M. Renn (arenn@urbanophile.com) | |
| */ | |
| public final class SocketPermission extends Permission | |
| implements java.io.Serializable | |
| { | |
| // FIXME: Needs serialization work, including readObject/writeObject methods. | |
| /** | |
| * A hostname/port combination as described above | |
| */ | |
| private transient String hostport; | |
| /** | |
| * A comma separated list of actions for which we have permission | |
| */ | |
| private String actions; | |
| /** | |
| * Initializes a new instance of <code>SocketPermission</code> with the | |
| * specified host/port combination and actions string. | |
| * | |
| * @param hostport The hostname/port number combination | |
| * @param perms The actions string | |
| */ | |
| public SocketPermission(String hostport, String actions) | |
| { | |
| super(hostport); | |
| this.hostport = hostport; | |
| this.actions = actions; | |
| } | |
| /** | |
| * Tests this object for equality against another. This will be true if | |
| * and only if the passed object is an instance of | |
| * <code>SocketPermission</code> and both its hostname/port combination | |
| * and permissions string are identical. | |
| * | |
| * @param obj The object to test against for equality | |
| * | |
| * @return <code>true</code> if object is equal to this object, | |
| * <code>false</code> otherwise. | |
| */ | |
| public boolean equals(Object obj) | |
| { | |
| if (obj == null) | |
| return (false); | |
| if (!(obj instanceof SocketPermission)) | |
| return (false); | |
| if (((SocketPermission) obj).hostport.equals(hostport)) | |
| if (((SocketPermission) obj).actions.equals(actions)) | |
| return (true); | |
| return (false); | |
| } | |
| /** | |
| * Returns a hash code value for this object. Overrides the | |
| * Permission.hashCode() | |
| * | |
| * @return A hash code | |
| */ | |
| public int hashCode() | |
| { | |
| int hash = 100; | |
| // FIXME: Get a real hash function | |
| for (int i = 0; i < hostport.length(); i++) | |
| hash = hash + (int) hostport.charAt(i) * 7; | |
| return (hash); | |
| } | |
| /** | |
| * Returns the list of permission actions in this object in canonical | |
| * order. The canonical order is "connect,listen,accept,resolve" | |
| * | |
| * @return The permitted action string. | |
| */ | |
| public String getActions() | |
| { | |
| boolean found = false; | |
| StringBuffer sb = new StringBuffer(""); | |
| if (actions.indexOf("connect") != -1) | |
| { | |
| sb.append("connect"); | |
| found = true; | |
| } | |
| if (actions.indexOf("listen") != -1) | |
| if (found) | |
| sb.append(",listen"); | |
| else | |
| { | |
| sb.append("listen"); | |
| found = true; | |
| } | |
| if (actions.indexOf("accept") != -1) | |
| if (found) | |
| sb.append(",accept"); | |
| else | |
| { | |
| sb.append("accept"); | |
| found = true; | |
| } | |
| if (found) | |
| sb.append(",resolve"); | |
| else if (actions.indexOf("resolve") != -1) | |
| sb.append("resolve"); | |
| return (sb.toString()); | |
| } | |
| /** | |
| * Returns a new <code>PermissionCollection</code> object that can hold | |
| * <code>SocketPermission</code>'s. | |
| * | |
| * @return A new <code>PermissionCollection</code>. | |
| */ | |
| public PermissionCollection newPermissionCollection() | |
| { | |
| // FIXME: Implement | |
| return (null); | |
| } | |
| /** | |
| * Returns true if the permission object passed it is implied by the | |
| * this permission. This will be true if | |
| * <p><ul> | |
| * <li>The argument is of type SocketPermission | |
| * <li>The actions list of the argument are in this object's actions | |
| * <li>The port range of the argument is within this objects port range | |
| * <li>The hostname is equal to or a subset of this objects hostname | |
| * </ul> | |
| * <p> | |
| * The argument's hostname will be a subset of this object's hostname if: | |
| * <p><ul> | |
| * <li>The argument's hostname or IP address is equal to this object's. | |
| * <li>The argument's canonical hostname is equal to this object's. | |
| * <li>The argument's canonical name matches this domains hostname with wildcards | |
| * </ul> | |
| * | |
| * @param perm The Permission to check against | |
| * | |
| * @return <code>true</code> if the <code>Permission</code> is implied by | |
| * this object, <code>false</code> otherwise. | |
| */ | |
| public boolean implies(Permission perm) | |
| { | |
| SocketPermission p; | |
| // First make sure we are the right object type | |
| if (perm instanceof SocketPermission) | |
| p = (SocketPermission) perm; | |
| else | |
| return (false); | |
| // Next check the actions | |
| String ourlist = getActions(); | |
| String theirlist = p.getActions(); | |
| if (!ourlist.startsWith(theirlist)) | |
| return (false); | |
| // Now check ports | |
| int ourfirstport = 0, ourlastport = 0, theirfirstport = 0, theirlastport = | |
| 0; | |
| // Get ours | |
| if (hostport.indexOf(":") == -1) | |
| { | |
| ourfirstport = 0; | |
| ourlastport = 65535; | |
| } | |
| else | |
| { | |
| // FIXME: Needs bulletproofing. | |
| // This will dump if hostport if all sorts of bad data was passed to | |
| // the constructor | |
| String range = hostport.substring(hostport.indexOf(":") + 1); | |
| if (range.startsWith("-")) | |
| ourfirstport = 0; | |
| else if (range.indexOf("-") == -1) | |
| ourfirstport = Integer.parseInt(range); | |
| else | |
| ourfirstport = | |
| Integer.parseInt(range.substring(0, range.indexOf("-"))); | |
| if (range.endsWith("-")) | |
| ourlastport = 65535; | |
| else if (range.indexOf("-") == -1) | |
| ourlastport = Integer.parseInt(range); | |
| else | |
| ourlastport = | |
| Integer.parseInt(range. | |
| substring(range.indexOf("-") + 1, | |
| range.length())); | |
| } | |
| // Get theirs | |
| if (p.hostport.indexOf(":") == -1) | |
| { | |
| theirfirstport = 0; | |
| ourlastport = 65535; | |
| } | |
| else | |
| { | |
| // This will dump if hostport if all sorts of bad data was passed to | |
| // the constructor | |
| String range = p.hostport.substring(hostport.indexOf(":") + 1); | |
| if (range.startsWith("-")) | |
| theirfirstport = 0; | |
| else if (range.indexOf("-") == -1) | |
| theirfirstport = Integer.parseInt(range); | |
| else | |
| theirfirstport = | |
| Integer.parseInt(range.substring(0, range.indexOf("-"))); | |
| if (range.endsWith("-")) | |
| theirlastport = 65535; | |
| else if (range.indexOf("-") == -1) | |
| theirlastport = Integer.parseInt(range); | |
| else | |
| theirlastport = | |
| Integer.parseInt(range. | |
| substring(range.indexOf("-") + 1, | |
| range.length())); | |
| } | |
| // Now check them | |
| if ((theirfirstport < ourfirstport) || (theirlastport > ourlastport)) | |
| return (false); | |
| // Finally we can check the hosts | |
| String ourhost, theirhost; | |
| // Get ours | |
| if (hostport.indexOf(":") == -1) | |
| ourhost = hostport; | |
| else | |
| ourhost = hostport.substring(0, hostport.indexOf(":")); | |
| // Get theirs | |
| if (p.hostport.indexOf(":") == -1) | |
| theirhost = p.hostport; | |
| else | |
| theirhost = p.hostport.substring(0, p.hostport.indexOf(":")); | |
| // Are they equal? | |
| if (ourhost.equals(theirhost)) | |
| return (true); | |
| // Try the canonical names | |
| String ourcanonical = null, theircanonical = null; | |
| try | |
| { | |
| ourcanonical = InetAddress.getByName(ourhost).getHostName(); | |
| theircanonical = InetAddress.getByName(theirhost).getHostName(); | |
| } | |
| catch (UnknownHostException e) | |
| { | |
| // Who didn't resolve? Just assume current address is canonical enough | |
| // Is this ok to do? | |
| if (ourcanonical == null) | |
| ourcanonical = ourhost; | |
| if (theircanonical == null) | |
| theircanonical = theirhost; | |
| } | |
| if (ourcanonical.equals(theircanonical)) | |
| return (true); | |
| // Well, last chance. Try for a wildcard | |
| if (ourhost.indexOf("*.") != -1) | |
| { | |
| String wild_domain = ourhost.substring(ourhost.indexOf("*" + 1)); | |
| if (theircanonical.endsWith(wild_domain)) | |
| return (true); | |
| } | |
| // Didn't make it | |
| return (false); | |
| } | |
| } |