KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > net > SocketPermission


1 /*
2  * @(#)SocketPermission.java 1.65 07/09/14
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7  
8 package java.net;
9
10 import java.util.Enumeration JavaDoc;
11 import java.util.Vector JavaDoc;
12 import java.util.List JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.Collections JavaDoc;
15 import java.util.StringTokenizer JavaDoc;
16 import java.net.InetAddress JavaDoc;
17 import java.security.Permission JavaDoc;
18 import java.security.PermissionCollection JavaDoc;
19 import java.security.Policy JavaDoc;
20 import java.io.Serializable JavaDoc;
21 import java.io.ObjectStreamField JavaDoc;
22 import java.io.ObjectOutputStream JavaDoc;
23 import java.io.ObjectInputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import sun.net.util.IPAddressUtil;
26 import sun.security.util.SecurityConstants;
27 import sun.security.util.Debug;
28
29
30 /**
31  * This class represents access to a network via sockets.
32  * A SocketPermission consists of a
33  * host specification and a set of "actions" specifying ways to
34  * connect to that host. The host is specified as
35  * <pre>
36  * host = (hostname | IPv4address | iPv6reference) [:portrange]
37  * portrange = portnumber | -portnumber | portnumber-[portnumber]
38  * </pre>
39  * The host is expressed as a DNS name, as a numerical IP address,
40  * or as "localhost" (for the local machine).
41  * The wildcard "*" may be included once in a DNS name host
42  * specification. If it is included, it must be in the leftmost
43  * position, as in "*.sun.com".
44  * <p>
45  * The format of the IPv6reference should follow that specified in <a
46  * HREF="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format
47  * for Literal IPv6 Addresses in URLs</i></a>:
48  * <pre>
49  * ipv6reference = "[" IPv6address "]"
50  *</pre>
51  * For example, you can construct a SocketPermission instance
52  * as the following:
53  * <pre>
54  * String hostAddress = inetaddress.getHostAddress();
55  * if (inetaddress instanceof Inet6Address) {
56  * sp = new SocketPermission("[" + hostAddress + "]:" + port, action);
57  * } else {
58  * sp = new SocketPermission(hostAddress + ":" + port, action);
59  * }
60  * </pre>
61  * or
62  * <pre>
63  * String host = url.getHost();
64  * sp = new SocketPermission(host + ":" + port, action);
65  * </pre>
66  * <p>
67  * The <A HREF="Inet6Address.html#lform">full uncompressed form</A> of
68  * an IPv6 literal address is also valid.
69  * <p>
70  * The port or portrange is optional. A port specification of the
71  * form "N-", where <i>N</i> is a port number, signifies all ports
72  * numbered <i>N</i> and above, while a specification of the
73  * form "-N" indicates all ports numbered <i>N</i> and below.
74  * <p>
75  * The possible ways to connect to the host are
76  * <pre>
77  * accept
78  * connect
79  * listen
80  * resolve
81  * </pre>
82  * The "listen" action is only meaningful when used with "localhost".
83  * The "resolve" action is implied when any of the other actions are present.
84  * The action "resolve" refers to host/ip name service lookups.
85  *
86  * <p>As an example of the creation and meaning of SocketPermissions,
87  * note that if the following permission:
88  *
89  * <pre>
90  * p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept");
91  * </pre>
92  *
93  * is granted to some code, it allows that code to connect to port 7777 on
94  * <code>puffin.eng.sun.com</code>, and to accept connections on that port.
95  *
96  * <p>Similarly, if the following permission:
97  *
98  * <pre>
99  * p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept");
100  * p2 = new SocketPermission("localhost:1024-", "accept,connect,listen");
101  * </pre>
102  *
103  * is granted to some code, it allows that code to
104  * accept connections on, connect to, or listen on any port between
105  * 1024 and 65535 on the local host.
106  *
107  * <p>Note: Granting code permission to accept or make connections to remote
108  * hosts may be dangerous because malevolent code can then more easily
109  * transfer and share confidential data among parties who may not
110  * otherwise have access to the data.
111  *
112  * @see java.security.Permissions
113  * @see SocketPermission
114  *
115  * @version 1.65 07/09/14
116  *
117  * @author Marianne Mueller
118  * @author Roland Schemers
119  *
120  * @serial exclude
121  */

