Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / java / net / SocketPermission.java
blob0cd18c772e03b69ba6f0845571b3480b0b6841aa
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)
9 any later version.
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
19 02111-1307 USA.
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
24 combination.
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. */
38 package java.net;
40 import java.io.Serializable;
41 import java.security.Permission;
42 import java.security.PermissionCollection;
45 /**
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.
49 * <p>
50 * The host/port combination is specified as followed
51 * <p>
52 * <pre>
53 * hostname[:[-]port[-[port]]]
54 * </pre>
55 * <p>
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.
61 * <p>
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
66 * examples:
67 * <p><ul>
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>
72 * </ul><p>
73 * The permission list is a comma separated list of individual permissions.
74 * These individual permissions are:
75 * <p>
76 * <pre>
77 * accept
78 * connect
79 * listen
80 * resolve
81 * </pre>
82 * <p>
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
85 * exist.
86 * <p>
87 * Here are a variety of examples of how to create SocketPermission's
88 * <p><pre>
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
95 * and up.
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
100 * </pre><p>
102 * This class also supports IPv6 addresses. These should be specified
103 * in either RFC 2732 format or in full uncompressed form.
105 * @since 1.2
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)
134 super(hostport);
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))
154 return false;
156 if (((SocketPermission) obj).hostport.equals(hostport))
157 if (((SocketPermission) obj).actions.equals(actions))
158 return true;
160 return false;
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()
171 int hash = 100;
172 if (hostport != null)
173 hash += hostport.hashCode();
174 if (actions != null)
175 hash += actions.hashCode();
176 return hash;
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");
193 found = true;
196 if (actions.indexOf("listen") != -1)
197 if (found)
198 sb.append(",listen");
199 else
201 sb.append("listen");
202 found = true;
205 if (actions.indexOf("accept") != -1)
206 if (found)
207 sb.append(",accept");
208 else
210 sb.append("accept");
211 found = true;
214 if (found)
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()
230 // FIXME: Implement
232 return null;
236 * Returns true if the permission object passed it is implied by the
237 * this permission. This will be true if:
239 * <ul>
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>
244 * </ul>
246 * <p>The argument's hostname will be a subset of this object's hostname if:</p>
248 * <ul>
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
252 * wildcards</li>
253 * </ul>
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)
262 SocketPermission p;
264 // First make sure we are the right object type
265 if (perm instanceof SocketPermission)
266 p = (SocketPermission) perm;
267 else
268 return false;
270 // Next check the actions
271 String ourlist = getActions();
272 String theirlist = p.getActions();
274 if (! ourlist.startsWith(theirlist))
275 return false;
277 // Now check ports
278 int ourfirstport = 0;
280 // Now check ports
281 int ourlastport = 0;
283 // Now check ports
284 int theirfirstport = 0;
286 // Now check ports
287 int theirlastport = 0;
289 // Get ours
290 if (hostport.indexOf(":") == -1)
292 ourfirstport = 0;
293 ourlastport = 65535;
295 else
297 // FIXME: Needs bulletproofing.
298 // This will dump if hostport if all sorts of bad data was passed to
299 // the constructor
300 String range = hostport.substring(hostport.indexOf(":") + 1);
301 if (range.startsWith("-"))
302 ourfirstport = 0;
303 else if (range.indexOf("-") == -1)
304 ourfirstport = Integer.parseInt(range);
305 else
306 ourfirstport =
307 Integer.parseInt(range.substring(0, range.indexOf("-")));
309 if (range.endsWith("-"))
310 ourlastport = 65535;
311 else if (range.indexOf("-") == -1)
312 ourlastport = Integer.parseInt(range);
313 else
314 ourlastport =
315 Integer.parseInt(range.substring(range.indexOf("-") + 1,
316 range.length()));
319 // Get theirs
320 if (p.hostport.indexOf(":") == -1)
322 theirfirstport = 0;
323 ourlastport = 65535;
325 else
327 // This will dump if hostport if all sorts of bad data was passed to
328 // the constructor
329 String range = p.hostport.substring(hostport.indexOf(":") + 1);
330 if (range.startsWith("-"))
331 theirfirstport = 0;
332 else if (range.indexOf("-") == -1)
333 theirfirstport = Integer.parseInt(range);
334 else
335 theirfirstport =
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);
342 else
343 theirlastport =
344 Integer.parseInt(range.substring(range.indexOf("-") + 1,
345 range.length()));
348 // Now check them
349 if ((theirfirstport < ourfirstport) || (theirlastport > ourlastport))
350 return false;
352 // Finally we can check the hosts
353 String ourhost;
355 // Finally we can check the hosts
356 String theirhost;
358 // Get ours
359 if (hostport.indexOf(":") == -1)
360 ourhost = hostport;
361 else
362 ourhost = hostport.substring(0, hostport.indexOf(":"));
364 // Get theirs
365 if (p.hostport.indexOf(":") == -1)
366 theirhost = p.hostport;
367 else
368 theirhost = p.hostport.substring(0, p.hostport.indexOf(":"));
370 // Are they equal?
371 if (ourhost.equals(theirhost))
372 return true;
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
387 // Is this ok to do?
388 if (ourcanonical == null)
389 ourcanonical = ourhost;
390 if (theircanonical == null)
391 theircanonical = theirhost;
394 if (ourcanonical.equals(theircanonical))
395 return true;
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))
402 return true;
405 // Didn't make it
406 return false;