OSDN Git Service

2003-10-08 Michael Koch <konqueror@gmx.de>
[pf3gnuchains/gcc-fork.git] / libjava / java / net / SocketPermission.java
1 /* SocketPermission.java -- Class modeling permissions for socket operations
2    Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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.
10
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.
15
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.
20
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.
25
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. */
37
38 package java.net;
39
40 import java.io.Serializable;
41 import java.security.Permission;
42 import java.security.PermissionCollection;
43
44 /**
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.
48  * <p>
49  * The host/port combination is specified as followed
50  * <p>
51  * <pre>
52  * hostname[:[-]port[-[port]]]
53  * </pre>
54  * <p>
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.
60  * <p>
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
65  * examples:
66  * <p><ul>
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
71  * </ul><p>
72  * The permission list is a comma separated list of individual permissions.
73  * These individual permissions are:
74  * <p>
75  * accept<br>
76  * connect<br>
77  * listen<br>
78  * resolve<br>
79  * <p>
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
82  * exist.
83  * <p>
84  * Here are a variety of examples of how to create SocketPermission's
85  * <p><pre>
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
92  *   and up.
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
97  * </pre><p>
98  *
99  * This class also supports IPv6 addresses.  These should be specified
100  * in either RFC 2732 format or in full uncompressed form.
101  *
102  * @since 1.2
103  *
104  * @author Aaron M. Renn (arenn@urbanophile.com)
105  */
106 public final class SocketPermission extends Permission
107   implements Serializable
108 {
109   static final long serialVersionUID = -7204263841984476862L;
110
111 // FIXME: Needs serialization work, including readObject/writeObject methods.
112   /**
113    * A hostname/port combination as described above
114    */
115   private transient String hostport;
116
117   /**
118    * A comma separated list of actions for which we have permission
119    */
120   private String actions;
121
122   /**
123    * Initializes a new instance of <code>SocketPermission</code> with the 
124    * specified host/port combination and actions string.
125    *
126    * @param hostport The hostname/port number combination
127    * @param actions The actions string
128    */
129   public SocketPermission(String hostport, String actions)
130   {
131     super(hostport);
132
133     this.hostport = hostport;
134     this.actions = actions;
135   }
136
137   /**
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.
142    *
143    * @param obj The object to test against for equality
144    *
145    * @return <code>true</code> if object is equal to this object, 
146    *         <code>false</code> otherwise.
147    */
148   public boolean equals(Object obj)
149   {
150     if (obj == null)
151       return (false);
152
153     if (!(obj instanceof SocketPermission))
154       return (false);
155
156     if (((SocketPermission) obj).hostport.equals(hostport))
157       if (((SocketPermission) obj).actions.equals(actions))
158         return (true);
159
160     return (false);
161   }
162
163   /**
164    * Returns a hash code value for this object.  Overrides the 
165    * <code>Permission.hashCode()</code>.
166    *
167    * @return A hash code
168    */
169   public int hashCode()
170   {
171     int hash = 100;
172     if (hostport != null)
173       hash += hostport.hashCode();
174     if (actions != null)
175       hash += actions.hashCode();
176     return hash;
177   }
178
179   /**
180    * Returns the list of permission actions in this object in canonical
181    * order.  The canonical order is "connect,listen,accept,resolve"
182    *
183    * @return The permitted action string.
184    */
185   public String getActions()
186   {
187     boolean found = false;
188     StringBuffer sb = new StringBuffer("");
189
190     if (actions.indexOf("connect") != -1)
191       {
192         sb.append("connect");
193         found = true;
194       }
195
196     if (actions.indexOf("listen") != -1)
197       if (found)
198           sb.append(",listen");
199       else
200         {
201           sb.append("listen");
202           found = true;
203         }
204
205     if (actions.indexOf("accept") != -1)
206       if (found)
207         sb.append(",accept");
208       else
209         {
210           sb.append("accept");
211           found = true;
212         }
213
214     if (found)
215       sb.append(",resolve");
216     else if (actions.indexOf("resolve") != -1)
217       sb.append("resolve");
218
219     return (sb.toString());
220   }
221
222   /**
223    * Returns a new <code>PermissionCollection</code> object that can hold
224    * <code>SocketPermission</code>'s.
225    *
226    * @return A new <code>PermissionCollection</code>.
227    */
228   public PermissionCollection newPermissionCollection()
229   {
230     // FIXME: Implement
231
232     return (null);
233   }
234
235   /**
236    * Returns true if the permission object passed it is implied by the
237    * this permission.  This will be true if 
238    * <p><ul>
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
243    * </ul>
244    * <p>
245    * The argument's hostname will be a subset of this object's hostname if:
246    * <p><ul>
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
250    * wildcards
251    * </ul>
252    *
253    * @param perm The <code>Permission</code> to check against
254    *
255    * @return <code>true</code> if the <code>Permission</code> is implied by 
256    * this object, <code>false</code> otherwise.
257    */
258   public boolean implies(Permission perm)
259   {
260     SocketPermission p;
261
262     // First make sure we are the right object type
263     if (perm instanceof SocketPermission)
264       p = (SocketPermission) perm;
265     else
266       return (false);
267
268     // Next check the actions
269     String ourlist = getActions();
270     String theirlist = p.getActions();
271
272     if (!ourlist.startsWith(theirlist))
273       return (false);
274
275     // Now check ports
276     int ourfirstport = 0, ourlastport = 0, theirfirstport = 0, theirlastport =
277       0;
278
279     // Get ours
280     if (hostport.indexOf(":") == -1)
281       {
282         ourfirstport = 0;
283         ourlastport = 65535;
284       }
285     else
286       {
287         // FIXME:  Needs bulletproofing.
288         // This will dump if hostport if all sorts of bad data was passed to
289         // the constructor
290         String range = hostport.substring(hostport.indexOf(":") + 1);
291         if (range.startsWith("-"))
292           ourfirstport = 0;
293         else if (range.indexOf("-") == -1)
294           ourfirstport = Integer.parseInt(range);
295         else
296           ourfirstport =
297             Integer.parseInt(range.substring(0, range.indexOf("-")));
298
299         if (range.endsWith("-"))
300           ourlastport = 65535;
301         else if (range.indexOf("-") == -1)
302           ourlastport = Integer.parseInt(range);
303         else
304           ourlastport =
305             Integer.parseInt(range.
306                              substring(range.indexOf("-") + 1,
307                                        range.length()));
308       }
309
310     // Get theirs
311     if (p.hostport.indexOf(":") == -1)
312       {
313         theirfirstport = 0;
314         ourlastport = 65535;
315       }
316     else
317       {
318         // This will dump if hostport if all sorts of bad data was passed to
319         // the constructor
320         String range = p.hostport.substring(hostport.indexOf(":") + 1);
321         if (range.startsWith("-"))
322           theirfirstport = 0;
323         else if (range.indexOf("-") == -1)
324           theirfirstport = Integer.parseInt(range);
325         else
326           theirfirstport =
327             Integer.parseInt(range.substring(0, range.indexOf("-")));
328
329         if (range.endsWith("-"))
330           theirlastport = 65535;
331         else if (range.indexOf("-") == -1)
332           theirlastport = Integer.parseInt(range);
333         else
334           theirlastport =
335             Integer.parseInt(range.
336                              substring(range.indexOf("-") + 1,
337                                        range.length()));
338       }
339
340     // Now check them
341     if ((theirfirstport < ourfirstport) || (theirlastport > ourlastport))
342       return (false);
343
344     // Finally we can check the hosts
345     String ourhost, theirhost;
346
347     // Get ours
348     if (hostport.indexOf(":") == -1)
349       ourhost = hostport;
350     else
351       ourhost = hostport.substring(0, hostport.indexOf(":"));
352
353     // Get theirs
354     if (p.hostport.indexOf(":") == -1)
355       theirhost = p.hostport;
356     else
357       theirhost = p.hostport.substring(0, p.hostport.indexOf(":"));
358
359     // Are they equal?
360     if (ourhost.equals(theirhost))
361       return (true);
362
363     // Try the canonical names
364     String ourcanonical = null, theircanonical = null;
365     try
366       {
367         ourcanonical = InetAddress.getByName(ourhost).getHostName();
368         theircanonical = InetAddress.getByName(theirhost).getHostName();
369       }
370     catch (UnknownHostException e)
371       {
372         // Who didn't resolve?  Just assume current address is canonical enough
373         // Is this ok to do?
374         if (ourcanonical == null)
375           ourcanonical = ourhost;
376         if (theircanonical == null)
377           theircanonical = theirhost;
378       }
379
380     if (ourcanonical.equals(theircanonical))
381       return (true);
382
383     // Well, last chance.  Try for a wildcard
384     if (ourhost.indexOf("*.") != -1)
385       {
386         String wild_domain = ourhost.substring(ourhost.indexOf("*" + 1));
387         if (theircanonical.endsWith(wild_domain))
388           return (true);
389       }
390
391     // Didn't make it
392     return (false);
393   }
394 }