122
123 public final class SocketPermission extends Permission JavaDoc
124 implements java.io.Serializable JavaDoc
125 {
126     private static final long serialVersionUID = -7204263841984476862L;
127
128     /**
129      * Connect to host:port
130      */

131     private final static int CONNECT = 0x1;
132
133     /**
134      * Listen on host:port
135      */

136     private final static int LISTEN = 0x2;
137
138     /**
139      * Accept a connection from host:port
140      */

141     private final static int ACCEPT = 0x4;
142
143     /**
144      * Resolve DNS queries
145      */

146     private final static int RESOLVE = 0x8;
147
148     /**
149      * No actions
150      */

151     private final static int NONE = 0x0;
152
153     /**
154      * All actions
155      */

156     private final static int ALL = CONNECT|LISTEN|ACCEPT|RESOLVE;
157
158     // various port constants
159
private static final int PORT_MIN = 0;
160     private static final int PORT_MAX = 65535;
161     private static final int PRIV_PORT_MAX = 1023;
162
163     // the actions mask
164
private transient int mask;
165
166     /**
167      * the actions string.
168      *
169      * @serial
170      */

171
172     private String JavaDoc actions; // Left null as long as possible, then
173
// created and re-used in the getAction function.
174

175     // hostname part as it is passed
176
private transient String JavaDoc hostname;
177     
178     // the canonical name of the host
179
// in the case of "*.foo.com", cname is ".foo.com".
180

181     private transient String JavaDoc cname;
182
183     // all the IP addresses of the host
184
private transient InetAddress JavaDoc[] addresses;
185
186     // true if the hostname is a wildcard (e.g. "*.sun.com")
187
private transient boolean wildcard;
188
189     // true if we were initialized with a single numeric IP address
190
private transient boolean init_with_ip;
191
192     // true if this SocketPermission represents an invalid/unknown host
193
// used for implies when the delayed lookup has already failed
194
private transient boolean invalid;
195
196     // port range on host
197
private transient int[] portrange;
198
199     private transient boolean defaultDeny = false;
200
201     // true if this SocketPermission represents a hostname
202
// that failed our reverse mapping heuristic test
203
private transient boolean untrusted;
204
205     // true if the trustProxy system property is set
206
private static boolean trustProxy;
207
208     // true if the sun.net.trustNameService system property is set
209
private static boolean trustNameService;
210
211     private static Debug debug = null;
212     private static boolean debugInit = false;
213
214     static {
215     Boolean JavaDoc tmp = (Boolean JavaDoc) java.security.AccessController.doPrivileged(
216                 new sun.security.action.GetBooleanAction("trustProxy"));
217     trustProxy = tmp.booleanValue();
218     tmp = (Boolean JavaDoc) java.security.AccessController.doPrivileged(
219                 new sun.security.action.GetBooleanAction("sun.net.trustNameService"));
220     trustNameService = tmp.booleanValue();
221     }
222
223     private static synchronized Debug getDebug()
224     {
225         if (!debugInit) {
226             debug = Debug.getInstance("access");
227             debugInit = true;
228         }
229         return debug;
230     }
231
232     /**
233      * Creates a new SocketPermission object with the specified actions.
234      * The host is expressed as a DNS name, or as a numerical IP address.
235      * Optionally, a port or a portrange may be supplied (separated
236      * from the DNS name or IP address by a colon).
237      * <p>
238      * To specify the local machine, use "localhost" as the <i>host</i>.
239      * Also note: An empty <i>host</i> String ("") is equivalent to "localhost".
240      * <p>
241      * The <i>actions</i> parameter contains a comma-separated list of the
242      * actions granted for the specified host (and port(s)). Possible actions are
243      * "connect", "listen", "accept", "resolve", or
244      * any combination of those. "resolve" is automatically added
245      * when any of the other three are specified.
246      * <p>
247      * Examples of SocketPermission instantiation are the following:
248      * <pre>
249      * nr = new SocketPermission("www.catalog.com", "connect");
250      * nr = new SocketPermission("www.sun.com:80", "connect");
251      * nr = new SocketPermission("*.sun.com", "connect");
252      * nr = new SocketPermission("*.edu", "resolve");
253      * nr = new SocketPermission("204.160.241.0", "connect");
254      * nr = new SocketPermission("localhost:1024-65535", "listen");
255      * nr = new SocketPermission("204.160.241.0:1024-65535", "connect");
256      * </pre>
257      *
258      * @param host the hostname or IPaddress of the computer, optionally
259      * including a colon followed by a port or port range.
260      * @param action the action string.
261      */

262     public SocketPermission(String JavaDoc host, String JavaDoc action) {
263     super(getHost(host));
264     // name initialized to getHost(host); NPE detected in getHost()
265
init(getName(), getMask(action));
266     }
267
268
269     SocketPermission(String JavaDoc host, int mask) {
270     super(getHost(host));
271     // name initialized to getHost(host); NPE detected in getHost()
272
init(getName(), mask);
273     }
274
275     private void setDeny() {
276     defaultDeny = true;
277     }
278
279     private static String JavaDoc getHost(String JavaDoc host)
280     {
281     if (host.equals("")) {
282         return "localhost";
283     } else {
284         /* IPv6 literal address used in this context should follow
285          * the format specified in RFC 2732;
286          * if not, we try to solve the unambiguous case
287          */

288         int ind;
289         if (host.charAt(0) != '[') {
290         if ((ind = host.indexOf(':')) != host.lastIndexOf(':')) {
291             /* More than one ":", meaning IPv6 address is not
292              * in RFC 2732 format;
293              * We will rectify user errors for all unambiguious cases
294              */

295             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(host, ":");
296             int tokens = st.countTokens();
297             if (tokens == 9) {
298             // IPv6 address followed by port
299
ind = host.lastIndexOf(':');
300             host = "[" + host.substring(0, ind) + "]" +
301                 host.substring(ind);
302             } else if (tokens == 8 && host.indexOf("::") == -1) {
303             // IPv6 address only, not followed by port
304
host = "[" + host + "]";
305             } else {
306             // could be ambiguous
307
throw new IllegalArgumentException JavaDoc("Ambiguous"+
308                                " hostport part");
309             }
310         }
311         }
312         return host;
313     }
314     }
315
316     private int[] parsePort(String JavaDoc port)
317     throws Exception JavaDoc
318     {
319
320     if (port == null || port.equals("") || port.equals("*")) {
321         return new int[] {PORT_MIN, PORT_MAX};
322     }
323
324     int dash = port.indexOf('-');
325
326     if (dash == -1) {
327         int p = Integer.parseInt(port);
328         return new int[] {p, p};
329     } else {
330         String JavaDoc low = port.substring(0, dash);
331         String JavaDoc high = port.substring(dash+1);
332         int l,h;
333
334         if (low.equals("")) {
335         l = PORT_MIN;
336         } else {
337         l = Integer.parseInt(low);
338         }
339
340         if (high.equals("")) {
341         h = PORT_MAX;
342         } else {
343         h = Integer.parseInt(high);
344         }
345         if (l < 0 || h < 0 || h<l)
346         throw new IllegalArgumentException JavaDoc("invalid port range");
347
348         return new int[] {l, h};
349     }
350     }
351
352     /**
353      * Initialize the SocketPermission object. We don't do any DNS lookups
354      * as this point, instead we hold off until the implies method is
355      * called.
356      */

357     private void init(String JavaDoc host, int mask) {
358     // Set the integer mask that represents the actions
359

360     if ((mask & ALL) != mask)
361         throw new IllegalArgumentException JavaDoc("invalid actions mask");
362
363     // always OR in RESOLVE if we allow any of the others
364
this.mask = mask | RESOLVE;
365
366     // Parse the host name. A name has up to three components, the
367
// hostname, a port number, or two numbers representing a port
368
// range. "www.sun.com:8080-9090" is a valid host name.
369

370     // With IPv6 an address can be 2010:836B:4179::836B:4179
371
// An IPv6 address needs to be enclose in []
372
// For ex: [2010:836B:4179::836B:4179]:8080-9090
373
// Refer to RFC 2732 for more information.
374

375     int rb = 0 ;
376     int start = 0, end = 0;
377     int sep = -1;
378     String JavaDoc hostport = host;
379     if (host.charAt(0) == '[') {
380         start = 1;
381         rb = host.indexOf(']');
382         if (rb != -1) {
383         host = host.substring(start, rb);
384         } else {
385         throw new
386             IllegalArgumentException JavaDoc("invalid host/port: "+host);
387         }
388         sep = hostport.indexOf(':', rb+1);
389     } else {
390         start = 0;
391         sep = host.indexOf(':', rb);
392         end = sep;
393         if (sep != -1) {
394         host = host.substring(start, end);
395         }
396     }
397     
398     if (sep != -1) {
399         String JavaDoc port = hostport.substring(sep+1);
400         try {
401         portrange = parsePort(port);
402         } catch (Exception JavaDoc e) {
403         throw new
404             IllegalArgumentException JavaDoc("invalid port range: "+port);
405         }
406     } else {
407         portrange = new int[] { PORT_MIN, PORT_MAX };
408     }
409         
410     hostname = host;
411
412     // is this a domain wildcard specification
413
if (host.lastIndexOf('*') > 0) {
414         throw new
415            IllegalArgumentException JavaDoc("invalid host wildcard specification");
416     } else if (host.startsWith("*")) {
417         wildcard = true;
418         if (host.equals("*")) {
419         cname = "";
420         } else if (host.startsWith("*.")) {
421         cname = host.substring(1).toLowerCase();
422         } else {
423           throw new
424            IllegalArgumentException JavaDoc("invalid host wildcard specification");
425         }
426         return;
427     } else {
428         if (host.length() > 0) {
429             // see if we are being initialized with an IP address.
430
char ch = host.charAt(0);
431             if (ch == ':' || Character.digit(ch, 16) != -1) {
432             byte ip[] = IPAddressUtil.textToNumericFormatV4(host);
433             if (ip == null) {
434                 ip = IPAddressUtil.textToNumericFormatV6(host);
435             }
436             if (ip != null) {
437                 try {
438                 addresses =
439                     new InetAddress JavaDoc[]
440                 {InetAddress.getByAddress(ip) };
441                 init_with_ip = true;
442                 } catch (UnknownHostException JavaDoc uhe) {
443                 // this shouldn't happen
444
invalid = true;
445             }
446             }
447         }
448         }
449     }
450     }
451
452     /**
453      * Convert an action string to an integer actions mask.
454      *
455      * @param action the action string
456      * @return the action mask
457      */

458     private static int getMask(String JavaDoc action) {
459
460     if (action == null) {
461         throw new NullPointerException JavaDoc("action can't be null");
462     }
463
464     if (action.equals("")) {
465         throw new IllegalArgumentException JavaDoc("action can't be empty");
466     }
467
468     int mask = NONE;
469
470     // Check against use of constants (used heavily within the JDK)
471
if (action == SecurityConstants.SOCKET_RESOLVE_ACTION) {
472         return RESOLVE;
473     } else if (action == SecurityConstants.SOCKET_CONNECT_ACTION) {
474         return CONNECT;
475     } else if (action == SecurityConstants.SOCKET_LISTEN_ACTION) {
476         return LISTEN;
477     } else if (action == SecurityConstants.SOCKET_ACCEPT_ACTION) {
478         return ACCEPT;
479     } else if (action == SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION) {
480         return CONNECT|ACCEPT;
481     }
482
483     char[] a = action.toCharArray();
484
485     int i = a.length - 1;
486     if (i < 0)
487         return mask;
488
489     while (i != -1) {
490         char c;
491
492         // skip whitespace
493
while ((i!=-1) && ((c = a[i]) == ' ' ||
494                    c == '\r' ||
495                    c == '\n' ||
496                    c == '\f' ||
497                    c == '\t'))
498         i--;
499
500         // check for the known strings
501
int matchlen;
502
503         if (i >= 6 && (a[i-6] == 'c' || a[i-6] == 'C') &&
504               (a[i-5] == 'o' || a[i-5] == 'O') &&
505               (a[i-4] == 'n' || a[i-4] == 'N') &&
506               (a[i-3] == 'n' || a[i-3] == 'N') &&
507               (a[i-2] == 'e' || a[i-2] == 'E') &&
508               (a[i-1] == 'c' || a[i-1] == 'C') &&
509               (a[i] == 't' || a[i] == 'T'))
510         {
511         matchlen = 7;
512         mask |= CONNECT;
513
514         } else if (i >= 6 && (a[i-6] == 'r' || a[i-6] == 'R') &&
515                  (a[i-5] == 'e' || a[i-5] == 'E') &&
516                  (a[i-4] == 's' || a[i-4] == 'S') &&
517                  (a[i-3] == 'o' || a[i-3] == 'O') &&
518                  (a[i-2] == 'l' || a[i-2] == 'L') &&
519                  (a[i-1] == 'v' || a[i-1] == 'V') &&
520                  (a[i] == 'e' || a[i] == 'E'))
521         {
522         matchlen = 7;
523         mask |= RESOLVE;
524
525         } else if (i >= 5 && (a[i-5] == 'l' || a[i-5] == 'L') &&
526                  (a[i-4] == 'i' || a[i-4] == 'I') &&
527                  (a[i-3] == 's' || a[i-3] == 'S') &&
528                  (a[i-2] == 't' || a[i-2] == 'T') &&
529                  (a[i-1] == 'e' || a[i-1] == 'E') &&
530                  (a[i] == 'n' || a[i] == 'N'))
531         {
532         matchlen = 6;
533         mask |= LISTEN;
534
535         } else if (i >= 5 && (a[i-5] == 'a' || a[i-5] == 'A') &&
536                  (a[i-4] == 'c' || a[i-4] == 'C') &&
537                  (a[i-3] == 'c' || a[i-3] == 'C') &&
538                  (a[i-2] == 'e' || a[i-2] == 'E') &&
539                  (a[i-1] == 'p' || a[i-1] == 'P') &&
540                  (a[i] == 't' || a[i] == 'T'))
541         {
542         matchlen = 6;
543         mask |= ACCEPT;
544
545         } else {
546         // parse error
547
throw new IllegalArgumentException JavaDoc(
548             "invalid permission: " + action);
549         }
550
551         // make sure we didn't just match the tail of a word
552
// like "ackbarfaccept". Also, skip to the comma.
553
boolean seencomma = false;
554         while (i >= matchlen && !seencomma) {
555         switch(a[i-matchlen]) {
556         case ',':
557             seencomma = true;
558             /*FALLTHROUGH*/
559         case ' ': case '\r': case '\n':
560         case '\f': case '\t':
561             break;
562         default:
563             throw new IllegalArgumentException JavaDoc(
564                 "invalid permission: " + action);
565         }
566         i--;
567         }
568
569         // point i at the location of the comma minus one (or -1).
570
i -= matchlen;
571     }
572
573     return mask;
574     }
575
576     /**
577      * attempt to get the fully qualified domain name
578      *
579      */

580     void getCanonName()
581     throws UnknownHostException JavaDoc
582     {
583     if (cname != null || invalid || untrusted) return;
584
585     // attempt to get the canonical name
586

587     try {
588         // first get the IP addresses if we don't have them yet
589
// this is because we need the IP address to then get
590
// FQDN.
591
if (addresses == null) {
592         getIP();
593         }
594
595         // we have to do this check, otherwise we might not
596
// get the fully qualified domain name
597
if (init_with_ip) {
598         cname = addresses[0].getHostName(false).toLowerCase();
599         } else {
600             cname = InetAddress.getByName(addresses[0].getHostAddress()).
601                                               getHostName(false).toLowerCase();
602             if (!trustNameService && sun.net.www.URLConnection.isProxiedHost(hostname)) {
603             if (!match(cname, hostname) &&
604             (defaultDeny || !cname.equals(addresses[0].getHostAddress()))) {
605             // Last chance
606
if (!authorized(hostname, addresses[0].getAddress())) {
607                 untrusted = true;
608                 Debug debug = getDebug();
609                 if (debug != null && Debug.isOn("failure")) {
610                 debug.println("socket access restriction: proxied host " + "(" + addresses[0] + ")" + " does not match " + cname + " from reverse lookup");
611                 }
612             }
613             }
614         }
615         }
616     } catch (UnknownHostException JavaDoc uhe) {
617         invalid = true;
618         throw uhe;
619     }
620     }
621
622     private boolean match(String JavaDoc cname, String JavaDoc hname) {
623     String JavaDoc a = cname.toLowerCase();
624     String JavaDoc b = hname.toLowerCase();
625     if (a.startsWith(b) &&
626         ((a.length() == b.length()) || (a.charAt(b.length()) == '.')))
627         return true;
628     if (b.endsWith(".akamai.net") || b.endsWith(".akamai.com"))
629         return true;
630     String JavaDoc af = fragment(a);
631     String JavaDoc bf = fragment(b);
632     return af.length() != 0 && bf.length() != 0 && fragment(a).equals(fragment(b));
633     }
634
635
636     // www.sun.com. -> sun.com
637
// www.sun.co.uk -> sun.co.uk
638
// www.sun.com.au -> sun.com.au
639
private String JavaDoc fragment(String JavaDoc cname) {
640         int dot;
641         dot = cname.lastIndexOf('.');
642         if (dot == -1)
643         return cname;
644         if (dot == 0)
645             return "";
646         if (dot == cname.length() - 1) {
647             cname = cname.substring(0, cname.length() -1);
648             dot = cname.lastIndexOf('.');
649         }
650         if (dot < 1)
651             return "";
652         int second = cname.lastIndexOf('.', dot - 1);
653         if (second == -1)
654             return cname;
655         if (((cname.length() - dot) <= 3) && ((dot - second) <= 4) && second > 0) {
656         if (dot - second == 4) {
657         String JavaDoc s = cname.substring(second + 1, dot);
658         if (!(s.equals("com") || s.equals("org") || s.equals("edu"))) {
659                 return cname.substring(second + 1);
660         }
661         }
662             int third = cname.lastIndexOf('.', second - 1);
663             if (third == -1)
664             return cname.substring(second + 1);
665             else
666                 return cname.substring(third + 1);
667         }
668         return cname.substring(second + 1);
669     }
670
671
672     private boolean authorized(String JavaDoc cname, byte[] addr) {
673     if (addr.length == 4)
674         return authorizedIPv4(cname, addr);
675     else if (addr.length == 16)
676         return authorizedIPv6(cname, addr);
677     else
678         return false;
679     }
680
681     private boolean authorizedIPv4(String JavaDoc cname, byte[] addr) {
682         String JavaDoc authHost = "";
683         InetAddress JavaDoc auth;
684
685     try {
686             authHost = "auth." +
687             (addr[3] & 0xff) + "." + (addr[2] & 0xff) + "." +
688             (addr[1] & 0xff) + "." + (addr[0] & 0xff) +
689             ".in-addr.arpa";
690         //auth = InetAddress.getAllByName0(authHost, false)[0];
691
authHost = hostname + '.' + authHost;
692         auth = InetAddress.getAllByName0(authHost, false)[0];
693         if (auth.equals(InetAddress.getByAddress(addr)))
694             return true;
695         Debug debug = getDebug();
696         if (debug != null && Debug.isOn("failure")) {
697         debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr));
698         }
699     } catch (UnknownHostException JavaDoc uhe) {
700         Debug debug = getDebug();
701         if (debug != null && Debug.isOn("failure")) {
702         debug.println("socket access restriction: forward lookup failed for " + authHost);
703         }
704     } catch (IOException JavaDoc x) {
705     }
706     return false;
707     }
708
709     private boolean authorizedIPv6(String JavaDoc cname, byte[] addr) {
710         String JavaDoc authHost = "";
711         InetAddress JavaDoc auth;
712
713     try {
714             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(39);
715
716             for (int i = 15; i >= 0; i--) {
717                 sb.append(Integer.toHexString(((addr[i]) & 0x0f)));
718                 sb.append('.');
719                 sb.append(Integer.toHexString(((addr[i] >> 4) & 0x0f)));
720                 sb.append('.');
721             }
722             authHost = "auth." + sb.toString() + "IP6.ARPA";
723         //auth = InetAddress.getAllByName0(authHost, false)[0];
724
authHost = hostname + '.' + authHost;
725         auth = InetAddress.getAllByName0(authHost, false)[0];
726         if (auth.equals(InetAddress.getByAddress(addr)))
727             return true;
728         Debug debug = getDebug();
729         if (debug != null && Debug.isOn("failure")) {
730         debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr));
731         }
732     } catch (UnknownHostException JavaDoc uhe) {
733         Debug debug = getDebug();
734         if (debug != null && Debug.isOn("failure")) {
735         debug.println("socket access restriction: forward lookup failed for " + authHost);
736         }
737     } catch (IOException JavaDoc x) {
738     }
739     return false;
740     }
741
742
743     /**
744      * get IP addresses. Sets invalid to true if we can't get them.
745      *
746      */

