| /******************************************************************************* |
| * Copyright (c) 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.osgi.framework.internal.core; |
| |
| import java.io.*; |
| import java.security.*; |
| import java.util.Vector; |
| import org.eclipse.osgi.framework.adaptor.PermissionStorage; |
| import org.eclipse.osgi.framework.debug.Debug; |
| import org.osgi.framework.FrameworkEvent; |
| import org.osgi.service.permissionadmin.PermissionAdmin; |
| import org.osgi.service.permissionadmin.PermissionInfo; |
| |
| /** |
| * Permission Admin service for the OSGi specification. |
| * |
| * The Permission Admin service allows operators to |
| * manage the permissions of bundles. There is at most one Permission Admin |
| * service present in the Framework. |
| * <p> |
| * Access to the Permission Admin service is protected by |
| * corresponding |
| * <tt>ServicePermission</tt>. In addition the <tt>AdminPermission</tt> |
| * is required to actually set permissions. |
| * |
| * <p>Bundle permissions are managed using a permission table. A bundle's location |
| * serves as the key into this permission table. The value of a table entry is |
| * the set of permissions (of type <tt>PermissionInfo</tt>) granted to the |
| * bundle with the given location. |
| * A bundle may have an entry in the permission table prior to being installed |
| * in the Framework. |
| * |
| * <p>The permissions specified in <tt>setDefaultPermissions</tt> are used as the |
| * default |
| * permissions which are granted to all bundles that do not have an entry in |
| * the permission table. |
| * |
| * <p>Any changes to a bundle's permissions in the permission table will take |
| * effect no later than when bundle's <tt>java.security.ProtectionDomain</tt> |
| * is involved in a permission check, and will be made persistent. |
| * |
| * <p>Only permission classes on the system classpath or from an exported |
| * package are considered during a permission check. |
| * Additionally, only permission classes that are subclasses of |
| * <tt>java.security.Permission</tt> and define a 2-argument constructor |
| * that takes a <i>name</i> string and an <i>actions</i> string can be used. |
| * <p> |
| * Permissions implicitly granted by the Framework (for example, a bundle's |
| * permission to access its persistent storage area) cannot be changed, and |
| * are not reflected in the permissions returned by <tt>getPermissions</tt> |
| * and <tt>getDefaultPermissions</tt>. |
| */ |
| public class PermissionAdminImpl implements PermissionAdmin { |
| /** framework object */ |
| protected Framework framework; |
| |
| /** permission storage object */ |
| protected PermissionStorage storage; |
| |
| /** The permissions to use if no other permissions can be determined */ |
| protected PermissionInfo[] defaultDefaultPermissionInfos; |
| |
| /** The basic implied permissions for a bundle */ |
| protected PermissionInfo[] baseImpliedPermissionInfos; |
| |
| /** The permission collection containing the default assigned permissions */ |
| protected BundleCombinedPermissions defaultAssignedPermissions; |
| |
| /** |
| * Construstor. |
| * |
| * @param framework Framework object. |
| */ |
| protected PermissionAdminImpl(Framework framework, PermissionStorage storage) { |
| this.framework = framework; |
| this.storage = storage; |
| |
| defaultDefaultPermissionInfos = getPermissionInfos(Constants.OSGI_DEFAULT_DEFAULT_PERMISSIONS); |
| baseImpliedPermissionInfos = getPermissionInfos(Constants.OSGI_BASE_IMPLIED_PERMISSIONS); |
| |
| // if (Debug.DEBUG) |
| // { |
| // // This is necessary to allow File.getAbsolutePath() in debug statements. |
| // int _length = baseImpliedPermissionInfos.length; |
| // |
| // PermissionInfo[] debugBaseImpliedPermissionInfos = new PermissionInfo[_length + 1]; |
| // |
| // System.arraycopy(baseImpliedPermissionInfos, 0, debugBaseImpliedPermissionInfos, 0, _length); |
| // |
| // debugBaseImpliedPermissionInfos[_length] = new PermissionInfo("(java.util.PropertyPermission \"user.dir\" \"read\")"); |
| // |
| // baseImpliedPermissionInfos = debugBaseImpliedPermissionInfos; |
| // } |
| |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Default default assigned bundle permissions"); |
| if (defaultDefaultPermissionInfos == null) { |
| Debug.println(" <none>"); |
| } else { |
| for (int i = 0; i < defaultDefaultPermissionInfos.length; i++) { |
| Debug.println(" " + defaultDefaultPermissionInfos[i]); |
| } |
| } |
| |
| Debug.println("Base implied bundle permissions"); |
| if (baseImpliedPermissionInfos == null) { |
| Debug.println(" <none>"); |
| } else { |
| for (int i = 0; i < baseImpliedPermissionInfos.length; i++) { |
| Debug.println(" " + baseImpliedPermissionInfos[i]); |
| } |
| } |
| } |
| |
| defaultAssignedPermissions = new BundleCombinedPermissions(null); |
| defaultAssignedPermissions.setAssignedPermissions(createDefaultAssignedPermissions(getDefaultPermissions())); |
| } |
| |
| /** |
| * Gets the permissions assigned to the bundle with the specified |
| * location. |
| * |
| * @param location The location of the bundle whose permissions are to |
| * be returned. |
| * |
| * @return The permissions assigned to the bundle with the specified |
| * location, or <tt>null</tt> if that bundle has not been assigned any |
| * permissions. |
| */ |
| public PermissionInfo[] getPermissions(String location) { |
| if (location == null) { |
| throw new NullPointerException(); |
| } |
| |
| PermissionStorage storage = new org.eclipse.osgi.framework.util.SecurePermissionStorage(this.storage); |
| |
| try { |
| String[] data = storage.getPermissionData(location); |
| |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Getting permissions for location: " + location); |
| if (data == null) { |
| Debug.println(" <none>"); |
| } else { |
| for (int i = 0; i < data.length; i++) { |
| Debug.println(" " + data[i]); |
| } |
| } |
| } |
| |
| return makePermissionInfo(data); |
| } catch (IOException e) { |
| framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, e); |
| |
| return null; |
| } |
| } |
| |
| /** |
| * Assigns the specified permissions to the bundle with the specified |
| * location. |
| * |
| * @param location The location of the bundle that will be assigned the |
| * permissions. |
| * @param perms The permissions to be assigned, or <tt>null</tt> |
| * if the specified location is to be removed from the permission table. |
| * @exception SecurityException if the caller does not have the |
| * <tt>AdminPermission</tt>. |
| */ |
| public void setPermissions(String location, PermissionInfo[] permissions) { |
| framework.checkAdminPermission(); |
| |
| if (location == null) { |
| throw new NullPointerException(); |
| } |
| |
| PermissionStorage storage = new org.eclipse.osgi.framework.util.SecurePermissionStorage(this.storage); |
| |
| try { |
| String[] data = makePermissionData(permissions); |
| |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Setting permissions for location: " + location); |
| if (data == null) { |
| Debug.println(" <none>"); |
| } else { |
| for (int i = 0; i < data.length; i++) { |
| Debug.println(" " + data[i]); |
| } |
| } |
| } |
| |
| storage.setPermissionData(location, data); |
| } catch (IOException e) { |
| framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, e); |
| |
| return; |
| } |
| |
| AbstractBundle bundle = framework.getBundleByLocation(location); |
| |
| if ((bundle != null) && (bundle.getBundleId() != 0)) { |
| ProtectionDomain domain = bundle.getProtectionDomain(); |
| |
| if (domain != null) { |
| BundleCombinedPermissions combined = (BundleCombinedPermissions) domain.getPermissions(); |
| |
| if (permissions == null) { |
| combined.setAssignedPermissions(defaultAssignedPermissions); |
| } else { |
| combined.setAssignedPermissions(createPermissions(permissions, bundle)); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns the bundle locations that have permissions assigned to them, |
| * that is, bundle locations for which an entry |
| * exists in the permission table. |
| * |
| * @return The locations of bundles that have been assigned any |
| * permissions, or <tt>null</tt> if the permission table is empty. |
| */ |
| public String[] getLocations() { |
| PermissionStorage storage = new org.eclipse.osgi.framework.util.SecurePermissionStorage(this.storage); |
| |
| try { |
| String[] locations = storage.getLocations(); |
| |
| return locations; |
| } catch (IOException e) { |
| framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, e); |
| |
| return null; |
| } |
| } |
| |
| /** |
| * Gets the default permissions. |
| * |
| * <p>These are the permissions granted to any bundle that does not |
| * have permissions assigned to its location. |
| * |
| * @return The default permissions, or <tt>null</tt> if default |
| * permissions have not been defined. |
| */ |
| public PermissionInfo[] getDefaultPermissions() { |
| PermissionStorage storage = new org.eclipse.osgi.framework.util.SecurePermissionStorage(this.storage); |
| |
| try { |
| String[] data = storage.getPermissionData(null); |
| |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Getting default permissions"); |
| if (data == null) { |
| Debug.println(" <none>"); |
| } else { |
| for (int i = 0; i < data.length; i++) { |
| Debug.println(" " + data[i]); |
| } |
| } |
| } |
| |
| return makePermissionInfo(data); |
| } catch (IOException e) { |
| framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, e); |
| |
| return null; |
| } |
| } |
| |
| /** |
| * Sets the default permissions. |
| * |
| * <p>These are the permissions granted to any bundle that does not |
| * have permissions assigned to its location. |
| * |
| * @param permissions The default permissions. |
| * @exception SecurityException if the caller does not have the |
| * <tt>AdminPermission</tt>. |
| */ |
| public void setDefaultPermissions(PermissionInfo[] permissions) { |
| framework.checkAdminPermission(); |
| |
| PermissionStorage storage = new org.eclipse.osgi.framework.util.SecurePermissionStorage(this.storage); |
| |
| try { |
| String[] data = makePermissionData(permissions); |
| |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Setting default permissions"); |
| if (data == null) { |
| Debug.println(" <none>"); |
| } else { |
| for (int i = 0; i < data.length; i++) { |
| Debug.println(" " + data[i]); |
| } |
| } |
| } |
| |
| storage.setPermissionData(null, data); |
| } catch (IOException e) { |
| framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, e); |
| |
| return; |
| } |
| |
| defaultAssignedPermissions.setAssignedPermissions(createDefaultAssignedPermissions(permissions)); |
| } |
| |
| /** |
| * Make a PermissionInfo array from an array of encoded permission Strings. |
| * |
| * @param data Array of encoded permission Strings |
| * @return Array of PermissionInfo objects. |
| */ |
| protected PermissionInfo[] makePermissionInfo(String[] data) { |
| if (data == null) { |
| return null; |
| } |
| |
| int size = data.length; |
| |
| PermissionInfo[] permissions = new PermissionInfo[size]; |
| |
| for (int i = 0; i < size; i++) { |
| permissions[i] = new PermissionInfo(data[i]); |
| } |
| |
| return permissions; |
| } |
| |
| /** |
| * Make an array of encoded permission Strings from a PermissionInfo array. |
| * |
| * @param permissions Array of PermissionInfor objects. |
| * @return Array of encoded permission Strings |
| */ |
| protected String[] makePermissionData(PermissionInfo[] permissions) { |
| if (permissions == null) { |
| return null; |
| } |
| |
| int size = permissions.length; |
| |
| String[] data = new String[size]; |
| |
| for (int i = 0; i < size; i++) { |
| data[i] = permissions[i].getEncoded(); |
| } |
| |
| return data; |
| } |
| |
| /** |
| * This method is called by the Bundle object to create the |
| * PermissionCollection used by the bundle's ProtectionDomain. |
| * |
| * @param location Location string of the bundle. |
| * @return BundleCombinedPermission object with the bundle's |
| * dynamic permissions. |
| */ |
| protected PermissionCollection createPermissionCollection(AbstractBundle bundle) { |
| BundlePermissionCollection implied = getImpliedPermissions(bundle); |
| |
| BundleCombinedPermissions combined = new BundleCombinedPermissions(implied); |
| |
| BundlePermissionCollection assigned = getAssignedPermissions(bundle); |
| |
| combined.setAssignedPermissions(assigned); |
| |
| return combined; |
| } |
| |
| /** |
| * Creates the default assigned permissions for bundles that |
| * have no assigned permissions. |
| * The default permissions are assigned via the PermissionAdmin service |
| * and may change dynamically. |
| * |
| * @return A PermissionCollection of the default assigned permissions. |
| */ |
| protected BundlePermissionCollection createDefaultAssignedPermissions(PermissionInfo[] info) { |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Creating default assigned permissions"); |
| } |
| |
| if (info == null) { |
| info = defaultDefaultPermissionInfos; |
| } |
| |
| return createPermissions(info, null); |
| } |
| |
| /** |
| * Returns the assigned permissions for a bundle. |
| * These permissions are assigned via the PermissionAdmin service |
| * and may change dynamically. |
| * |
| * @param bundle The bundle to create the permissions for. |
| * @return A PermissionCollection of the assigned permissions. |
| */ |
| protected BundlePermissionCollection getAssignedPermissions(AbstractBundle bundle) { |
| String location = bundle.getLocation(); |
| |
| PermissionInfo[] info = getPermissions(location); |
| |
| if (info == null) { |
| return defaultAssignedPermissions; |
| } |
| |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Creating assigned permissions for " + bundle); |
| } |
| |
| return createPermissions(info, bundle); |
| } |
| |
| /** |
| * Returns the implied permissions for a bundle. |
| * These permissions never change. |
| * |
| * @param bundle The bundle to create the permissions for. |
| * @return A PermissionCollection of the implied permissions. |
| */ |
| protected BundlePermissionCollection getImpliedPermissions(AbstractBundle bundle) { |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Creating implied permissions for " + bundle); |
| } |
| |
| BundlePermissionCollection collection = createPermissions(baseImpliedPermissionInfos, bundle); |
| |
| Permission permission = new BundleResourcePermission(bundle.getBundleId()); |
| |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Created permission: " + permission); |
| } |
| |
| collection.add(permission); |
| |
| return collection; |
| } |
| |
| /** |
| * Read the permissions from the specified resource. |
| * |
| * @return An array of PermissionInfo objects from the specified |
| * resource. |
| */ |
| protected PermissionInfo[] getPermissionInfos(String resource) { |
| PermissionInfo[] info = null; |
| |
| InputStream in = getClass().getResourceAsStream(resource); |
| |
| if (in != null) { |
| try { |
| Vector permissions = new Vector(); |
| |
| BufferedReader reader; |
| try { |
| reader = new BufferedReader(new InputStreamReader(in, "UTF8")); |
| } catch (UnsupportedEncodingException e) { |
| reader = new BufferedReader(new InputStreamReader(in)); |
| } |
| |
| while (true) { |
| String line = reader.readLine(); |
| |
| if (line == null) /* EOF */ { |
| break; |
| } |
| |
| line = line.trim(); |
| |
| if ((line.length() == 0) || line.startsWith("#") || line.startsWith("//")) /* comments */ { |
| continue; |
| } |
| |
| try { |
| permissions.addElement(new PermissionInfo(line)); |
| } catch (IllegalArgumentException iae) { |
| /* incorrectly encoded permission */ |
| |
| framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, iae); |
| } |
| } |
| |
| int size = permissions.size(); |
| |
| if (size > 0) { |
| info = new PermissionInfo[size]; |
| |
| permissions.copyInto(info); |
| } |
| } catch (IOException e) { |
| } finally { |
| try { |
| in.close(); |
| } catch (IOException ee) { |
| } |
| } |
| } |
| |
| return info; |
| } |
| |
| /** |
| * Create a PermissionCollection from a PermissionInfo array. |
| * |
| * @param info Array of PermissionInfo objects. |
| * @param bundle The target bundle for the permissions. |
| * @return A PermissionCollection containing Permission objects. |
| */ |
| protected BundlePermissionCollection createPermissions(PermissionInfo[] info, final AbstractBundle bundle) { |
| BundlePermissionCollection collection = new BundlePermissions(framework.packageAdmin); |
| |
| /* add the permissions */ |
| int size = info.length; |
| for (int i = 0; i < size; i++) { |
| PermissionInfo perm = info[i]; |
| |
| String type = perm.getType(); |
| |
| if (type.equals("java.io.FilePermission")) { |
| /* map FilePermissions for relative names to |
| * the bundle's data area |
| */ |
| String name = perm.getName(); |
| |
| if (!name.equals("<<ALL FILES>>")) { |
| File file = new File(name); |
| |
| if (!file.isAbsolute()) /* relative name */ { |
| if (bundle == null) /* default permissions */ { |
| continue; /* no relative file permissions */ |
| } |
| |
| File target = framework.getDataFile(bundle, name); |
| |
| if (target == null) /* no bundle data file area */ { |
| continue; /* no relative file permissions */ |
| } |
| |
| perm = new PermissionInfo(type, target.getPath(), perm.getActions()); |
| } |
| } |
| } |
| |
| collection.add(createPermission(perm)); |
| } |
| |
| return collection; |
| } |
| |
| /** |
| * Create a Permission object from a PermissionInfo object. |
| * If the type of the permission is not loadable from |
| * this object's classloader (i.e. the system classloader) |
| * then an UnresolvedPermission is returned. |
| * |
| * @param info Description of the desired permission. |
| * @return A permission object. |
| */ |
| protected Permission createPermission(PermissionInfo info) { |
| String type = info.getType(); |
| String name = info.getName(); |
| String actions = info.getActions(); |
| |
| UnresolvedPermission permission = new UnresolvedPermission(type, name, actions); |
| |
| try { |
| /* Only search the system classloader (ours) at this point. |
| * Permission classes exported by bundles will be |
| * resolved later. |
| * This is done so that permission classes exported by bundles |
| * may be easily unresolved during packageRefresh. |
| */ |
| Class clazz = Class.forName(type); |
| |
| Permission resolved = permission.resolve(clazz); |
| |
| if (resolved != null) { |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Created permission: " + resolved); |
| } |
| |
| return resolved; |
| } |
| } catch (ClassNotFoundException e) { |
| } |
| |
| if (Debug.DEBUG && Debug.DEBUG_SECURITY) { |
| Debug.println("Created permission: " + permission); |
| } |
| |
| return permission; |
| } |
| } |