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