747     void getIP()
748     throws UnknownHostException JavaDoc
749     {
750     if (addresses != null || wildcard || invalid) return;
751
752     try {
753         // now get all the IP addresses
754
String JavaDoc host;
755         if (getName().charAt(0) == '[') {
756         // Literal IPv6 address
757
host = getName().substring(1, getName().indexOf(']'));
758         } else {
759         int i = getName().indexOf(":");
760         if (i == -1)
761             host = getName();
762         else {
763             host = getName().substring(0,i);
764         }
765         }
766
767         addresses =
768         new InetAddress JavaDoc[] {InetAddress.getAllByName0(host, false)[0]};
769
770     } catch (UnknownHostException JavaDoc uhe) {
771         invalid = true;
772         throw uhe;
773     } catch (IndexOutOfBoundsException JavaDoc iobe) {
774         invalid = true;
775         throw new UnknownHostException JavaDoc(getName());
776     }
777     }
778
779     /**
780      * Checks if this socket permission object "implies" the
781      * specified permission.
782      * <P>
783      * More specifically, this method first ensures that all of the following
784      * are true (and returns false if any of them are not):<p>
785      * <ul>
786      * <li> <i>p</i> is an instanceof SocketPermission,<p>
787      * <li> <i>p</i>'s actions are a proper subset of this
788      * object's actions, and<p>
789      * <li> <i>p</i>'s port range is included in this port range. Note:
790      * port range is ignored when p only contains the action, 'resolve'.<p>
791      * </ul>
792      *
793      * Then <code>implies</code> checks each of the following, in order,
794      * and for each returns true if the stated condition is true:<p>
795      * <ul>
796      * <li> If this object was initialized with a single IP address and one of <i>p</i>'s
797      * IP addresses is equal to this object's IP address.<p>
798      * <li>If this object is a wildcard domain (such as *.sun.com), and
799      * <i>p</i>'s canonical name (the name without any preceding *)
800      * ends with this object's canonical host name. For example, *.sun.com
801      * implies *.eng.sun.com..<p>
802      * <li>If this object was not initialized with a single IP address, and one of this
803      * object's IP addresses equals one of <i>p</i>'s IP addresses.<p>
804      * <li>If this canonical name equals <i>p</i>'s canonical name.<p>
805      * </ul>
806      *
807      * If none of the above are true, <code>implies</code> returns false.
808      * @param p the permission to check against.
809      *
810      * @return true if the specified permission is implied by this object,
811      * false if not.
812      */

