1:
37:
38: package ;
39:
40: import ;
41: import ;
42:
43: import ;
44: import ;
45:
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: import ;
75: import ;
76:
77:
147: public final class PolicyFile extends Policy
148: {
149:
150:
151:
152:
153: protected static final Logger logger = SystemLogger.SYSTEM;
154:
155: private static GetPropertyAction prop = new GetPropertyAction("file.separator");
156: private static final String fs = (String) AccessController.doPrivileged(prop);
157:
158: private static final String DEFAULT_POLICY =
159: (String) AccessController.doPrivileged(prop.setParameters("java.home"))
160: + fs + "lib" + fs + "security" + fs + "java.policy";
161: private static final String DEFAULT_USER_POLICY =
162: (String) AccessController.doPrivileged(prop.setParameters("user.home")) +
163: fs + ".java.policy";
164:
165: private final Map cs2pc;
166:
167:
168:
169:
170: public PolicyFile()
171: {
172: cs2pc = new HashMap();
173: refresh();
174: }
175:
176:
177:
178:
179: public PermissionCollection getPermissions(CodeSource codeSource)
180: {
181: Permissions perms = new Permissions();
182: for (Iterator it = cs2pc.entrySet().iterator(); it.hasNext(); )
183: {
184: Map.Entry e = (Map.Entry) it.next();
185: CodeSource cs = (CodeSource) e.getKey();
186: if (cs.implies(codeSource))
187: {
188: logger.log (Component.POLICY, "{0} -> {1}", new Object[]
189: { cs, codeSource });
190: PermissionCollection pc = (PermissionCollection) e.getValue();
191: for (Enumeration ee = pc.elements(); ee.hasMoreElements(); )
192: {
193: perms.add((Permission) ee.nextElement());
194: }
195: }
196: else
197: logger.log (Component.POLICY, "{0} !-> {1}", new Object[]
198: { cs, codeSource });
199: }
200: logger.log (Component.POLICY, "returning permissions {0} for {1}",
201: new Object[] { perms, codeSource });
202: return perms;
203: }
204:
205: public void refresh()
206: {
207: cs2pc.clear();
208: final List policyFiles = new LinkedList();
209: try
210: {
211: policyFiles.add (new File (DEFAULT_POLICY).toURL());
212: policyFiles.add (new File (DEFAULT_USER_POLICY).toURL ());
213:
214: AccessController.doPrivileged(
215: new PrivilegedExceptionAction()
216: {
217: public Object run() throws Exception
218: {
219: String allow = Security.getProperty ("policy.allowSystemProperty");
220: if (allow == null || Boolean.getBoolean (allow))
221: {
222: String s = System.getProperty ("java.security.policy");
223: logger.log (Component.POLICY, "java.security.policy={0}", s);
224: if (s != null)
225: {
226: boolean only = s.startsWith ("=");
227: if (only)
228: s = s.substring (1);
229: policyFiles.clear ();
230: policyFiles.add (new URL (s));
231: if (only)
232: return null;
233: }
234: }
235: for (int i = 1; ; i++)
236: {
237: String pname = "policy.url." + i;
238: String s = Security.getProperty (pname);
239: logger.log (Component.POLICY, "{0}={1}", new Object []
240: { pname, s });
241: if (s == null)
242: break;
243: policyFiles.add (new URL (s));
244: }
245: return null;
246: }
247: });
248: }
249: catch (PrivilegedActionException pae)
250: {
251: logger.log (Component.POLICY, "reading policy properties", pae);
252: }
253: catch (MalformedURLException mue)
254: {
255: logger.log (Component.POLICY, "setting default policies", mue);
256: }
257:
258: logger.log (Component.POLICY, "building policy from URLs {0}",
259: policyFiles);
260: for (Iterator it = policyFiles.iterator(); it.hasNext(); )
261: {
262: try
263: {
264: URL url = (URL) it.next();
265: parse(url);
266: }
267: catch (IOException ioe)
268: {
269: logger.log (Component.POLICY, "reading policy", ioe);
270: }
271: }
272: }
273:
274: public String toString()
275: {
276: return super.toString() + " [ " + cs2pc.toString() + " ]";
277: }
278:
279:
280:
281:
282: private static final int STATE_BEGIN = 0;
283: private static final int STATE_GRANT = 1;
284: private static final int STATE_PERMS = 2;
285:
286:
294: private void parse(final URL url) throws IOException
295: {
296: logger.log (Component.POLICY, "reading policy file from {0}", url);
297: final StreamTokenizer in = new StreamTokenizer(new InputStreamReader(url.openStream()));
298: in.resetSyntax();
299: in.slashSlashComments(true);
300: in.slashStarComments(true);
301: in.wordChars('A', 'Z');
302: in.wordChars('a', 'z');
303: in.wordChars('0', '9');
304: in.wordChars('.', '.');
305: in.wordChars('_', '_');
306: in.wordChars('$', '$');
307: in.whitespaceChars(' ', ' ');
308: in.whitespaceChars('\t', '\t');
309: in.whitespaceChars('\f', '\f');
310: in.whitespaceChars('\n', '\n');
311: in.whitespaceChars('\r', '\r');
312: in.quoteChar('\'');
313: in.quoteChar('"');
314:
315: int tok;
316: int state = STATE_BEGIN;
317: List keystores = new LinkedList();
318: URL currentBase = null;
319: List currentCerts = new LinkedList();
320: Permissions currentPerms = new Permissions();
321: while ((tok = in.nextToken()) != StreamTokenizer.TT_EOF)
322: {
323: switch (tok)
324: {
325: case '{':
326: if (state != STATE_GRANT)
327: error(url, in, "spurious '{'");
328: state = STATE_PERMS;
329: tok = in.nextToken();
330: break;
331: case '}':
332: if (state != STATE_PERMS)
333: error(url, in, "spurious '}'");
334: state = STATE_BEGIN;
335: currentPerms.setReadOnly();
336: Certificate[] c = null;
337: if (!currentCerts.isEmpty())
338: c = (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]);
339: cs2pc.put(new CodeSource(currentBase, c), currentPerms);
340: currentCerts.clear();
341: currentPerms = new Permissions();
342: currentBase = null;
343: tok = in.nextToken();
344: if (tok != ';')
345: in.pushBack();
346: continue;
347: }
348: if (tok != StreamTokenizer.TT_WORD)
349: {
350: error(url, in, "expecting word token");
351: }
352:
353:
354: if (in.sval.equalsIgnoreCase("keystore"))
355: {
356: String alg = KeyStore.getDefaultType();
357: tok = in.nextToken();
358: if (tok != '"' && tok != '\'')
359: error(url, in, "expecting key store URL");
360: String store = in.sval;
361: tok = in.nextToken();
362: if (tok == ',')
363: {
364: tok = in.nextToken();
365: if (tok != '"' && tok != '\'')
366: error(url, in, "expecting key store type");
367: alg = in.sval;
368: tok = in.nextToken();
369: }
370: if (tok != ';')
371: error(url, in, "expecting semicolon");
372: try
373: {
374: KeyStore keystore = KeyStore.getInstance(alg);
375: keystore.load(new URL(url, store).openStream(), null);
376: keystores.add(keystore);
377: }
378: catch (Exception x)
379: {
380: error(url, in, x.toString());
381: }
382: }
383: else if (in.sval.equalsIgnoreCase("grant"))
384: {
385: if (state != STATE_BEGIN)
386: error(url, in, "extraneous grant keyword");
387: state = STATE_GRANT;
388: }
389: else if (in.sval.equalsIgnoreCase("signedBy"))
390: {
391: if (state != STATE_GRANT && state != STATE_PERMS)
392: error(url, in, "spurious 'signedBy'");
393: if (keystores.isEmpty())
394: error(url, in, "'signedBy' with no keystores");
395: tok = in.nextToken();
396: if (tok != '"' && tok != '\'')
397: error(url, in, "expecting signedBy name");
398: StringTokenizer st = new StringTokenizer(in.sval, ",");
399: while (st.hasMoreTokens())
400: {
401: String alias = st.nextToken();
402: for (Iterator it = keystores.iterator(); it.hasNext(); )
403: {
404: KeyStore keystore = (KeyStore) it.next();
405: try
406: {
407: if (keystore.isCertificateEntry(alias))
408: currentCerts.add(keystore.getCertificate(alias));
409: }
410: catch (KeyStoreException kse)
411: {
412: error(url, in, kse.toString());
413: }
414: }
415: }
416: tok = in.nextToken();
417: if (tok != ',')
418: {
419: if (state != STATE_GRANT)
420: error(url, in, "spurious ','");
421: in.pushBack();
422: }
423: }
424: else if (in.sval.equalsIgnoreCase("codeBase"))
425: {
426: if (state != STATE_GRANT)
427: error(url, in, "spurious 'codeBase'");
428: tok = in.nextToken();
429: if (tok != '"' && tok != '\'')
430: error(url, in, "expecting code base URL");
431: String base = expand(in.sval);
432: if (File.separatorChar != '/')
433: base = base.replace(File.separatorChar, '/');
434: try
435: {
436: currentBase = new URL(base);
437: }
438: catch (MalformedURLException mue)
439: {
440: error(url, in, mue.toString());
441: }
442: tok = in.nextToken();
443: if (tok != ',')
444: in.pushBack();
445: }
446: else if (in.sval.equalsIgnoreCase("principal"))
447: {
448: if (state != STATE_GRANT)
449: error(url, in, "spurious 'principal'");
450: tok = in.nextToken();
451: if (tok == StreamTokenizer.TT_WORD)
452: {
453: tok = in.nextToken();
454: if (tok != '"' && tok != '\'')
455: error(url, in, "expecting principal name");
456: String name = in.sval;
457: Principal p = null;
458: try
459: {
460: Class pclass = Class.forName(in.sval);
461: Constructor c =
462: pclass.getConstructor(new Class[] { String.class });
463: p = (Principal) c.newInstance(new Object[] { name });
464: }
465: catch (Exception x)
466: {
467: error(url, in, x.toString());
468: }
469: for (Iterator it = keystores.iterator(); it.hasNext(); )
470: {
471: KeyStore ks = (KeyStore) it.next();
472: try
473: {
474: for (Enumeration e = ks.aliases(); e.hasMoreElements(); )
475: {
476: String alias = (String) e.nextElement();
477: if (ks.isCertificateEntry(alias))
478: {
479: Certificate cert = ks.getCertificate(alias);
480: if (!(cert instanceof X509Certificate))
481: continue;
482: if (p.equals(((X509Certificate) cert).getSubjectDN()) ||
483: p.equals(((X509Certificate) cert).getSubjectX500Principal()))
484: currentCerts.add(cert);
485: }
486: }
487: }
488: catch (KeyStoreException kse)
489: {
490: error(url, in, kse.toString());
491: }
492: }
493: }
494: else if (tok == '"' || tok == '\'')
495: {
496: String alias = in.sval;
497: for (Iterator it = keystores.iterator(); it.hasNext(); )
498: {
499: KeyStore ks = (KeyStore) it.next();
500: try
501: {
502: if (ks.isCertificateEntry(alias))
503: currentCerts.add(ks.getCertificate(alias));
504: }
505: catch (KeyStoreException kse)
506: {
507: error(url, in, kse.toString());
508: }
509: }
510: }
511: else
512: error(url, in, "expecting principal");
513: tok = in.nextToken();
514: if (tok != ',')
515: in.pushBack();
516: }
517: else if (in.sval.equalsIgnoreCase("permission"))
518: {
519: if (state != STATE_PERMS)
520: error(url, in, "spurious 'permission'");
521: tok = in.nextToken();
522: if (tok != StreamTokenizer.TT_WORD)
523: error(url, in, "expecting permission class name");
524: String className = in.sval;
525: Class clazz = null;
526: try
527: {
528: clazz = Class.forName(className);
529: }
530: catch (ClassNotFoundException cnfe)
531: {
532: }
533: tok = in.nextToken();
534: if (tok == ';')
535: {
536: if (clazz == null)
537: {
538: currentPerms.add(new UnresolvedPermission(className,
539: null, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
540: continue;
541: }
542: try
543: {
544: currentPerms.add((Permission) clazz.newInstance());
545: }
546: catch (Exception x)
547: {
548: error(url, in, x.toString());
549: }
550: continue;
551: }
552: if (tok != '"' && tok != '\'')
553: error(url, in, "expecting permission target");
554: String target = expand(in.sval);
555: tok = in.nextToken();
556: if (tok == ';')
557: {
558: if (clazz == null)
559: {
560: currentPerms.add(new UnresolvedPermission(className,
561: target, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
562: continue;
563: }
564: try
565: {
566: Constructor c =
567: clazz.getConstructor(new Class[] { String.class });
568: currentPerms.add((Permission) c.newInstance(
569: new Object[] { target }));
570: }
571: catch (Exception x)
572: {
573: error(url, in, x.toString());
574: }
575: continue;
576: }
577: if (tok != ',')
578: error(url, in, "expecting ','");
579: tok = in.nextToken();
580: if (tok == StreamTokenizer.TT_WORD)
581: {
582: if (!in.sval.equalsIgnoreCase("signedBy"))
583: error(url, in, "expecting 'signedBy'");
584: try
585: {
586: Constructor c =
587: clazz.getConstructor(new Class[] { String.class });
588: currentPerms.add((Permission) c.newInstance(
589: new Object[] { target }));
590: }
591: catch (Exception x)
592: {
593: error(url, in, x.toString());
594: }
595: in.pushBack();
596: continue;
597: }
598: if (tok != '"' && tok != '\'')
599: error(url, in, "expecting permission action");
600: String action = in.sval;
601: if (clazz == null)
602: {
603: currentPerms.add(new UnresolvedPermission(className,
604: target, action, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
605: continue;
606: }
607: else
608: {
609: try
610: {
611: Constructor c = clazz.getConstructor(
612: new Class[] { String.class, String.class });
613: currentPerms.add((Permission) c.newInstance(
614: new Object[] { target, action }));
615: }
616: catch (Exception x)
617: {
618: error(url, in, x.toString());
619: }
620: }
621: tok = in.nextToken();
622: if (tok != ';' && tok != ',')
623: error(url, in, "expecting ';' or ','");
624: }
625: }
626: }
627:
628:
632: private static String expand(final String s)
633: {
634: final CPStringBuilder result = new CPStringBuilder();
635: final CPStringBuilder prop = new CPStringBuilder();
636: int state = 0;
637: for (int i = 0; i < s.length(); i++)
638: {
639: switch (state)
640: {
641: case 0:
642: if (s.charAt(i) == '$')
643: state = 1;
644: else
645: result.append(s.charAt(i));
646: break;
647: case 1:
648: if (s.charAt(i) == '{')
649: state = 2;
650: else
651: {
652: state = 0;
653: result.append('$').append(s.charAt(i));
654: }
655: break;
656: case 2:
657: if (s.charAt(i) == '}')
658: {
659: String p = prop.toString();
660: if (p.equals("/"))
661: p = "file.separator";
662: p = System.getProperty(p);
663: if (p == null)
664: p = "";
665: result.append(p);
666: prop.setLength(0);
667: state = 0;
668: }
669: else
670: prop.append(s.charAt(i));
671: break;
672: }
673: }
674: if (state != 0)
675: result.append('$').append('{').append(prop);
676: return result.toString();
677: }
678:
679:
682: private static void error(URL base, StreamTokenizer in, String msg)
683: throws IOException
684: {
685: throw new IOException(base+":"+in.lineno()+": "+msg);
686: }
687: }