History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/net/SocketPermission.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/net/SocketPermission.java+1376−0
@@ -0,0 +1,1376 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.net;
27+
28+import java.util.Enumeration;
29+import java.util.Vector;
30+import java.util.List;
31+import java.util.ArrayList;
32+import java.util.Collections;
33+import java.util.StringTokenizer;
34+import java.net.InetAddress;
35+import java.security.Permission;
36+import java.security.PermissionCollection;
37+import java.io.Serializable;
38+import java.io.ObjectStreamField;
39+import java.io.ObjectOutputStream;
40+import java.io.ObjectInputStream;
41+import java.io.IOException;
42+import sun.net.util.IPAddressUtil;
43+import sun.net.RegisteredDomain;
44+import sun.security.util.SecurityConstants;
45+import sun.security.util.Debug;
46+
47+
48+/**
49+ * This class represents access to a network via sockets.
50+ * A SocketPermission consists of a
51+ * host specification and a set of "actions" specifying ways to
52+ * connect to that host. The host is specified as
53+ * <pre>
54+ * host = (hostname | IPv4address | iPv6reference) [:portrange]
55+ * portrange = portnumber | -portnumber | portnumber-[portnumber]
56+ * </pre>
57+ * The host is expressed as a DNS name, as a numerical IP address,
58+ * or as "localhost" (for the local machine).
59+ * The wildcard "*" may be included once in a DNS name host
60+ * specification. If it is included, it must be in the leftmost
61+ * position, as in "*.sun.com".
62+ * <p>
63+ * The format of the IPv6reference should follow that specified in <a
64+ * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format
65+ * for Literal IPv6 Addresses in URLs</i></a>:
66+ * <pre>
67+ * ipv6reference = "[" IPv6address "]"
68+ *</pre>
69+ * For example, you can construct a SocketPermission instance
70+ * as the following:
71+ * <pre>
72+ * String hostAddress = inetaddress.getHostAddress();
73+ * if (inetaddress instanceof Inet6Address) {
74+ * sp = new SocketPermission("[" + hostAddress + "]:" + port, action);
75+ * } else {
76+ * sp = new SocketPermission(hostAddress + ":" + port, action);
77+ * }
78+ * </pre>
79+ * or
80+ * <pre>
81+ * String host = url.getHost();
82+ * sp = new SocketPermission(host + ":" + port, action);
83+ * </pre>
84+ * <p>
85+ * The <A HREF="Inet6Address.html#lform">full uncompressed form</A> of
86+ * an IPv6 literal address is also valid.
87+ * <p>
88+ * The port or portrange is optional. A port specification of the
89+ * form "N-", where <i>N</i> is a port number, signifies all ports
90+ * numbered <i>N</i> and above, while a specification of the
91+ * form "-N" indicates all ports numbered <i>N</i> and below.
92+ * <p>
93+ * The possible ways to connect to the host are
94+ * <pre>
95+ * accept
96+ * connect
97+ * listen
98+ * resolve
99+ * </pre>
100+ * The "listen" action is only meaningful when used with "localhost".
101+ * The "resolve" action is implied when any of the other actions are present.
102+ * The action "resolve" refers to host/ip name service lookups.
103+ * <P>
104+ * The actions string is converted to lowercase before processing.
105+ * <p>As an example of the creation and meaning of SocketPermissions,
106+ * note that if the following permission:
107+ *
108+ * <pre>
109+ * p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept");
110+ * </pre>
111+ *
112+ * is granted to some code, it allows that code to connect to port 7777 on
113+ * <code>puffin.eng.sun.com</code>, and to accept connections on that port.
114+ *
115+ * <p>Similarly, if the following permission:
116+ *
117+ * <pre>
118+ * p2 = new SocketPermission("localhost:1024-", "accept,connect,listen");
119+ * </pre>
120+ *
121+ * is granted to some code, it allows that code to
122+ * accept connections on, connect to, or listen on any port between
123+ * 1024 and 65535 on the local host.
124+ *
125+ * <p>Note: Granting code permission to accept or make connections to remote
126+ * hosts may be dangerous because malevolent code can then more easily
127+ * transfer and share confidential data among parties who may not
128+ * otherwise have access to the data.
129+ *
130+ * @see java.security.Permissions
131+ * @see SocketPermission
132+ *
133+ *
134+ * @author Marianne Mueller
135+ * @author Roland Schemers
136+ *
137+ * @serial exclude
138+ */
139+
140+public final class SocketPermission extends Permission
141+implements java.io.Serializable
142+{
143+ private static final long serialVersionUID = -7204263841984476862L;
144+
145+ /**
146+ * Connect to host:port
147+ */
148+ private final static int CONNECT = 0x1;
149+
150+ /**
151+ * Listen on host:port
152+ */
153+ private final static int LISTEN = 0x2;
154+
155+ /**
156+ * Accept a connection from host:port
157+ */
158+ private final static int ACCEPT = 0x4;
159+
160+ /**
161+ * Resolve DNS queries
162+ */
163+ private final static int RESOLVE = 0x8;
164+
165+ /**
166+ * No actions
167+ */
168+ private final static int NONE = 0x0;
169+
170+ /**
171+ * All actions
172+ */
173+ private final static int ALL = CONNECT|LISTEN|ACCEPT|RESOLVE;
174+
175+ // various port constants
176+ private static final int PORT_MIN = 0;
177+ private static final int PORT_MAX = 65535;
178+ private static final int PRIV_PORT_MAX = 1023;
179+
180+ // the actions mask
181+ private transient int mask;
182+
183+ /**
184+ * the actions string.
185+ *
186+ * @serial
187+ */
188+
189+ private String actions; // Left null as long as possible, then
190+ // created and re-used in the getAction function.
191+
192+ // hostname part as it is passed
193+ private transient String hostname;
194+
195+ // the canonical name of the host
196+ // in the case of "*.foo.com", cname is ".foo.com".
197+
198+ private transient String cname;
199+
200+ // all the IP addresses of the host
201+ private transient InetAddress[] addresses;
202+
203+ // true if the hostname is a wildcard (e.g. "*.sun.com")
204+ private transient boolean wildcard;
205+
206+ // true if we were initialized with a single numeric IP address
207+ private transient boolean init_with_ip;
208+
209+ // true if this SocketPermission represents an invalid/unknown host
210+ // used for implies when the delayed lookup has already failed
211+ private transient boolean invalid;
212+
213+ // port range on host
214+ private transient int[] portrange;
215+
216+ private transient boolean defaultDeny = false;
217+
218+ // true if this SocketPermission represents a hostname
219+ // that failed our reverse mapping heuristic test
220+ private transient boolean untrusted;
221+ private transient boolean trusted;
222+
223+ // true if the sun.net.trustNameService system property is set
224+ private static boolean trustNameService;
225+
226+ private static Debug debug = null;
227+ private static boolean debugInit = false;
228+
229+ static {
230+ Boolean tmp = java.security.AccessController.doPrivileged(
231+ new sun.security.action.GetBooleanAction("sun.net.trustNameService"));
232+ trustNameService = tmp.booleanValue();
233+ }
234+
235+ private static synchronized Debug getDebug()
236+ {
237+ if (!debugInit) {
238+ debug = Debug.getInstance("access");
239+ debugInit = true;
240+ }
241+ return debug;
242+ }
243+
244+ /**
245+ * Creates a new SocketPermission object with the specified actions.
246+ * The host is expressed as a DNS name, or as a numerical IP address.
247+ * Optionally, a port or a portrange may be supplied (separated
248+ * from the DNS name or IP address by a colon).
249+ * <p>
250+ * To specify the local machine, use "localhost" as the <i>host</i>.
251+ * Also note: An empty <i>host</i> String ("") is equivalent to "localhost".
252+ * <p>
253+ * The <i>actions</i> parameter contains a comma-separated list of the
254+ * actions granted for the specified host (and port(s)). Possible actions are
255+ * "connect", "listen", "accept", "resolve", or
256+ * any combination of those. "resolve" is automatically added
257+ * when any of the other three are specified.
258+ * <p>
259+ * Examples of SocketPermission instantiation are the following:
260+ * <pre>
261+ * nr = new SocketPermission("www.catalog.com", "connect");
262+ * nr = new SocketPermission("www.sun.com:80", "connect");
263+ * nr = new SocketPermission("*.sun.com", "connect");
264+ * nr = new SocketPermission("*.edu", "resolve");
265+ * nr = new SocketPermission("204.160.241.0", "connect");
266+ * nr = new SocketPermission("localhost:1024-65535", "listen");
267+ * nr = new SocketPermission("204.160.241.0:1024-65535", "connect");
268+ * </pre>
269+ *
270+ * @param host the hostname or IPaddress of the computer, optionally
271+ * including a colon followed by a port or port range.
272+ * @param action the action string.
273+ */
274+ public SocketPermission(String host, String action) {
275+ super(getHost(host));
276+ // name initialized to getHost(host); NPE detected in getHost()
277+ init(getName(), getMask(action));
278+ }
279+
280+
281+ SocketPermission(String host, int mask) {
282+ super(getHost(host));
283+ // name initialized to getHost(host); NPE detected in getHost()
284+ init(getName(), mask);
285+ }
286+
287+ private void setDeny() {
288+ defaultDeny = true;
289+ }
290+
291+ private static String getHost(String host)
292+ {
293+ if (host.equals("")) {
294+ return "localhost";
295+ } else {
296+ /* IPv6 literal address used in this context should follow
297+ * the format specified in RFC 2732;
298+ * if not, we try to solve the unambiguous case
299+ */
300+ int ind;
301+ if (host.charAt(0) != '[') {
302+ if ((ind = host.indexOf(':')) != host.lastIndexOf(':')) {
303+ /* More than one ":", meaning IPv6 address is not
304+ * in RFC 2732 format;
305+ * We will rectify user errors for all unambiguious cases
306+ */
307+ StringTokenizer st = new StringTokenizer(host, ":");
308+ int tokens = st.countTokens();
309+ if (tokens == 9) {
310+ // IPv6 address followed by port
311+ ind = host.lastIndexOf(':');
312+ host = "[" + host.substring(0, ind) + "]" +
313+ host.substring(ind);
314+ } else if (tokens == 8 && host.indexOf("::") == -1) {
315+ // IPv6 address only, not followed by port
316+ host = "[" + host + "]";
317+ } else {
318+ // could be ambiguous
319+ throw new IllegalArgumentException("Ambiguous"+
320+ " hostport part");
321+ }
322+ }
323+ }
324+ return host;
325+ }
326+ }
327+
328+ private int[] parsePort(String port)
329+ throws Exception
330+ {
331+
332+ if (port == null || port.equals("") || port.equals("*")) {
333+ return new int[] {PORT_MIN, PORT_MAX};
334+ }
335+
336+ int dash = port.indexOf('-');
337+
338+ if (dash == -1) {
339+ int p = Integer.parseInt(port);
340+ return new int[] {p, p};
341+ } else {
342+ String low = port.substring(0, dash);
343+ String high = port.substring(dash+1);
344+ int l,h;
345+
346+ if (low.equals("")) {
347+ l = PORT_MIN;
348+ } else {
349+ l = Integer.parseInt(low);
350+ }
351+
352+ if (high.equals("")) {
353+ h = PORT_MAX;
354+ } else {
355+ h = Integer.parseInt(high);
356+ }
357+ if (l < 0 || h < 0 || h<l)
358+ throw new IllegalArgumentException("invalid port range");
359+
360+ return new int[] {l, h};
361+ }
362+ }
363+
364+ /**
365+ * Initialize the SocketPermission object. We don't do any DNS lookups
366+ * as this point, instead we hold off until the implies method is
367+ * called.
368+ */
369+ private void init(String host, int mask) {
370+ // Set the integer mask that represents the actions
371+
372+ if ((mask & ALL) != mask)
373+ throw new IllegalArgumentException("invalid actions mask");
374+
375+ // always OR in RESOLVE if we allow any of the others
376+ this.mask = mask | RESOLVE;
377+
378+ // Parse the host name. A name has up to three components, the
379+ // hostname, a port number, or two numbers representing a port
380+ // range. "www.sun.com:8080-9090" is a valid host name.
381+
382+ // With IPv6 an address can be 2010:836B:4179::836B:4179
383+ // An IPv6 address needs to be enclose in []
384+ // For ex: [2010:836B:4179::836B:4179]:8080-9090
385+ // Refer to RFC 2732 for more information.
386+
387+ int rb = 0 ;
388+ int start = 0, end = 0;
389+ int sep = -1;
390+ String hostport = host;
391+ if (host.charAt(0) == '[') {
392+ start = 1;
393+ rb = host.indexOf(']');
394+ if (rb != -1) {
395+ host = host.substring(start, rb);
396+ } else {
397+ throw new
398+ IllegalArgumentException("invalid host/port: "+host);
399+ }
400+ sep = hostport.indexOf(':', rb+1);
401+ } else {
402+ start = 0;
403+ sep = host.indexOf(':', rb);
404+ end = sep;
405+ if (sep != -1) {
406+ host = host.substring(start, end);
407+ }
408+ }
409+
410+ if (sep != -1) {
411+ String port = hostport.substring(sep+1);
412+ try {
413+ portrange = parsePort(port);
414+ } catch (Exception e) {
415+ throw new
416+ IllegalArgumentException("invalid port range: "+port);
417+ }
418+ } else {
419+ portrange = new int[] { PORT_MIN, PORT_MAX };
420+ }
421+
422+ hostname = host;
423+
424+ // is this a domain wildcard specification
425+ if (host.lastIndexOf('*') > 0) {
426+ throw new
427+ IllegalArgumentException("invalid host wildcard specification");
428+ } else if (host.startsWith("*")) {
429+ wildcard = true;
430+ if (host.equals("*")) {
431+ cname = "";
432+ } else if (host.startsWith("*.")) {
433+ cname = host.substring(1).toLowerCase();
434+ } else {
435+ throw new
436+ IllegalArgumentException("invalid host wildcard specification");
437+ }
438+ return;
439+ } else {
440+ if (host.length() > 0) {
441+ // see if we are being initialized with an IP address.
442+ char ch = host.charAt(0);
443+ if (ch == ':' || Character.digit(ch, 16) != -1) {
444+ byte ip[] = IPAddressUtil.textToNumericFormatV4(host);
445+ if (ip == null) {
446+ ip = IPAddressUtil.textToNumericFormatV6(host);
447+ }
448+ if (ip != null) {
449+ try {
450+ addresses =
451+ new InetAddress[]
452+ {InetAddress.getByAddress(ip) };
453+ init_with_ip = true;
454+ } catch (UnknownHostException uhe) {
455+ // this shouldn't happen
456+ invalid = true;
457+ }
458+ }
459+ }
460+ }
461+ }
462+ }
463+
464+ /**
465+ * Convert an action string to an integer actions mask.
466+ *
467+ * @param action the action string
468+ * @return the action mask
469+ */
470+ private static int getMask(String action) {
471+
472+ if (action == null) {
473+ throw new NullPointerException("action can't be null");
474+ }
475+
476+ if (action.equals("")) {
477+ throw new IllegalArgumentException("action can't be empty");
478+ }
479+
480+ int mask = NONE;
481+
482+ // Check against use of constants (used heavily within the JDK)
483+ if (action == SecurityConstants.SOCKET_RESOLVE_ACTION) {
484+ return RESOLVE;
485+ } else if (action == SecurityConstants.SOCKET_CONNECT_ACTION) {
486+ return CONNECT;
487+ } else if (action == SecurityConstants.SOCKET_LISTEN_ACTION) {
488+ return LISTEN;
489+ } else if (action == SecurityConstants.SOCKET_ACCEPT_ACTION) {
490+ return ACCEPT;
491+ } else if (action == SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION) {
492+ return CONNECT|ACCEPT;
493+ }
494+
495+ char[] a = action.toCharArray();
496+
497+ int i = a.length - 1;
498+ if (i < 0)
499+ return mask;
500+
501+ while (i != -1) {
502+ char c;
503+
504+ // skip whitespace
505+ while ((i!=-1) && ((c = a[i]) == ' ' ||
506+ c == '\r' ||
507+ c == '\n' ||
508+ c == '\f' ||
509+ c == '\t'))
510+ i--;
511+
512+ // check for the known strings
513+ int matchlen;
514+
515+ if (i >= 6 && (a[i-6] == 'c' || a[i-6] == 'C') &&
516+ (a[i-5] == 'o' || a[i-5] == 'O') &&
517+ (a[i-4] == 'n' || a[i-4] == 'N') &&
518+ (a[i-3] == 'n' || a[i-3] == 'N') &&
519+ (a[i-2] == 'e' || a[i-2] == 'E') &&
520+ (a[i-1] == 'c' || a[i-1] == 'C') &&
521+ (a[i] == 't' || a[i] == 'T'))
522+ {
523+ matchlen = 7;
524+ mask |= CONNECT;
525+
526+ } else if (i >= 6 && (a[i-6] == 'r' || a[i-6] == 'R') &&
527+ (a[i-5] == 'e' || a[i-5] == 'E') &&
528+ (a[i-4] == 's' || a[i-4] == 'S') &&
529+ (a[i-3] == 'o' || a[i-3] == 'O') &&
530+ (a[i-2] == 'l' || a[i-2] == 'L') &&
531+ (a[i-1] == 'v' || a[i-1] == 'V') &&
532+ (a[i] == 'e' || a[i] == 'E'))
533+ {
534+ matchlen = 7;
535+ mask |= RESOLVE;
536+
537+ } else if (i >= 5 && (a[i-5] == 'l' || a[i-5] == 'L') &&
538+ (a[i-4] == 'i' || a[i-4] == 'I') &&
539+ (a[i-3] == 's' || a[i-3] == 'S') &&
540+ (a[i-2] == 't' || a[i-2] == 'T') &&
541+ (a[i-1] == 'e' || a[i-1] == 'E') &&
542+ (a[i] == 'n' || a[i] == 'N'))
543+ {
544+ matchlen = 6;
545+ mask |= LISTEN;
546+
547+ } else if (i >= 5 && (a[i-5] == 'a' || a[i-5] == 'A') &&
548+ (a[i-4] == 'c' || a[i-4] == 'C') &&
549+ (a[i-3] == 'c' || a[i-3] == 'C') &&
550+ (a[i-2] == 'e' || a[i-2] == 'E') &&
551+ (a[i-1] == 'p' || a[i-1] == 'P') &&
552+ (a[i] == 't' || a[i] == 'T'))
553+ {
554+ matchlen = 6;
555+ mask |= ACCEPT;
556+
557+ } else {
558+ // parse error
559+ throw new IllegalArgumentException(
560+ "invalid permission: " + action);
561+ }
562+
563+ // make sure we didn't just match the tail of a word
564+ // like "ackbarfaccept". Also, skip to the comma.
565+ boolean seencomma = false;
566+ while (i >= matchlen && !seencomma) {
567+ switch(a[i-matchlen]) {
568+ case ',':
569+ seencomma = true;
570+ /*FALLTHROUGH*/
571+ case ' ': case '\r': case '\n':
572+ case '\f': case '\t':
573+ break;
574+ default:
575+ throw new IllegalArgumentException(
576+ "invalid permission: " + action);
577+ }
578+ i--;
579+ }
580+
581+ // point i at the location of the comma minus one (or -1).
582+ i -= matchlen;
583+ }
584+
585+ return mask;
586+ }
587+
588+ private boolean isUntrusted()
589+ throws UnknownHostException
590+ {
591+ if (trusted) return false;
592+ if (invalid || untrusted) return true;
593+ try {
594+ if (!trustNameService && (defaultDeny ||
595+ sun.net.www.URLConnection.isProxiedHost(hostname))) {
596+ if (this.cname == null) {
597+ this.getCanonName();
598+ }
599+ if (!match(cname, hostname)) {
600+ // Last chance
601+ if (!authorized(hostname, addresses[0].getAddress())) {
602+ untrusted = true;
603+ Debug debug = getDebug();
604+ if (debug != null && Debug.isOn("failure")) {
605+ debug.println("socket access restriction: proxied host " + "(" + addresses[0] + ")" + " does not match " + cname + " from reverse lookup");
606+ }
607+ return true;
608+ }
609+ }
610+ trusted = true;
611+ }
612+ } catch (UnknownHostException uhe) {
613+ invalid = true;
614+ throw uhe;
615+ }
616+ return false;
617+ }
618+
619+ /**
620+ * attempt to get the fully qualified domain name
621+ *
622+ */
623+ void getCanonName()
624+ throws UnknownHostException
625+ {
626+ if (cname != null || invalid || untrusted) return;
627+
628+ // attempt to get the canonical name
629+
630+ try {
631+ // first get the IP addresses if we don't have them yet
632+ // this is because we need the IP address to then get
633+ // FQDN.
634+ if (addresses == null) {
635+ getIP();
636+ }
637+
638+ // we have to do this check, otherwise we might not
639+ // get the fully qualified domain name
640+ if (init_with_ip) {
641+ cname = addresses[0].getHostName(false).toLowerCase();
642+ } else {
643+ cname = InetAddress.getByName(addresses[0].getHostAddress()).
644+ getHostName(false).toLowerCase();
645+ }
646+ } catch (UnknownHostException uhe) {
647+ invalid = true;
648+ throw uhe;
649+ }
650+ }
651+
652+ private transient String cdomain, hdomain;
653+
654+ private boolean match(String cname, String hname) {
655+ String a = cname.toLowerCase();
656+ String b = hname.toLowerCase();
657+ if (a.startsWith(b) &&
658+ ((a.length() == b.length()) || (a.charAt(b.length()) == '.')))
659+ return true;
660+ if (cdomain == null) {
661+ cdomain = RegisteredDomain.getRegisteredDomain(a);
662+ }
663+ if (hdomain == null) {
664+ hdomain = RegisteredDomain.getRegisteredDomain(b);
665+ }
666+
667+ return cdomain.length() != 0 && hdomain.length() != 0
668+ && cdomain.equals(hdomain);
669+ }
670+
671+ private boolean authorized(String cname, byte[] addr) {
672+ if (addr.length == 4)
673+ return authorizedIPv4(cname, addr);
674+ else if (addr.length == 16)
675+ return authorizedIPv6(cname, addr);
676+ else
677+ return false;
678+ }
679+
680+ private boolean authorizedIPv4(String cname, byte[] addr) {
681+ String authHost = "";
682+ InetAddress auth;
683+
684+ try {
685+ authHost = "auth." +
686+ (addr[3] & 0xff) + "." + (addr[2] & 0xff) + "." +
687+ (addr[1] & 0xff) + "." + (addr[0] & 0xff) +
688+ ".in-addr.arpa";
689+ // Following check seems unnecessary
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+ }
696+ Debug debug = getDebug();
697+ if (debug != null && Debug.isOn("failure")) {
698+ debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr));
699+ }
700+ } catch (UnknownHostException uhe) {
701+ Debug debug = getDebug();
702+ if (debug != null && Debug.isOn("failure")) {
703+ debug.println("socket access restriction: forward lookup failed for " + authHost);
704+ }
705+ }
706+ return false;
707+ }
708+
709+ private boolean authorizedIPv6(String cname, byte[] addr) {
710+ String authHost = "";
711+ InetAddress auth;
712+
713+ try {
714+ StringBuffer sb = new StringBuffer(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 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+ }
738+ return false;
739+ }
740+
741+
742+ /**
743+ * get IP addresses. Sets invalid to true if we can't get them.
744+ *
745+ */
746+ void getIP()
747+ throws UnknownHostException
748+ {
749+ if (addresses != null || wildcard || invalid) return;
750+
751+ try {
752+ // now get all the IP addresses
753+ String host;
754+ if (getName().charAt(0) == '[') {
755+ // Literal IPv6 address
756+ host = getName().substring(1, getName().indexOf(']'));
757+ } else {
758+ int i = getName().indexOf(":");
759+ if (i == -1)
760+ host = getName();
761+ else {
762+ host = getName().substring(0,i);
763+ }
764+ }
765+
766+ addresses =
767+ new InetAddress[] {InetAddress.getAllByName0(host, false)[0]};
768+
769+ } catch (UnknownHostException uhe) {
770+ invalid = true;
771+ throw uhe;
772+ } catch (IndexOutOfBoundsException iobe) {
773+ invalid = true;
774+ throw new UnknownHostException(getName());
775+ }
776+ }
777+
778+ /**
779+ * Checks if this socket permission object "implies" the
780+ * specified permission.
781+ * <P>
782+ * More specifically, this method first ensures that all of the following
783+ * are true (and returns false if any of them are not):<p>
784+ * <ul>
785+ * <li> <i>p</i> is an instanceof SocketPermission,<p>
786+ * <li> <i>p</i>'s actions are a proper subset of this
787+ * object's actions, and<p>
788+ * <li> <i>p</i>'s port range is included in this port range. Note:
789+ * port range is ignored when p only contains the action, 'resolve'.<p>
790+ * </ul>
791+ *
792+ * Then <code>implies</code> checks each of the following, in order,
793+ * and for each returns true if the stated condition is true:<p>
794+ * <ul>
795+ * <li> If this object was initialized with a single IP address and one of <i>p</i>'s
796+ * IP addresses is equal to this object's IP address.<p>
797+ * <li>If this object is a wildcard domain (such as *.sun.com), and
798+ * <i>p</i>'s canonical name (the name without any preceding *)
799+ * ends with this object's canonical host name. For example, *.sun.com
800+ * implies *.eng.sun.com..<p>
801+ * <li>If this object was not initialized with a single IP address, and one of this
802+ * object's IP addresses equals one of <i>p</i>'s IP addresses.<p>
803+ * <li>If this canonical name equals <i>p</i>'s canonical name.<p>
804+ * </ul>
805+ *
806+ * If none of the above are true, <code>implies</code> returns false.
807+ * @param p the permission to check against.
808+ *
809+ * @return true if the specified permission is implied by this object,
810+ * false if not.
811+ */
812+
813+ public boolean implies(Permission p) {
814+ int i,j;
815+
816+ if (!(p instanceof SocketPermission))
817+ return false;
818+
819+ if (p == this)
820+ return true;
821+
822+ SocketPermission that = (SocketPermission) p;
823+
824+ return ((this.mask & that.mask) == that.mask) &&
825+ impliesIgnoreMask(that);
826+ }
827+
828+ /**
829+ * Checks if the incoming Permission's action are a proper subset of
830+ * the this object's actions.
831+ * <P>
832+ * Check, in the following order:
833+ * <ul>
834+ * <li> Checks that "p" is an instanceof a SocketPermission
835+ * <li> Checks that "p"'s actions are a proper subset of the
836+ * current object's actions.
837+ * <li> Checks that "p"'s port range is included in this port range
838+ * <li> If this object was initialized with an IP address, checks that
839+ * one of "p"'s IP addresses is equal to this object's IP address.
840+ * <li> If either object is a wildcard domain (i.e., "*.sun.com"),
841+ * attempt to match based on the wildcard.
842+ * <li> If this object was not initialized with an IP address, attempt
843+ * to find a match based on the IP addresses in both objects.
844+ * <li> Attempt to match on the canonical hostnames of both objects.
845+ * </ul>
846+ * @param p the incoming permission request
847+ *
848+ * @return true if "permission" is a proper subset of the current object,
849+ * false if not.
850+ */
851+
852+ boolean impliesIgnoreMask(SocketPermission that) {
853+ int i,j;
854+
855+ if ((that.mask & RESOLVE) != that.mask) {
856+ // check port range
857+ if ((that.portrange[0] < this.portrange[0]) ||
858+ (that.portrange[1] > this.portrange[1])) {
859+ return false;
860+ }
861+ }
862+
863+ // allow a "*" wildcard to always match anything
864+ if (this.wildcard && "".equals(this.cname))
865+ return true;
866+
867+ // return if either one of these NetPerm objects are invalid...
868+ if (this.invalid || that.invalid) {
869+ return compareHostnames(that);
870+ }
871+
872+ try {
873+ if (this.init_with_ip) { // we only check IP addresses
874+ if (that.wildcard)
875+ return false;
876+
877+ if (that.init_with_ip) {
878+ return (this.addresses[0].equals(that.addresses[0]));
879+ } else {
880+ if (that.addresses == null) {
881+ that.getIP();
882+ }
883+ for (i=0; i < that.addresses.length; i++) {
884+ if (this.addresses[0].equals(that.addresses[i]))
885+ return true;
886+ }
887+ }
888+ // since "this" was initialized with an IP address, we
889+ // don't check any other cases
890+ return false;
891+ }
892+
893+ // check and see if we have any wildcards...
894+ if (this.wildcard || that.wildcard) {
895+ // if they are both wildcards, return true iff
896+ // that's cname ends with this cname (i.e., *.sun.com
897+ // implies *.eng.sun.com)
898+ if (this.wildcard && that.wildcard)
899+ return (that.cname.endsWith(this.cname));
900+
901+ // a non-wildcard can't imply a wildcard
902+ if (that.wildcard)
903+ return false;
904+
905+ // this is a wildcard, lets see if that's cname ends with
906+ // it...
907+ if (that.cname == null) {
908+ that.getCanonName();
909+ }
910+ return (that.cname.endsWith(this.cname));
911+ }
912+
913+ // comapare IP addresses
914+ if (this.addresses == null) {
915+ this.getIP();
916+ }
917+
918+ if (that.addresses == null) {
919+ that.getIP();
920+ }
921+
922+ if (!(that.init_with_ip && this.isUntrusted())) {
923+ for (j = 0; j < this.addresses.length; j++) {
924+ for (i=0; i < that.addresses.length; i++) {
925+ if (this.addresses[j].equals(that.addresses[i]))
926+ return true;
927+ }
928+ }
929+
930+ // XXX: if all else fails, compare hostnames?
931+ // Do we really want this?
932+ if (this.cname == null) {
933+ this.getCanonName();
934+ }
935+
936+ if (that.cname == null) {
937+ that.getCanonName();
938+ }
939+
940+ return (this.cname.equalsIgnoreCase(that.cname));
941+ }
942+
943+ } catch (UnknownHostException uhe) {
944+ return compareHostnames(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 compareHostnames(SocketPermission that) {
954+ // we see if the original names/IPs passed in were equal.
955+
956+ String thisHost = hostname;
957+ String thatHost = that.hostname;
958+
959+ if (thisHost == null)
960+ return false;
961+ else
962+ return thisHost.equalsIgnoreCase(thatHost);
963+ }
964+
965+ /**
966+ * Checks two SocketPermission objects for equality.
967+ * <P>
968+ * @param obj the object to test for equality with this object.
969+ *
970+ * @return true if <i>obj</i> is a SocketPermission, and has the
971+ * same hostname, port range, and actions as this
972+ * SocketPermission object. However, port range will be ignored
973+ * in the comparison if <i>obj</i> only contains the action, 'resolve'.
974+ */
975+ public boolean equals(Object obj) {
976+ if (obj == this)
977+ return true;
978+
979+ if (! (obj instanceof SocketPermission))
980+ return false;
981+
982+ SocketPermission that = (SocketPermission) obj;
983+
984+ //this is (overly?) complex!!!
985+
986+ // check the mask first
987+ if (this.mask != that.mask) return false;
988+
989+ if ((that.mask & RESOLVE) != that.mask) {
990+ // now check the port range...
991+ if ((this.portrange[0] != that.portrange[0]) ||
992+ (this.portrange[1] != that.portrange[1])) {
993+ return false;
994+ }
995+ }
996+
997+ // short cut. This catches:
998+ // "crypto" equal to "crypto", or
999+ // "1.2.3.4" equal to "1.2.3.4.", or
1000+ // "*.edu" equal to "*.edu", but it
1001+ // does not catch "crypto" equal to
1002+ // "crypto.eng.sun.com".
1003+
1004+ if (this.getName().equalsIgnoreCase(that.getName())) {
1005+ return true;
1006+ }
1007+
1008+ // we now attempt to get the Canonical (FQDN) name and
1009+ // compare that. If this fails, about all we can do is return
1010+ // false.
1011+
1012+ try {
1013+ this.getCanonName();
1014+ that.getCanonName();
1015+ } catch (UnknownHostException uhe) {
1016+ return false;
1017+ }
1018+
1019+ if (this.invalid || that.invalid)
1020+ return false;
1021+
1022+ if (this.cname != null) {
1023+ return this.cname.equalsIgnoreCase(that.cname);
1024+ }
1025+
1026+ return false;
1027+ }
1028+
1029+ /**
1030+ * Returns the hash code value for this object.
1031+ *
1032+ * @return a hash code value for this object.
1033+ */
1034+
1035+ public int hashCode() {
1036+ /*
1037+ * If this SocketPermission was initialized with an IP address
1038+ * or a wildcard, use getName().hashCode(), otherwise use
1039+ * the hashCode() of the host name returned from
1040+ * java.net.InetAddress.getHostName method.
1041+ */
1042+
1043+ if (init_with_ip || wildcard) {
1044+ return this.getName().hashCode();
1045+ }
1046+
1047+ try {
1048+ getCanonName();
1049+ } catch (UnknownHostException uhe) {
1050+
1051+ }
1052+
1053+ if (invalid || cname == null)
1054+ return this.getName().hashCode();
1055+ else
1056+ return this.cname.hashCode();
1057+ }
1058+
1059+ /**
1060+ * Return the current action mask.
1061+ *
1062+ * @return the actions mask.
1063+ */
1064+
1065+ int getMask() {
1066+ return mask;
1067+ }
1068+
1069+ /**
1070+ * Returns the "canonical string representation" of the actions in the
1071+ * specified mask.
1072+ * Always returns present actions in the following order:
1073+ * connect, listen, accept, resolve.
1074+ *
1075+ * @param mask a specific integer action mask to translate into a string
1076+ * @return the canonical string representation of the actions
1077+ */
1078+ private static String getActions(int mask)
1079+ {
1080+ StringBuilder sb = new StringBuilder();
1081+ boolean comma = false;
1082+
1083+ if ((mask & CONNECT) == CONNECT) {
1084+ comma = true;
1085+ sb.append("connect");
1086+ }
1087+
1088+ if ((mask & LISTEN) == LISTEN) {
1089+ if (comma) sb.append(',');
1090+ else comma = true;
1091+ sb.append("listen");
1092+ }
1093+
1094+ if ((mask & ACCEPT) == ACCEPT) {
1095+ if (comma) sb.append(',');
1096+ else comma = true;
1097+ sb.append("accept");
1098+ }
1099+
1100+
1101+ if ((mask & RESOLVE) == RESOLVE) {
1102+ if (comma) sb.append(',');
1103+ else comma = true;
1104+ sb.append("resolve");
1105+ }
1106+
1107+ return sb.toString();
1108+ }
1109+
1110+ /**
1111+ * Returns the canonical string representation of the actions.
1112+ * Always returns present actions in the following order:
1113+ * connect, listen, accept, resolve.
1114+ *
1115+ * @return the canonical string representation of the actions.
1116+ */
1117+ public String getActions()
1118+ {
1119+ if (actions == null)
1120+ actions = getActions(this.mask);
1121+
1122+ return actions;
1123+ }
1124+
1125+ /**
1126+ * Returns a new PermissionCollection object for storing SocketPermission
1127+ * objects.
1128+ * <p>
1129+ * SocketPermission objects must be stored in a manner that allows them
1130+ * to be inserted into the collection in any order, but that also enables the
1131+ * PermissionCollection <code>implies</code>
1132+ * method to be implemented in an efficient (and consistent) manner.
1133+ *
1134+ * @return a new PermissionCollection object suitable for storing SocketPermissions.
1135+ */
1136+
1137+ public PermissionCollection newPermissionCollection() {
1138+ return new SocketPermissionCollection();
1139+ }
1140+
1141+ /**
1142+ * WriteObject is called to save the state of the SocketPermission
1143+ * to a stream. The actions are serialized, and the superclass
1144+ * takes care of the name.
1145+ */
1146+ private synchronized void writeObject(java.io.ObjectOutputStream s)
1147+ throws IOException
1148+ {
1149+ // Write out the actions. The superclass takes care of the name
1150+ // call getActions to make sure actions field is initialized
1151+ if (actions == null)
1152+ getActions();
1153+ s.defaultWriteObject();
1154+ }
1155+
1156+ /**
1157+ * readObject is called to restore the state of the SocketPermission from
1158+ * a stream.
1159+ */
1160+ private synchronized void readObject(java.io.ObjectInputStream s)
1161+ throws IOException, ClassNotFoundException
1162+ {
1163+ // Read in the action, then initialize the rest
1164+ s.defaultReadObject();
1165+ init(getName(),getMask(actions));
1166+ }
1167+
1168+ /*
1169+ public String toString()
1170+ {
1171+ StringBuffer s = new StringBuffer(super.toString() + "\n" +
1172+ "cname = " + cname + "\n" +
1173+ "wildcard = " + wildcard + "\n" +
1174+ "invalid = " + invalid + "\n" +
1175+ "portrange = " + portrange[0] + "," + portrange[1] + "\n");
1176+ if (addresses != null) for (int i=0; i<addresses.length; i++) {
1177+ s.append( addresses[i].getHostAddress());
1178+ s.append("\n");
1179+ } else {
1180+ s.append("(no addresses)\n");
1181+ }
1182+
1183+ return s.toString();
1184+ }
1185+
1186+ public static void main(String args[]) throws Exception {
1187+ SocketPermission this_ = new SocketPermission(args[0], "connect");
1188+ SocketPermission that_ = new SocketPermission(args[1], "connect");
1189+ System.out.println("-----\n");
1190+ System.out.println("this.implies(that) = " + this_.implies(that_));
1191+ System.out.println("-----\n");
1192+ System.out.println("this = "+this_);
1193+ System.out.println("-----\n");
1194+ System.out.println("that = "+that_);
1195+ System.out.println("-----\n");
1196+
1197+ SocketPermissionCollection nps = new SocketPermissionCollection();
1198+ nps.add(this_);
1199+ nps.add(new SocketPermission("www-leland.stanford.edu","connect"));
1200+ nps.add(new SocketPermission("www-sun.com","connect"));
1201+ System.out.println("nps.implies(that) = " + nps.implies(that_));
1202+ System.out.println("-----\n");
1203+ }
1204+ */
1205+}
1206+
1207+/**
1208+
1209+if (init'd with IP, key is IP as string)
1210+if wildcard, its the wild card
1211+else its the cname?
1212+
1213+ *
1214+ * @see java.security.Permission
1215+ * @see java.security.Permissions
1216+ * @see java.security.PermissionCollection
1217+ *
1218+ *
1219+ * @author Roland Schemers
1220+ *
1221+ * @serial include
1222+ */
1223+
1224+final class SocketPermissionCollection extends PermissionCollection
1225+implements Serializable
1226+{
1227+ // Not serialized; see serialization section at end of class
1228+ private transient List perms;
1229+
1230+ /**
1231+ * Create an empty SocketPermissions object.
1232+ *
1233+ */
1234+
1235+ public SocketPermissionCollection() {
1236+ perms = new ArrayList();
1237+ }
1238+
1239+ /**
1240+ * Adds a permission to the SocketPermissions. The key for the hash is
1241+ * the name in the case of wildcards, or all the IP addresses.
1242+ *
1243+ * @param permission the Permission object to add.
1244+ *
1245+ * @exception IllegalArgumentException - if the permission is not a
1246+ * SocketPermission
1247+ *
1248+ * @exception SecurityException - if this SocketPermissionCollection object
1249+ * has been marked readonly
1250+ */
1251+
1252+ public void add(Permission permission)
1253+ {
1254+ if (! (permission instanceof SocketPermission))
1255+ throw new IllegalArgumentException("invalid permission: "+
1256+ permission);
1257+ if (isReadOnly())
1258+ throw new SecurityException(
1259+ "attempt to add a Permission to a readonly PermissionCollection");
1260+
1261+ // optimization to ensure perms most likely to be tested
1262+ // show up early (4301064)
1263+ synchronized (this) {
1264+ perms.add(0, permission);
1265+ }
1266+ }
1267+
1268+ /**
1269+ * Check and see if this collection of permissions implies the permissions
1270+ * expressed in "permission".
1271+ *
1272+ * @param p the Permission object to compare
1273+ *
1274+ * @return true if "permission" is a proper subset of a permission in
1275+ * the collection, false if not.
1276+ */
1277+
1278+ public boolean implies(Permission permission)
1279+ {
1280+ if (! (permission instanceof SocketPermission))
1281+ return false;
1282+
1283+ SocketPermission np = (SocketPermission) permission;
1284+
1285+ int desired = np.getMask();
1286+ int effective = 0;
1287+ int needed = desired;
1288+
1289+ synchronized (this) {
1290+ int len = perms.size();
1291+ //System.out.println("implies "+np);
1292+ for (int i = 0; i < len; i++) {
1293+ SocketPermission x = (SocketPermission) perms.get(i);
1294+ //System.out.println(" trying "+x);
1295+ if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(np)) {
1296+ effective |= x.getMask();
1297+ if ((effective & desired) == desired)
1298+ return true;
1299+ needed = (desired ^ effective);
1300+ }
1301+ }
1302+ }
1303+ return false;
1304+ }
1305+
1306+ /**
1307+ * Returns an enumeration of all the SocketPermission objects in the
1308+ * container.
1309+ *
1310+ * @return an enumeration of all the SocketPermission objects.
1311+ */
1312+
1313+ public Enumeration elements() {
1314+ // Convert Iterator into Enumeration
1315+ synchronized (this) {
1316+ return Collections.enumeration(perms);
1317+ }
1318+ }
1319+
1320+ private static final long serialVersionUID = 2787186408602843674L;
1321+
1322+ // Need to maintain serialization interoperability with earlier releases,
1323+ // which had the serializable field:
1324+
1325+ //
1326+ // The SocketPermissions for this set.
1327+ // @serial
1328+ //
1329+ // private Vector permissions;
1330+
1331+ /**
1332+ * @serialField permissions java.util.Vector
1333+ * A list of the SocketPermissions for this set.
1334+ */
1335+ private static final ObjectStreamField[] serialPersistentFields = {
1336+ new ObjectStreamField("permissions", Vector.class),
1337+ };
1338+
1339+ /**
1340+ * @serialData "permissions" field (a Vector containing the SocketPermissions).
1341+ */
1342+ /*
1343+ * Writes the contents of the perms field out as a Vector for
1344+ * serialization compatibility with earlier releases.
1345+ */
1346+ private void writeObject(ObjectOutputStream out) throws IOException {
1347+ // Don't call out.defaultWriteObject()
1348+
1349+ // Write out Vector
1350+ Vector permissions = new Vector(perms.size());
1351+
1352+ synchronized (this) {
1353+ permissions.addAll(perms);
1354+ }
1355+
1356+ ObjectOutputStream.PutField pfields = out.putFields();
1357+ pfields.put("permissions", permissions);
1358+ out.writeFields();
1359+ }
1360+
1361+ /*
1362+ * Reads in a Vector of SocketPermissions and saves them in the perms field.
1363+ */
1364+ private void readObject(ObjectInputStream in) throws IOException,
1365+ ClassNotFoundException {
1366+ // Don't call in.defaultReadObject()
1367+
1368+ // Read in serialized fields
1369+ ObjectInputStream.GetField gfields = in.readFields();
1370+
1371+ // Get the one we want
1372+ Vector permissions = (Vector)gfields.get("permissions", null);
1373+ perms = new ArrayList(permissions.size());
1374+ perms.addAll(permissions);
1375+ }
1376+}