813
814     public boolean implies(Permission JavaDoc p) {
815     int i,j;
816
817     if (!(p instanceof SocketPermission JavaDoc))
818         return false;
819
820     SocketPermission JavaDoc that = (SocketPermission JavaDoc) p;
821
822     return ((this.mask & that.mask) == that.mask) &&
823                                     impliesIgnoreMask(that);
824     }
825
826     /**
827      * Checks if the incoming Permission's action are a proper subset of
828      * the this object's actions.
829      * <P>
830      * Check, in the following order:
831      * <ul>
832      * <li> Checks that "p" is an instanceof a SocketPermission
833      * <li> Checks that "p"'s actions are a proper subset of the
834      * current object's actions.
835      * <li> Checks that "p"'s port range is included in this port range
836      * <li> If this object was initialized with an IP address, checks that
837      * one of "p"'s IP addresses is equal to this object's IP address.
838      * <li> If either object is a wildcard domain (i.e., "*.sun.com"),
839      * attempt to match based on the wildcard.
840      * <li> If this object was not initialized with an IP address, attempt
841      * to find a match based on the IP addresses in both objects.
842      * <li> Attempt to match on the canonical hostnames of both objects.
843      * </ul>
844      * @param p the incoming permission request
845      *
846      * @return true if "permission" is a proper subset of the current object,
847      * false if not.
848      */

