Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/java/security/Permissions.java
41152 views
1
/*
2
* Copyright (c) 1997, 2021, 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 java.security;
27
28
import java.io.InvalidObjectException;
29
import java.io.IOException;
30
import java.io.ObjectInputStream;
31
import java.io.ObjectOutputStream;
32
import java.io.ObjectStreamField;
33
import java.io.Serializable;
34
import java.util.Enumeration;
35
import java.util.Hashtable;
36
import java.util.Iterator;
37
import java.util.List;
38
import java.util.Map;
39
import java.util.NoSuchElementException;
40
import java.util.concurrent.ConcurrentHashMap;
41
42
/**
43
* This class represents a heterogeneous collection of Permissions. That is,
44
* it contains different types of Permission objects, organized into
45
* PermissionCollections. For example, if any
46
* {@code java.io.FilePermission} objects are added to an instance of
47
* this class, they are all stored in a single
48
* PermissionCollection. It is the PermissionCollection returned by a call to
49
* the {@code newPermissionCollection} method in the FilePermission class.
50
* Similarly, any {@code java.lang.RuntimePermission} objects are
51
* stored in the PermissionCollection returned by a call to the
52
* {@code newPermissionCollection} method in the
53
* RuntimePermission class. Thus, this class represents a collection of
54
* PermissionCollections.
55
*
56
* <p>When the {@code add} method is called to add a Permission, the
57
* Permission is stored in the appropriate PermissionCollection. If no such
58
* collection exists yet, the Permission object's class is determined and the
59
* {@code newPermissionCollection} method is called on that class to create
60
* the PermissionCollection and add it to the Permissions object. If
61
* {@code newPermissionCollection} returns null, then a default
62
* PermissionCollection that uses a hashtable will be created and used. Each
63
* hashtable entry stores a Permission object as both the key and the value.
64
*
65
* <p> Enumerations returned via the {@code elements} method are
66
* not <em>fail-fast</em>. Modifications to a collection should not be
67
* performed while enumerating over that collection.
68
*
69
* @see Permission
70
* @see PermissionCollection
71
* @see AllPermission
72
*
73
*
74
* @author Marianne Mueller
75
* @author Roland Schemers
76
* @since 1.2
77
*
78
* @serial exclude
79
*/
80
81
public final class Permissions extends PermissionCollection
82
implements Serializable
83
{
84
/**
85
* Key is permissions Class, value is PermissionCollection for that class.
86
* Not serialized; see serialization section at end of class.
87
*/
88
private transient ConcurrentHashMap<Class<?>, PermissionCollection> permsMap;
89
90
// optimization. keep track of whether unresolved permissions need to be
91
// checked
92
private transient boolean hasUnresolved = false;
93
94
// optimization. keep track of the AllPermission collection
95
// - package private for ProtectionDomain optimization
96
PermissionCollection allPermission;
97
98
/**
99
* Creates a new Permissions object containing no PermissionCollections.
100
*/
101
public Permissions() {
102
permsMap = new ConcurrentHashMap<>(11);
103
allPermission = null;
104
}
105
106
/**
107
* Adds a permission object to the PermissionCollection for the class the
108
* permission belongs to. For example, if <i>permission</i> is a
109
* FilePermission, it is added to the FilePermissionCollection stored
110
* in this Permissions object.
111
*
112
* This method creates
113
* a new PermissionCollection object (and adds the permission to it)
114
* if an appropriate collection does not yet exist.
115
*
116
* @param permission the Permission object to add.
117
*
118
* @throws SecurityException if this Permissions object is
119
* marked as readonly.
120
*
121
* @see PermissionCollection#isReadOnly()
122
*/
123
@Override
124
public void add(Permission permission) {
125
if (isReadOnly())
126
throw new SecurityException(
127
"attempt to add a Permission to a readonly Permissions object");
128
129
PermissionCollection pc = getPermissionCollection(permission, true);
130
pc.add(permission);
131
132
// No sync; staleness -> optimizations delayed, which is OK
133
if (permission instanceof AllPermission) {
134
allPermission = pc;
135
}
136
if (permission instanceof UnresolvedPermission) {
137
hasUnresolved = true;
138
}
139
}
140
141
/**
142
* Checks to see if this object's PermissionCollection for permissions of
143
* the specified permission's class implies the permissions
144
* expressed in the <i>permission</i> object. Returns true if the
145
* combination of permissions in the appropriate PermissionCollection
146
* (e.g., a FilePermissionCollection for a FilePermission) together
147
* imply the specified permission.
148
*
149
* <p>For example, suppose there is a FilePermissionCollection in this
150
* Permissions object, and it contains one FilePermission that specifies
151
* "read" access for all files in all subdirectories of the "/tmp"
152
* directory, and another FilePermission that specifies "write" access
153
* for all files in the "/tmp/scratch/foo" directory.
154
* Then if the {@code implies} method
155
* is called with a permission specifying both "read" and "write" access
156
* to files in the "/tmp/scratch/foo" directory, {@code true} is
157
* returned.
158
*
159
* <p>Additionally, if this PermissionCollection contains the
160
* AllPermission, this method will always return true.
161
*
162
* @param permission the Permission object to check.
163
*
164
* @return true if "permission" is implied by the permissions in the
165
* PermissionCollection it
166
* belongs to, false if not.
167
*/
168
@Override
169
public boolean implies(Permission permission) {
170
// No sync; staleness -> skip optimization, which is OK
171
if (allPermission != null) {
172
return true; // AllPermission has already been added
173
} else {
174
PermissionCollection pc = getPermissionCollection(permission,
175
false);
176
if (pc != null) {
177
return pc.implies(permission);
178
} else {
179
// none found
180
return false;
181
}
182
}
183
}
184
185
/**
186
* Returns an enumeration of all the Permission objects in all the
187
* PermissionCollections in this Permissions object.
188
*
189
* @return an enumeration of all the Permissions.
190
*/
191
@Override
192
public Enumeration<Permission> elements() {
193
// go through each Permissions in the hash table
194
// and call their elements() function.
195
196
return new PermissionsEnumerator(permsMap.values().iterator());
197
}
198
199
/**
200
* Gets the PermissionCollection in this Permissions object for
201
* permissions whose type is the same as that of <i>p</i>.
202
* For example, if <i>p</i> is a FilePermission,
203
* the FilePermissionCollection
204
* stored in this Permissions object will be returned.
205
*
206
* If createEmpty is true,
207
* this method creates a new PermissionCollection object for the specified
208
* type of permission objects if one does not yet exist.
209
* To do so, it first calls the {@code newPermissionCollection} method
210
* on <i>p</i>. Subclasses of class Permission
211
* override that method if they need to store their permissions in a
212
* particular PermissionCollection object in order to provide the
213
* correct semantics when the {@code PermissionCollection.implies}
214
* method is called.
215
* If the call returns a PermissionCollection, that collection is stored
216
* in this Permissions object. If the call returns null and createEmpty
217
* is true, then
218
* this method instantiates and stores a default PermissionCollection
219
* that uses a hashtable to store its permission objects.
220
*
221
* createEmpty is ignored when creating empty PermissionCollection
222
* for unresolved permissions because of the overhead of determining the
223
* PermissionCollection to use.
224
*
225
* createEmpty should be set to false when this method is invoked from
226
* implies() because it incurs the additional overhead of creating and
227
* adding an empty PermissionCollection that will just return false.
228
* It should be set to true when invoked from add().
229
*/
230
private PermissionCollection getPermissionCollection(Permission p,
231
boolean createEmpty) {
232
PermissionCollection pc = permsMap.get(p.getClass());
233
if ((!hasUnresolved && !createEmpty) || pc != null) {
234
// Collection not to be created, or already created
235
return pc;
236
}
237
return createPermissionCollection(p, createEmpty);
238
}
239
240
private PermissionCollection createPermissionCollection(Permission p,
241
boolean createEmpty) {
242
synchronized (permsMap) {
243
// Re-read under lock
244
Class<?> c = p.getClass();
245
PermissionCollection pc = permsMap.get(c);
246
247
// Collection already created
248
if (pc != null) {
249
return pc;
250
}
251
252
// Create and add permission collection to map if it is absent.
253
// Check for unresolved permissions
254
pc = (hasUnresolved ? getUnresolvedPermissions(p) : null);
255
256
// if still null, create a new collection
257
if (pc == null && createEmpty) {
258
259
pc = p.newPermissionCollection();
260
261
// still no PermissionCollection?
262
// We'll give them a PermissionsHash.
263
if (pc == null) {
264
pc = new PermissionsHash();
265
}
266
}
267
if (pc != null) {
268
// Add pc, resolving any race
269
PermissionCollection oldPc = permsMap.putIfAbsent(c, pc);
270
if (oldPc != null) {
271
pc = oldPc;
272
}
273
}
274
return pc;
275
}
276
}
277
278
/**
279
* Resolves any unresolved permissions of type p.
280
*
281
* @param p the type of unresolved permission to resolve
282
*
283
* @return PermissionCollection containing the unresolved permissions,
284
* or null if there were no unresolved permissions of type p.
285
*
286
*/
287
private PermissionCollection getUnresolvedPermissions(Permission p)
288
{
289
UnresolvedPermissionCollection uc =
290
(UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);
291
292
// we have no unresolved permissions if uc is null
293
if (uc == null)
294
return null;
295
296
List<UnresolvedPermission> unresolvedPerms =
297
uc.getUnresolvedPermissions(p);
298
299
// we have no unresolved permissions of this type if unresolvedPerms is null
300
if (unresolvedPerms == null)
301
return null;
302
303
java.security.cert.Certificate[] certs = null;
304
305
Object[] signers = p.getClass().getSigners();
306
307
int n = 0;
308
if (signers != null) {
309
for (int j=0; j < signers.length; j++) {
310
if (signers[j] instanceof java.security.cert.Certificate) {
311
n++;
312
}
313
}
314
certs = new java.security.cert.Certificate[n];
315
n = 0;
316
for (int j=0; j < signers.length; j++) {
317
if (signers[j] instanceof java.security.cert.Certificate) {
318
certs[n++] = (java.security.cert.Certificate)signers[j];
319
}
320
}
321
}
322
323
PermissionCollection pc = null;
324
synchronized (unresolvedPerms) {
325
int len = unresolvedPerms.size();
326
for (int i = 0; i < len; i++) {
327
UnresolvedPermission up = unresolvedPerms.get(i);
328
Permission perm = up.resolve(p, certs);
329
if (perm != null) {
330
if (pc == null) {
331
pc = p.newPermissionCollection();
332
if (pc == null)
333
pc = new PermissionsHash();
334
}
335
pc.add(perm);
336
}
337
}
338
}
339
return pc;
340
}
341
342
@java.io.Serial
343
private static final long serialVersionUID = 4858622370623524688L;
344
345
// Need to maintain serialization interoperability with earlier releases,
346
// which had the serializable field:
347
// private Hashtable perms;
348
349
/**
350
* @serialField perms java.util.Hashtable
351
* A table of the Permission classes and PermissionCollections.
352
* @serialField allPermission java.security.PermissionCollection
353
*/
354
@java.io.Serial
355
private static final ObjectStreamField[] serialPersistentFields = {
356
new ObjectStreamField("perms", Hashtable.class),
357
new ObjectStreamField("allPermission", PermissionCollection.class),
358
};
359
360
/**
361
* @serialData Default fields.
362
*/
363
/*
364
* Writes the contents of the permsMap field out as a Hashtable for
365
* serialization compatibility with earlier releases. allPermission
366
* unchanged.
367
*/
368
@java.io.Serial
369
private void writeObject(ObjectOutputStream out) throws IOException {
370
// Don't call out.defaultWriteObject()
371
372
// Copy perms into a Hashtable
373
Hashtable<Class<?>, PermissionCollection> perms =
374
new Hashtable<>(permsMap.size()*2); // no sync; estimate
375
perms.putAll(permsMap);
376
377
// Write out serializable fields
378
ObjectOutputStream.PutField pfields = out.putFields();
379
380
pfields.put("allPermission", allPermission); // no sync; staleness OK
381
pfields.put("perms", perms);
382
out.writeFields();
383
}
384
385
/*
386
* Reads in a Hashtable of Class/PermissionCollections and saves them in the
387
* permsMap field. Reads in allPermission.
388
*/
389
@java.io.Serial
390
private void readObject(ObjectInputStream in) throws IOException,
391
ClassNotFoundException {
392
// Don't call defaultReadObject()
393
394
// Read in serialized fields
395
ObjectInputStream.GetField gfields = in.readFields();
396
397
// Get allPermission
398
allPermission = (PermissionCollection) gfields.get("allPermission", null);
399
400
// Get permissions
401
// writeObject writes a Hashtable<Class<?>, PermissionCollection> for
402
// the perms key, so this cast is safe, unless the data is corrupt.
403
@SuppressWarnings("unchecked")
404
Hashtable<Class<?>, PermissionCollection> perms =
405
(Hashtable<Class<?>, PermissionCollection>)gfields.get("perms", null);
406
permsMap = new ConcurrentHashMap<>(perms.size()*2);
407
permsMap.putAll(perms);
408
409
// Check that Class is mapped to PermissionCollection containing
410
// Permissions of the same class
411
for (Map.Entry<Class<?>, PermissionCollection> e : perms.entrySet()) {
412
Class<?> k = e.getKey();
413
PermissionCollection v = e.getValue();
414
Enumeration<Permission> en = v.elements();
415
while (en.hasMoreElements()) {
416
Permission p = en.nextElement();
417
if (!k.equals(p.getClass())) {
418
throw new InvalidObjectException("Permission with class " +
419
k + " incorrectly mapped to PermissionCollection " +
420
"containing Permission with " + p.getClass());
421
}
422
}
423
}
424
425
// Set hasUnresolved
426
UnresolvedPermissionCollection uc =
427
(UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);
428
hasUnresolved = (uc != null && uc.elements().hasMoreElements());
429
}
430
}
431
432
final class PermissionsEnumerator implements Enumeration<Permission> {
433
434
// all the perms
435
private Iterator<PermissionCollection> perms;
436
// the current set
437
private Enumeration<Permission> permset;
438
439
PermissionsEnumerator(Iterator<PermissionCollection> e) {
440
perms = e;
441
permset = getNextEnumWithMore();
442
}
443
444
// No need to synchronize; caller should sync on object as required
445
public boolean hasMoreElements() {
446
// if we enter with permissionimpl null, we know
447
// there are no more left.
448
449
if (permset == null)
450
return false;
451
452
// try to see if there are any left in the current one
453
454
if (permset.hasMoreElements())
455
return true;
456
457
// get the next one that has something in it...
458
permset = getNextEnumWithMore();
459
460
// if it is null, we are done!
461
return (permset != null);
462
}
463
464
// No need to synchronize; caller should sync on object as required
465
public Permission nextElement() {
466
467
// hasMoreElements will update permset to the next permset
468
// with something in it...
469
470
if (hasMoreElements()) {
471
return permset.nextElement();
472
} else {
473
throw new NoSuchElementException("PermissionsEnumerator");
474
}
475
476
}
477
478
private Enumeration<Permission> getNextEnumWithMore() {
479
while (perms.hasNext()) {
480
PermissionCollection pc = perms.next();
481
Enumeration<Permission> next =pc.elements();
482
if (next.hasMoreElements())
483
return next;
484
}
485
return null;
486
487
}
488
}
489
490
/**
491
* A PermissionsHash stores a homogeneous set of permissions in a hashtable.
492
*
493
* @see Permission
494
* @see Permissions
495
*
496
*
497
* @author Roland Schemers
498
*
499
* @serial include
500
*/
501
502
final class PermissionsHash extends PermissionCollection
503
implements Serializable
504
{
505
/**
506
* Key and value are (same) permissions objects.
507
* Not serialized; see serialization section at end of class.
508
*/
509
private transient ConcurrentHashMap<Permission, Permission> permsMap;
510
511
/**
512
* Create an empty PermissionsHash object.
513
*/
514
PermissionsHash() {
515
permsMap = new ConcurrentHashMap<>(11);
516
}
517
518
/**
519
* Adds a permission to the PermissionsHash.
520
*
521
* @param permission the Permission object to add.
522
*/
523
@Override
524
public void add(Permission permission) {
525
permsMap.put(permission, permission);
526
}
527
528
/**
529
* Check and see if this set of permissions implies the permissions
530
* expressed in "permission".
531
*
532
* @param permission the Permission object to compare
533
*
534
* @return true if "permission" is a proper subset of a permission in
535
* the set, false if not.
536
*/
537
@Override
538
public boolean implies(Permission permission) {
539
// attempt a fast lookup and implies. If that fails
540
// then enumerate through all the permissions.
541
Permission p = permsMap.get(permission);
542
543
// If permission is found, then p.equals(permission)
544
if (p == null) {
545
for (Permission p_ : permsMap.values()) {
546
if (p_.implies(permission))
547
return true;
548
}
549
return false;
550
} else {
551
return true;
552
}
553
}
554
555
/**
556
* Returns an enumeration of all the Permission objects in the container.
557
*
558
* @return an enumeration of all the Permissions.
559
*/
560
@Override
561
public Enumeration<Permission> elements() {
562
return permsMap.elements();
563
}
564
565
@java.io.Serial
566
private static final long serialVersionUID = -8491988220802933440L;
567
// Need to maintain serialization interoperability with earlier releases,
568
// which had the serializable field:
569
// private Hashtable perms;
570
/**
571
* @serialField perms java.util.Hashtable
572
* A table of the Permissions (both key and value are same).
573
*/
574
@java.io.Serial
575
private static final ObjectStreamField[] serialPersistentFields = {
576
new ObjectStreamField("perms", Hashtable.class),
577
};
578
579
/**
580
* Writes the contents of the permsMap field out as a Hashtable for
581
* serialization compatibility with earlier releases.
582
*
583
* @param out the {@code ObjectOutputStream} to which data is written
584
* @throws IOException if an I/O error occurs
585
*/
586
@java.io.Serial
587
private void writeObject(ObjectOutputStream out) throws IOException {
588
// Don't call out.defaultWriteObject()
589
590
// Copy perms into a Hashtable
591
Hashtable<Permission, Permission> perms =
592
new Hashtable<>(permsMap.size()*2);
593
perms.putAll(permsMap);
594
595
// Write out serializable fields
596
ObjectOutputStream.PutField pfields = out.putFields();
597
pfields.put("perms", perms);
598
out.writeFields();
599
}
600
601
/**
602
* Reads in a Hashtable of Permission/Permission and saves them in the
603
* permsMap field.
604
*
605
* @param in the {@code ObjectInputStream} from which data is read
606
* @throws IOException if an I/O error occurs
607
* @throws ClassNotFoundException if a serialized class cannot be loaded
608
*/
609
@java.io.Serial
610
private void readObject(ObjectInputStream in) throws IOException,
611
ClassNotFoundException {
612
// Don't call defaultReadObject()
613
614
// Read in serialized fields
615
ObjectInputStream.GetField gfields = in.readFields();
616
617
// Get permissions
618
// writeObject writes a Hashtable<Class<?>, PermissionCollection> for
619
// the perms key, so this cast is safe, unless the data is corrupt.
620
@SuppressWarnings("unchecked")
621
Hashtable<Permission, Permission> perms =
622
(Hashtable<Permission, Permission>)gfields.get("perms", null);
623
permsMap = new ConcurrentHashMap<>(perms.size()*2);
624
permsMap.putAll(perms);
625
626
// check that the Permission key and value are the same object
627
for (Map.Entry<Permission, Permission> e : perms.entrySet()) {
628
Permission k = e.getKey();
629
Permission v = e.getValue();
630
if (k != v) {
631
throw new InvalidObjectException("Permission (" + k +
632
") incorrectly mapped to Permission (" + v + ")");
633
}
634
}
635
}
636
}
637
638