1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  this work for additional information regarding copyright ownership.
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  the License.  You may obtain a copy of the License at
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  See the License for the specific language governing permissions and
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  limitations under the License.
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage java.security;
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.InvalidObjectException;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ObjectInputStream;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ObjectOutputStream;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ObjectStreamField;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Collections;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Enumeration;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.HashMap;
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Hashtable;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Iterator;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Map;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.apache.harmony.security.internal.nls.Messages;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Specific {@code PermissionCollection} for storing {@code BasicPermissions} of
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * arbitrary type.
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @see BasicPermission
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @see PermissionCollection
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectfinal class BasicPermissionCollection extends PermissionCollection {
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final long serialVersionUID = 739301742472979399L;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final ObjectStreamField[] serialPersistentFields = {
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        new ObjectStreamField("all_allowed", Boolean.TYPE), //$NON-NLS-1$
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        new ObjectStreamField("permissions", Hashtable.class), //$NON-NLS-1$
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        new ObjectStreamField("permClass", Class.class), }; //$NON-NLS-1$
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //should be final, but because of writeObject() cannot be
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private transient Map<String, Permission> items = new HashMap<String, Permission>();
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // true if this Collection contains a BasicPermission with '*' as its permission name
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private transient boolean allEnabled; // = false;
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Class<? extends Permission> permClass;
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Adds a permission to the collection. The first added permission must be a
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * subclass of BasicPermission, next permissions must be of the same class
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * as the first one.
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see java.security.PermissionCollection#add(java.security.Permission)
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
65e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes    @Override
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void add(Permission permission) {
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isReadOnly()) {
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (permission == null) {
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException(Messages.getString("security.20")); //$NON-NLS-1$
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Class<? extends Permission> inClass = permission.getClass();
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (permClass != null) {
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (permClass != inClass) {
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    permission));
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if( !(permission instanceof BasicPermission)) {
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                permission));
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // this is the first element provided that another thread did not add
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            synchronized (this) {
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (permClass != null && inClass != permClass) {
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        permission));
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                permClass = inClass;
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String name = permission.getName();
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        items.put(name, permission);
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        allEnabled = allEnabled || (name.length() == 1 && '*' == name.charAt(0));
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns enumeration of contained elements.
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
102e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes    @Override
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public Enumeration<Permission> elements() {
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return Collections.enumeration(items.values());
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Indicates whether the argument permission is implied by the receiver.
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return boolean {@code true} if the argument permission is implied by the
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *         receiver, and {@code false} if it is not.
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param permission
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            the permission to check.
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see Permission
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
116e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes    @Override
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public boolean implies(Permission permission) {
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (permission == null || permission.getClass() != permClass) {
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (allEnabled) {
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return true;
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String checkName = permission.getName();
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //first check direct coincidence
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (items.containsKey(checkName)) {
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return true;
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //now check if there are suitable wildcards
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //suppose we have "a.b.c", let's check "a.b.*" and "a.*"
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char[] name = checkName.toCharArray();
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //I presume that "a.b.*" does not imply "a.b."
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //so the dot at end is ignored
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int pos = name.length - 2;
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (; pos >= 0; pos--) {
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (name[pos] == '.') {
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        while (pos >= 0) {
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            name[pos + 1] = '*';
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (items.containsKey(new String(name, 0, pos + 2))) {
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return true;
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (--pos; pos >= 0; pos--) {
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (name[pos] == '.') {
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Expected format is the following:
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <dl>
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <dt>boolean all_allowed
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <dd>This is set to true if this BasicPermissionCollection contains a
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * {@code BasicPermission} with '*' as its permission name.
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <dt>Class&lt;T&gt; permClass
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <dd>The class to which all {@code BasicPermission}s in this
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * BasicPermissionCollection belongs.
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <dt>Hashtable&lt;K,V&gt; permissions
164e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes     * <dd>The {@code BasicPermission}s in this collection. All {@code
165e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes     * BasicPermission}s in the collection must belong to the same class. The
166e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes     * Hashtable is indexed by the {@code BasicPermission} name; the value of
167e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes     * the Hashtable entry is the permission.
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * </dl>
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ObjectOutputStream.PutField fields = out.putFields();
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        fields.put("all_allowed", allEnabled); //$NON-NLS-1$
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        fields.put("permissions", new Hashtable<String, Permission>(items)); //$NON-NLS-1$
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        fields.put("permClass", permClass); //$NON-NLS-1$
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.writeFields();
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Reads the object from stream and checks its consistency: all contained
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * permissions must be of the same subclass of BasicPermission.
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void readObject(java.io.ObjectInputStream in) throws IOException,
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ClassNotFoundException {
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ObjectInputStream.GetField fields = in.readFields();
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        items = new HashMap<String, Permission>();
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        synchronized (this) {
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            permClass = (Class<? extends Permission>)fields.get("permClass", null); //$NON-NLS-1$
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            items.putAll((Hashtable<String, Permission>) fields.get(
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    "permissions", new Hashtable<String, Permission>())); //$NON-NLS-1$
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (Iterator<Permission> iter = items.values().iterator(); iter.hasNext();) {
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (iter.next().getClass() != permClass) {
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new InvalidObjectException(Messages.getString("security.24")); //$NON-NLS-1$
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            allEnabled = fields.get("all_allowed", false); //$NON-NLS-1$
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (allEnabled && !items.containsKey("*")) { //$NON-NLS-1$
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new InvalidObjectException(Messages.getString("security.25")); //$NON-NLS-1$
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
203