849
850     boolean impliesIgnoreMask(SocketPermission JavaDoc that) {
851     int i,j;
852
853     if ((that.mask & RESOLVE) != that.mask) {
854         // check port range
855
if ((that.portrange[0] < this.portrange[0]) ||
856             (that.portrange[1] > this.portrange[1])) {
857             return false;
858         }
859     }
860
861     // allow a "*" wildcard to always match anything
862
if (this.wildcard && "".equals(this.cname))
863         return true;
864
865     // return if either one of these NetPerm objects are invalid...
866
if (this.invalid || that.invalid) {
867         return (trustProxy ? inProxyWeTrust(that) : false);
868     }
869
870
871     try {
872         if (this.init_with_ip) { // we only check IP addresses
873
if (that.wildcard)
874             return false;
875
876         if (that.init_with_ip) {
877             return (this.addresses[0].equals(that.addresses[0]));
878         } else {
879             if (that.addresses == null) {
880             that.getIP();
881             }
882             for (i=0; i < that.addresses.length; i++) {
883             if (this.addresses[0].equals(that.addresses[i]))
884                 return true;
885             }
886         }
887         // since "this" was initialized with an IP address, we
888
// don't check any other cases
889
return false;
890         }
891
892         // check and see if we have any wildcards...
893
if (this.wildcard || that.wildcard) {
894         // if they are both wildcards, return true iff
895
// that's cname ends with this cname (i.e., *.sun.com
896
// implies *.eng.sun.com)
897
if (this.wildcard && that.wildcard)
898             return (that.cname.endsWith(this.cname));
899
900         // a non-wildcard can't imply a wildcard
901
if (that.wildcard)
902             return false;
903
904         // this is a wildcard, lets see if that's cname ends with
905
// it...
906
if (that.cname == null) {
907             that.getCanonName();
908         }
909         return (that.cname.endsWith(this.cname));
910         }
911
912         if (this.cname == null) {
913         this.getCanonName();
914         }
915
916         // comapare IP addresses
917
if (this.addresses == null) {
918         this.getIP();
919         }
920
921         if (that.addresses == null) {
922         that.getIP();
923         }
924
925         if (!(that.init_with_ip && this.untrusted)) {
926             for (j = 0; j < this.addresses.length; j++) {
927             for (i=0; i < that.addresses.length; i++) {
928                 if (this.addresses[j].equals(that.addresses[i]))
929                 return true;
930             }
931             }
932
933             // XXX: if all else fails, compare hostnames?
934
// Do we really want this?
935
if (that.cname == null) {
936             that.getCanonName();
937             }
938
939             return (this.cname.equalsIgnoreCase(that.cname));
940         }
941
942     } catch (UnknownHostException JavaDoc uhe) {
943         if (trustProxy)
944         return inProxyWeTrust(that);
945     }
946
947     // make sure the first thing that is done here is to return
948
// false. If not, uncomment the return false in the above catch.
949

950     return false;
951     }
952
953     private boolean inProxyWeTrust(SocketPermission JavaDoc that) {
954     // if we trust the proxy, we see if the original names/IPs passed
955
// in were equal.
956

957     String JavaDoc thisHost = hostname;
958     String JavaDoc thatHost = that.hostname;
959
960     if (thisHost == null)
961         return false;
962     else
963         return thisHost.equalsIgnoreCase(thatHost);
964
965     }
966     /**
967      * Checks two SocketPermission objects for equality.
968      * <P>
969      * @param obj the object to test for equality with this object.
970      *
971      * @return true if <i>obj</i> is a SocketPermission, and has the
972      * same hostname, port range, and actions as this
973      * SocketPermission object. However, port range will be ignored
974      * in the comparison if <i>obj</i> only contains the action, 'resolve'.
975      */

