1. /*
  2. * @(#)SocketPermission.java 1.30 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN 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.Hashtable;
  11. import java.util.StringTokenizer;
  12. import java.net.InetAddress;
  13. import java.security.Permission;
  14. import java.security.PermissionCollection;
  15. import java.io.Serializable;
  16. import java.io.IOException;
  17. /**
  18. * This class represents access to a network via sockets.
  19. * A SocketPermission consists of a
  20. * host specification and a set of "actions" specifying ways to
  21. * connect to that host. The host is specified as
  22. * <pre>
  23. * host = (hostname | IPaddress)[:portrange]
  24. * portrange = portnumber | -portnumber | portnumber-[portnumber]
  25. * </pre>
  26. * The host is expressed as a DNS name, as a numerical IP address,
  27. * or as "localhost" (for the local machine).
  28. * The wildcard "*" may be included once in a DNS name host
  29. * specification. If it is included, it must be in the leftmost
  30. * position, as in "*.sun.com".
  31. * <p>
  32. * The port or portrange is optional. A port specification of the
  33. * form "N-", where <i>N</i> is a port number, signifies all ports
  34. * numbered <i>N</i> and above, while a specification of the
  35. * form "-N" indicates all ports numbered <i>N</i> and below.
  36. * <p>
  37. * The possible ways to connect to the host are
  38. * <pre>
  39. * accept
  40. * connect
  41. * listen
  42. * resolve
  43. * </pre>
  44. * The "listen" action is only meaningful when used with "localhost".
  45. * The "resolve" (resolve host/ip name service lookups) action is implied
  46. * when any of the other actions are present.
  47. *
  48. * <p>As an example of the creation and meaning of SocketPermissions,
  49. * note that if the following permission:
  50. *
  51. * <pre>
  52. * p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept");
  53. * </pre>
  54. *
  55. * is granted to some code, it allows that code to connect to port 7777 on
  56. * <code>puffin.eng.sun.com</code>, and to accept connections on that port.
  57. *
  58. * <p>Similarly, if the following permission:
  59. *
  60. * <pre>
  61. * p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept");
  62. * p2 = new SocketPermission("localhost:1024-", "accept,connect,listen");
  63. * </pre>
  64. *
  65. * is granted to some code, it allows that code to
  66. * accept connections on, connect to, or listen on any port between
  67. * 1024 and 65535 on the local host.
  68. *
  69. * <p>Note: Granting code permission to accept or make connections to remote
  70. * hosts may be dangerous because malevolent code can then more easily
  71. * transfer and share confidential data among parties who may not
  72. * otherwise have access to the data.
  73. *
  74. * @see Permissions
  75. * @see SocketPermissions
  76. *
  77. * @version 1.30 01/11/29
  78. *
  79. * @author Marianne Mueller
  80. * @author Roland Schemers
  81. */
  82. public final class SocketPermission extends Permission
  83. implements java.io.Serializable
  84. {
  85. /**
  86. * Connect to host:port
  87. */
  88. private final static int CONNECT = 0x1;
  89. /**
  90. * Listen on host:port
  91. */
  92. private final static int LISTEN = 0x2;
  93. /**
  94. * Accept a connection from host:port
  95. */
  96. private final static int ACCEPT = 0x4;
  97. /**
  98. * Resolve DNS queries
  99. */
  100. private final static int RESOLVE = 0x8;
  101. /**
  102. * No actions
  103. */
  104. private final static int NONE = 0x0;
  105. /**
  106. * All actions
  107. */
  108. private final static int ALL = CONNECT|LISTEN|ACCEPT|RESOLVE;
  109. // various port constants
  110. private static final int PORT_MIN = 0;
  111. private static final int PORT_MAX = 65535;
  112. private static final int PRIV_PORT_MAX = 1023;
  113. // the actions mask
  114. private transient int mask;
  115. /**
  116. * the actions string.
  117. *
  118. * @serial
  119. */
  120. private String actions; // Left null as long as possible, then
  121. // created and re-used in the getAction function.
  122. // the canonical name of the host
  123. // in the case of "*.foo.com", cname is ".foo.com".
  124. private transient String cname;
  125. // all the IP addresses of the host
  126. private transient InetAddress[] addresses;
  127. // true if the hostname is a wildcard (e.g. "*.sun.com")
  128. private transient boolean wildcard;
  129. // true if we were initialized with a single numeric IP address
  130. private transient boolean init_with_ip;
  131. // true if this SocketPermission represents an invalid/unknown host
  132. // used for implies when the delayed lookup has already failed
  133. private transient boolean invalid;
  134. // port range on host
  135. private transient int[] portrange;
  136. // true if the trustProxy system property is set
  137. private static boolean trustProxy;
  138. static {
  139. Boolean tmp = (Boolean) java.security.AccessController.doPrivileged(
  140. new sun.security.action.GetBooleanAction("trustProxy"));
  141. trustProxy = tmp.booleanValue();
  142. }
  143. /**
  144. * Creates a new SocketPermission object with the specified actions.
  145. * The host is expressed as a DNS name, or as a numerical IP address.
  146. * Optionally, a port or a portrange may be supplied (separated
  147. * from the DNS name or IP address by a colon).
  148. * <p>
  149. * To specify the local machine, use "localhost" as the <i>host</i>.
  150. * Also note: An empty <i>host</i> String ("") is equivalent to "localhost".
  151. * <p>
  152. * The <i>actions</i> parameter contains a comma-separated list of the
  153. * actions granted for the specified host (and port(s)). Possible actions are
  154. * "connect", "listen", "accept", "resolve", or
  155. * any combination of those. "resolve" is automatically added
  156. * when any of the other three are specified.
  157. * <p>
  158. * Examples of SocketPermission instantiation are the following:
  159. * <pre>
  160. * nr = new SocketPermission("www.catalog.com", "connect");
  161. * nr = new SocketPermission("www.sun.com:80", "connect");
  162. * nr = new SocketPermission("*.sun.com", "connect");
  163. * nr = new SocketPermission("*.edu", "resolve");
  164. * nr = new SocketPermission("204.160.241.0", "connect");
  165. * nr = new SocketPermission("localhost:1024-65535", "listen");
  166. * nr = new SocketPermission("204.160.241.0:1024-65535", "connect");
  167. * </pre>
  168. *
  169. * @param host the hostname or IPaddress of the computer, optionally
  170. * including a colon followed by a port or port range.
  171. * @param action the action string.
  172. */
  173. public SocketPermission(String host, String action) {
  174. super(getHost(host));
  175. init(host, getMask(action));
  176. }
  177. SocketPermission(String host, int mask) {
  178. super(getHost(host));
  179. init(host, mask);
  180. }
  181. private static String getHost(String host)
  182. {
  183. if (host.equals(""))
  184. return "localhost";
  185. else
  186. return host;
  187. }
  188. private boolean isDottedIP(String host)
  189. {
  190. char[] h = host.toCharArray();
  191. int n = h.length - 1;
  192. int components = 0;
  193. if (n > -1 && h[0] == '.')
  194. return false;
  195. while (n != -1) {
  196. char c0, c1, c2;
  197. c0 = h[n];
  198. if (n < 2) {
  199. c2 = '.';
  200. if (n == 1) {
  201. c1 = h[0];
  202. } else {
  203. c1 = '.';
  204. }
  205. n = -1;
  206. } else {
  207. c1 = h[n-1];
  208. if (c1 == '.') {
  209. c2 = '.';
  210. n -= 2;
  211. } else {
  212. c2 = h[n-2];
  213. if (c2 == '.') {
  214. n -= 3;
  215. } else {
  216. if ((n-3) != -1) {
  217. if (h[n-3] != '.')
  218. return false;
  219. n -= 4;
  220. } else
  221. n -= 3;
  222. }
  223. }
  224. }
  225. if (c0 < '0' || c0 > '9' ||
  226. (c1 < '0' && c1 != '.') || c1 > '9' ||
  227. (c2 < '0' && c2 != '.') || c2 > '2' ||
  228. (c2 == '2' && (c1 > '5' || (c1 == '5' && c0 > '5'))))
  229. return false;
  230. components++;
  231. }
  232. return (components == 4);
  233. }
  234. private int[] parsePort(String port)
  235. throws Exception
  236. {
  237. if (port == null || port.equals("") || port.equals("*")) {
  238. return new int[] {PORT_MIN, PORT_MAX};
  239. }
  240. int dash = port.indexOf('-');
  241. if (dash == -1) {
  242. int p = Integer.parseInt(port);
  243. return new int[] {p, p};
  244. } else {
  245. String low = port.substring(0, dash);
  246. String high = port.substring(dash+1);
  247. int l,h;
  248. if (low.equals("")) {
  249. l = PORT_MIN;
  250. } else {
  251. l = Integer.parseInt(low);
  252. }
  253. if (high.equals("")) {
  254. h = PORT_MAX;
  255. } else {
  256. h = Integer.parseInt(high);
  257. }
  258. if (h<l)
  259. throw new IllegalArgumentException("invalid port range");
  260. return new int[] {l, h};
  261. }
  262. }
  263. /**
  264. * Initialize the SocketPermission object. We don't do any DNS lookups
  265. * as this point, instead we hold off until the implies method is
  266. * called.
  267. */
  268. private void init(String host, int mask) {
  269. if (host == null)
  270. throw new NullPointerException("host can't be null");
  271. host = getHost(host);
  272. // Set the integer mask that represents the actions
  273. if ((mask & ALL) != mask)
  274. throw new IllegalArgumentException("invalid actions mask");
  275. // always OR in RESOLVE if we allow any of the others
  276. this.mask = mask | RESOLVE;
  277. // Parse the host name. A name has up to three components, the
  278. // hostname, a port number, or two numbers representing a port
  279. // range. "www.sun.com:8080-9090" is a valid host name.
  280. int sep = host.indexOf(':');
  281. if (sep != -1) {
  282. String port = host.substring(sep+1);
  283. host = host.substring(0, sep);
  284. try {
  285. portrange = parsePort(port);
  286. } catch (Exception e) {
  287. throw new
  288. IllegalArgumentException("invalid port range: "+port);
  289. }
  290. } else {
  291. portrange = new int[] { PORT_MIN, PORT_MAX };
  292. }
  293. // is this a domain wildcard specification
  294. if (host.startsWith("*")) {
  295. wildcard = true;
  296. if (host.equals("*")) {
  297. cname = "";
  298. } else if (host.startsWith("*.")) {
  299. cname = host.substring(1).toLowerCase();
  300. } else {
  301. throw new
  302. IllegalArgumentException("invalid host wildcard specification");
  303. }
  304. return;
  305. } else {
  306. // see if we are being initialized with an IP address.
  307. if (isDottedIP(host)) {
  308. try {
  309. addresses =
  310. new InetAddress[] {InetAddress.getByName(host) };
  311. init_with_ip = true;
  312. } catch (UnknownHostException uhe) {
  313. // this shouldn't happen
  314. invalid = true;
  315. }
  316. }
  317. }
  318. }
  319. /**
  320. * Convert an action string to an integer actions mask.
  321. *
  322. * @param action the action string
  323. * @return the action mask
  324. */
  325. private static int getMask(String action) {
  326. if (action == null) {
  327. throw new NullPointerException("action can't be null");
  328. }
  329. if (action.equals("")) {
  330. throw new IllegalArgumentException("action can't be empty");
  331. }
  332. int mask = NONE;
  333. if (action == null) {
  334. return mask;
  335. }
  336. char[] a = action.toCharArray();
  337. int i = a.length - 1;
  338. if (i < 0)
  339. return mask;
  340. while (i != -1) {
  341. char c;
  342. // skip whitespace
  343. while ((i!=-1) && ((c = a[i]) == ' ' ||
  344. c == '\r' ||
  345. c == '\n' ||
  346. c == '\f' ||
  347. c == '\t'))
  348. i--;
  349. // check for the known strings
  350. int matchlen;
  351. if (i >= 6 && (a[i-6] == 'c' || a[i-6] == 'C') &&
  352. (a[i-5] == 'o' || a[i-5] == 'O') &&
  353. (a[i-4] == 'n' || a[i-4] == 'N') &&
  354. (a[i-3] == 'n' || a[i-3] == 'N') &&
  355. (a[i-2] == 'e' || a[i-2] == 'E') &&
  356. (a[i-1] == 'c' || a[i-1] == 'C') &&
  357. (a[i] == 't' || a[i] == 'T'))
  358. {
  359. matchlen = 7;
  360. mask |= CONNECT;
  361. } else if (i >= 6 && (a[i-6] == 'r' || a[i-6] == 'R') &&
  362. (a[i-5] == 'e' || a[i-5] == 'E') &&
  363. (a[i-4] == 's' || a[i-4] == 'S') &&
  364. (a[i-3] == 'o' || a[i-3] == 'O') &&
  365. (a[i-2] == 'l' || a[i-2] == 'L') &&
  366. (a[i-1] == 'v' || a[i-1] == 'V') &&
  367. (a[i] == 'e' || a[i] == 'E'))
  368. {
  369. matchlen = 7;
  370. mask |= RESOLVE;
  371. } else if (i >= 5 && (a[i-5] == 'l' || a[i-5] == 'L') &&
  372. (a[i-4] == 'i' || a[i-4] == 'I') &&
  373. (a[i-3] == 's' || a[i-3] == 'S') &&
  374. (a[i-2] == 't' || a[i-2] == 'T') &&
  375. (a[i-1] == 'e' || a[i-1] == 'E') &&
  376. (a[i] == 'n' || a[i] == 'N'))
  377. {
  378. matchlen = 6;
  379. mask |= LISTEN;
  380. } else if (i >= 5 && (a[i-5] == 'a' || a[i-5] == 'A') &&
  381. (a[i-4] == 'c' || a[i-4] == 'C') &&
  382. (a[i-3] == 'c' || a[i-3] == 'C') &&
  383. (a[i-2] == 'e' || a[i-2] == 'E') &&
  384. (a[i-1] == 'p' || a[i-1] == 'P') &&
  385. (a[i] == 't' || a[i] == 'T'))
  386. {
  387. matchlen = 6;
  388. mask |= ACCEPT;
  389. } else {
  390. // parse error
  391. throw new IllegalArgumentException(
  392. "invalid permission: " + action);
  393. }
  394. // make sure we didn't just match the tail of a word
  395. // like "ackbarfaccept". Also, skip to the comma.
  396. boolean seencomma = false;
  397. while (i >= matchlen && !seencomma) {
  398. switch(a[i-matchlen]) {
  399. case ',':
  400. seencomma = true;
  401. /*FALLTHROUGH*/
  402. case ' ': case '\r': case '\n':
  403. case '\f': case '\t':
  404. break;
  405. default:
  406. throw new IllegalArgumentException(
  407. "invalid permission: " + action);
  408. }
  409. i--;
  410. }
  411. // point i at the location of the comma minus one (or -1).
  412. i -= matchlen;
  413. }
  414. return mask;
  415. }
  416. /**
  417. * attempt to get the fully qualified domain name
  418. *
  419. */
  420. void getCanonName()
  421. throws UnknownHostException
  422. {
  423. if (cname != null || invalid) return;
  424. // attempt to get the canonical name
  425. try {
  426. // first get the IP addresses if we don't have them yet
  427. // this is because we need the IP address to then get
  428. // FQDN.
  429. if (addresses == null) {
  430. getIP();
  431. }
  432. // we have to do this check, otherwise we might not
  433. // get the fully qualified domain name
  434. if (init_with_ip) {
  435. cname = addresses[0].getHostName(false).toLowerCase();
  436. } else {
  437. cname = InetAddress.getByName(addresses[0].getHostAddress()).
  438. getHostName(false).toLowerCase();
  439. }
  440. } catch (UnknownHostException uhe) {
  441. invalid = true;
  442. throw uhe;
  443. }
  444. }
  445. /**
  446. * get IP addresses. Sets invalid to true if we can't get them.
  447. *
  448. */
  449. void getIP()
  450. throws UnknownHostException
  451. {
  452. if (addresses != null || wildcard || invalid) return;
  453. try {
  454. // now get all the IP addresses
  455. String host;
  456. int i = getName().indexOf(":");
  457. if (i == -1)
  458. host = getName();
  459. else {
  460. host = getName().substring(0,i);
  461. }
  462. addresses =
  463. new InetAddress[] {InetAddress.getAllByName0(host, false)[0]};
  464. } catch (UnknownHostException uhe) {
  465. invalid = true;
  466. throw uhe;
  467. }
  468. }
  469. /**
  470. * Checks if this socket permission object "implies" the
  471. * specified permission.
  472. * <P>
  473. * More specifically, this method first ensures that all of the following
  474. * are true (and returns false if any of them are not):<p>
  475. * <ul>
  476. * <li> <i>p</i> is an instanceof SocketPermission,<p>
  477. * <li> <i>p</i>'s actions are a proper subset of this
  478. * object's actions, and<p>
  479. * <li> <i>p</i>'s port range is included in this port range.<p>
  480. * </ul>
  481. *
  482. * Then <code>implies</code> checks each of the following, in order,
  483. * and for each returns true if the stated condition is true:<p>
  484. * <ul>
  485. * <li> If this object was initialized with a single IP address and one of <i>p</i>'s
  486. * IP addresses is equal to this object's IP address.<p>
  487. * <li>If this object is a wildcard domain (such as *.sun.com), and
  488. * <i>p</i>'s canonical name (the name without any preceding *)
  489. * ends with this object's canonical host name. For example, *.sun.com
  490. * implies *.eng.sun.com..<p>
  491. * <li>If this object was not initialized with a single IP address, and one of this
  492. * object's IP addresses equals one of <i>p</i>'s IP addresses.<p>
  493. * <li>If this canonical name equals <i>p</i>'s canonical name.<p>
  494. * </ul>
  495. *
  496. * If none of the above are true, <code>implies</code> returns false.
  497. * @param p the permission to check against.
  498. *
  499. * @return true if the specified permission is implied by this object,
  500. * false if not.
  501. */
  502. public boolean implies(Permission p) {
  503. int i,j;
  504. if (!(p instanceof SocketPermission))
  505. return false;
  506. SocketPermission that = (SocketPermission) p;
  507. return ((this.mask & that.mask) == that.mask) &&
  508. impliesIgnoreMask(that);
  509. }
  510. /**
  511. * Checks if the incoming Permission's action are a proper subset of
  512. * the this object's actions.
  513. * <P>
  514. * Check, in the following order:
  515. * <ul>
  516. * <li> Checks that "p" is an instanceof a SocketPermission
  517. * <li> Checks that "p"'s actions are a proper subset of the
  518. * current object's actions.
  519. * <li> Checks that "p"'s port range is included in this port range
  520. * <li> If this object was initialized with an IP address, checks that
  521. * one of "p"'s IP addresses is equal to this object's IP address.
  522. * <li> If either object is a wildcard domain (i.e., "*.sun.com"),
  523. * attempt to match based on the wildcard.
  524. * <li> If this object was not initialized with an IP address, attempt
  525. * to find a match based on the IP addresses in both objects.
  526. * <li> Attempt to match on the canonical hostnames of both objects.
  527. * </ul>
  528. * @param p the incoming permission request
  529. *
  530. * @return true if "permission" is a proper subset of the current object,
  531. * false if not.
  532. */
  533. boolean impliesIgnoreMask(SocketPermission that) {
  534. int i,j;
  535. if ((that.mask & RESOLVE) != that.mask) {
  536. // check port range
  537. if ((that.portrange[0] < this.portrange[0]) ||
  538. (that.portrange[1] > this.portrange[1])) {
  539. return false;
  540. }
  541. }
  542. // allow a "*" wildcard to always match anything
  543. if (this.wildcard && this.getName().equals("*"))
  544. return true;
  545. // return if either one of these NetPerm objects are invalid...
  546. if (this.invalid || that.invalid) {
  547. return (trustProxy ? inProxyWeTrust(that) : false);
  548. }
  549. try {
  550. if (this.init_with_ip) { // we only check IP addresses
  551. if (that.wildcard)
  552. return false;
  553. if (that.init_with_ip) {
  554. return (this.addresses[0].equals(that.addresses[0]));
  555. } else {
  556. if (that.addresses == null) {
  557. that.getIP();
  558. }
  559. for (i=0; i < that.addresses.length; i++) {
  560. if (this.addresses[0].equals(that.addresses[i]))
  561. return true;
  562. }
  563. }
  564. // since "this" was initialized with an IP address, we
  565. // don't check any other cases
  566. return false;
  567. }
  568. // check and see if we have any wildcards...
  569. if (this.wildcard || that.wildcard) {
  570. // if they are both wildcards, return true iff
  571. // that's cname ends with this cname (i.e., *.sun.com
  572. // implies *.eng.sun.com)
  573. if (this.wildcard && that.wildcard)
  574. return (that.cname.endsWith(this.cname));
  575. // a non-wildcard can't imply a wildcard
  576. if (that.wildcard)
  577. return false;
  578. // this is a wildcard, lets see if that's cname ends with
  579. // it...
  580. if (that.cname == null) {
  581. that.getCanonName();
  582. }
  583. return (that.cname.endsWith(this.cname));
  584. }
  585. // comapare IP addresses
  586. if (this.addresses == null) {
  587. this.getIP();
  588. }
  589. if (that.addresses == null) {
  590. that.getIP();
  591. }
  592. for (j = 0; j < this.addresses.length; j++) {
  593. for (i=0; i < that.addresses.length; i++) {
  594. if (this.addresses[j].equals(that.addresses[i]))
  595. return true;
  596. }
  597. }
  598. // XXX: if all else fails, compare hostnames?
  599. // Do we really want this?
  600. if (this.cname == null) {
  601. this.getCanonName();
  602. }
  603. if (that.cname == null) {
  604. that.getCanonName();
  605. }
  606. return (this.cname.equalsIgnoreCase(that.cname));
  607. } catch (UnknownHostException uhe) {
  608. if (trustProxy)
  609. return inProxyWeTrust(that);
  610. }
  611. // make sure the first thing that is done here is to return
  612. // false. If not, uncomment the return false in the above catch.
  613. return false;
  614. }
  615. private boolean inProxyWeTrust(SocketPermission that) {
  616. // if we trust the proxy, we see if the original names/IPs passed
  617. // in were equal.
  618. String thisHost = getName();
  619. String thatHost = that.getName();
  620. int sep = thisHost.indexOf(':');
  621. if (sep != -1)
  622. thisHost = thisHost.substring(0, sep);
  623. sep = thatHost.indexOf(':');
  624. if (sep != -1)
  625. thatHost = thatHost.substring(0, sep);
  626. if (thisHost == null)
  627. return false;
  628. else
  629. return thisHost.equalsIgnoreCase(thatHost);
  630. }
  631. /**
  632. * Checks two SocketPermission objects for equality.
  633. * <P>
  634. * @param obj the object to test for equality with this object.
  635. *
  636. * @return true if <i>obj</i> is a SocketPermission, and has the same hostname,
  637. * port range, and
  638. * actions as this SocketPermission object.
  639. */
  640. public boolean equals(Object obj) {
  641. if (obj == this)
  642. return true;
  643. if (! (obj instanceof SocketPermission))
  644. return false;
  645. SocketPermission that = (SocketPermission) obj;
  646. //this is (overly?) complex!!!
  647. // check the mask first
  648. if (this.mask != that.mask) return false;
  649. // now check the port range...
  650. if ((this.portrange[0] != that.portrange[0]) ||
  651. (this.portrange[1] != that.portrange[1])) {
  652. return false;
  653. }
  654. // short cut. This catches:
  655. // "crypto" equal to "crypto", or
  656. // "1.2.3.4" equal to "1.2.3.4.", or
  657. // "*.edu" equal to "*.edu", but it
  658. // does not catch "crypto" equal to
  659. // "crypto.eng.sun.com".
  660. if (this.getName().equalsIgnoreCase(that.getName())) {
  661. return true;
  662. }
  663. // we now attempt to get the Canonical (FQDN) name and
  664. // compare that. If this fails, about all we can do is return
  665. // false.
  666. try {
  667. this.getCanonName();
  668. that.getCanonName();
  669. } catch (UnknownHostException uhe) {
  670. return false;
  671. }
  672. if (this.invalid || that.invalid)
  673. return false;
  674. if (this.cname != null) {
  675. return this.cname.equalsIgnoreCase(that.cname);
  676. }
  677. return false;
  678. }
  679. /**
  680. * Returns the hash code value for this object.
  681. *
  682. * @return a hash code value for this object.
  683. */
  684. public int hashCode() {
  685. /*
  686. * If this SocketPermission was initialized with an IP address
  687. * or a wildcard, use getName().hashCode(), otherwise use
  688. * the hashCode() of the host name returned from
  689. * java.net.InetAddress.getHostName method.
  690. */
  691. if (init_with_ip || wildcard) {
  692. return this.getName().hashCode();
  693. }
  694. try {
  695. getCanonName();
  696. } catch (UnknownHostException uhe) {
  697. }
  698. if (invalid || cname == null)
  699. return this.getName().hashCode();
  700. else
  701. return this.cname.hashCode();
  702. }
  703. /**
  704. * Return the current action mask.
  705. *
  706. * @return the actions mask.
  707. */
  708. int getMask() {
  709. return mask;
  710. }
  711. /**
  712. * Returns the "canonical string representation" of the actions in the
  713. * specified mask.
  714. * Always returns present actions in the following order:
  715. * connect, listen, accept, resolve.
  716. *
  717. * @param mask a specific integer action mask to translate into a string
  718. * @return the canonical string representation of the actions
  719. */
  720. private static String getActions(int mask)
  721. {
  722. StringBuffer sb = new StringBuffer();
  723. boolean comma = false;
  724. if ((mask & CONNECT) == CONNECT) {
  725. comma = true;
  726. sb.append("connect");
  727. }
  728. if ((mask & LISTEN) == LISTEN) {
  729. if (comma) sb.append(',');
  730. else comma = true;
  731. sb.append("listen");
  732. }
  733. if ((mask & ACCEPT) == ACCEPT) {
  734. if (comma) sb.append(',');
  735. else comma = true;
  736. sb.append("accept");
  737. }
  738. if ((mask & RESOLVE) == RESOLVE) {
  739. if (comma) sb.append(',');
  740. else comma = true;
  741. sb.append("resolve");
  742. }
  743. return sb.toString();
  744. }
  745. /**
  746. * Returns the canonical string representation of the actions.
  747. * Always returns present actions in the following order:
  748. * connect, listen, accept, resolve.
  749. *
  750. * @return the canonical string representation of the actions.
  751. */
  752. public String getActions()
  753. {
  754. if (actions == null)
  755. actions = getActions(this.mask);
  756. return actions;
  757. }
  758. /**
  759. * Returns a new PermissionCollection object for storing SocketPermission
  760. * objects.
  761. * <p>
  762. * SocketPermission objects must be stored in a manner that allows them
  763. * to be inserted into the collection in any order, but that also enables the
  764. * PermissionCollection <code>implies</code>
  765. * method to be implemented in an efficient (and consistent) manner.
  766. *
  767. * @return a new PermissionCollection object suitable for storing SocketPermissions.
  768. */
  769. public PermissionCollection newPermissionCollection() {
  770. return new SocketPermissionCollection();
  771. }
  772. /**
  773. * WriteObject is called to save the state of the SocketPermission
  774. * to a stream. The actions are serialized, and the superclass
  775. * takes care of the name.
  776. */
  777. private synchronized void writeObject(java.io.ObjectOutputStream s)
  778. throws IOException
  779. {
  780. // Write out the actions. The superclass takes care of the name
  781. // call getActions to make sure actions field is initialized
  782. if (actions == null)
  783. getActions();
  784. s.defaultWriteObject();
  785. }
  786. /**
  787. * readObject is called to restore the state of the SocketPermission from
  788. * a stream.
  789. */
  790. private synchronized void readObject(java.io.ObjectInputStream s)
  791. throws IOException, ClassNotFoundException
  792. {
  793. // Read in the action, then initialize the rest
  794. s.defaultReadObject();
  795. init(getName(),getMask(actions));
  796. }
  797. /*
  798. public String toString()
  799. {
  800. StringBuffer s = new StringBuffer(super.toString() + "\n" +
  801. "cname = " + cname + "\n" +
  802. "wildcard = " + wildcard + "\n" +
  803. "invalid = " + invalid + "\n" +
  804. "portrange = " + portrange[0] + "," + portrange[1] + "\n");
  805. if (addresses != null) for (int i=0; i<addresses.length; i++) {
  806. s.append( addresses[i].getHostAddress());
  807. s.append("\n");
  808. } else {
  809. s.append("(no addresses)\n");
  810. }
  811. return s.toString();
  812. }
  813. public static void main(String args[]) throws Exception {
  814. SocketPermission this_ = new SocketPermission(args[0], "connect");
  815. SocketPermission that_ = new SocketPermission(args[1], "connect");
  816. System.out.println("-----\n");
  817. System.out.println("this.implies(that) = " + this_.implies(that_));
  818. System.out.println("-----\n");
  819. System.out.println("this = "+this_);
  820. System.out.println("-----\n");
  821. System.out.println("that = "+that_);
  822. System.out.println("-----\n");
  823. SocketPermissionCollection nps = new SocketPermissionCollection();
  824. nps.add(this_);
  825. nps.add(new SocketPermission("www-leland.stanford.edu","connect"));
  826. nps.add(new SocketPermission("www-sun.com","connect"));
  827. System.out.println("nps.implies(that) = " + nps.implies(that_));
  828. System.out.println("-----\n");
  829. }
  830. */
  831. }
  832. /**
  833. if (init'd with IP, key is IP as string)
  834. if wildcard, its the wild card
  835. else its the cname?
  836. *
  837. * @see java.security.Permission
  838. * @see java.security.Permissions
  839. * @see java.security.PermissionCollection
  840. *
  841. * @version 1.30 02/10/07
  842. *
  843. * @author Roland Schemers
  844. */
  845. final class SocketPermissionCollection extends PermissionCollection
  846. implements Serializable
  847. {
  848. /**
  849. * The SocketPermissions for this set.
  850. */
  851. private Vector permissions;
  852. /**
  853. * Create an empty SocketPermissions object.
  854. *
  855. */
  856. public SocketPermissionCollection() {
  857. permissions = new Vector();
  858. }
  859. /**
  860. * Adds a permission to the SocketPermissions. The key for the hash is
  861. * the name in the case of wildcards, or all the IP addresses.
  862. *
  863. * @param permission the Permission object to add.
  864. */
  865. public void add(Permission permission)
  866. {
  867. if (! (permission instanceof SocketPermission))
  868. throw new IllegalArgumentException("invalid permission: "+
  869. permission);
  870. if (isReadOnly())
  871. throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection");
  872. // optimization to ensure perms most likely to be tested
  873. // show up early (4301064)
  874. permissions.add(0, permission);
  875. }
  876. /**
  877. * Check and see if this collection of permissions implies the permissions
  878. * expressed in "permission".
  879. *
  880. * @param p the Permission object to compare
  881. *
  882. * @return true if "permission" is a proper subset of a permission in
  883. * the collection, false if not.
  884. */
  885. public boolean implies(Permission permission)
  886. {
  887. if (! (permission instanceof SocketPermission))
  888. return false;
  889. SocketPermission np = (SocketPermission) permission;
  890. int desired = np.getMask();
  891. int effective = 0;
  892. int needed = desired;
  893. Enumeration e = permissions.elements();
  894. //System.out.println("implies "+np);
  895. while (e.hasMoreElements()) {
  896. SocketPermission x = (SocketPermission) e.nextElement();
  897. //System.out.println(" trying "+x);
  898. if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(np)) {
  899. effective |= x.getMask();
  900. if ((effective & desired) == desired)
  901. return true;
  902. needed = (desired ^ effective);
  903. }
  904. }
  905. return false;
  906. }
  907. /**
  908. * Returns an enumeration of all the SocketPermission objects in the
  909. * container.
  910. *
  911. * @return an enumeration of all the SocketPermission objects.
  912. */
  913. public Enumeration elements()
  914. {
  915. return permissions.elements();
  916. }
  917. }