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