976     public boolean equals(Object JavaDoc obj) {
977     if (obj == this)
978         return true;
979
980     if (! (obj instanceof SocketPermission JavaDoc))
981         return false;
982
983     SocketPermission JavaDoc that = (SocketPermission JavaDoc) obj;
984
985     //this is (overly?) complex!!!
986

987     // check the mask first
988
if (this.mask != that.mask) return false;
989
990     if ((that.mask & RESOLVE) != that.mask) {
991         // now check the port range...
992
if ((this.portrange[0] != that.portrange[0]) ||
993         (this.portrange[1] != that.portrange[1])) {
994         return false;
995         }
996     }
997
998     // short cut. This catches:
999
// "crypto" equal to "crypto", or
1000
// "1.2.3.4" equal to "1.2.3.4.", or
1001
// "*.edu" equal to "*.edu", but it
1002
// does not catch "crypto" equal to
1003
// "crypto.eng.sun.com".
1004

1005    if (this.getName().equalsIgnoreCase(that.getName())) {
1006        return true;
1007    }
1008
1009    // we now attempt to get the Canonical (FQDN) name and
1010
// compare that. If this fails, about all we can do is return
1011
// false.
1012

1013    try {
1014        this.getCanonName();
1015        that.getCanonName();
1016    } catch (UnknownHostException JavaDoc uhe) {
1017        return false;
1018    }
1019
1020    if (this.invalid || that.invalid)
1021        return false;
1022
1023    if (this.cname != null) {
1024        return this.cname.equalsIgnoreCase(that.cname);
1025    }
1026
1027    return false;
1028    }
1029
1030    /**
1031     * Returns the hash code value for this object.
1032     *
1033     * @return a hash code value for this object.
1034     */

