1 /* SocketPermission.java -- Class modeling permissions for socket operations
2 Copyright (C) 1998, 2000, 2001, 2002 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.io.Serializable;
41 import java.security.Permission;
42 import java.security.PermissionCollection;
45 * This class models a specific set of permssions for connecting to a
46 * host. There are two elements to this, the host/port combination and
47 * the permission list.
49 * The host/port combination is specified as followed
52 * hostname[:[-]port[-[port]]]
55 * The hostname portion can be either a hostname or IP address. If it is
56 * a hostname, a wildcard is allowed in hostnames. This wildcard is a "*"
57 * and matches one or more characters. Only one "*" may appear in the
58 * host and it must be the leftmost character. For example,
59 * "*.urbanophile.com" matches all hosts in the "urbanophile.com" domain.
61 * The port portion can be either a single value, or a range of values
62 * treated as inclusive. The first or the last port value in the range
63 * can be omitted in which case either the minimum or maximum legal
64 * value for a port (respectively) is used by default. Here are some
67 * <li>8080 - Represents port 8080 only
68 * <li>2000-3000 - Represents ports 2000 through 3000 inclusive
69 * <li>-4000 - Represents ports 0 through 4000 inclusive
70 * <li>1024- - Represents ports 1024 through 65535 inclusive
72 * The permission list is a comma separated list of individual permissions.
73 * These individual permissions are:
80 * The "listen" permission is only relevant if the host is localhost. If
81 * any permission at all is specified, then resolve permission is implied to
84 * Here are a variety of examples of how to create SocketPermission's
86 * SocketPermission("www.urbanophile.com", "connect");
87 * Can connect to any port on www.urbanophile.com
88 * SocketPermission("www.urbanophile.com:80", "connect,accept");
89 * Can connect to or accept connections from www.urbanophile.com on port 80
90 * SocketPermission("localhost:1024-", "listen,accept,connect");
91 * Can connect to, accept from, an listen on any local port number 1024
93 * SocketPermission("*.edu", "connect");
94 * Can connect to any host in the edu domain
95 * SocketPermission("197.197.20.1", "accept");
96 * Can accept connections from 197.197.20.1
99 * This class also supports IPv6 addresses. These should be specified
100 * in either RFC 2732 format or in full uncompressed form.
104 * @author Aaron M. Renn (arenn@urbanophile.com)
106 public final class SocketPermission extends Permission
107 implements Serializable
109 static final long serialVersionUID = -7204263841984476862L;
111 // FIXME: Needs serialization work, including readObject/writeObject methods.
113 * A hostname/port combination as described above
115 private transient String hostport;
118 * A comma separated list of actions for which we have permission
120 private String actions;
123 * Initializes a new instance of <code>SocketPermission</code> with the
124 * specified host/port combination and actions string.
126 * @param hostport The hostname/port number combination
127 * @param actions The actions string
129 public SocketPermission(String hostport, String actions)
133 this.hostport = hostport;
134 this.actions = actions;
138 * Tests this object for equality against another. This will be true if
139 * and only if the passed object is an instance of
140 * <code>SocketPermission</code> and both its hostname/port combination
141 * and permissions string are identical.
143 * @param obj The object to test against for equality
145 * @return <code>true</code> if object is equal to this object,
146 * <code>false</code> otherwise.
148 public boolean equals(Object obj)
153 if (!(obj instanceof SocketPermission))
156 if (((SocketPermission) obj).hostport.equals(hostport))
157 if (((SocketPermission) obj).actions.equals(actions))
164 * Returns a hash code value for this object. Overrides the
165 * <code>Permission.hashCode()</code>.
167 * @return A hash code
169 public int hashCode()
172 if (hostport != null)
173 hash += hostport.hashCode();
175 hash += actions.hashCode();
180 * Returns the list of permission actions in this object in canonical
181 * order. The canonical order is "connect,listen,accept,resolve"
183 * @return The permitted action string.
185 public String getActions()
187 boolean found = false;
188 StringBuffer sb = new StringBuffer("");
190 if (actions.indexOf("connect") != -1)
192 sb.append("connect");
196 if (actions.indexOf("listen") != -1)
198 sb.append(",listen");
205 if (actions.indexOf("accept") != -1)
207 sb.append(",accept");
215 sb.append(",resolve");
216 else if (actions.indexOf("resolve") != -1)
217 sb.append("resolve");
219 return (sb.toString());
223 * Returns a new <code>PermissionCollection</code> object that can hold
224 * <code>SocketPermission</code>'s.
226 * @return A new <code>PermissionCollection</code>.
228 public PermissionCollection newPermissionCollection()
236 * Returns true if the permission object passed it is implied by the
237 * this permission. This will be true if
239 * <li>The argument is of type <code>SocketPermission</code>
240 * <li>The actions list of the argument are in this object's actions
241 * <li>The port range of the argument is within this objects port range
242 * <li>The hostname is equal to or a subset of this objects hostname
245 * The argument's hostname will be a subset of this object's hostname if:
247 * <li>The argument's hostname or IP address is equal to this object's.
248 * <li>The argument's canonical hostname is equal to this object's.
249 * <li>The argument's canonical name matches this domains hostname with
253 * @param perm The <code>Permission</code> to check against
255 * @return <code>true</code> if the <code>Permission</code> is implied by
256 * this object, <code>false</code> otherwise.
258 public boolean implies(Permission perm)
262 // First make sure we are the right object type
263 if (perm instanceof SocketPermission)
264 p = (SocketPermission) perm;
268 // Next check the actions
269 String ourlist = getActions();
270 String theirlist = p.getActions();
272 if (!ourlist.startsWith(theirlist))
276 int ourfirstport = 0, ourlastport = 0, theirfirstport = 0, theirlastport =
280 if (hostport.indexOf(":") == -1)
287 // FIXME: Needs bulletproofing.
288 // This will dump if hostport if all sorts of bad data was passed to
290 String range = hostport.substring(hostport.indexOf(":") + 1);
291 if (range.startsWith("-"))
293 else if (range.indexOf("-") == -1)
294 ourfirstport = Integer.parseInt(range);
297 Integer.parseInt(range.substring(0, range.indexOf("-")));
299 if (range.endsWith("-"))
301 else if (range.indexOf("-") == -1)
302 ourlastport = Integer.parseInt(range);
305 Integer.parseInt(range.
306 substring(range.indexOf("-") + 1,
311 if (p.hostport.indexOf(":") == -1)
318 // This will dump if hostport if all sorts of bad data was passed to
320 String range = p.hostport.substring(hostport.indexOf(":") + 1);
321 if (range.startsWith("-"))
323 else if (range.indexOf("-") == -1)
324 theirfirstport = Integer.parseInt(range);
327 Integer.parseInt(range.substring(0, range.indexOf("-")));
329 if (range.endsWith("-"))
330 theirlastport = 65535;
331 else if (range.indexOf("-") == -1)
332 theirlastport = Integer.parseInt(range);
335 Integer.parseInt(range.
336 substring(range.indexOf("-") + 1,
341 if ((theirfirstport < ourfirstport) || (theirlastport > ourlastport))
344 // Finally we can check the hosts
345 String ourhost, theirhost;
348 if (hostport.indexOf(":") == -1)
351 ourhost = hostport.substring(0, hostport.indexOf(":"));
354 if (p.hostport.indexOf(":") == -1)
355 theirhost = p.hostport;
357 theirhost = p.hostport.substring(0, p.hostport.indexOf(":"));
360 if (ourhost.equals(theirhost))
363 // Try the canonical names
364 String ourcanonical = null, theircanonical = null;
367 ourcanonical = InetAddress.getByName(ourhost).getHostName();
368 theircanonical = InetAddress.getByName(theirhost).getHostName();
370 catch (UnknownHostException e)
372 // Who didn't resolve? Just assume current address is canonical enough
374 if (ourcanonical == null)
375 ourcanonical = ourhost;
376 if (theircanonical == null)
377 theircanonical = theirhost;
380 if (ourcanonical.equals(theircanonical))
383 // Well, last chance. Try for a wildcard
384 if (ourhost.indexOf("*.") != -1)
386 String wild_domain = ourhost.substring(ourhost.indexOf("*" + 1));
387 if (theircanonical.endsWith(wild_domain))