1. /*
  2. * @(#)PolicyParser.java 1.37 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.security.auth;
  8. import java.io.*;
  9. import java.lang.RuntimePermission;
  10. import java.net.MalformedURLException;
  11. import java.net.SocketPermission;
  12. import java.net.URL;
  13. import java.util.Enumeration;
  14. import java.util.Hashtable;
  15. import java.util.LinkedList;
  16. import java.util.ListIterator;
  17. import java.util.Vector;
  18. import java.util.StringTokenizer;
  19. import java.security.GeneralSecurityException;
  20. import sun.security.util.PropertyExpander;
  21. /**
  22. * The policy for a Java runtime (specifying
  23. * which permissions are available for code from various principals)
  24. * is represented as a separate
  25. * persistent configuration. The configuration may be stored as a
  26. * flat ASCII file, as a serialized binary file of
  27. * the Policy class, or as a database. <p>
  28. *
  29. * <p>The Java runtime creates one global Policy object, which is used to
  30. * represent the static policy configuration file. It is consulted by
  31. * a ProtectionDomain when the protection domain initializes its set of
  32. * permissions. <p>
  33. *
  34. * <p>The Policy <code>init</code> method parses the policy
  35. * configuration file, and then
  36. * populates the Policy object. The Policy object is agnostic in that
  37. * it is not involved in making policy decisions. It is merely the
  38. * Java runtime representation of the persistent policy configuration
  39. * file. <p>
  40. *
  41. * <p>When a protection domain needs to initialize its set of
  42. * permissions, it executes code such as the following
  43. * to ask the global Policy object to populate a
  44. * Permissions object with the appropriate permissions:
  45. * <pre>
  46. * policy = Policy.getPolicy();
  47. * Permissions perms = policy.getPermissions(MyCodeSource)
  48. * </pre>
  49. *
  50. * <p>The protection domain passes in a CodeSource
  51. * object, which encapsulates its codebase (URL) and public key attributes.
  52. * The Policy object evaluates the global policy in light of who the
  53. * principal is and returns an appropriate Permissions object.
  54. *
  55. * deprecated As of JDK 1.4, replaced by
  56. * {@link sun.security.provider.PolicyParser}.
  57. * This class is entirely deprecated.
  58. *
  59. * @version 1.37, 01/23/03
  60. * @author Roland Schemers
  61. *
  62. * @since JDK1.2
  63. */
  64. class PolicyParser {
  65. private static final java.util.ResourceBundle rb =
  66. (java.util.ResourceBundle)java.security.AccessController.doPrivileged
  67. (new java.security.PrivilegedAction() {
  68. public Object run() {
  69. return (java.util.ResourceBundle.getBundle
  70. ("sun.security.util.AuthResources"));
  71. }
  72. });
  73. private Vector grantEntries;
  74. // Convenience variables for parsing
  75. private static final sun.security.util.Debug debug =
  76. sun.security.util.Debug.getInstance("parser", "\t[Auth Policy Parser]");
  77. private StreamTokenizer st;
  78. private int lookahead;
  79. private int linenum;
  80. private boolean expandProp = false;
  81. private String keyStoreUrlString = null; // unexpanded
  82. private String keyStoreType = null;
  83. private String expand(String value)
  84. throws PropertyExpander.ExpandException
  85. {
  86. if (expandProp)
  87. return PropertyExpander.expand(value);
  88. else
  89. return value;
  90. }
  91. /**
  92. * Creates a PolicyParser object.
  93. */
  94. public PolicyParser() {
  95. grantEntries = new Vector();
  96. }
  97. public PolicyParser(boolean expandProp) {
  98. this();
  99. this.expandProp = expandProp;
  100. }
  101. /**
  102. * Reads a policy configuration into the Policy object using a
  103. * Reader object. <p>
  104. *
  105. * @param policy the policy Reader object.
  106. *
  107. * @exception ParsingException if the policy configuration contains
  108. * a syntax error.
  109. *
  110. * @exception IOException if an error occurs while reading the policy
  111. * configuration.
  112. */
  113. public void read(Reader policy)
  114. throws ParsingException, IOException
  115. {
  116. if (!(policy instanceof BufferedReader)) {
  117. policy = new BufferedReader(policy);
  118. }
  119. /**
  120. * Configure the stream tokenizer:
  121. * Recognize strings between "..."
  122. * Don't convert words to lowercase
  123. * Recognize both C-style and C++-style comments
  124. * Treat end-of-line as white space, not as a token
  125. */
  126. st = new StreamTokenizer(policy);
  127. st.resetSyntax();
  128. st.wordChars('a', 'z');
  129. st.wordChars('A', 'Z');
  130. st.wordChars('.', '.');
  131. st.wordChars('0', '9');
  132. st.wordChars('_', '_');
  133. st.wordChars('$', '$');
  134. st.wordChars(128 + 32, 255);
  135. st.whitespaceChars(0, ' ');
  136. st.commentChar('/');
  137. st.quoteChar('\'');
  138. st.quoteChar('"');
  139. st.lowerCaseMode(false);
  140. st.ordinaryChar('/');
  141. st.slashSlashComments(true);
  142. st.slashStarComments(true);
  143. /**
  144. * The main parsing loop. The loop is executed once
  145. * for each entry in the config file. The entries
  146. * are delimited by semicolons. Once we've read in
  147. * the information for an entry, go ahead and try to
  148. * add it to the policy vector.
  149. *
  150. */
  151. lookahead = st.nextToken();
  152. while (lookahead != StreamTokenizer.TT_EOF) {
  153. if (peek("grant")) {
  154. GrantEntry ge = parseGrantEntry();
  155. // could be null if we couldn't expand a property
  156. if (ge != null)
  157. add(ge);
  158. } else if (peek("keystore") && keyStoreUrlString==null) {
  159. // only one keystore entry per policy file, others will be
  160. // ignored
  161. parseKeyStoreEntry();
  162. } else {
  163. // error?
  164. }
  165. match(";");
  166. }
  167. }
  168. public void add(GrantEntry ge)
  169. {
  170. grantEntries.addElement(ge);
  171. }
  172. public void replace(GrantEntry origGe, GrantEntry newGe)
  173. {
  174. grantEntries.setElementAt(newGe, grantEntries.indexOf(origGe));
  175. }
  176. public boolean remove(GrantEntry ge)
  177. {
  178. return grantEntries.removeElement(ge);
  179. }
  180. /**
  181. * Returns the (possibly expanded) keystore location, or null if the
  182. * expansion fails.
  183. */
  184. public String getKeyStoreUrl() {
  185. try {
  186. if (keyStoreUrlString!=null && keyStoreUrlString.length()!=0) {
  187. return expand(keyStoreUrlString).replace(File.separatorChar,
  188. '/');
  189. }
  190. } catch (PropertyExpander.ExpandException peee) {
  191. return null;
  192. }
  193. return null;
  194. }
  195. public void setKeyStoreUrl(String url) {
  196. keyStoreUrlString = url;
  197. }
  198. public String getKeyStoreType() {
  199. return keyStoreType;
  200. }
  201. public void setKeyStoreType(String type) {
  202. keyStoreType = type;
  203. }
  204. /**
  205. * Enumerate all the entries in the global policy object.
  206. * This method is used by policy admin tools. The tools
  207. * should use the Enumeration methods on the returned object
  208. * to fetch the elements sequentially.
  209. */
  210. public Enumeration grantElements(){
  211. return grantEntries.elements();
  212. }
  213. /**
  214. * write out the policy
  215. */
  216. public void write(Writer policy)
  217. {
  218. PrintWriter out = new PrintWriter(new BufferedWriter(policy));
  219. Enumeration enum = grantElements();
  220. out.println("/* AUTOMATICALLY GENERATED ON "+
  221. (new java.util.Date()) + "*/");
  222. out.println("/* DO NOT EDIT */");
  223. out.println();
  224. // write the (unexpanded) keystore entry as the first entry of the
  225. // policy file
  226. if (keyStoreUrlString != null) {
  227. writeKeyStoreEntry(out);
  228. }
  229. // write "grant" entries
  230. while (enum.hasMoreElements()) {
  231. GrantEntry ge = (GrantEntry) enum.nextElement();
  232. ge.write(out);
  233. out.println();
  234. }
  235. out.flush();
  236. }
  237. /**
  238. * parses a keystore entry
  239. */
  240. private void parseKeyStoreEntry() throws ParsingException, IOException {
  241. match("keystore");
  242. keyStoreUrlString = match("quoted string");
  243. // parse keystore type
  244. if (!peek(",")) {
  245. return; // default type
  246. }
  247. match(",");
  248. if (peek("\"")) {
  249. keyStoreType = match("quoted string");
  250. } else {
  251. throw new ParsingException(st.lineno(),
  252. rb.getString("expected keystore type"));
  253. }
  254. }
  255. /**
  256. * writes the (unexpanded) keystore entry
  257. */
  258. private void writeKeyStoreEntry(PrintWriter out) {
  259. out.print("keystore \"");
  260. out.print(keyStoreUrlString);
  261. out.print('"');
  262. if (keyStoreType != null && keyStoreType.length() > 0)
  263. out.print(", \"" + keyStoreType + "\"");
  264. out.println(";");
  265. out.println();
  266. }
  267. /**
  268. * parse a Grant entry
  269. */
  270. private GrantEntry parseGrantEntry()
  271. throws ParsingException, IOException
  272. {
  273. GrantEntry e = new GrantEntry();
  274. LinkedList principals = null;
  275. boolean ignoreEntry = false;
  276. match("grant");
  277. while(!peek("{")) {
  278. if (peekAndMatch("Codebase")) {
  279. e.codeBase = match("quoted string");
  280. peekAndMatch(",");
  281. } else if (peekAndMatch("SignedBy")) {
  282. e.signedBy = match("quoted string");
  283. peekAndMatch(",");
  284. } else if (peekAndMatch("Principal")) {
  285. if (principals == null) {
  286. principals = new LinkedList();
  287. }
  288. // check for principalClass wildcard
  289. String principalClass;
  290. if (peek("*")) {
  291. match("*");
  292. principalClass = PrincipalEntry.WILDCARD_CLASS;
  293. } else {
  294. principalClass = match("principal type");
  295. }
  296. // check for principalName wildcard
  297. String principalName;
  298. if (peek("*")) {
  299. match("*");
  300. principalName = PrincipalEntry.WILDCARD_NAME;
  301. } else {
  302. principalName = match("quoted string");
  303. }
  304. // disallow WILDCARD_CLASS && actual name
  305. if (principalClass.equals(PrincipalEntry.WILDCARD_CLASS) &&
  306. !principalName.equals(PrincipalEntry.WILDCARD_NAME)) {
  307. if (debug != null)
  308. debug.println("disallowing principal that has " +
  309. "WILDCARD class but no WILDCARD name");
  310. throw new ParsingException
  311. (st.lineno(),
  312. rb.getString("can not specify Principal with a ") +
  313. rb.getString("wildcard class without a wildcard name"));
  314. }
  315. try {
  316. principalName = expand(principalName);
  317. principals.add
  318. (new PrincipalEntry(principalClass, principalName));
  319. } catch (PropertyExpander.ExpandException peee) {
  320. // ignore the entire policy entry
  321. // but continue parsing all the info
  322. // so we can get to the next entry
  323. if (debug != null)
  324. debug.println("principal name expansion failed: " +
  325. principalName);
  326. ignoreEntry = true;
  327. }
  328. peekAndMatch(",");
  329. } else {
  330. throw new
  331. ParsingException(st.lineno(),
  332. rb.getString("expected codeBase or SignedBy"));
  333. }
  334. }
  335. // disallow non principal-based grant entries
  336. if (principals == null) {
  337. throw new ParsingException
  338. (st.lineno(),
  339. rb.getString("only Principal-based grant entries permitted"));
  340. }
  341. e.principals = principals;
  342. match("{");
  343. while(!peek("}")) {
  344. if (peek("Permission")) {
  345. try {
  346. PermissionEntry pe = parsePermissionEntry();
  347. e.add(pe);
  348. } catch (PropertyExpander.ExpandException peee) {
  349. // ignore. The add never happened
  350. skipEntry(); // BugId 4219343
  351. }
  352. match(";");
  353. } else {
  354. throw new
  355. ParsingException(st.lineno(),
  356. rb.getString("expected permission entry"));
  357. }
  358. }
  359. match("}");
  360. try {
  361. if (e.codeBase != null)
  362. e.codeBase = expand(e.codeBase).replace(File.separatorChar, '/');
  363. e.signedBy = expand(e.signedBy);
  364. } catch (PropertyExpander.ExpandException peee) {
  365. return null;
  366. }
  367. return (ignoreEntry == true) ? null : e;
  368. }
  369. /**
  370. * parse a Permission entry
  371. */
  372. private PermissionEntry parsePermissionEntry()
  373. throws ParsingException, IOException, PropertyExpander.ExpandException
  374. {
  375. PermissionEntry e = new PermissionEntry();
  376. // Permission
  377. match("Permission");
  378. e.permission = match("permission type");
  379. if (peek("\"")) {
  380. // Permission name
  381. e.name = expand(match("quoted string"));
  382. }
  383. if (!peek(",")) {
  384. return e;
  385. }
  386. match(",");
  387. if (peek("\"")) {
  388. e.action = expand(match("quoted string"));
  389. if (!peek(",")) {
  390. return e;
  391. }
  392. match(",");
  393. }
  394. if (peekAndMatch("SignedBy")) {
  395. e.signedBy = expand(match("quoted string"));
  396. }
  397. return e;
  398. }
  399. private boolean peekAndMatch(String expect)
  400. throws ParsingException, IOException
  401. {
  402. if (peek(expect)) {
  403. match(expect);
  404. return true;
  405. } else {
  406. return false;
  407. }
  408. }
  409. private boolean peek(String expect) {
  410. boolean found = false;
  411. switch (lookahead) {
  412. case StreamTokenizer.TT_WORD:
  413. if (expect.equalsIgnoreCase(st.sval))
  414. found = true;
  415. break;
  416. case ',':
  417. if (expect.equalsIgnoreCase(","))
  418. found = true;
  419. break;
  420. case '{':
  421. if (expect.equalsIgnoreCase("{"))
  422. found = true;
  423. break;
  424. case '}':
  425. if (expect.equalsIgnoreCase("}"))
  426. found = true;
  427. break;
  428. case '"':
  429. if (expect.equalsIgnoreCase("\""))
  430. found = true;
  431. break;
  432. case '*':
  433. if (expect.equalsIgnoreCase("*"))
  434. found = true;
  435. break;
  436. default:
  437. }
  438. return found;
  439. }
  440. private String match(String expect)
  441. throws ParsingException, IOException
  442. {
  443. String value = null;
  444. switch (lookahead) {
  445. case StreamTokenizer.TT_NUMBER:
  446. throw new ParsingException(st.lineno(), expect,
  447. rb.getString("number ") +
  448. String.valueOf(st.nval));
  449. case StreamTokenizer.TT_EOF:
  450. throw new ParsingException
  451. (rb.getString("expected ") + expect +
  452. rb.getString(", read end of file"));
  453. case StreamTokenizer.TT_WORD:
  454. if (expect.equalsIgnoreCase(st.sval)) {
  455. lookahead = st.nextToken();
  456. } else if (expect.equalsIgnoreCase("permission type")) {
  457. value = st.sval;
  458. lookahead = st.nextToken();
  459. } else if (expect.equalsIgnoreCase("principal type")) {
  460. value = st.sval;
  461. lookahead = st.nextToken();
  462. } else {
  463. throw new ParsingException(st.lineno(), expect, st.sval);
  464. }
  465. break;
  466. case '"':
  467. if (expect.equalsIgnoreCase("quoted string")) {
  468. value = st.sval;
  469. lookahead = st.nextToken();
  470. } else if (expect.equalsIgnoreCase("permission type")) {
  471. value = st.sval;
  472. lookahead = st.nextToken();
  473. } else if (expect.equalsIgnoreCase("principal type")) {
  474. value = st.sval;
  475. lookahead = st.nextToken();
  476. } else {
  477. throw new ParsingException(st.lineno(), expect, st.sval);
  478. }
  479. break;
  480. case ',':
  481. if (expect.equalsIgnoreCase(","))
  482. lookahead = st.nextToken();
  483. else
  484. throw new ParsingException(st.lineno(), expect, ",");
  485. break;
  486. case '{':
  487. if (expect.equalsIgnoreCase("{"))
  488. lookahead = st.nextToken();
  489. else
  490. throw new ParsingException(st.lineno(), expect, "{");
  491. break;
  492. case '}':
  493. if (expect.equalsIgnoreCase("}"))
  494. lookahead = st.nextToken();
  495. else
  496. throw new ParsingException(st.lineno(), expect, "}");
  497. break;
  498. case ';':
  499. if (expect.equalsIgnoreCase(";"))
  500. lookahead = st.nextToken();
  501. else
  502. throw new ParsingException(st.lineno(), expect, ";");
  503. break;
  504. case '*':
  505. if (expect.equalsIgnoreCase("*"))
  506. lookahead = st.nextToken();
  507. else
  508. throw new ParsingException(st.lineno(), expect, "*");
  509. break;
  510. default:
  511. throw new ParsingException(st.lineno(), expect,
  512. new String(new char[] {(char)lookahead}));
  513. }
  514. return value;
  515. }
  516. /**
  517. * skip all tokens for this entry leaving the delimiter ";"
  518. * in the stream.
  519. */
  520. private void skipEntry()
  521. throws ParsingException, IOException
  522. {
  523. while(lookahead != ';') {
  524. switch (lookahead) {
  525. case StreamTokenizer.TT_NUMBER:
  526. throw new ParsingException(st.lineno(), ";",
  527. rb.getString("number ") +
  528. String.valueOf(st.nval));
  529. case StreamTokenizer.TT_EOF:
  530. throw new ParsingException
  531. (rb.getString("expected ';', read end of file"));
  532. default:
  533. lookahead = st.nextToken();
  534. }
  535. }
  536. }
  537. /**
  538. * Each grant entry in the policy configuration file is
  539. * represented by a
  540. * GrantEntry object. <p>
  541. *
  542. * <p>
  543. * For example, the entry
  544. * <pre>
  545. * grant signedBy "Duke" {
  546. * permission java.io.FilePermission "/tmp", "read,write";
  547. * };
  548. *
  549. * </pre>
  550. * is represented internally
  551. * <pre>
  552. *
  553. * pe = new PermissionEntry("java.io.FilePermission",
  554. * "/tmp", "read,write");
  555. *
  556. * ge = new GrantEntry("Duke", null);
  557. *
  558. * ge.add(pe);
  559. *
  560. * </pre>
  561. *
  562. * @author Roland Schemers
  563. *
  564. * version 1.19, 05/21/98
  565. */
  566. static class GrantEntry {
  567. public String signedBy;
  568. public String codeBase;
  569. public LinkedList principals;
  570. public Vector permissionEntries;
  571. public GrantEntry() {
  572. permissionEntries = new Vector();
  573. }
  574. public GrantEntry(String signedBy, String codeBase) {
  575. this.codeBase = codeBase;
  576. this.signedBy = signedBy;
  577. permissionEntries = new Vector();
  578. }
  579. public void add(PermissionEntry pe)
  580. {
  581. permissionEntries.addElement(pe);
  582. }
  583. public boolean remove(PermissionEntry pe)
  584. {
  585. return permissionEntries.removeElement(pe);
  586. }
  587. public boolean contains(PermissionEntry pe)
  588. {
  589. return permissionEntries.contains(pe);
  590. }
  591. /**
  592. * Enumerate all the permission entries in this GrantEntry.
  593. */
  594. public Enumeration permissionElements(){
  595. return permissionEntries.elements();
  596. }
  597. public void write(PrintWriter out) {
  598. out.print("grant");
  599. if (signedBy != null) {
  600. out.print(" signedBy \"");
  601. out.print(signedBy);
  602. out.print('"');
  603. if (codeBase != null)
  604. out.print(", ");
  605. }
  606. if (codeBase != null) {
  607. out.print(" codeBase \"");
  608. out.print(codeBase);
  609. out.print('"');
  610. if (principals != null && principals.size() > 0)
  611. out.print(",\n");
  612. }
  613. if (principals != null && principals.size() > 0) {
  614. ListIterator pli = principals.listIterator();
  615. while (pli.hasNext()) {
  616. out.print("\tPrincipal ");
  617. PrincipalEntry pe = (PrincipalEntry)pli.next();
  618. out.print((String)pe.principalClass +
  619. " \"" + pe.principalName + "\"");
  620. if (pli.hasNext())
  621. out.print(",\n");
  622. }
  623. }
  624. out.println(" {");
  625. Enumeration enum = permissionEntries.elements();
  626. while (enum.hasMoreElements()) {
  627. PermissionEntry pe =
  628. (PermissionEntry) enum.nextElement();
  629. out.write(" ");
  630. pe.write(out);
  631. }
  632. out.println("};");
  633. }
  634. }
  635. /**
  636. * Principal info (class and name) in a grant entry
  637. */
  638. static class PrincipalEntry {
  639. static final String WILDCARD_CLASS = "WILDCARD_PRINCIPAL_CLASS";
  640. static final String WILDCARD_NAME = "WILDCARD_PRINCIPAL_NAME";
  641. String principalClass;
  642. String principalName;
  643. /**
  644. * A PrincipalEntry consists of the <code>Principal</code>
  645. * class and <code>Principal</code> name.
  646. *
  647. * <p>
  648. *
  649. * @param principalClass the <code>Principal</code> class. <p>
  650. *
  651. * @param principalName the <code>Principal</code> name. <p>
  652. */
  653. public PrincipalEntry(String principalClass, String principalName) {
  654. if (principalClass == null || principalName == null)
  655. throw new NullPointerException
  656. ("null principalClass or principalName");
  657. this.principalClass = principalClass;
  658. this.principalName = principalName;
  659. }
  660. /**
  661. * Test for equality between the specified object and this object.
  662. * Two PrincipalEntries are equal if their PrincipalClass and
  663. * PrincipalName values are equal.
  664. *
  665. * <p>
  666. *
  667. * @param obj the object to test for equality with this object.
  668. *
  669. * @return true if the objects are equal, false otherwise.
  670. */
  671. public boolean equals(Object obj) {
  672. if (this == obj)
  673. return true;
  674. if (!(obj instanceof PrincipalEntry))
  675. return false;
  676. PrincipalEntry that = (PrincipalEntry)obj;
  677. if (this.principalClass.equals(that.principalClass) &&
  678. this.principalName.equals(that.principalName)) {
  679. return true;
  680. }
  681. return false;
  682. }
  683. /**
  684. * Return a hashcode for this <code>PrincipalEntry</code>.
  685. *
  686. * <p>
  687. *
  688. * @return a hashcode for this <code>PrincipalEntry</code>.
  689. */
  690. public int hashCode() {
  691. return principalClass.hashCode();
  692. }
  693. }
  694. /**
  695. * Each permission entry in the policy configuration file is
  696. * represented by a
  697. * PermissionEntry object. <p>
  698. *
  699. * <p>
  700. * For example, the entry
  701. * <pre>
  702. * permission java.io.FilePermission "/tmp", "read,write";
  703. * </pre>
  704. * is represented internally
  705. * <pre>
  706. *
  707. * pe = new PermissionEntry("java.io.FilePermission",
  708. * "/tmp", "read,write");
  709. * </pre>
  710. *
  711. * @author Roland Schemers
  712. *
  713. * version 1.19, 05/21/98
  714. */
  715. static class PermissionEntry {
  716. public String permission;
  717. public String name;
  718. public String action;
  719. public String signedBy;
  720. public PermissionEntry() {
  721. }
  722. public PermissionEntry(String permission,
  723. String name,
  724. String action) {
  725. this.permission = permission;
  726. this.name = name;
  727. this.action = action;
  728. }
  729. /**
  730. * Calculates a hash code value for the object. Objects
  731. * which are equal will also have the same hashcode.
  732. */
  733. public int hashCode() {
  734. int retval = permission.hashCode();
  735. if (name != null) retval ^= name.hashCode();
  736. if (action != null) retval ^= action.hashCode();
  737. return retval;
  738. }
  739. public boolean equals(Object obj) {
  740. if (obj == this)
  741. return true;
  742. if (! (obj instanceof PermissionEntry))
  743. return false;
  744. PermissionEntry that = (PermissionEntry) obj;
  745. if (this.permission == null) {
  746. if (that.permission != null) return false;
  747. } else {
  748. if (!this.permission.equals(that.permission)) return false;
  749. }
  750. if (this.name == null) {
  751. if (that.name != null) return false;
  752. } else {
  753. if (!this.name.equals(that.name)) return false;
  754. }
  755. if (this.action == null) {
  756. if (that.action != null) return false;
  757. } else {
  758. if (!this.action.equals(that.action)) return false;
  759. }
  760. if (this.signedBy == null) {
  761. if (that.signedBy != null) return false;
  762. } else {
  763. if (!this.signedBy.equals(that.signedBy)) return false;
  764. }
  765. // everything matched -- the 2 objects are equal
  766. return true;
  767. }
  768. public void write(PrintWriter out) {
  769. out.print("permission ");
  770. out.print(permission);
  771. if (name != null) {
  772. out.print(" \"");
  773. // have to add escape chars for quotes
  774. if (name.indexOf("\"") != -1) {
  775. int numQuotes = 0;
  776. char[] chars = name.toCharArray();
  777. // count the number of quote chars
  778. for (int i = 0; i < chars.length; i++) {
  779. if (chars[i] == '"')
  780. numQuotes++;
  781. }
  782. // now, add an escape char before each quote
  783. char[] newChars = new char[chars.length + numQuotes];
  784. for (int i = 0, j = 0; i < chars.length; i++) {
  785. if (chars[i] != '"') {
  786. newChars[j++] = chars[i];
  787. } else {
  788. newChars[j++] = '\\';
  789. newChars[j++] = chars[i];
  790. }
  791. }
  792. name = new String(newChars);
  793. }
  794. out.print(name);
  795. out.print('"');
  796. }
  797. if (action != null) {
  798. out.print(", \"");
  799. out.print(action);
  800. out.print('"');
  801. }
  802. if (signedBy != null) {
  803. out.print(", signedBy \"");
  804. out.print(signedBy);
  805. out.print('"');
  806. }
  807. out.println(";");
  808. }
  809. }
  810. static class ParsingException extends GeneralSecurityException {
  811. /**
  812. * Constructs a ParsingException with the specified
  813. * detail message. A detail message is a String that describes
  814. * this particular exception, which may, for example, specify which
  815. * algorithm is not available.
  816. *
  817. * @param msg the detail message.
  818. */
  819. public ParsingException(String msg) {
  820. super(msg);
  821. }
  822. public ParsingException(int line, String msg) {
  823. super(rb.getString("line ") + line + rb.getString(": ") + msg);
  824. }
  825. public ParsingException(int line, String expect, String actual) {
  826. super(rb.getString("line ") + line + rb.getString(": expected '") +
  827. expect + rb.getString("', found '") + actual +
  828. rb.getString("'"));
  829. }
  830. }
  831. public static void main(String arg[]) throws Exception {
  832. PolicyParser pp = new PolicyParser(true);
  833. pp.read(new FileReader(arg[0]));
  834. FileWriter fr = new FileWriter(arg[1]);
  835. pp.write(fr);
  836. fr.close();
  837. }
  838. }