1035
1036    public int hashCode() {
1037    /*
1038     * If this SocketPermission was initialized with an IP address
1039     * or a wildcard, use getName().hashCode(), otherwise use
1040     * the hashCode() of the host name returned from
1041     * java.net.InetAddress.getHostName method.
1042     */

1043
1044    if (init_with_ip || wildcard) {
1045        return this.getName().hashCode();
1046    }
1047
1048    try {
1049        getCanonName();
1050    } catch (UnknownHostException JavaDoc uhe) {
1051
1052    }
1053
1054    if (invalid || cname == null)
1055        return this.getName().hashCode();
1056    else
1057        return this.cname.hashCode();
1058    }
1059
1060    /**
1061     * Return the current action mask.
1062     *
1063     * @return the actions mask.
1064     */

1065
1066    int getMask() {
1067    return mask;
1068    }
1069
1070    /**
1071     * Returns the "canonical string representation" of the actions in the
1072     * specified mask.
1073     * Always returns present actions in the following order:
1074     * connect, listen, accept, resolve.
1075     *
1076     * @param mask a specific integer action mask to translate into a string
1077     * @return the canonical string representation of the actions
1078     */

1079    private static String JavaDoc getActions(int mask)
1080    {
1081    StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
1082        boolean comma = false;
1083
1084    if ((mask & CONNECT) == CONNECT) {
1085        comma = true;
1086        sb.append("connect");
1087    }
1088
1089    if ((mask & LISTEN) == LISTEN) {
1090        if (comma) sb.append(',');
1091            else comma = true;
1092        sb.append("listen");
1093    }
1094
1095    if ((mask & ACCEPT) == ACCEPT) {
1096        if (comma) sb.append(',');
1097            else comma = true;
1098        sb.append("accept");
1099    }
1100
1101
1102    if ((mask & RESOLVE) == RESOLVE) {
1103        if (comma) sb.append(',');
1104            else comma = true;
1105        sb.append("resolve");
1106    }
1107
1108    return sb.toString();
1109    }
1110
1111    /**
1112     * Returns the canonical string representation of the actions.
1113     * Always returns present actions in the following order:
1114     * connect, listen, accept, resolve.
1115     *
1116     * @return the canonical string representation of the actions.
1117     */

1118    public String JavaDoc getActions()
1119    {
1120    if (actions == null)
1121        actions = getActions(this.mask);
1122
1123    return actions;
1124    }
1125
1126    /**
1127     * Returns a new PermissionCollection object for storing SocketPermission
1128     * objects.
1129     * <p>
1130     * SocketPermission objects must be stored in a manner that allows them
1131     * to be inserted into the collection in any order, but that also enables the
1132     * PermissionCollection <code>implies</code>
1133     * method to be implemented in an efficient (and consistent) manner.
1134     *
1135     * @return a new PermissionCollection object suitable for storing SocketPermissions.
1136     */

1137
1138    public PermissionCollection JavaDoc newPermissionCollection() {
1139    return new SocketPermissionCollection();
1140    }
1141
1142    /**
1143     * WriteObject is called to save the state of the SocketPermission
1144     * to a stream. The actions are serialized, and the superclass
1145     * takes care of the name.
1146     */

1147    private synchronized void writeObject(java.io.ObjectOutputStream JavaDoc s)
1148        throws IOException JavaDoc
1149    {
1150    // Write out the actions. The superclass takes care of the name
1151
// call getActions to make sure actions field is initialized
1152
if (actions == null)
1153        getActions();
1154    s.defaultWriteObject();
1155    }
1156
1157    /**
1158     * readObject is called to restore the state of the SocketPermission from
1159     * a stream.
1160     */

1161    private synchronized void readObject(java.io.ObjectInputStream JavaDoc s)
1162         throws IOException JavaDoc, ClassNotFoundException JavaDoc
1163    {
1164    // Read in the action, then initialize the rest
1165
s.defaultReadObject();
1166    init(getName(),getMask(actions));
1167    }
1168
1169    /*
1170    public String toString()
1171    {
1172    StringBuffer s = new StringBuffer(super.toString() + "\n" +
1173        "cname = " + cname + "\n" +
1174        "wildcard = " + wildcard + "\n" +
1175        "invalid = " + invalid + "\n" +
1176            "portrange = " + portrange[0] + "," + portrange[1] + "\n");
1177    if (addresses != null) for (int i=0; i<addresses.length; i++) {
1178        s.append( addresses[i].getHostAddress());
1179        s.append("\n");
1180    } else {
1181        s.append("(no addresses)\n");
1182    }
1183
1184    return s.toString();
1185    }
1186
1187    public static void main(String args[]) throws Exception {
1188    SocketPermission this_ = new SocketPermission(args[0], "connect");
1189    SocketPermission that_ = new SocketPermission(args[1], "connect");
1190    System.out.println("-----\n");
1191    System.out.println("this.implies(that) = " + this_.implies(that_));
1192    System.out.println("-----\n");
1193    System.out.println("this = "+this_);
1194    System.out.println("-----\n");
1195    System.out.println("that = "+that_);
1196    System.out.println("-----\n");
1197
1198    SocketPermissionCollection nps = new SocketPermissionCollection();
1199    nps.add(this_);
1200    nps.add(new SocketPermission("www-leland.stanford.edu","connect"));
1201    nps.add(new SocketPermission("www-sun.com","connect"));
1202    System.out.println("nps.implies(that) = " + nps.implies(that_));
1203    System.out.println("-----\n");
1204    }
1205    */

