OSDN Git Service

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