View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    * 
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.river.tool.envcheck.plugins;
19  
20  import org.apache.river.tool.envcheck.AbstractPlugin;
21  import org.apache.river.tool.envcheck.EnvCheck;
22  import org.apache.river.tool.envcheck.Reporter;
23  import org.apache.river.tool.envcheck.Reporter.Message;
24  import org.apache.river.tool.envcheck.SubVMTask;
25  import org.apache.river.tool.envcheck.Util;
26  import java.io.ByteArrayOutputStream;
27  import java.io.PrintStream;
28  import java.net.URL;
29  import java.security.AllPermission;
30  import java.security.CodeSource;
31  import java.security.Policy;
32  import java.security.PermissionCollection;
33  import org.apache.river.start.ServiceDescriptor;
34  import org.apache.river.start.SharedActivationGroupDescriptor;
35  import org.apache.river.start.NonActivatableServiceDescriptor;
36  
37  /**
38   * Check the security policy for existence, for valid syntax, and that it does
39   * not grant <code>AllPermissions</code> to all protection domains.
40   */
41  public class CheckPolicy extends AbstractPlugin {
42  
43      /** the plugin container */
44      private EnvCheck envCheck;
45  
46      /**
47       * Perform policy file checks for the current VM and all service
48       * descriptors.
49       */
50      public void run(EnvCheck envCheck) {
51  	this.envCheck = envCheck;
52  	checkProperty();
53  	ServiceDescriptor[] d = envCheck.getDescriptors();
54  	for (int i = 0; i < d.length; i++) { 
55  	    checkDescriptor(d[i]);
56  	}
57      }
58  
59      /** 
60       * Check existence and accessibility of the policy file. If accessible,
61       * check for syntax errors. If none, check for <code>AllPermission</code>
62       * being granted. The syntax errors (and allpermissions) are checked
63       * in a subtask to ensure that the policy has not already been loaded.
64       */
65      private void checkProperty() {
66  	String policyName = envCheck.getProperty("java.security.policy");
67  	if (policyAccessible(policyName, getString("policyprop"))) {
68  	    Object o = envCheck.launch(taskName("AllPermissionsTask"));
69  	    Message message;
70  	    String source = getString("cmdpolicy", policyName);
71  	    if (o instanceof String) {
72  		message = new Message(Reporter.ERROR,
73  				      getString("parseerror", o),
74  				      null);
75  		Reporter.print(message, source);
76  	    } else if (o instanceof Boolean) {
77  		if (((Boolean) o).booleanValue()) { // true => all permissions
78  		    message = new Message(Reporter.WARNING,
79  					  getString("grantsall"),
80  					  getString("allExp"));
81  		    Reporter.print(message, source);
82  		}
83  	    } else {
84  		handleUnexpectedSubtaskReturn(o, source);
85  	    }
86  	}
87      }
88  
89      /**
90       * Load the policy and capture any error text generated. The call
91       * to <code>getPolicy</code> must be the first one made in the
92       * VM since subsequent calls to <code>getPolicy</code> are silent
93       *
94       * @return the error text produced, or a zero-length string if none
95       */
96      private static String loadPolicy() {
97  	PrintStream oldErr = System.err;
98  	ByteArrayOutputStream s = new ByteArrayOutputStream();
99  	System.setErr(new PrintStream(s));
100 	Policy policy = Policy.getPolicy();
101 	System.setErr(oldErr);
102 	return s.toString();
103     }
104 
105     /**
106      * Check accessibility of the policy file.
107      *
108      * @param policy the name of the policy file
109      * @param source source of the policy file
110      * @return <code>true</code> if accessible
111      */
112     private boolean policyAccessible(String policy, String source) {
113 	Message message;
114 	boolean ret;
115 	if (policy == null) {
116 	    message = new Message(Reporter.WARNING,
117 				  getString("nopolicy"),
118 				  getString("policyExp"));
119 	    ret = false;
120 	} else {
121 	    String errorMsg = 
122 		Util.checkFileName(policy, getString("policyfile"));
123 	    if (errorMsg != null) {
124 		message = new Message(Reporter.ERROR,
125 				      errorMsg,
126 				      getString("policyExp"));
127 		ret = false;
128 	    } else {
129 		message = new Message(Reporter.INFO,
130 				      getString("policyOK"),
131 				      getString("policyExp"));
132 		ret = true;
133 	    }
134 	}
135 	Reporter.print(message, source);
136 	return ret;
137     }
138 
139     /**
140      * Check the policy file provided in any
141      * <code>ServiceDescriptor</code>
142      *
143      * @param d the descriptor
144      */
145     private void checkDescriptor(ServiceDescriptor d) {
146 	String policy;
147 	NonActivatableServiceDescriptor nad = null;
148 	SharedActivationGroupDescriptor gd = null;
149 	String source = null;
150 	if (d instanceof SharedActivationGroupDescriptor) {
151 	    gd = (SharedActivationGroupDescriptor) d;
152 	    policy = gd.getPolicy();
153 	    source = getString("for", 
154 			      policy,
155 			      "SharedActivationGroupDescriptor");
156 	} else {
157 	    nad = (NonActivatableServiceDescriptor) d;
158             gd = envCheck.getGroupDescriptor();
159 	    policy = nad.getPolicy();
160 	    source = getString("for", 
161 			       policy,
162 			       nad.getImplClassName());
163 	}
164 	if (!policyAccessible(policy, source)) {
165 	    return; 
166 	}
167 	Object o = envCheck.launch(nad, gd, taskName("AllPermissionsTask"));
168 	if (o instanceof String) {
169 	    Message message = new Message(Reporter.ERROR,
170 					  getString("parseerror", o),
171 					  null);
172 	    Reporter.print(message, source);
173 	} else if (o instanceof Boolean) {
174 	    if (((Boolean) o).booleanValue()) { // true means all permissions
175 		Message message = new Message(Reporter.WARNING,
176 					      getString("grantsall"),
177 					      getString("allExp"));
178 		Reporter.print(message, source);
179 	    }
180 	} else {
181 	    handleUnexpectedSubtaskReturn(o, source);
182 	}
183     }
184 
185     /**
186      * Task the check the policy in a child VM. 
187      */
188     public static class AllPermissionsTask implements SubVMTask {
189 
190 	/**
191 	 * Perform the syntax check and the <code>AllPermission</code> check
192 	 *
193 	 * @return a <code>String</code> containing the error message if there
194 	 *         was a syntax error in the policy file, a
195 	 *         <code>Throwable</code> if an unexpected exception is
196 	 *         thrown, a <code>Boolean(true)</code> if
197 	 *         <code>AllPermission</code> is granted, or a
198 	 *         <code>Boolean(false)</code> if not granted.
199 	 */
200 	public Object run(String[] args) {
201 	    String errMsg = loadPolicy();
202 	    if (errMsg.length() > 0) {
203 		return errMsg;
204 	    }
205 	    try {
206 		Policy policy = Policy.getPolicy();
207 		PermissionCollection permCol = 
208 		    policy.getPermissions(
209                                 new CodeSource(new URL("file:/foo"),
210 				(java.security.cert.Certificate[]) null));
211 		if (permCol.implies(new AllPermission("", ""))) {
212 		    return new Boolean(true); // true => allpermissions
213 		} 
214 	    } catch (SecurityException e) { // can't be all permissions 
215 	    } catch (Throwable t) {
216 		return t;
217 	    }
218 	    return new Boolean(false);
219 	}
220     }
221 }