Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/provider/PolicyParser.java
38830 views
1
/*
2
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.provider;
27
28
import java.io.*;
29
import java.lang.RuntimePermission;
30
import java.net.SocketPermission;
31
import java.net.URL;
32
import java.security.GeneralSecurityException;
33
import java.security.Principal;
34
import java.text.MessageFormat;
35
import java.util.*;
36
import javax.security.auth.x500.X500Principal;
37
38
import sun.security.util.Debug;
39
import sun.security.util.PropertyExpander;
40
import sun.security.util.ResourcesMgr;
41
42
/**
43
* The policy for a Java runtime (specifying
44
* which permissions are available for code from various principals)
45
* is represented as a separate
46
* persistent configuration. The configuration may be stored as a
47
* flat ASCII file, as a serialized binary file of
48
* the Policy class, or as a database. <p>
49
*
50
* <p>The Java runtime creates one global Policy object, which is used to
51
* represent the static policy configuration file. It is consulted by
52
* a ProtectionDomain when the protection domain initializes its set of
53
* permissions. <p>
54
*
55
* <p>The Policy <code>init</code> method parses the policy
56
* configuration file, and then
57
* populates the Policy object. The Policy object is agnostic in that
58
* it is not involved in making policy decisions. It is merely the
59
* Java runtime representation of the persistent policy configuration
60
* file. <p>
61
*
62
* <p>When a protection domain needs to initialize its set of
63
* permissions, it executes code such as the following
64
* to ask the global Policy object to populate a
65
* Permissions object with the appropriate permissions:
66
* <pre>
67
* policy = Policy.getPolicy();
68
* Permissions perms = policy.getPermissions(protectiondomain)
69
* </pre>
70
*
71
* <p>The protection domain contains a CodeSource
72
* object, which encapsulates its codebase (URL) and public key attributes.
73
* It also contains the principals associated with the domain.
74
* The Policy object evaluates the global policy in light of who the
75
* principal is and what the code source is and returns an appropriate
76
* Permissions object.
77
*
78
* @author Roland Schemers
79
* @author Ram Marti
80
*
81
* @since 1.2
82
*/
83
84
public class PolicyParser {
85
86
private static final String EXTDIRS_PROPERTY = "java.ext.dirs";
87
private static final String OLD_EXTDIRS_EXPANSION =
88
"${" + EXTDIRS_PROPERTY + "}";
89
90
// package-private: used by PolicyFile for static policy
91
static final String EXTDIRS_EXPANSION = "${{" + EXTDIRS_PROPERTY + "}}";
92
93
94
private Vector<GrantEntry> grantEntries;
95
private Map<String, DomainEntry> domainEntries;
96
97
// Convenience variables for parsing
98
private static final Debug debug = Debug.getInstance("parser",
99
"\t[Policy Parser]");
100
private StreamTokenizer st;
101
private int lookahead;
102
private boolean expandProp = false;
103
private String keyStoreUrlString = null; // unexpanded
104
private String keyStoreType = null;
105
private String keyStoreProvider = null;
106
private String storePassURL = null;
107
108
private String expand(String value)
109
throws PropertyExpander.ExpandException
110
{
111
return expand(value, false);
112
}
113
114
private String expand(String value, boolean encodeURL)
115
throws PropertyExpander.ExpandException
116
{
117
if (!expandProp) {
118
return value;
119
} else {
120
return PropertyExpander.expand(value, encodeURL);
121
}
122
}
123
124
/**
125
* Creates a PolicyParser object.
126
*/
127
128
public PolicyParser() {
129
grantEntries = new Vector<GrantEntry>();
130
}
131
132
133
public PolicyParser(boolean expandProp) {
134
this();
135
this.expandProp = expandProp;
136
}
137
138
/**
139
* Reads a policy configuration into the Policy object using a
140
* Reader object. <p>
141
*
142
* @param policy the policy Reader object.
143
*
144
* @exception ParsingException if the policy configuration contains
145
* a syntax error.
146
*
147
* @exception IOException if an error occurs while reading the policy
148
* configuration.
149
*/
150
151
public void read(Reader policy)
152
throws ParsingException, IOException
153
{
154
if (!(policy instanceof BufferedReader)) {
155
policy = new BufferedReader(policy);
156
}
157
158
/**
159
* Configure the stream tokenizer:
160
* Recognize strings between "..."
161
* Don't convert words to lowercase
162
* Recognize both C-style and C++-style comments
163
* Treat end-of-line as white space, not as a token
164
*/
165
st = new StreamTokenizer(policy);
166
167
st.resetSyntax();
168
st.wordChars('a', 'z');
169
st.wordChars('A', 'Z');
170
st.wordChars('.', '.');
171
st.wordChars('0', '9');
172
st.wordChars('_', '_');
173
st.wordChars('$', '$');
174
st.wordChars(128 + 32, 255);
175
st.whitespaceChars(0, ' ');
176
st.commentChar('/');
177
st.quoteChar('\'');
178
st.quoteChar('"');
179
st.lowerCaseMode(false);
180
st.ordinaryChar('/');
181
st.slashSlashComments(true);
182
st.slashStarComments(true);
183
184
/**
185
* The main parsing loop. The loop is executed once
186
* for each entry in the config file. The entries
187
* are delimited by semicolons. Once we've read in
188
* the information for an entry, go ahead and try to
189
* add it to the policy vector.
190
*
191
*/
192
193
lookahead = st.nextToken();
194
GrantEntry ge = null;
195
while (lookahead != StreamTokenizer.TT_EOF) {
196
if (peek("grant")) {
197
ge = parseGrantEntry();
198
// could be null if we couldn't expand a property
199
if (ge != null)
200
add(ge);
201
} else if (peek("keystore") && keyStoreUrlString==null) {
202
// only one keystore entry per policy file, others will be
203
// ignored
204
parseKeyStoreEntry();
205
} else if (peek("keystorePasswordURL") && storePassURL==null) {
206
// only one keystore passwordURL per policy file, others will be
207
// ignored
208
parseStorePassURL();
209
} else if (ge == null && keyStoreUrlString == null &&
210
storePassURL == null && peek("domain")) {
211
if (domainEntries == null) {
212
domainEntries = new TreeMap<>();
213
}
214
DomainEntry de = parseDomainEntry();
215
if (de != null) {
216
String domainName = de.getName();
217
if (!domainEntries.containsKey(domainName)) {
218
domainEntries.put(domainName, de);
219
} else {
220
MessageFormat form =
221
new MessageFormat(ResourcesMgr.getString(
222
"duplicate.keystore.domain.name"));
223
Object[] source = {domainName};
224
throw new ParsingException(form.format(source));
225
}
226
}
227
} else {
228
// error?
229
}
230
match(";");
231
}
232
233
if (keyStoreUrlString == null && storePassURL != null) {
234
throw new ParsingException(ResourcesMgr.getString
235
("keystorePasswordURL.can.not.be.specified.without.also.specifying.keystore"));
236
}
237
}
238
239
public void add(GrantEntry ge)
240
{
241
grantEntries.addElement(ge);
242
}
243
244
public void replace(GrantEntry origGe, GrantEntry newGe)
245
{
246
grantEntries.setElementAt(newGe, grantEntries.indexOf(origGe));
247
}
248
249
public boolean remove(GrantEntry ge)
250
{
251
return grantEntries.removeElement(ge);
252
}
253
254
/**
255
* Returns the (possibly expanded) keystore location, or null if the
256
* expansion fails.
257
*/
258
public String getKeyStoreUrl() {
259
try {
260
if (keyStoreUrlString!=null && keyStoreUrlString.length()!=0) {
261
return expand(keyStoreUrlString, true).replace
262
(File.separatorChar, '/');
263
}
264
} catch (PropertyExpander.ExpandException peee) {
265
if (debug != null) {
266
debug.println(peee.toString());
267
}
268
return null;
269
}
270
return null;
271
}
272
273
public void setKeyStoreUrl(String url) {
274
keyStoreUrlString = url;
275
}
276
277
public String getKeyStoreType() {
278
return keyStoreType;
279
}
280
281
public void setKeyStoreType(String type) {
282
keyStoreType = type;
283
}
284
285
public String getKeyStoreProvider() {
286
return keyStoreProvider;
287
}
288
289
public void setKeyStoreProvider(String provider) {
290
keyStoreProvider = provider;
291
}
292
293
public String getStorePassURL() {
294
try {
295
if (storePassURL!=null && storePassURL.length()!=0) {
296
return expand(storePassURL, true).replace
297
(File.separatorChar, '/');
298
}
299
} catch (PropertyExpander.ExpandException peee) {
300
if (debug != null) {
301
debug.println(peee.toString());
302
}
303
return null;
304
}
305
return null;
306
}
307
308
public void setStorePassURL(String storePassURL) {
309
this.storePassURL = storePassURL;
310
}
311
312
/**
313
* Enumerate all the entries in the global policy object.
314
* This method is used by policy admin tools. The tools
315
* should use the Enumeration methods on the returned object
316
* to fetch the elements sequentially.
317
*/
318
public Enumeration<GrantEntry> grantElements(){
319
return grantEntries.elements();
320
}
321
322
public Collection<DomainEntry> getDomainEntries() {
323
return domainEntries.values();
324
}
325
326
/**
327
* write out the policy
328
*/
329
330
public void write(Writer policy)
331
{
332
PrintWriter out = new PrintWriter(new BufferedWriter(policy));
333
334
Enumeration<GrantEntry> enum_ = grantElements();
335
336
out.println("/* AUTOMATICALLY GENERATED ON "+
337
(new java.util.Date()) + "*/");
338
out.println("/* DO NOT EDIT */");
339
out.println();
340
341
// write the (unexpanded) keystore entry as the first entry of the
342
// policy file
343
if (keyStoreUrlString != null) {
344
writeKeyStoreEntry(out);
345
}
346
if (storePassURL != null) {
347
writeStorePassURL(out);
348
}
349
350
// write "grant" entries
351
while (enum_.hasMoreElements()) {
352
GrantEntry ge = enum_.nextElement();
353
ge.write(out);
354
out.println();
355
}
356
out.flush();
357
}
358
359
/**
360
* parses a keystore entry
361
*/
362
private void parseKeyStoreEntry() throws ParsingException, IOException {
363
match("keystore");
364
keyStoreUrlString = match("quoted string");
365
366
// parse keystore type
367
if (!peek(",")) {
368
return; // default type
369
}
370
match(",");
371
372
if (peek("\"")) {
373
keyStoreType = match("quoted string");
374
} else {
375
throw new ParsingException(st.lineno(),
376
ResourcesMgr.getString("expected.keystore.type"));
377
}
378
379
// parse keystore provider
380
if (!peek(",")) {
381
return; // provider optional
382
}
383
match(",");
384
385
if (peek("\"")) {
386
keyStoreProvider = match("quoted string");
387
} else {
388
throw new ParsingException(st.lineno(),
389
ResourcesMgr.getString("expected.keystore.provider"));
390
}
391
}
392
393
private void parseStorePassURL() throws ParsingException, IOException {
394
match("keyStorePasswordURL");
395
storePassURL = match("quoted string");
396
}
397
398
/**
399
* writes the (unexpanded) keystore entry
400
*/
401
private void writeKeyStoreEntry(PrintWriter out) {
402
out.print("keystore \"");
403
out.print(keyStoreUrlString);
404
out.print('"');
405
if (keyStoreType != null && keyStoreType.length() > 0)
406
out.print(", \"" + keyStoreType + "\"");
407
if (keyStoreProvider != null && keyStoreProvider.length() > 0)
408
out.print(", \"" + keyStoreProvider + "\"");
409
out.println(";");
410
out.println();
411
}
412
413
private void writeStorePassURL(PrintWriter out) {
414
out.print("keystorePasswordURL \"");
415
out.print(storePassURL);
416
out.print('"');
417
out.println(";");
418
out.println();
419
}
420
421
/**
422
* parse a Grant entry
423
*/
424
private GrantEntry parseGrantEntry()
425
throws ParsingException, IOException
426
{
427
GrantEntry e = new GrantEntry();
428
LinkedList<PrincipalEntry> principals = null;
429
boolean ignoreEntry = false;
430
431
match("grant");
432
433
while(!peek("{")) {
434
435
if (peekAndMatch("Codebase")) {
436
if (e.codeBase != null)
437
throw new ParsingException(
438
st.lineno(),
439
ResourcesMgr.getString
440
("multiple.Codebase.expressions"));
441
e.codeBase = match("quoted string");
442
peekAndMatch(",");
443
} else if (peekAndMatch("SignedBy")) {
444
if (e.signedBy != null)
445
throw new ParsingException(
446
st.lineno(),
447
ResourcesMgr.getString(
448
"multiple.SignedBy.expressions"));
449
e.signedBy = match("quoted string");
450
451
// verify syntax of the aliases
452
StringTokenizer aliases = new StringTokenizer(e.signedBy,
453
",", true);
454
int actr = 0;
455
int cctr = 0;
456
while (aliases.hasMoreTokens()) {
457
String alias = aliases.nextToken().trim();
458
if (alias.equals(","))
459
cctr++;
460
else if (alias.length() > 0)
461
actr++;
462
}
463
if (actr <= cctr)
464
throw new ParsingException(
465
st.lineno(),
466
ResourcesMgr.getString(
467
"SignedBy.has.empty.alias"));
468
469
peekAndMatch(",");
470
} else if (peekAndMatch("Principal")) {
471
if (principals == null) {
472
principals = new LinkedList<>();
473
}
474
475
String principalClass;
476
String principalName;
477
478
if (peek("\"")) {
479
// both the principalClass and principalName
480
// will be replaced later
481
principalClass = PrincipalEntry.REPLACE_NAME;
482
principalName = match("principal type");
483
} else {
484
// check for principalClass wildcard
485
if (peek("*")) {
486
match("*");
487
principalClass = PrincipalEntry.WILDCARD_CLASS;
488
} else {
489
principalClass = match("principal type");
490
}
491
492
// check for principalName wildcard
493
if (peek("*")) {
494
match("*");
495
principalName = PrincipalEntry.WILDCARD_NAME;
496
} else {
497
principalName = match("quoted string");
498
}
499
500
// disallow WILDCARD_CLASS && actual name
501
if (principalClass.equals(PrincipalEntry.WILDCARD_CLASS) &&
502
!principalName.equals(PrincipalEntry.WILDCARD_NAME)) {
503
if (debug != null) {
504
debug.println("disallowing principal that " +
505
"has WILDCARD class but no WILDCARD name");
506
}
507
throw new ParsingException
508
(st.lineno(),
509
ResourcesMgr.getString
510
("can.not.specify.Principal.with.a.wildcard.class.without.a.wildcard.name"));
511
}
512
}
513
514
try {
515
principalName = expand(principalName);
516
517
if (principalClass.equals
518
("javax.security.auth.x500.X500Principal") &&
519
!principalName.equals(PrincipalEntry.WILDCARD_NAME)) {
520
521
// 4702543: X500 names with an EmailAddress
522
// were encoded incorrectly. construct a new
523
// X500Principal with correct encoding.
524
525
X500Principal p = new X500Principal
526
((new X500Principal(principalName)).toString());
527
principalName = p.getName();
528
}
529
530
principals.add
531
(new PrincipalEntry(principalClass, principalName));
532
} catch (PropertyExpander.ExpandException peee) {
533
// ignore the entire policy entry
534
// but continue parsing all the info
535
// so we can get to the next entry
536
if (debug != null) {
537
debug.println("principal name expansion failed: " +
538
principalName);
539
}
540
ignoreEntry = true;
541
}
542
peekAndMatch(",");
543
544
} else {
545
throw new ParsingException(st.lineno(),
546
ResourcesMgr.getString(
547
"expected.codeBase.or.SignedBy.or.Principal"));
548
}
549
}
550
551
if (principals != null) e.principals = principals;
552
match("{");
553
554
while(!peek("}")) {
555
if (peek("Permission")) {
556
try {
557
PermissionEntry pe = parsePermissionEntry();
558
e.add(pe);
559
} catch (PropertyExpander.ExpandException peee) {
560
// ignore. The add never happened
561
if (debug != null) {
562
debug.println(peee.toString());
563
}
564
skipEntry(); // BugId 4219343
565
}
566
match(";");
567
} else {
568
throw new
569
ParsingException(st.lineno(),
570
ResourcesMgr.getString(
571
"expected.permission.entry"));
572
}
573
}
574
match("}");
575
576
try {
577
if (e.signedBy != null) e.signedBy = expand(e.signedBy);
578
if (e.codeBase != null) {
579
580
// For backward compatibility with 1.4
581
if (e.codeBase.equals(OLD_EXTDIRS_EXPANSION)) {
582
e.codeBase = EXTDIRS_EXPANSION;
583
}
584
int es;
585
if ((es=e.codeBase.indexOf(EXTDIRS_EXPANSION)) < 0) {
586
e.codeBase = expand(e.codeBase, true).replace
587
(File.separatorChar, '/');
588
} else {
589
// expand the system property "java.ext.dirs",
590
// parse it into its path components,
591
// and then create a grant entry for each component
592
String[] extDirs = parseExtDirs(e.codeBase, es);
593
if (extDirs != null && extDirs.length > 0) {
594
for (int i = 0; i < extDirs.length; i++) {
595
GrantEntry newGe = (GrantEntry)e.clone();
596
newGe.codeBase = extDirs[i];
597
add(newGe);
598
599
if (debug != null) {
600
debug.println("creating policy entry for " +
601
"expanded java.ext.dirs path:\n\t\t" +
602
extDirs[i]);
603
}
604
}
605
}
606
ignoreEntry = true;
607
}
608
}
609
} catch (PropertyExpander.ExpandException peee) {
610
if (debug != null) {
611
debug.println(peee.toString());
612
}
613
return null;
614
}
615
616
return (ignoreEntry == true) ? null : e;
617
}
618
619
/**
620
* parse a Permission entry
621
*/
622
private PermissionEntry parsePermissionEntry()
623
throws ParsingException, IOException, PropertyExpander.ExpandException
624
{
625
PermissionEntry e = new PermissionEntry();
626
627
// Permission
628
match("Permission");
629
e.permission = match("permission type");
630
631
if (peek("\"")) {
632
// Permission name
633
e.name = expand(match("quoted string"));
634
}
635
636
if (!peek(",")) {
637
return e;
638
}
639
match(",");
640
641
if (peek("\"")) {
642
e.action = expand(match("quoted string"));
643
if (!peek(",")) {
644
return e;
645
}
646
match(",");
647
}
648
649
if (peekAndMatch("SignedBy")) {
650
e.signedBy = expand(match("quoted string"));
651
}
652
return e;
653
}
654
655
/**
656
* parse a domain entry
657
*/
658
private DomainEntry parseDomainEntry()
659
throws ParsingException, IOException
660
{
661
boolean ignoreEntry = false;
662
DomainEntry domainEntry;
663
String name = null;
664
Map<String, String> properties = new HashMap<>();
665
666
match("domain");
667
name = match("domain name");
668
669
while(!peek("{")) {
670
// get the domain properties
671
properties = parseProperties("{");
672
}
673
match("{");
674
domainEntry = new DomainEntry(name, properties);
675
676
while(!peek("}")) {
677
678
match("keystore");
679
name = match("keystore name");
680
// get the keystore properties
681
if (!peek("}")) {
682
properties = parseProperties(";");
683
}
684
match(";");
685
domainEntry.add(new KeyStoreEntry(name, properties));
686
}
687
match("}");
688
689
return (ignoreEntry == true) ? null : domainEntry;
690
}
691
692
/*
693
* Return a collection of domain properties or keystore properties.
694
*/
695
private Map<String, String> parseProperties(String terminator)
696
throws ParsingException, IOException {
697
698
Map<String, String> properties = new HashMap<>();
699
String key;
700
String value;
701
while (!peek(terminator)) {
702
key = match("property name");
703
match("=");
704
705
try {
706
value = expand(match("quoted string"));
707
} catch (PropertyExpander.ExpandException peee) {
708
throw new IOException(peee.getLocalizedMessage());
709
}
710
properties.put(key.toLowerCase(Locale.ENGLISH), value);
711
}
712
713
return properties;
714
}
715
716
// package-private: used by PolicyFile for static policy
717
static String[] parseExtDirs(String codebase, int start) {
718
719
String s = System.getProperty(EXTDIRS_PROPERTY);
720
String globalPrefix = (start > 0 ? codebase.substring(0, start) : "file:");
721
int end = start + EXTDIRS_EXPANSION.length();
722
String globalSuffix = (end < codebase.length() ? codebase.substring(end) :
723
(String) null);
724
725
String[] dirs = null;
726
String localSuffix;
727
if (s != null) {
728
StringTokenizer st =
729
new StringTokenizer(s, File.pathSeparator);
730
int count = st.countTokens();
731
dirs = new String[count];
732
for (int i = 0; i < count; i++) {
733
File file = new File(st.nextToken());
734
dirs[i] = sun.net.www.ParseUtil.encodePath
735
(file.getAbsolutePath());
736
737
if (!dirs[i].startsWith("/")) {
738
dirs[i] = "/" + dirs[i];
739
}
740
741
localSuffix = (globalSuffix == null ?
742
(dirs[i].endsWith("/") ? "*" : "/*") :
743
globalSuffix);
744
745
dirs[i] = globalPrefix + dirs[i] + localSuffix;
746
}
747
}
748
return dirs;
749
}
750
751
private boolean peekAndMatch(String expect)
752
throws ParsingException, IOException
753
{
754
if (peek(expect)) {
755
match(expect);
756
return true;
757
} else {
758
return false;
759
}
760
}
761
762
private boolean peek(String expect) {
763
boolean found = false;
764
765
switch (lookahead) {
766
767
case StreamTokenizer.TT_WORD:
768
if (expect.equalsIgnoreCase(st.sval))
769
found = true;
770
break;
771
case ',':
772
if (expect.equalsIgnoreCase(","))
773
found = true;
774
break;
775
case '{':
776
if (expect.equalsIgnoreCase("{"))
777
found = true;
778
break;
779
case '}':
780
if (expect.equalsIgnoreCase("}"))
781
found = true;
782
break;
783
case '"':
784
if (expect.equalsIgnoreCase("\""))
785
found = true;
786
break;
787
case '*':
788
if (expect.equalsIgnoreCase("*"))
789
found = true;
790
break;
791
case ';':
792
if (expect.equalsIgnoreCase(";"))
793
found = true;
794
break;
795
default:
796
797
}
798
return found;
799
}
800
801
private String match(String expect)
802
throws ParsingException, IOException
803
{
804
String value = null;
805
806
switch (lookahead) {
807
case StreamTokenizer.TT_NUMBER:
808
throw new ParsingException(st.lineno(), expect,
809
ResourcesMgr.getString("number.") +
810
String.valueOf(st.nval));
811
case StreamTokenizer.TT_EOF:
812
MessageFormat form = new MessageFormat(
813
ResourcesMgr.getString
814
("expected.expect.read.end.of.file."));
815
Object[] source = {expect};
816
throw new ParsingException(form.format(source));
817
case StreamTokenizer.TT_WORD:
818
if (expect.equalsIgnoreCase(st.sval)) {
819
lookahead = st.nextToken();
820
} else if (expect.equalsIgnoreCase("permission type")) {
821
value = st.sval;
822
lookahead = st.nextToken();
823
} else if (expect.equalsIgnoreCase("principal type")) {
824
value = st.sval;
825
lookahead = st.nextToken();
826
} else if (expect.equalsIgnoreCase("domain name") ||
827
expect.equalsIgnoreCase("keystore name") ||
828
expect.equalsIgnoreCase("property name")) {
829
value = st.sval;
830
lookahead = st.nextToken();
831
} else {
832
throw new ParsingException(st.lineno(), expect,
833
st.sval);
834
}
835
break;
836
case '"':
837
if (expect.equalsIgnoreCase("quoted string")) {
838
value = st.sval;
839
lookahead = st.nextToken();
840
} else if (expect.equalsIgnoreCase("permission type")) {
841
value = st.sval;
842
lookahead = st.nextToken();
843
} else if (expect.equalsIgnoreCase("principal type")) {
844
value = st.sval;
845
lookahead = st.nextToken();
846
} else {
847
throw new ParsingException(st.lineno(), expect, st.sval);
848
}
849
break;
850
case ',':
851
if (expect.equalsIgnoreCase(","))
852
lookahead = st.nextToken();
853
else
854
throw new ParsingException(st.lineno(), expect, ",");
855
break;
856
case '{':
857
if (expect.equalsIgnoreCase("{"))
858
lookahead = st.nextToken();
859
else
860
throw new ParsingException(st.lineno(), expect, "{");
861
break;
862
case '}':
863
if (expect.equalsIgnoreCase("}"))
864
lookahead = st.nextToken();
865
else
866
throw new ParsingException(st.lineno(), expect, "}");
867
break;
868
case ';':
869
if (expect.equalsIgnoreCase(";"))
870
lookahead = st.nextToken();
871
else
872
throw new ParsingException(st.lineno(), expect, ";");
873
break;
874
case '*':
875
if (expect.equalsIgnoreCase("*"))
876
lookahead = st.nextToken();
877
else
878
throw new ParsingException(st.lineno(), expect, "*");
879
break;
880
case '=':
881
if (expect.equalsIgnoreCase("="))
882
lookahead = st.nextToken();
883
else
884
throw new ParsingException(st.lineno(), expect, "=");
885
break;
886
default:
887
throw new ParsingException(st.lineno(), expect,
888
new String(new char[] {(char)lookahead}));
889
}
890
return value;
891
}
892
893
/**
894
* skip all tokens for this entry leaving the delimiter ";"
895
* in the stream.
896
*/
897
private void skipEntry() throws ParsingException, IOException {
898
while(lookahead != ';') {
899
switch (lookahead) {
900
case StreamTokenizer.TT_NUMBER:
901
throw new ParsingException(st.lineno(), ";",
902
ResourcesMgr.getString("number.") +
903
String.valueOf(st.nval));
904
case StreamTokenizer.TT_EOF:
905
throw new ParsingException(ResourcesMgr.getString
906
("expected.read.end.of.file."));
907
default:
908
lookahead = st.nextToken();
909
}
910
}
911
}
912
913
/**
914
* Each grant entry in the policy configuration file is
915
* represented by a
916
* GrantEntry object. <p>
917
*
918
* <p>
919
* For example, the entry
920
* <pre>
921
* grant signedBy "Duke" {
922
* permission java.io.FilePermission "/tmp", "read,write";
923
* };
924
*
925
* </pre>
926
* is represented internally
927
* <pre>
928
*
929
* pe = new PermissionEntry("java.io.FilePermission",
930
* "/tmp", "read,write");
931
*
932
* ge = new GrantEntry("Duke", null);
933
*
934
* ge.add(pe);
935
*
936
* </pre>
937
*
938
* @author Roland Schemers
939
*
940
* version 1.19, 05/21/98
941
*/
942
943
public static class GrantEntry {
944
945
public String signedBy;
946
public String codeBase;
947
public LinkedList<PrincipalEntry> principals;
948
public Vector<PermissionEntry> permissionEntries;
949
950
public GrantEntry() {
951
principals = new LinkedList<PrincipalEntry>();
952
permissionEntries = new Vector<PermissionEntry>();
953
}
954
955
public GrantEntry(String signedBy, String codeBase) {
956
this.codeBase = codeBase;
957
this.signedBy = signedBy;
958
principals = new LinkedList<PrincipalEntry>();
959
permissionEntries = new Vector<PermissionEntry>();
960
}
961
962
public void add(PermissionEntry pe)
963
{
964
permissionEntries.addElement(pe);
965
}
966
967
public boolean remove(PrincipalEntry pe)
968
{
969
return principals.remove(pe);
970
}
971
972
public boolean remove(PermissionEntry pe)
973
{
974
return permissionEntries.removeElement(pe);
975
}
976
977
public boolean contains(PrincipalEntry pe)
978
{
979
return principals.contains(pe);
980
}
981
982
public boolean contains(PermissionEntry pe)
983
{
984
return permissionEntries.contains(pe);
985
}
986
987
/**
988
* Enumerate all the permission entries in this GrantEntry.
989
*/
990
public Enumeration<PermissionEntry> permissionElements(){
991
return permissionEntries.elements();
992
}
993
994
995
public void write(PrintWriter out) {
996
out.print("grant");
997
if (signedBy != null) {
998
out.print(" signedBy \"");
999
out.print(signedBy);
1000
out.print('"');
1001
if (codeBase != null)
1002
out.print(", ");
1003
}
1004
if (codeBase != null) {
1005
out.print(" codeBase \"");
1006
out.print(codeBase);
1007
out.print('"');
1008
if (principals != null && principals.size() > 0)
1009
out.print(",\n");
1010
}
1011
if (principals != null && principals.size() > 0) {
1012
Iterator<PrincipalEntry> pli = principals.iterator();
1013
while (pli.hasNext()) {
1014
out.print(" ");
1015
PrincipalEntry pe = pli.next();
1016
pe.write(out);
1017
if (pli.hasNext())
1018
out.print(",\n");
1019
}
1020
}
1021
out.println(" {");
1022
Enumeration<PermissionEntry> enum_ = permissionEntries.elements();
1023
while (enum_.hasMoreElements()) {
1024
PermissionEntry pe = enum_.nextElement();
1025
out.write(" ");
1026
pe.write(out);
1027
}
1028
out.println("};");
1029
}
1030
1031
public Object clone() {
1032
GrantEntry ge = new GrantEntry();
1033
ge.codeBase = this.codeBase;
1034
ge.signedBy = this.signedBy;
1035
ge.principals = new LinkedList<PrincipalEntry>(this.principals);
1036
ge.permissionEntries =
1037
new Vector<PermissionEntry>(this.permissionEntries);
1038
return ge;
1039
}
1040
}
1041
1042
/**
1043
* Principal info (class and name) in a grant entry
1044
*/
1045
public static class PrincipalEntry implements Principal {
1046
1047
public static final String WILDCARD_CLASS = "WILDCARD_PRINCIPAL_CLASS";
1048
public static final String WILDCARD_NAME = "WILDCARD_PRINCIPAL_NAME";
1049
public static final String REPLACE_NAME = "PolicyParser.REPLACE_NAME";
1050
1051
String principalClass;
1052
String principalName;
1053
1054
/**
1055
* A PrincipalEntry consists of the Principal class and Principal name.
1056
*
1057
* @param principalClass the Principal class
1058
* @param principalName the Principal name
1059
* @throws NullPointerException if principalClass or principalName
1060
* are null
1061
*/
1062
public PrincipalEntry(String principalClass, String principalName) {
1063
if (principalClass == null || principalName == null)
1064
throw new NullPointerException(ResourcesMgr.getString(
1065
"null.principalClass.or.principalName"));
1066
this.principalClass = principalClass;
1067
this.principalName = principalName;
1068
}
1069
1070
boolean isWildcardName() {
1071
return principalName.equals(WILDCARD_NAME);
1072
}
1073
1074
boolean isWildcardClass() {
1075
return principalClass.equals(WILDCARD_CLASS);
1076
}
1077
1078
boolean isReplaceName() {
1079
return principalClass.equals(REPLACE_NAME);
1080
}
1081
1082
public String getPrincipalClass() {
1083
return principalClass;
1084
}
1085
1086
public String getPrincipalName() {
1087
return principalName;
1088
}
1089
1090
public String getDisplayClass() {
1091
if (isWildcardClass()) {
1092
return "*";
1093
} else if (isReplaceName()) {
1094
return "";
1095
}
1096
else return principalClass;
1097
}
1098
1099
public String getDisplayName() {
1100
return getDisplayName(false);
1101
}
1102
1103
public String getDisplayName(boolean addQuote) {
1104
if (isWildcardName()) {
1105
return "*";
1106
}
1107
else {
1108
if (addQuote) return "\"" + principalName + "\"";
1109
else return principalName;
1110
}
1111
}
1112
1113
@Override
1114
public String getName() {
1115
return principalName;
1116
}
1117
1118
@Override
1119
public String toString() {
1120
if (!isReplaceName()) {
1121
return getDisplayClass() + "/" + getDisplayName();
1122
} else {
1123
return getDisplayName();
1124
}
1125
}
1126
1127
/**
1128
* Test for equality between the specified object and this object.
1129
* Two PrincipalEntries are equal if their class and name values
1130
* are equal.
1131
*
1132
* @param obj the object to test for equality with this object
1133
* @return true if the objects are equal, false otherwise
1134
*/
1135
@Override
1136
public boolean equals(Object obj) {
1137
if (this == obj)
1138
return true;
1139
1140
if (!(obj instanceof PrincipalEntry))
1141
return false;
1142
1143
PrincipalEntry that = (PrincipalEntry)obj;
1144
return (principalClass.equals(that.principalClass) &&
1145
principalName.equals(that.principalName));
1146
}
1147
1148
/**
1149
* Return a hashcode for this PrincipalEntry.
1150
*
1151
* @return a hashcode for this PrincipalEntry
1152
*/
1153
@Override
1154
public int hashCode() {
1155
return principalClass.hashCode();
1156
}
1157
1158
public void write(PrintWriter out) {
1159
out.print("principal " + getDisplayClass() + " " +
1160
getDisplayName(true));
1161
}
1162
}
1163
1164
/**
1165
* Each permission entry in the policy configuration file is
1166
* represented by a
1167
* PermissionEntry object. <p>
1168
*
1169
* <p>
1170
* For example, the entry
1171
* <pre>
1172
* permission java.io.FilePermission "/tmp", "read,write";
1173
* </pre>
1174
* is represented internally
1175
* <pre>
1176
*
1177
* pe = new PermissionEntry("java.io.FilePermission",
1178
* "/tmp", "read,write");
1179
* </pre>
1180
*
1181
* @author Roland Schemers
1182
*
1183
* version 1.19, 05/21/98
1184
*/
1185
1186
public static class PermissionEntry {
1187
1188
public String permission;
1189
public String name;
1190
public String action;
1191
public String signedBy;
1192
1193
public PermissionEntry() {
1194
}
1195
1196
public PermissionEntry(String permission,
1197
String name,
1198
String action) {
1199
this.permission = permission;
1200
this.name = name;
1201
this.action = action;
1202
}
1203
1204
/**
1205
* Calculates a hash code value for the object. Objects
1206
* which are equal will also have the same hashcode.
1207
*/
1208
@Override
1209
public int hashCode() {
1210
int retval = permission.hashCode();
1211
if (name != null) retval ^= name.hashCode();
1212
if (action != null) retval ^= action.hashCode();
1213
return retval;
1214
}
1215
1216
@Override
1217
public boolean equals(Object obj) {
1218
if (obj == this)
1219
return true;
1220
1221
if (! (obj instanceof PermissionEntry))
1222
return false;
1223
1224
PermissionEntry that = (PermissionEntry) obj;
1225
1226
if (this.permission == null) {
1227
if (that.permission != null) return false;
1228
} else {
1229
if (!this.permission.equals(that.permission)) return false;
1230
}
1231
1232
if (this.name == null) {
1233
if (that.name != null) return false;
1234
} else {
1235
if (!this.name.equals(that.name)) return false;
1236
}
1237
1238
if (this.action == null) {
1239
if (that.action != null) return false;
1240
} else {
1241
if (!this.action.equals(that.action)) return false;
1242
}
1243
1244
if (this.signedBy == null) {
1245
if (that.signedBy != null) return false;
1246
} else {
1247
if (!this.signedBy.equals(that.signedBy)) return false;
1248
}
1249
1250
// everything matched -- the 2 objects are equal
1251
return true;
1252
}
1253
1254
public void write(PrintWriter out) {
1255
out.print("permission ");
1256
out.print(permission);
1257
if (name != null) {
1258
out.print(" \"");
1259
1260
// ATTENTION: regex with double escaping,
1261
// the normal forms look like:
1262
// $name =~ s/\\/\\\\/g; and
1263
// $name =~ s/\"/\\\"/g;
1264
// and then in a java string, it's escaped again
1265
1266
out.print(name.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\\"", "\\\\\\\""));
1267
out.print('"');
1268
}
1269
if (action != null) {
1270
out.print(", \"");
1271
out.print(action);
1272
out.print('"');
1273
}
1274
if (signedBy != null) {
1275
out.print(", signedBy \"");
1276
out.print(signedBy);
1277
out.print('"');
1278
}
1279
out.println(";");
1280
}
1281
}
1282
1283
/**
1284
* Each domain entry in the keystore domain configuration file is
1285
* represented by a DomainEntry object.
1286
*/
1287
static class DomainEntry {
1288
private final String name;
1289
private final Map<String, String> properties;
1290
private final Map<String, KeyStoreEntry> entries;
1291
1292
DomainEntry(String name, Map<String, String> properties) {
1293
this.name = name;
1294
this.properties = properties;
1295
entries = new HashMap<>();
1296
}
1297
1298
String getName() {
1299
return name;
1300
}
1301
1302
Map<String, String> getProperties() {
1303
return properties;
1304
}
1305
1306
Collection<KeyStoreEntry> getEntries() {
1307
return entries.values();
1308
}
1309
1310
void add(KeyStoreEntry entry) throws ParsingException {
1311
String keystoreName = entry.getName();
1312
if (!entries.containsKey(keystoreName)) {
1313
entries.put(keystoreName, entry);
1314
} else {
1315
MessageFormat form = new MessageFormat(ResourcesMgr.getString(
1316
"duplicate.keystore.name"));
1317
Object[] source = {keystoreName};
1318
throw new ParsingException(form.format(source));
1319
}
1320
}
1321
1322
@Override
1323
public String toString() {
1324
StringBuilder s =
1325
new StringBuilder("\ndomain ").append(name);
1326
1327
if (properties != null) {
1328
for (Map.Entry<String, String> property :
1329
properties.entrySet()) {
1330
s.append("\n ").append(property.getKey()).append('=')
1331
.append(property.getValue());
1332
}
1333
}
1334
s.append(" {\n");
1335
1336
if (entries != null) {
1337
for (KeyStoreEntry entry : entries.values()) {
1338
s.append(entry).append("\n");
1339
}
1340
}
1341
s.append("}");
1342
1343
return s.toString();
1344
}
1345
}
1346
1347
/**
1348
* Each keystore entry in the keystore domain configuration file is
1349
* represented by a KeyStoreEntry object.
1350
*/
1351
1352
static class KeyStoreEntry {
1353
private final String name;
1354
private final Map<String, String> properties;
1355
1356
KeyStoreEntry(String name, Map<String, String> properties) {
1357
this.name = name;
1358
this.properties = properties;
1359
}
1360
1361
String getName() {
1362
return name;
1363
}
1364
1365
Map<String, String> getProperties() {
1366
return properties;
1367
}
1368
1369
@Override
1370
public String toString() {
1371
StringBuilder s = new StringBuilder("\n keystore ").append(name);
1372
if (properties != null) {
1373
for (Map.Entry<String, String> property :
1374
properties.entrySet()) {
1375
s.append("\n ").append(property.getKey()).append('=')
1376
.append(property.getValue());
1377
}
1378
}
1379
s.append(";");
1380
1381
return s.toString();
1382
}
1383
}
1384
1385
public static class ParsingException extends GeneralSecurityException {
1386
1387
private static final long serialVersionUID = -4330692689482574072L;
1388
1389
private String i18nMessage;
1390
1391
/**
1392
* Constructs a ParsingException with the specified
1393
* detail message. A detail message is a String that describes
1394
* this particular exception, which may, for example, specify which
1395
* algorithm is not available.
1396
*
1397
* @param msg the detail message.
1398
*/
1399
public ParsingException(String msg) {
1400
super(msg);
1401
i18nMessage = msg;
1402
}
1403
1404
public ParsingException(int line, String msg) {
1405
super("line " + line + ": " + msg);
1406
MessageFormat form = new MessageFormat
1407
(ResourcesMgr.getString("line.number.msg"));
1408
Object[] source = {new Integer(line), msg};
1409
i18nMessage = form.format(source);
1410
}
1411
1412
public ParsingException(int line, String expect, String actual) {
1413
super("line " + line + ": expected [" + expect +
1414
"], found [" + actual + "]");
1415
MessageFormat form = new MessageFormat(ResourcesMgr.getString
1416
("line.number.expected.expect.found.actual."));
1417
Object[] source = {new Integer(line), expect, actual};
1418
i18nMessage = form.format(source);
1419
}
1420
1421
@Override
1422
public String getLocalizedMessage() {
1423
return i18nMessage;
1424
}
1425
}
1426
1427
public static void main(String arg[]) throws Exception {
1428
try (FileReader fr = new FileReader(arg[0]);
1429
FileWriter fw = new FileWriter(arg[1])) {
1430
PolicyParser pp = new PolicyParser(true);
1431
pp.read(fr);
1432
pp.write(fw);
1433
}
1434
}
1435
}
1436
1437