/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.jini.tool.envcheck.plugins;
import com.sun.jini.tool.envcheck.AbstractPlugin;
import com.sun.jini.tool.envcheck.Plugin;
import com.sun.jini.tool.envcheck.EnvCheck;
import com.sun.jini.tool.envcheck.Reporter;
import com.sun.jini.tool.envcheck.Reporter.Message;
import com.sun.jini.tool.envcheck.SubVMTask;
import com.sun.jini.tool.envcheck.Util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
import java.net.URL;
import java.net.MalformedURLException;
import java.rmi.RMISecurityManager;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.Policy;
import java.security.PermissionCollection;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Enumeration;
import com.sun.jini.start.ServiceDescriptor;
import com.sun.jini.start.SharedActivatableServiceDescriptor;
import com.sun.jini.start.SharedActivationGroupDescriptor;
import com.sun.jini.start.NonActivatableServiceDescriptor;
/**
* Check the security policy for existence, for valid syntax, and that it does
* not grant <code>AllPermissions</code> to all protection domains.
*/
public class CheckPolicy extends AbstractPlugin {
/** the plugin container */
private EnvCheck envCheck;
/**
* Perform policy file checks for the current VM and all service
* descriptors.
*/
public void run(EnvCheck envCheck) {
this.envCheck = envCheck;
checkProperty();
ServiceDescriptor[] d = envCheck.getDescriptors();
for (int i = 0; i < d.length; i++) {
checkDescriptor(d[i]);
}
}
/**
* Check existence and accessibility of the policy file. If accessible,
* check for syntax errors. If none, check for <code>AllPermission</code>
* being granted. The syntax errors (and allpermissions) are checked
* in a subtask to ensure that the policy has not already been loaded.
*/
private void checkProperty() {
String policyName = envCheck.getProperty("java.security.policy");
if (policyAccessible(policyName, getString("policyprop"))) {
Object o = envCheck.launch(taskName("AllPermissionsTask"));
Message message;
String source = getString("cmdpolicy", policyName);
if (o instanceof String) {
message = new Message(Reporter.ERROR,
getString("parseerror", o),
null);
Reporter.print(message, source);
} else if (o instanceof Boolean) {
if (((Boolean) o).booleanValue()) { // true => all permissions
message = new Message(Reporter.WARNING,
getString("grantsall"),
getString("allExp"));
Reporter.print(message, source);
}
} else {
handleUnexpectedSubtaskReturn(o, source);
}
}
}
/**
* Load the policy and capture any error text generated. The call
* to <code>getPolicy</code> must be the first one made in the
* VM since subsequent calls to <code>getPolicy</code> are silent
*
* @return the error text produced, or a zero-length string if none
*/
private static String loadPolicy() {
PrintStream oldErr = System.err;
ByteArrayOutputStream s = new ByteArrayOutputStream();
System.setErr(new PrintStream(s));
Policy policy = Policy.getPolicy();
System.setErr(oldErr);
return s.toString();
}
/**
* Check accessibility of the policy file.
*
* @param policy the name of the policy file
* @param source source of the policy file
* @return <code>true</code> if accessible
*/
private boolean policyAccessible(String policy, String source) {
Message message;
boolean ret;
if (policy == null) {
message = new Message(Reporter.WARNING,
getString("nopolicy"),
getString("policyExp"));
ret = false;
} else {
String errorMsg =
Util.checkFileName(policy, getString("policyfile"));
if (errorMsg != null) {
message = new Message(Reporter.ERROR,
errorMsg,
getString("policyExp"));
ret = false;
} else {
message = new Message(Reporter.INFO,
getString("policyOK"),
getString("policyExp"));
ret = true;
}
}
Reporter.print(message, source);
return ret;
}
/**
* Check the policy file provided in any
* <code>ServiceDescriptor</code>
*
* @param d the descriptor
*/
private void checkDescriptor(ServiceDescriptor d) {
String policy;
NonActivatableServiceDescriptor nad = null;
SharedActivationGroupDescriptor gd = null;
String source = null;
if (d instanceof SharedActivationGroupDescriptor) {
gd = (SharedActivationGroupDescriptor) d;
policy = gd.getPolicy();
source = getString("for",
policy,
"SharedActivationGroupDescriptor");
} else {
nad = (NonActivatableServiceDescriptor) d;
gd = envCheck.getGroupDescriptor();
policy = nad.getPolicy();
source = getString("for",
policy,
nad.getImplClassName());
}
if (!policyAccessible(policy, source)) {
return;
}
Object o = envCheck.launch(nad, gd, taskName("AllPermissionsTask"));
if (o instanceof String) {
Message message = new Message(Reporter.ERROR,
getString("parseerror", o),
null);
Reporter.print(message, source);
} else if (o instanceof Boolean) {
if (((Boolean) o).booleanValue()) { // true means all permissions
Message message = new Message(Reporter.WARNING,
getString("grantsall"),
getString("allExp"));
Reporter.print(message, source);
}
} else {
handleUnexpectedSubtaskReturn(o, source);
}
}
/**
* Task the check the policy in a child VM.
*/
public static class AllPermissionsTask implements SubVMTask {
/**
* Perform the syntax check and the <code>AllPermission</code> check
*
* @return a <code>String</code> containing the error message if there
* was a syntax error in the policy file, a
* <code>Throwable</code> if an unexpected exception is
* thrown, a <code>Boolean(true)</code> if
* <code>AllPermission</code> is granted, or a
* <code>Boolean(false)</code> if not granted.
*/
public Object run(String[] args) {
String errMsg = loadPolicy();
if (errMsg.length() > 0) {
return errMsg;
}
try {
Policy policy = Policy.getPolicy();
PermissionCollection permCol =
policy.getPermissions(
new CodeSource(new URL("file:/foo"),
(java.security.cert.Certificate[]) null));
if (permCol.implies(new AllPermission("", ""))) {
return new Boolean(true); // true => allpermissions
}
} catch (SecurityException e) { // can't be all permissions
} catch (Throwable t) {
return t;
}
return new Boolean(false);
}
}
}