1 /* SocketPermission.java -- Class modeling permissions for socket operations
2 Copyright (C) 1998, 2000, 2001, 2002, 2004 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
;
46 * This class models a specific set of permssions for connecting to a
47 * host. There are two elements to this, the host/port combination and
48 * the permission list.
50 * The host/port combination is specified as followed
53 * hostname[:[-]port[-[port]]]
56 * The hostname portion can be either a hostname or IP address. If it is
57 * a hostname, a wildcard is allowed in hostnames. This wildcard is a "*"
58 * and matches one or more characters. Only one "*" may appear in the
59 * host and it must be the leftmost character. For example,
60 * "*.urbanophile.com" matches all hosts in the "urbanophile.com" domain.
62 * The port portion can be either a single value, or a range of values
63 * treated as inclusive. The first or the last port value in the range
64 * can be omitted in which case either the minimum or maximum legal
65 * value for a port (respectively) is used by default. Here are some
68 * <li>8080 - Represents port 8080 only</li>
69 * <li>2000-3000 - Represents ports 2000 through 3000 inclusive</li>
70 * <li>-4000 - Represents ports 0 through 4000 inclusive</li>
71 * <li>1024- - Represents ports 1024 through 65535 inclusive</li>
73 * The permission list is a comma separated list of individual permissions.
74 * These individual permissions are:
83 * The "listen" permission is only relevant if the host is localhost. If
84 * any permission at all is specified, then resolve permission is implied to
87 * Here are a variety of examples of how to create SocketPermission's
89 * SocketPermission("www.urbanophile.com", "connect");
90 * Can connect to any port on www.urbanophile.com
91 * SocketPermission("www.urbanophile.com:80", "connect,accept");
92 * Can connect to or accept connections from www.urbanophile.com on port 80
93 * SocketPermission("localhost:1024-", "listen,accept,connect");
94 * Can connect to, accept from, an listen on any local port number 1024
96 * SocketPermission("*.edu", "connect");
97 * Can connect to any host in the edu domain
98 * SocketPermission("197.197.20.1", "accept");
99 * Can accept connections from 197.197.20.1
102 * This class also supports IPv6 addresses. These should be specified
103 * in either RFC 2732 format or in full uncompressed form.
107 * @author Aaron M. Renn (arenn@urbanophile.com)
109 public final class SocketPermission
extends Permission
implements Serializable
111 static final long serialVersionUID
= -7204263841984476862L;
113 // FIXME: Needs serialization work, including readObject/writeObject methods.
116 * A hostname/port combination as described above
118 private transient String hostport
;
121 * A comma separated list of actions for which we have permission
123 private String actions
;
126 * Initializes a new instance of <code>SocketPermission</code> with the
127 * specified host/port combination and actions string.
129 * @param hostport The hostname/port number combination
130 * @param actions The actions string
132 public SocketPermission(String hostport
, String actions
)
136 this.hostport
= hostport
;
137 this.actions
= actions
;
141 * Tests this object for equality against another. This will be true if
142 * and only if the passed object is an instance of
143 * <code>SocketPermission</code> and both its hostname/port combination
144 * and permissions string are identical.
146 * @param obj The object to test against for equality
148 * @return <code>true</code> if object is equal to this object,
149 * <code>false</code> otherwise.
151 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:
240 * <li>The argument is of type <code>SocketPermission</code></li>
241 * <li>The actions list of the argument are in this object's actions</li>
242 * <li>The port range of the argument is within this objects port range</li>
243 * <li>The hostname is equal to or a subset of this objects hostname</li>
246 * <p>The argument's hostname will be a subset of this object's hostname if:</p>
249 * <li>The argument's hostname or IP address is equal to this object's.</li>
250 * <li>The argument's canonical hostname is equal to this object's.</li>
251 * <li>The argument's canonical name matches this domains hostname with
255 * @param perm The <code>Permission</code> to check against
257 * @return <code>true</code> if the <code>Permission</code> is implied by
258 * this object, <code>false</code> otherwise.
260 public boolean implies(Permission perm
)
264 // First make sure we are the right object type
265 if (perm
instanceof SocketPermission
)
266 p
= (SocketPermission
) perm
;
270 // Next check the actions
271 String ourlist
= getActions();
272 String theirlist
= p
.getActions();
274 if (! ourlist
.startsWith(theirlist
))
278 int ourfirstport
= 0;
284 int theirfirstport
= 0;
287 int theirlastport
= 0;
290 if (hostport
.indexOf(":") == -1)
297 // FIXME: Needs bulletproofing.
298 // This will dump if hostport if all sorts of bad data was passed to
300 String range
= hostport
.substring(hostport
.indexOf(":") + 1);
301 if (range
.startsWith("-"))
303 else if (range
.indexOf("-") == -1)
304 ourfirstport
= Integer
.parseInt(range
);
307 Integer
.parseInt(range
.substring(0, range
.indexOf("-")));
309 if (range
.endsWith("-"))
311 else if (range
.indexOf("-") == -1)
312 ourlastport
= Integer
.parseInt(range
);
315 Integer
.parseInt(range
.substring(range
.indexOf("-") + 1,
320 if (p
.hostport
.indexOf(":") == -1)
327 // This will dump if hostport if all sorts of bad data was passed to
329 String range
= p
.hostport
.substring(hostport
.indexOf(":") + 1);
330 if (range
.startsWith("-"))
332 else if (range
.indexOf("-") == -1)
333 theirfirstport
= Integer
.parseInt(range
);
336 Integer
.parseInt(range
.substring(0, range
.indexOf("-")));
338 if (range
.endsWith("-"))
339 theirlastport
= 65535;
340 else if (range
.indexOf("-") == -1)
341 theirlastport
= Integer
.parseInt(range
);
344 Integer
.parseInt(range
.substring(range
.indexOf("-") + 1,
349 if ((theirfirstport
< ourfirstport
) || (theirlastport
> ourlastport
))
352 // Finally we can check the hosts
355 // Finally we can check the hosts
359 if (hostport
.indexOf(":") == -1)
362 ourhost
= hostport
.substring(0, hostport
.indexOf(":"));
365 if (p
.hostport
.indexOf(":") == -1)
366 theirhost
= p
.hostport
;
368 theirhost
= p
.hostport
.substring(0, p
.hostport
.indexOf(":"));
371 if (ourhost
.equals(theirhost
))
374 // Try the canonical names
375 String ourcanonical
= null;
377 // Try the canonical names
378 String theircanonical
= null;
381 ourcanonical
= InetAddress
.getByName(ourhost
).getHostName();
382 theircanonical
= InetAddress
.getByName(theirhost
).getHostName();
384 catch (UnknownHostException e
)
386 // Who didn't resolve? Just assume current address is canonical enough
388 if (ourcanonical
== null)
389 ourcanonical
= ourhost
;
390 if (theircanonical
== null)
391 theircanonical
= theirhost
;
394 if (ourcanonical
.equals(theircanonical
))
397 // Well, last chance. Try for a wildcard
398 if (ourhost
.indexOf("*.") != -1)
400 String wild_domain
= ourhost
.substring(ourhost
.indexOf("*" + 1));
401 if (theircanonical
.endsWith(wild_domain
))