Dead
[official-gcc.git] / gomp-20050608-branch / libjava / classpath / gnu / java / security / PolicyFile.java
blob3064f041b9d3938d81f96876721d974128426c06
1 /* PolicyFile.java -- policy file reader
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu.java.security;
40 import gnu.classpath.SystemProperties;
41 import gnu.classpath.debug.Component;
42 import gnu.classpath.debug.SystemLogger;
44 import java.io.File;
45 import java.io.IOException;
46 import java.io.InputStreamReader;
47 import java.io.StreamTokenizer;
48 import java.lang.reflect.Constructor;
49 import java.net.MalformedURLException;
50 import java.net.URL;
51 import java.security.AccessController;
52 import java.security.CodeSource;
53 import java.security.KeyStore;
54 import java.security.KeyStoreException;
55 import java.security.Permission;
56 import java.security.PermissionCollection;
57 import java.security.Permissions;
58 import java.security.Policy;
59 import java.security.Principal;
60 import java.security.PrivilegedActionException;
61 import java.security.PrivilegedExceptionAction;
62 import java.security.Security;
63 import java.security.UnresolvedPermission;
64 import java.security.cert.Certificate;
65 import java.security.cert.X509Certificate;
66 import java.util.Enumeration;
67 import java.util.HashMap;
68 import java.util.Iterator;
69 import java.util.LinkedList;
70 import java.util.List;
71 import java.util.Map;
72 import java.util.StringTokenizer;
73 import java.util.logging.Logger;
75 /**
76 * An implementation of a {@link java.security.Policy} object whose
77 * permissions are specified by a <em>policy file</em>.
79 * <p>The approximate syntax of policy files is:</p>
81 * <pre>
82 * policyFile ::= keystoreOrGrantEntries ;
84 * keystoreOrGrantEntries ::= keystoreOrGrantEntry |
85 * keystoreOrGrantEntries keystoreOrGrantEntry |
86 * EMPTY ;
88 * keystoreOrGrantEntry ::= keystoreEntry | grantEntry ;
90 * keystoreEntry ::= "keystore" keystoreUrl ';' |
91 * "keystore" keystoreUrl ',' keystoreAlgorithm ';' ;
93 * keystoreUrl ::= URL ;
94 * keystoreAlgorithm ::= STRING ;
96 * grantEntry ::= "grant" domainParameters '{' permissions '}' ';'
98 * domainParameters ::= domainParameter |
99 * domainParameter ',' domainParameters ;
101 * domainParameter ::= "signedBy" signerNames |
102 * "codeBase" codeBaseUrl |
103 * "principal" principalClassName principalName |
104 * "principal" principalName ;
106 * signerNames ::= quotedString ;
107 * codeBaseUrl ::= URL ;
108 * principalClassName ::= STRING ;
109 * principalName ::= quotedString ;
111 * quotedString ::= quoteChar STRING quoteChar ;
112 * quoteChar ::= '"' | '\'';
114 * permissions ::= permission | permissions permission ;
116 * permission ::= "permission" permissionClassName permissionTarget permissionAction |
117 * "permission" permissionClassName permissionTarget |
118 * "permission" permissionClassName;
119 * </pre>
121 * <p>Comments are either form of Java comments. Keystore entries only
122 * affect subsequent grant entries, so if a grant entry preceeds a
123 * keystore entry, that grant entry is not affected by that keystore
124 * entry. Certian instances of <code>${property-name}</code> will be
125 * replaced with <code>System.getProperty("property-name")</code> in
126 * quoted strings.</p>
128 * <p>This class will load the following files when created or
129 * refreshed, in order:</p>
131 * <ol>
132 * <li>The file <code>${java.home}/lib/security/java.policy</code>.</li>
133 * <li>All URLs specified by security properties
134 * <code>"policy.file.<i>n</i>"</code>, for increasing <i>n</i>
135 * starting from 1. The sequence stops at the first undefined
136 * property, so you must set <code>"policy.file.1"</code> if you also
137 * set <code>"policy.file.2"</code>, and so on.</li>
138 * <li>The URL specified by the property
139 * <code>"java.security.policy"</code>.</li>
140 * </ol>
142 * @author Casey Marshall (csm@gnu.org)
143 * @see java.security.Policy
145 public final class PolicyFile extends Policy
148 // Constants and fields.
149 // -------------------------------------------------------------------------
151 private static final Logger logger = SystemLogger.SYSTEM;
153 private static final String DEFAULT_POLICY =
154 SystemProperties.getProperty("java.home")
155 + SystemProperties.getProperty("file.separator") + "lib"
156 + SystemProperties.getProperty("file.separator") + "security"
157 + SystemProperties.getProperty("file.separator") + "java.policy";
158 private static final String DEFAULT_USER_POLICY =
159 SystemProperties.getProperty ("user.home") +
160 SystemProperties.getProperty ("file.separator") + ".java.policy";
162 private final Map cs2pc;
164 // Constructors.
165 // -------------------------------------------------------------------------
167 public PolicyFile()
169 cs2pc = new HashMap();
170 refresh();
173 // Instance methods.
174 // -------------------------------------------------------------------------
176 public PermissionCollection getPermissions(CodeSource codeSource)
178 Permissions perms = new Permissions();
179 for (Iterator it = cs2pc.entrySet().iterator(); it.hasNext(); )
181 Map.Entry e = (Map.Entry) it.next();
182 CodeSource cs = (CodeSource) e.getKey();
183 if (cs.implies(codeSource))
185 logger.log (Component.POLICY, "{0} -> {1}", new Object[]
186 { cs, codeSource });
187 PermissionCollection pc = (PermissionCollection) e.getValue();
188 for (Enumeration ee = pc.elements(); ee.hasMoreElements(); )
190 perms.add((Permission) ee.nextElement());
193 else
194 logger.log (Component.POLICY, "{0} !-> {1}", new Object[]
195 { cs, codeSource });
197 logger.log (Component.POLICY, "returning permissions {0} for {1}",
198 new Object[] { perms, codeSource });
199 return perms;
202 public void refresh()
204 cs2pc.clear();
205 final List policyFiles = new LinkedList();
208 policyFiles.add (new File (DEFAULT_POLICY).toURL());
209 policyFiles.add (new File (DEFAULT_USER_POLICY).toURL ());
211 AccessController.doPrivileged(
212 new PrivilegedExceptionAction()
214 public Object run() throws Exception
216 String allow = Security.getProperty ("policy.allowSystemProperty");
217 if (allow == null || Boolean.getBoolean (allow))
219 String s = SystemProperties.getProperty ("java.security.policy");
220 logger.log (Component.POLICY, "java.security.policy={0}", s);
221 if (s != null)
223 boolean only = s.startsWith ("=");
224 if (only)
225 s = s.substring (1);
226 policyFiles.clear ();
227 policyFiles.add (new URL (s));
228 if (only)
229 return null;
232 for (int i = 1; ; i++)
234 String pname = "policy.url." + i;
235 String s = Security.getProperty (pname);
236 logger.log (Component.POLICY, "{0}={1}", new Object []
237 { pname, s });
238 if (s == null)
239 break;
240 policyFiles.add (new URL (s));
242 return null;
246 catch (PrivilegedActionException pae)
248 logger.log (Component.POLICY, "reading policy properties", pae);
250 catch (MalformedURLException mue)
252 logger.log (Component.POLICY, "setting default policies", mue);
255 logger.log (Component.POLICY, "building policy from URLs {0}",
256 policyFiles);
257 for (Iterator it = policyFiles.iterator(); it.hasNext(); )
261 URL url = (URL) it.next();
262 parse(url);
264 catch (IOException ioe)
266 logger.log (Component.POLICY, "reading policy", ioe);
271 public String toString()
273 return super.toString() + " [ " + cs2pc.toString() + " ]";
276 // Own methods.
277 // -------------------------------------------------------------------------
279 private static final int STATE_BEGIN = 0;
280 private static final int STATE_GRANT = 1;
281 private static final int STATE_PERMS = 2;
284 * Parse a policy file, incorporating the permission definitions
285 * described therein.
287 * @param url The URL of the policy file to read.
288 * @throws IOException if an I/O error occurs, or if the policy file
289 * cannot be parsed.
291 private void parse(final URL url) throws IOException
293 logger.log (Component.POLICY, "reading policy file from {0}", url);
294 final StreamTokenizer in = new StreamTokenizer(new InputStreamReader(url.openStream()));
295 in.resetSyntax();
296 in.slashSlashComments(true);
297 in.slashStarComments(true);
298 in.wordChars('A', 'Z');
299 in.wordChars('a', 'z');
300 in.wordChars('0', '9');
301 in.wordChars('.', '.');
302 in.wordChars('_', '_');
303 in.wordChars('$', '$');
304 in.whitespaceChars(' ', ' ');
305 in.whitespaceChars('\t', '\t');
306 in.whitespaceChars('\f', '\f');
307 in.whitespaceChars('\n', '\n');
308 in.whitespaceChars('\r', '\r');
309 in.quoteChar('\'');
310 in.quoteChar('"');
312 int tok;
313 int state = STATE_BEGIN;
314 List keystores = new LinkedList();
315 URL currentBase = null;
316 List currentCerts = new LinkedList();
317 Permissions currentPerms = new Permissions();
318 while ((tok = in.nextToken()) != StreamTokenizer.TT_EOF)
320 switch (tok)
322 case '{':
323 if (state != STATE_GRANT)
324 error(url, in, "spurious '{'");
325 state = STATE_PERMS;
326 tok = in.nextToken();
327 break;
328 case '}':
329 if (state != STATE_PERMS)
330 error(url, in, "spurious '}'");
331 state = STATE_BEGIN;
332 currentPerms.setReadOnly();
333 Certificate[] c = null;
334 if (!currentCerts.isEmpty())
335 c = (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]);
336 cs2pc.put(new CodeSource(currentBase, c), currentPerms);
337 currentCerts.clear();
338 currentPerms = new Permissions();
339 currentBase = null;
340 tok = in.nextToken();
341 if (tok != ';')
342 in.pushBack();
343 continue;
345 if (tok != StreamTokenizer.TT_WORD)
347 error(url, in, "expecting word token");
350 // keystore "<keystore-path>" [',' "<keystore-type>"] ';'
351 if (in.sval.equalsIgnoreCase("keystore"))
353 String alg = KeyStore.getDefaultType();
354 tok = in.nextToken();
355 if (tok != '"' && tok != '\'')
356 error(url, in, "expecting key store URL");
357 String store = in.sval;
358 tok = in.nextToken();
359 if (tok == ',')
361 tok = in.nextToken();
362 if (tok != '"' && tok != '\'')
363 error(url, in, "expecting key store type");
364 alg = in.sval;
365 tok = in.nextToken();
367 if (tok != ';')
368 error(url, in, "expecting semicolon");
371 KeyStore keystore = KeyStore.getInstance(alg);
372 keystore.load(new URL(url, store).openStream(), null);
373 keystores.add(keystore);
375 catch (Exception x)
377 error(url, in, x.toString());
380 else if (in.sval.equalsIgnoreCase("grant"))
382 if (state != STATE_BEGIN)
383 error(url, in, "extraneous grant keyword");
384 state = STATE_GRANT;
386 else if (in.sval.equalsIgnoreCase("signedBy"))
388 if (state != STATE_GRANT && state != STATE_PERMS)
389 error(url, in, "spurious 'signedBy'");
390 if (keystores.isEmpty())
391 error(url, in, "'signedBy' with no keystores");
392 tok = in.nextToken();
393 if (tok != '"' && tok != '\'')
394 error(url, in, "expecting signedBy name");
395 StringTokenizer st = new StringTokenizer(in.sval, ",");
396 while (st.hasMoreTokens())
398 String alias = st.nextToken();
399 for (Iterator it = keystores.iterator(); it.hasNext(); )
401 KeyStore keystore = (KeyStore) it.next();
404 if (keystore.isCertificateEntry(alias))
405 currentCerts.add(keystore.getCertificate(alias));
407 catch (KeyStoreException kse)
409 error(url, in, kse.toString());
413 tok = in.nextToken();
414 if (tok != ',')
416 if (state != STATE_GRANT)
417 error(url, in, "spurious ','");
418 in.pushBack();
421 else if (in.sval.equalsIgnoreCase("codeBase"))
423 if (state != STATE_GRANT)
424 error(url, in, "spurious 'codeBase'");
425 tok = in.nextToken();
426 if (tok != '"' && tok != '\'')
427 error(url, in, "expecting code base URL");
428 String base = expand(in.sval);
429 if (File.separatorChar != '/')
430 base = base.replace(File.separatorChar, '/');
433 currentBase = new URL(base);
435 catch (MalformedURLException mue)
437 error(url, in, mue.toString());
439 tok = in.nextToken();
440 if (tok != ',')
441 in.pushBack();
443 else if (in.sval.equalsIgnoreCase("principal"))
445 if (state != STATE_GRANT)
446 error(url, in, "spurious 'principal'");
447 tok = in.nextToken();
448 if (tok == StreamTokenizer.TT_WORD)
450 tok = in.nextToken();
451 if (tok != '"' && tok != '\'')
452 error(url, in, "expecting principal name");
453 String name = in.sval;
454 Principal p = null;
457 Class pclass = Class.forName(in.sval);
458 Constructor c =
459 pclass.getConstructor(new Class[] { String.class });
460 p = (Principal) c.newInstance(new Object[] { name });
462 catch (Exception x)
464 error(url, in, x.toString());
466 for (Iterator it = keystores.iterator(); it.hasNext(); )
468 KeyStore ks = (KeyStore) it.next();
471 for (Enumeration e = ks.aliases(); e.hasMoreElements(); )
473 String alias = (String) e.nextElement();
474 if (ks.isCertificateEntry(alias))
476 Certificate cert = ks.getCertificate(alias);
477 if (!(cert instanceof X509Certificate))
478 continue;
479 if (p.equals(((X509Certificate) cert).getSubjectDN()) ||
480 p.equals(((X509Certificate) cert).getSubjectX500Principal()))
481 currentCerts.add(cert);
485 catch (KeyStoreException kse)
487 error(url, in, kse.toString());
491 else if (tok == '"' || tok == '\'')
493 String alias = in.sval;
494 for (Iterator it = keystores.iterator(); it.hasNext(); )
496 KeyStore ks = (KeyStore) it.next();
499 if (ks.isCertificateEntry(alias))
500 currentCerts.add(ks.getCertificate(alias));
502 catch (KeyStoreException kse)
504 error(url, in, kse.toString());
508 else
509 error(url, in, "expecting principal");
510 tok = in.nextToken();
511 if (tok != ',')
512 in.pushBack();
514 else if (in.sval.equalsIgnoreCase("permission"))
516 if (state != STATE_PERMS)
517 error(url, in, "spurious 'permission'");
518 tok = in.nextToken();
519 if (tok != StreamTokenizer.TT_WORD)
520 error(url, in, "expecting permission class name");
521 String className = in.sval;
522 Class clazz = null;
525 clazz = Class.forName(className);
527 catch (ClassNotFoundException cnfe)
530 tok = in.nextToken();
531 if (tok == ';')
533 if (clazz == null)
535 currentPerms.add(new UnresolvedPermission(className,
536 null, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
537 continue;
541 currentPerms.add((Permission) clazz.newInstance());
543 catch (Exception x)
545 error(url, in, x.toString());
547 continue;
549 if (tok != '"' && tok != '\'')
550 error(url, in, "expecting permission target");
551 String target = expand(in.sval);
552 tok = in.nextToken();
553 if (tok == ';')
555 if (clazz == null)
557 currentPerms.add(new UnresolvedPermission(className,
558 target, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
559 continue;
563 Constructor c =
564 clazz.getConstructor(new Class[] { String.class });
565 currentPerms.add((Permission) c.newInstance(
566 new Object[] { target }));
568 catch (Exception x)
570 error(url, in, x.toString());
572 continue;
574 if (tok != ',')
575 error(url, in, "expecting ','");
576 tok = in.nextToken();
577 if (tok == StreamTokenizer.TT_WORD)
579 if (!in.sval.equalsIgnoreCase("signedBy"))
580 error(url, in, "expecting 'signedBy'");
583 Constructor c =
584 clazz.getConstructor(new Class[] { String.class });
585 currentPerms.add((Permission) c.newInstance(
586 new Object[] { target }));
588 catch (Exception x)
590 error(url, in, x.toString());
592 in.pushBack();
593 continue;
595 if (tok != '"' && tok != '\'')
596 error(url, in, "expecting permission action");
597 String action = in.sval;
598 if (clazz == null)
600 currentPerms.add(new UnresolvedPermission(className,
601 target, action, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
602 continue;
604 else
608 Constructor c = clazz.getConstructor(
609 new Class[] { String.class, String.class });
610 currentPerms.add((Permission) c.newInstance(
611 new Object[] { target, action }));
613 catch (Exception x)
615 error(url, in, x.toString());
618 tok = in.nextToken();
619 if (tok != ';' && tok != ',')
620 error(url, in, "expecting ';' or ','");
626 * Expand all instances of <code>"${property-name}"</code> into
627 * <code>System.getProperty("property-name")</code>.
629 private static String expand(final String s)
631 final StringBuffer result = new StringBuffer();
632 final StringBuffer prop = new StringBuffer();
633 int state = 0;
634 for (int i = 0; i < s.length(); i++)
636 switch (state)
638 case 0:
639 if (s.charAt(i) == '$')
640 state = 1;
641 else
642 result.append(s.charAt(i));
643 break;
644 case 1:
645 if (s.charAt(i) == '{')
646 state = 2;
647 else
649 state = 0;
650 result.append('$').append(s.charAt(i));
652 break;
653 case 2:
654 if (s.charAt(i) == '}')
656 String p = prop.toString();
657 if (p.equals("/"))
658 p = "file.separator";
659 p = System.getProperty(p);
660 if (p == null)
661 p = "";
662 result.append(p);
663 prop.setLength(0);
664 state = 0;
666 else
667 prop.append(s.charAt(i));
668 break;
671 if (state != 0)
672 result.append('$').append('{').append(prop);
673 return result.toString();
677 * I miss macros.
679 private static void error(URL base, StreamTokenizer in, String msg)
680 throws IOException
682 throw new IOException(base+":"+in.lineno()+": "+msg);