1:
37:
38: package ;
39:
40: import ;
41: import ;
42: import ;
43:
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74:
75:
145: public final class PolicyFile extends Policy
146: {
147:
148:
149:
150:
151: private static final Logger logger = SystemLogger.SYSTEM;
152:
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";
161:
162: private final Map cs2pc;
163:
164:
165:
166:
167: public PolicyFile()
168: {
169: cs2pc = new HashMap();
170: refresh();
171: }
172:
173:
174:
175:
176: public PermissionCollection getPermissions(CodeSource codeSource)
177: {
178: Permissions perms = new Permissions();
179: for (Iterator it = cs2pc.entrySet().iterator(); it.hasNext(); )
180: {
181: Map.Entry e = (Map.Entry) it.next();
182: CodeSource cs = (CodeSource) e.getKey();
183: if (cs.implies(codeSource))
184: {
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(); )
189: {
190: perms.add((Permission) ee.nextElement());
191: }
192: }
193: else
194: logger.log (Component.POLICY, "{0} !-> {1}", new Object[]
195: { cs, codeSource });
196: }
197: logger.log (Component.POLICY, "returning permissions {0} for {1}",
198: new Object[] { perms, codeSource });
199: return perms;
200: }
201:
202: public void refresh()
203: {
204: cs2pc.clear();
205: final List policyFiles = new LinkedList();
206: try
207: {
208: policyFiles.add (new File (DEFAULT_POLICY).toURL());
209: policyFiles.add (new File (DEFAULT_USER_POLICY).toURL ());
210:
211: AccessController.doPrivileged(
212: new PrivilegedExceptionAction()
213: {
214: public Object run() throws Exception
215: {
216: String allow = Security.getProperty ("policy.allowSystemProperty");
217: if (allow == null || Boolean.getBoolean (allow))
218: {
219: String s = SystemProperties.getProperty ("java.security.policy");
220: logger.log (Component.POLICY, "java.security.policy={0}", s);
221: if (s != null)
222: {
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;
230: }
231: }
232: for (int i = 1; ; i++)
233: {
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));
241: }
242: return null;
243: }
244: });
245: }
246: catch (PrivilegedActionException pae)
247: {
248: logger.log (Component.POLICY, "reading policy properties", pae);
249: }
250: catch (MalformedURLException mue)
251: {
252: logger.log (Component.POLICY, "setting default policies", mue);
253: }
254:
255: logger.log (Component.POLICY, "building policy from URLs {0}",
256: policyFiles);
257: for (Iterator it = policyFiles.iterator(); it.hasNext(); )
258: {
259: try
260: {
261: URL url = (URL) it.next();
262: parse(url);
263: }
264: catch (IOException ioe)
265: {
266: logger.log (Component.POLICY, "reading policy", ioe);
267: }
268: }
269: }
270:
271: public String toString()
272: {
273: return super.toString() + " [ " + cs2pc.toString() + " ]";
274: }
275:
276:
277:
278:
279: private static final int STATE_BEGIN = 0;
280: private static final int STATE_GRANT = 1;
281: private static final int STATE_PERMS = 2;
282:
283:
291: private void parse(final URL url) throws IOException
292: {
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('"');
311:
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)
319: {
320: switch (tok)
321: {
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;
344: }
345: if (tok != StreamTokenizer.TT_WORD)
346: {
347: error(url, in, "expecting word token");
348: }
349:
350:
351: if (in.sval.equalsIgnoreCase("keystore"))
352: {
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 == ',')
360: {
361: tok = in.nextToken();
362: if (tok != '"' && tok != '\'')
363: error(url, in, "expecting key store type");
364: alg = in.sval;
365: tok = in.nextToken();
366: }
367: if (tok != ';')
368: error(url, in, "expecting semicolon");
369: try
370: {
371: KeyStore keystore = KeyStore.getInstance(alg);
372: keystore.load(new URL(url, store).openStream(), null);
373: keystores.add(keystore);
374: }
375: catch (Exception x)
376: {
377: error(url, in, x.toString());
378: }
379: }
380: else if (in.sval.equalsIgnoreCase("grant"))
381: {
382: if (state != STATE_BEGIN)
383: error(url, in, "extraneous grant keyword");
384: state = STATE_GRANT;
385: }
386: else if (in.sval.equalsIgnoreCase("signedBy"))
387: {
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())
397: {
398: String alias = st.nextToken();
399: for (Iterator it = keystores.iterator(); it.hasNext(); )
400: {
401: KeyStore keystore = (KeyStore) it.next();
402: try
403: {
404: if (keystore.isCertificateEntry(alias))
405: currentCerts.add(keystore.getCertificate(alias));
406: }
407: catch (KeyStoreException kse)
408: {
409: error(url, in, kse.toString());
410: }
411: }
412: }
413: tok = in.nextToken();
414: if (tok != ',')
415: {
416: if (state != STATE_GRANT)
417: error(url, in, "spurious ','");
418: in.pushBack();
419: }
420: }
421: else if (in.sval.equalsIgnoreCase("codeBase"))
422: {
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, '/');
431: try
432: {
433: currentBase = new URL(base);
434: }
435: catch (MalformedURLException mue)
436: {
437: error(url, in, mue.toString());
438: }
439: tok = in.nextToken();
440: if (tok != ',')
441: in.pushBack();
442: }
443: else if (in.sval.equalsIgnoreCase("principal"))
444: {
445: if (state != STATE_GRANT)
446: error(url, in, "spurious 'principal'");
447: tok = in.nextToken();
448: if (tok == StreamTokenizer.TT_WORD)
449: {
450: tok = in.nextToken();
451: if (tok != '"' && tok != '\'')
452: error(url, in, "expecting principal name");
453: String name = in.sval;
454: Principal p = null;
455: try
456: {
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 });
461: }
462: catch (Exception x)
463: {
464: error(url, in, x.toString());
465: }
466: for (Iterator it = keystores.iterator(); it.hasNext(); )
467: {
468: KeyStore ks = (KeyStore) it.next();
469: try
470: {
471: for (Enumeration e = ks.aliases(); e.hasMoreElements(); )
472: {
473: String alias = (String) e.nextElement();
474: if (ks.isCertificateEntry(alias))
475: {
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);
482: }
483: }
484: }
485: catch (KeyStoreException kse)
486: {
487: error(url, in, kse.toString());
488: }
489: }
490: }
491: else if (tok == '"' || tok == '\'')
492: {
493: String alias = in.sval;
494: for (Iterator it = keystores.iterator(); it.hasNext(); )
495: {
496: KeyStore ks = (KeyStore) it.next();
497: try
498: {
499: if (ks.isCertificateEntry(alias))
500: currentCerts.add(ks.getCertificate(alias));
501: }
502: catch (KeyStoreException kse)
503: {
504: error(url, in, kse.toString());
505: }
506: }
507: }
508: else
509: error(url, in, "expecting principal");
510: tok = in.nextToken();
511: if (tok != ',')
512: in.pushBack();
513: }
514: else if (in.sval.equalsIgnoreCase("permission"))
515: {
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;
523: try
524: {
525: clazz = Class.forName(className);
526: }
527: catch (ClassNotFoundException cnfe)
528: {
529: }
530: tok = in.nextToken();
531: if (tok == ';')
532: {
533: if (clazz == null)
534: {
535: currentPerms.add(new UnresolvedPermission(className,
536: null, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
537: continue;
538: }
539: try
540: {
541: currentPerms.add((Permission) clazz.newInstance());
542: }
543: catch (Exception x)
544: {
545: error(url, in, x.toString());
546: }
547: continue;
548: }
549: if (tok != '"' && tok != '\'')
550: error(url, in, "expecting permission target");
551: String target = expand(in.sval);
552: tok = in.nextToken();
553: if (tok == ';')
554: {
555: if (clazz == null)
556: {
557: currentPerms.add(new UnresolvedPermission(className,
558: target, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
559: continue;
560: }
561: try
562: {
563: Constructor c =
564: clazz.getConstructor(new Class[] { String.class });
565: currentPerms.add((Permission) c.newInstance(
566: new Object[] { target }));
567: }
568: catch (Exception x)
569: {
570: error(url, in, x.toString());
571: }
572: continue;
573: }
574: if (tok != ',')
575: error(url, in, "expecting ','");
576: tok = in.nextToken();
577: if (tok == StreamTokenizer.TT_WORD)
578: {
579: if (!in.sval.equalsIgnoreCase("signedBy"))
580: error(url, in, "expecting 'signedBy'");
581: try
582: {
583: Constructor c =
584: clazz.getConstructor(new Class[] { String.class });
585: currentPerms.add((Permission) c.newInstance(
586: new Object[] { target }));
587: }
588: catch (Exception x)
589: {
590: error(url, in, x.toString());
591: }
592: in.pushBack();
593: continue;
594: }
595: if (tok != '"' && tok != '\'')
596: error(url, in, "expecting permission action");
597: String action = in.sval;
598: if (clazz == null)
599: {
600: currentPerms.add(new UnresolvedPermission(className,
601: target, action, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
602: continue;
603: }
604: else
605: {
606: try
607: {
608: Constructor c = clazz.getConstructor(
609: new Class[] { String.class, String.class });
610: currentPerms.add((Permission) c.newInstance(
611: new Object[] { target, action }));
612: }
613: catch (Exception x)
614: {
615: error(url, in, x.toString());
616: }
617: }
618: tok = in.nextToken();
619: if (tok != ';' && tok != ',')
620: error(url, in, "expecting ';' or ','");
621: }
622: }
623: }
624:
625:
629: private static String expand(final String s)
630: {
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++)
635: {
636: switch (state)
637: {
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
648: {
649: state = 0;
650: result.append('$').append(s.charAt(i));
651: }
652: break;
653: case 2:
654: if (s.charAt(i) == '}')
655: {
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;
665: }
666: else
667: prop.append(s.charAt(i));
668: break;
669: }
670: }
671: if (state != 0)
672: result.append('$').append('{').append(prop);
673: return result.toString();
674: }
675:
676:
679: private static void error(URL base, StreamTokenizer in, String msg)
680: throws IOException
681: {
682: throw new IOException(base+":"+in.lineno()+": "+msg);
683: }
684: }