1206}
1207
1208/**
1209
1210if (init'd with IP, key is IP as string)
1211if wildcard, its the wild card
1212else its the cname?
1213
1214 *
1215 * @see java.security.Permission
1216 * @see java.security.Permissions
1217 * @see java.security.PermissionCollection
1218 *
1219 * @version 1.65 09/14/07
1220 *
1221 * @author Roland Schemers
1222 *
1223 * @serial include
1224 */

1225
1226final class SocketPermissionCollection extends PermissionCollection JavaDoc
1227implements Serializable JavaDoc
1228{
1229    // Not serialized; see serialization section at end of class
1230
private transient List JavaDoc perms;
1231
1232    /**
1233     * Create an empty SocketPermissions object.
1234     *
1235     */

1236
1237    public SocketPermissionCollection() {
1238    perms = new ArrayList JavaDoc();
1239    }
1240
1241    /**
1242     * Adds a permission to the SocketPermissions. The key for the hash is
1243     * the name in the case of wildcards, or all the IP addresses.
1244     *
1245     * @param permission the Permission object to add.
1246     *
1247     * @exception IllegalArgumentException - if the permission is not a
1248     * SocketPermission
1249     *
1250     * @exception SecurityException - if this SocketPermissionCollection object
1251     * has been marked readonly
1252     */

1253
1254    public void add(Permission JavaDoc permission)
1255    {
1256    if (! (permission instanceof SocketPermission JavaDoc))
1257        throw new IllegalArgumentException JavaDoc("invalid permission: "+
1258                           permission);
1259    if (isReadOnly())
1260        throw new SecurityException JavaDoc(
1261        "attempt to add a Permission to a readonly PermissionCollection");
1262
1263    // optimization to ensure perms most likely to be tested
1264
// show up early (4301064)
1265
synchronized (this) {
1266        perms.add(0, permission);
1267    }
1268    }
1269
1270    /**
1271     * Check and see if this collection of permissions implies the permissions
1272     * expressed in "permission".
1273     *
1274     * @param p the Permission object to compare
1275     *
1276     * @return true if "permission" is a proper subset of a permission in
1277     * the collection, false if not.
1278     */

1279
1280    public boolean implies(Permission JavaDoc permission)
1281    {
1282    if (! (permission instanceof SocketPermission JavaDoc))
1283        return false;
1284
1285    SocketPermission JavaDoc np = (SocketPermission JavaDoc) permission;
1286
1287    int desired = np.getMask();
1288    int effective = 0;
1289    int needed = desired;
1290
1291    synchronized (this) {
1292        int len = perms.size();
1293        //System.out.println("implies "+np);
1294
for (int i = 0; i < len; i++) {
1295        SocketPermission JavaDoc x = (SocketPermission JavaDoc) perms.get(i);
1296        //System.out.println(" trying "+x);
1297
if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(np)) {
1298            effective |= x.getMask();
1299            if ((effective & desired) == desired)
1300            return true;
1301            needed = (desired ^ effective);
1302        }
1303        }
1304    }
1305    return false;
1306    }
1307
1308    /**
1309     * Returns an enumeration of all the SocketPermission objects in the
1310     * container.
1311     *
1312     * @return an enumeration of all the SocketPermission objects.
1313     */

1314
1315    public Enumeration JavaDoc elements() {
1316        // Convert Iterator into Enumeration
1317
synchronized (this) {
1318        return Collections.enumeration(perms);
1319    }
1320    }
1321
1322    private static final long serialVersionUID = 2787186408602843674L;
1323
1324    // Need to maintain serialization interoperability with earlier releases,
1325
// which had the serializable field:
1326

1327    //
1328
// The SocketPermissions for this set.
1329
// @serial
1330
//
1331
// private Vector permissions;
1332

1333    /**
1334     * @serialField permissions java.util.Vector
1335     * A list of the SocketPermissions for this set.
1336     */

1337    private static final ObjectStreamField JavaDoc[] serialPersistentFields = {
1338        new ObjectStreamField JavaDoc("permissions", Vector JavaDoc.class),
1339    };
1340
1341    /**
1342     * @serialData "permissions" field (a Vector containing the SocketPermissions).
1343     */

1344    /*
1345     * Writes the contents of the perms field out as a Vector for
1346     * serialization compatibility with earlier releases.
1347     */

1348    private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
1349    // Don't call out.defaultWriteObject()
1350

1351    // Write out Vector
1352
Vector JavaDoc permissions = new Vector JavaDoc(perms.size());
1353
1354    synchronized (this) {
1355        permissions.addAll(perms);
1356    }
1357
1358        ObjectOutputStream.PutField JavaDoc pfields = out.putFields();
1359        pfields.put("permissions", permissions);
1360        out.writeFields();
1361    }
1362
1363    /*
1364     * Reads in a Vector of SocketPermissions and saves them in the perms field.
1365     */

1366    private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc,
1367    ClassNotFoundException JavaDoc {
1368    // Don't call in.defaultReadObject()
1369

1370    // Read in serialized fields
1371
ObjectInputStream.GetField JavaDoc gfields = in.readFields();
1372
1373    // Get the one we want
1374
Vector JavaDoc permissions = (Vector JavaDoc)gfields.get("permissions", null);
1375    perms = new ArrayList JavaDoc(permissions.size());
1376    perms.addAll(permissions);
1377    }
1378}
1379
Popular Tags