PageRenderTime 81ms CodeModel.GetById 47ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/jre-1.6.0/src/java/net/SocketPermission.java

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