blob: ed2fed095ae1c163658a20e0e2c829303e40fb02 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.framework.internal.core;
import java.io.*;
import java.net.URL;
import java.security.*;
import java.util.ArrayList;
import org.eclipse.osgi.framework.adaptor.BundleProtectionDomain;
import org.eclipse.osgi.framework.adaptor.PermissionStorage;
import org.eclipse.osgi.framework.debug.Debug;
import org.osgi.framework.AdminPermission;
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 {
private static final String ADMIN_IMPLIED_ACTIONS = AdminPermission.RESOURCE + ',' + AdminPermission.METADATA + ',' + AdminPermission.CLASS;
/** 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(getClass().getResource(Constants.OSGI_DEFAULT_DEFAULT_PERMISSIONS));
baseImpliedPermissionInfos = getPermissionInfos(getClass().getResource(Constants.OSGI_BASE_IMPLIED_PERMISSIONS));
if (Debug.DEBUG && Debug.DEBUG_SECURITY) {
Debug.println("Default default assigned bundle permissions"); //$NON-NLS-1$
if (defaultDefaultPermissionInfos == null) {
Debug.println(" <none>"); //$NON-NLS-1$
} else {
for (int i = 0; i < defaultDefaultPermissionInfos.length; i++) {
Debug.println(" " + defaultDefaultPermissionInfos[i]); //$NON-NLS-1$
}
}
Debug.println("Base implied bundle permissions"); //$NON-NLS-1$
if (baseImpliedPermissionInfos == null) {
Debug.println(" <none>"); //$NON-NLS-1$
} else {
for (int i = 0; i < baseImpliedPermissionInfos.length; i++) {
Debug.println(" " + baseImpliedPermissionInfos[i]); //$NON-NLS-1$
}
}
}
defaultAssignedPermissions = new BundleCombinedPermissions(null);
defaultAssignedPermissions.setAssignedPermissions(createDefaultAssignedPermissions(getDefaultPermissions()), true);
}
/**
* 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.internal.core.SecurePermissionStorage(this.storage);
try {
String[] data = storage.getPermissionData(location);
if (Debug.DEBUG && Debug.DEBUG_SECURITY) {
Debug.println("Getting permissions for location: " + location); //$NON-NLS-1$
if (data == null) {
Debug.println(" <none>"); //$NON-NLS-1$
} else {
for (int i = 0; i < data.length; i++) {
Debug.println(" " + data[i]); //$NON-NLS-1$
}
}
}
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 permissions 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>AllPermission</tt>.
*/
public void setPermissions(String location, PermissionInfo[] permissions) {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new AllPermission());
if (location == null) {
throw new NullPointerException();
}
PermissionStorage storage = new org.eclipse.osgi.framework.internal.core.SecurePermissionStorage(this.storage);
try {
String[] data = makePermissionData(permissions);
if (Debug.DEBUG && Debug.DEBUG_SECURITY) {
Debug.println("Setting permissions for location: " + location); //$NON-NLS-1$
if (data == null) {
Debug.println(" <none>"); //$NON-NLS-1$
} else {
for (int i = 0; i < data.length; i++) {
Debug.println(" " + data[i]); //$NON-NLS-1$
}
}
}
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, true);
} else {
combined.setAssignedPermissions(createPermissions(permissions, bundle, false), false);
}
}
}
}
/**
* 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.internal.core.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.internal.core.SecurePermissionStorage(this.storage);
try {
String[] data = storage.getPermissionData(null);
if (Debug.DEBUG && Debug.DEBUG_SECURITY) {
Debug.println("Getting default permissions"); //$NON-NLS-1$
if (data == null) {
Debug.println(" <none>"); //$NON-NLS-1$
} else {
for (int i = 0; i < data.length; i++) {
Debug.println(" " + data[i]); //$NON-NLS-1$
}
}
}
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>AllPermission</tt>.
*/
public void setDefaultPermissions(PermissionInfo[] permissions) {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new AllPermission());
PermissionStorage storage = new org.eclipse.osgi.framework.internal.core.SecurePermissionStorage(this.storage);
try {
String[] data = makePermissionData(permissions);
if (Debug.DEBUG && Debug.DEBUG_SECURITY) {
Debug.println("Setting default permissions"); //$NON-NLS-1$
if (data == null) {
Debug.println(" <none>"); //$NON-NLS-1$
} else {
for (int i = 0; i < data.length; i++) {
Debug.println(" " + data[i]); //$NON-NLS-1$
}
}
}
storage.setPermissionData(null, data);
} catch (IOException e) {
framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, e);
return;
}
defaultAssignedPermissions.setAssignedPermissions(createDefaultAssignedPermissions(permissions), true);
}
/**
* 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 bundle the bundle object
* @return BundleCombinedPermission object with the bundle's
* dynamic permissions.
*/
protected BundleProtectionDomain createProtectionDomain(AbstractBundle bundle) {
BundlePermissionCollection implied = getImpliedPermissions(bundle);
BundleCombinedPermissions combined = new BundleCombinedPermissions(implied);
BundlePermissionCollection assigned = getAssignedPermissions(bundle);
combined.setAssignedPermissions(assigned, assigned == defaultAssignedPermissions);
combined.setConditionalPermissions(new ConditionalPermissions(bundle, framework.condPermAdmin));
/* now process the permissions.perm file, if it exists, and build the
* restrictedPermissions using it. */
PermissionInfo[] permInfos = getPermissionInfos(bundle.getEntry("OSGI-INF/permissions.perm")); //$NON-NLS-1$
if (permInfos != null) {
ConditionalPermissionInfoImpl cpiArray[] = new ConditionalPermissionInfoImpl[1];
cpiArray[0] = new ConditionalPermissionInfoImpl(null, ConditionalPermissionAdminImpl.EMPTY_COND_INFO, permInfos);
ConditionalPermissionSet cps = new ConditionalPermissionSet(bundle, cpiArray, ConditionalPermissionAdminImpl.EMPTY_COND);
combined.setRestrictedPermissions(cps);
}
return new BundleProtectionDomainImpl(bundle, 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"); //$NON-NLS-1$
}
if (info == null) {
info = defaultDefaultPermissionInfos;
}
return createPermissions(info, null, false);
}
/**
* 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); //$NON-NLS-1$
}
return createPermissions(info, bundle, false);
}
/**
* 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); //$NON-NLS-1$
return createPermissions(baseImpliedPermissionInfos, bundle, true);
}
/**
* Read the permissions from the specified resource.
*
* @return An array of PermissionInfo objects from the specified
* resource.
*/
protected PermissionInfo[] getPermissionInfos(URL resource) {
if (resource == null)
return null;
PermissionInfo[] info = ConditionalPermissionAdminImpl.EMPTY_PERM_INFO;
DataInputStream in = null;
try {
in = new DataInputStream(resource.openStream());
ArrayList permissions = new ArrayList();
BufferedReader reader;
try {
reader = new BufferedReader(new InputStreamReader(in, "UTF8")); //$NON-NLS-1$
} 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 */ //$NON-NLS-1$ //$NON-NLS-2$
continue;
try {
permissions.add(new PermissionInfo(line));
} catch (IllegalArgumentException iae) {
/* incorrectly encoded permission */
framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, iae);
}
}
int size = permissions.size();
if (size > 0)
info = (PermissionInfo[]) permissions.toArray(new PermissionInfo[size]);
} catch (IOException e) {
// do nothing
} finally {
try {
if (in != null)
in.close();
} catch (IOException ee) {
// do nothing
}
}
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, boolean implied) {
if (info == null)
info = new PermissionInfo[0];
if (implied) {
// create the implied AdminPermission actions for this bundle
PermissionInfo impliedInfo = new PermissionInfo(AdminPermission.class.getName(), "(id=" + bundle.getBundleId() + ")", ADMIN_IMPLIED_ACTIONS); //$NON-NLS-1$ //$NON-NLS-2$
if (Debug.DEBUG && Debug.DEBUG_SECURITY)
Debug.println("Created permission: " + impliedInfo); //$NON-NLS-1$
PermissionInfo[] impliedInfos = new PermissionInfo[info.length + 1];
System.arraycopy(info, 0, impliedInfos, 0, info.length);
impliedInfos[info.length] = impliedInfo;
info = impliedInfos;
}
ConditionalPermissionInfoImpl cpiArray[] = new ConditionalPermissionInfoImpl[1];
cpiArray[0] = new ConditionalPermissionInfoImpl(null, ConditionalPermissionAdminImpl.EMPTY_COND_INFO, info);
return new ConditionalPermissionSet(bundle, cpiArray, ConditionalPermissionAdminImpl.EMPTY_COND);
}
}