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