1 /* SocketPermission.java -- Class modeling permissions for socket operations
2 Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
40 import java.security.Permission;
41 import java.security.PermissionCollection;
44 * This class models a specific set of permssions for connecting to a
45 * host. There are two elements to this, the host/port combination and
46 * the permission list.
48 * The host/port combination is specified as followed
51 * hostname[:[-]port[-[port]]]
54 * The hostname portion can be either a hostname or IP address. If it is
55 * a hostname, a wildcard is allowed in hostnames. This wildcard is a "*"
56 * and matches one or more characters. Only one "*" may appear in the
57 * host and it must be the leftmost character. For example,
58 * "*.urbanophile.com" matches all hosts in the "urbanophile.com" domain.
60 * The port portion can be either a single value, or a range of values
61 * treated as inclusive. The first or the last port value in the range
62 * can be omitted in which case either the minimum or maximum legal
63 * value for a port (respectively) is used by default. Here are some
66 * <li>8080 - Represents port 8080 only
67 * <li>2000-3000 - Represents ports 2000 through 3000 inclusive
68 * <li>-4000 - Represents ports 0 through 4000 inclusive
69 * <li>1024- - Represents ports 1024 through 65535 inclusive
71 * The permission list is a comma separated list of individual permissions.
72 * These individual permissions are:
79 * The "listen" permission is only relevant if the host is localhost. If
80 * any permission at all is specified, then resolve permission is implied to
83 * Here are a variety of examples of how to create SocketPermission's
85 * SocketPermission("www.urbanophile.com", "connect");
86 * Can connect to any port on www.urbanophile.com
87 * SocketPermission("www.urbanophile.com:80", "connect,accept");
88 * Can connect to or accept connections from www.urbanophile.com on port 80
89 * SocketPermission("localhost:1024-", "listen,accept,connect");
90 * Can connect to, accept from, an listen on any local port number 1024 and up.
91 * SocketPermission("*.edu", "connect");
92 * Can connect to any host in the edu domain
93 * SocketPermission("197.197.20.1", "accept");
94 * Can accept connections from 197.197.20.1
99 * @author Aaron M. Renn (arenn@urbanophile.com)
101 public final class SocketPermission extends Permission
102 implements java.io.Serializable
105 // FIXME: Needs serialization work, including readObject/writeObject methods.
107 * A hostname/port combination as described above
109 private transient String hostport;
112 * A comma separated list of actions for which we have permission
114 private String actions;
117 * Initializes a new instance of <code>SocketPermission</code> with the
118 * specified host/port combination and actions string.
120 * @param hostport The hostname/port number combination
121 * @param perms The actions string
123 public SocketPermission(String hostport, String actions)
127 this.hostport = hostport;
128 this.actions = actions;
132 * Tests this object for equality against another. This will be true if
133 * and only if the passed object is an instance of
134 * <code>SocketPermission</code> and both its hostname/port combination
135 * and permissions string are identical.
137 * @param obj The object to test against for equality
139 * @return <code>true</code> if object is equal to this object,
140 * <code>false</code> otherwise.
142 public boolean equals(Object obj)
147 if (!(obj instanceof SocketPermission))
150 if (((SocketPermission) obj).hostport.equals(hostport))
151 if (((SocketPermission) obj).actions.equals(actions))
158 * Returns a hash code value for this object. Overrides the
159 * Permission.hashCode()
161 * @return A hash code
163 public int hashCode()
167 // FIXME: Get a real hash function
168 for (int i = 0; i < hostport.length(); i++)
169 hash = hash + (int) hostport.charAt(i) * 7;
175 * Returns the list of permission actions in this object in canonical
176 * order. The canonical order is "connect,listen,accept,resolve"
178 * @return The permitted action string.
180 public String getActions()
182 boolean found = false;
183 StringBuffer sb = new StringBuffer("");
185 if (actions.indexOf("connect") != -1)
187 sb.append("connect");
191 if (actions.indexOf("listen") != -1)
193 sb.append(",listen");
200 if (actions.indexOf("accept") != -1)
202 sb.append(",accept");
210 sb.append(",resolve");
211 else if (actions.indexOf("resolve") != -1)
212 sb.append("resolve");
214 return (sb.toString());
218 * Returns a new <code>PermissionCollection</code> object that can hold
219 * <code>SocketPermission</code>'s.
221 * @return A new <code>PermissionCollection</code>.
223 public PermissionCollection newPermissionCollection()
231 * Returns true if the permission object passed it is implied by the
232 * this permission. This will be true if
234 * <li>The argument is of type SocketPermission
235 * <li>The actions list of the argument are in this object's actions
236 * <li>The port range of the argument is within this objects port range
237 * <li>The hostname is equal to or a subset of this objects hostname
240 * The argument's hostname will be a subset of this object's hostname if:
242 * <li>The argument's hostname or IP address is equal to this object's.
243 * <li>The argument's canonical hostname is equal to this object's.
244 * <li>The argument's canonical name matches this domains hostname with wildcards
247 * @param perm The Permission to check against
249 * @return <code>true</code> if the <code>Permission</code> is implied by
250 * this object, <code>false</code> otherwise.
252 public boolean implies(Permission perm)
256 // First make sure we are the right object type
257 if (perm instanceof SocketPermission)
258 p = (SocketPermission) perm;
262 // Next check the actions
263 String ourlist = getActions();
264 String theirlist = p.getActions();
266 if (!ourlist.startsWith(theirlist))
270 int ourfirstport = 0, ourlastport = 0, theirfirstport = 0, theirlastport =
274 if (hostport.indexOf(":") == -1)
281 // FIXME: Needs bulletproofing.
282 // This will dump if hostport if all sorts of bad data was passed to
284 String range = hostport.substring(hostport.indexOf(":") + 1);
285 if (range.startsWith("-"))
287 else if (range.indexOf("-") == -1)
288 ourfirstport = Integer.parseInt(range);
291 Integer.parseInt(range.substring(0, range.indexOf("-")));
293 if (range.endsWith("-"))
295 else if (range.indexOf("-") == -1)
296 ourlastport = Integer.parseInt(range);
299 Integer.parseInt(range.
300 substring(range.indexOf("-") + 1,
305 if (p.hostport.indexOf(":") == -1)
312 // This will dump if hostport if all sorts of bad data was passed to
314 String range = p.hostport.substring(hostport.indexOf(":") + 1);
315 if (range.startsWith("-"))
317 else if (range.indexOf("-") == -1)
318 theirfirstport = Integer.parseInt(range);
321 Integer.parseInt(range.substring(0, range.indexOf("-")));
323 if (range.endsWith("-"))
324 theirlastport = 65535;
325 else if (range.indexOf("-") == -1)
326 theirlastport = Integer.parseInt(range);
329 Integer.parseInt(range.
330 substring(range.indexOf("-") + 1,
335 if ((theirfirstport < ourfirstport) || (theirlastport > ourlastport))
338 // Finally we can check the hosts
339 String ourhost, theirhost;
342 if (hostport.indexOf(":") == -1)
345 ourhost = hostport.substring(0, hostport.indexOf(":"));
348 if (p.hostport.indexOf(":") == -1)
349 theirhost = p.hostport;
351 theirhost = p.hostport.substring(0, p.hostport.indexOf(":"));
354 if (ourhost.equals(theirhost))
357 // Try the canonical names
358 String ourcanonical = null, theircanonical = null;
361 ourcanonical = InetAddress.getByName(ourhost).getHostName();
362 theircanonical = InetAddress.getByName(theirhost).getHostName();
364 catch (UnknownHostException e)
366 // Who didn't resolve? Just assume current address is canonical enough
368 if (ourcanonical == null)
369 ourcanonical = ourhost;
370 if (theircanonical == null)
371 theircanonical = theirhost;
374 if (ourcanonical.equals(theircanonical))
377 // Well, last chance. Try for a wildcard
378 if (ourhost.indexOf("*.") != -1)
380 String wild_domain = ourhost.substring(ourhost.indexOf("*" + 1));
381 if (theircanonical.endsWith(wild_domain))