001
014
015 package com.liferay.portal.security.pacl.checker;
016
017 import com.liferay.portal.kernel.configuration.Filter;
018 import com.liferay.portal.kernel.deploy.DeployManagerUtil;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.servlet.ServletContextPool;
022 import com.liferay.portal.kernel.servlet.WebDirDetector;
023 import com.liferay.portal.kernel.util.ContextPathUtil;
024 import com.liferay.portal.kernel.util.JavaConstants;
025 import com.liferay.portal.kernel.util.PathUtil;
026 import com.liferay.portal.kernel.util.PropsKeys;
027 import com.liferay.portal.kernel.util.ReleaseInfo;
028 import com.liferay.portal.kernel.util.ServerDetector;
029 import com.liferay.portal.kernel.util.StringPool;
030 import com.liferay.portal.kernel.util.StringUtil;
031 import com.liferay.portal.kernel.util.UniqueList;
032 import com.liferay.portal.kernel.util.Validator;
033 import com.liferay.portal.util.PropsUtil;
034 import com.liferay.portal.util.PropsValues;
035
036 import java.io.File;
037 import java.io.FilePermission;
038 import java.io.IOException;
039
040 import java.net.JarURLConnection;
041 import java.net.URL;
042 import java.net.URLConnection;
043
044 import java.security.Permission;
045 import java.security.Permissions;
046
047 import java.util.Enumeration;
048 import java.util.Iterator;
049 import java.util.List;
050
051 import javax.servlet.ServletContext;
052
053 import sun.reflect.Reflection;
054
055
059 public class FileChecker extends BaseChecker {
060
061 public void afterPropertiesSet() {
062 try {
063 _rootDir = WebDirDetector.getRootDir(getClassLoader());
064 }
065 catch (Exception e) {
066
067
068
069 }
070
071 if (_log.isDebugEnabled()) {
072 _log.debug("Root directory " + _rootDir);
073 }
074
075 ServletContext servletContext = ServletContextPool.get(
076 getServletContextName());
077
078 if (servletContext != null) {
079 File tempDir = (File)servletContext.getAttribute(
080 JavaConstants.JAVAX_SERVLET_CONTEXT_TEMPDIR);
081
082 _workDir = tempDir.getAbsolutePath();
083
084 if (_log.isDebugEnabled()) {
085 _log.debug("Work directory " + _workDir);
086 }
087 }
088
089 _defaultReadPathsFromArray = new String[] {
090 "${/}",
091 "${auto.deploy.installed.dir}",
092 "${catalina.base}",
093 "${com.sun.aas.instanceRoot}",
094 "${com.sun.aas.installRoot}",
095 "${file.separator}",
096 "${java.io.tmpdir}",
097 "${jboss.home.dir}",
098 "${jetty.home}",
099 "${jonas.base}",
100 "${liferay.web.portal.dir}",
101 "${liferay.home}",
102 "${line.separator}",
103 "${org.apache.geronimo.home.dir}",
104 "${path.separator}",
105 "${plugin.servlet.context.name}",
106 "${release.info.version}",
107 "${resin.home}",
108 "${user.dir}",
109 "${user.home}",
110 "${user.name}",
111 "${weblogic.domain.dir}",
112 "${websphere.profile.dir}",
113 StringPool.DOUBLE_SLASH
114 };
115
116 String installedDir = StringPool.BLANK;
117
118 try {
119 if (DeployManagerUtil.getDeployManager() != null) {
120 installedDir = DeployManagerUtil.getInstalledDir();
121 }
122 }
123 catch (Exception e) {
124 _log.error(e, e);
125 }
126
127 _defaultReadPathsToArray = new String[] {
128 System.getProperty("file.separator"), installedDir,
129 System.getProperty("catalina.base"),
130 System.getProperty("com.sun.aas.instanceRoot"),
131 System.getProperty("com.sun.aas.installRoot"),
132 System.getProperty("file.separator"),
133 System.getProperty("java.io.tmpdir"),
134 System.getProperty("jboss.home.dir"),
135 System.getProperty("jetty.home"), System.getProperty("jonas.base"),
136 _portalDir, PropsValues.LIFERAY_HOME,
137 System.getProperty("line.separator"),
138 System.getProperty("org.apache.geronimo.home.dir"),
139 System.getProperty("path.separator"), getServletContextName(),
140 ReleaseInfo.getVersion(), System.getProperty("resin.home"),
141 System.getProperty("user.dir"), System.getProperty("user.home"),
142 System.getProperty("user.name"), System.getenv("DOMAIN_HOME"),
143 System.getenv("USER_INSTALL_ROOT"), StringPool.SLASH
144 };
145
146 if (_log.isDebugEnabled()) {
147 _log.debug(
148 "Default read paths replace with " +
149 StringUtil.merge(_defaultReadPathsToArray));
150 }
151
152 initPermissions();
153 }
154
155 @Override
156 public AuthorizationProperty generateAuthorizationProperty(
157 Object... arguments) {
158
159 if ((arguments == null) || (arguments.length != 1) ||
160 !(arguments[0] instanceof Permission)) {
161
162 return null;
163 }
164
165 Permission permission = (Permission)arguments[0];
166
167 String actions = permission.getActions();
168
169 String key = null;
170
171 if (actions.equals(FILE_PERMISSION_ACTION_DELETE)) {
172 key = "security-manager-files-delete";
173 }
174 else if (actions.equals(FILE_PERMISSION_ACTION_EXECUTE)) {
175 key = "security-manager-files-execute";
176 }
177 else if (actions.equals(FILE_PERMISSION_ACTION_READ)) {
178 key = "security-manager-files-read";
179 }
180 else if (actions.equals(FILE_PERMISSION_ACTION_WRITE)) {
181 key = "security-manager-files-write";
182 }
183 else {
184 return null;
185 }
186
187 AuthorizationProperty authorizationProperty =
188 new AuthorizationProperty();
189
190 authorizationProperty.setKey(key);
191 authorizationProperty.setValue(permission.getName());
192
193 return authorizationProperty;
194 }
195
196 public String getRootDir() {
197 return _rootDir;
198 }
199
200 public boolean implies(Permission permission) {
201 if (_permissions.implies(permission)) {
202 return true;
203 }
204
205 int stackIndex = getStackIndex(10, 9);
206
207 Class<?> callerClass1 = Reflection.getCallerClass(stackIndex);
208 Class<?> callerClass2 = Reflection.getCallerClass(stackIndex + 1);
209
210 Package callerClass1Package = callerClass1.getPackage();
211
212 String callerClass1PackageName = callerClass1Package.getName();
213
214 if (callerClass1PackageName.startsWith("java.") &&
215 !callerClass1.equals(ProcessBuilder.class) &&
216 isTrustedCaller(callerClass2, permission)) {
217
218 return true;
219 }
220
221 logSecurityException(
222 _log,
223 "Attempted to " + permission.getActions() + " on file " +
224 permission.getName());
225
226 return false;
227 }
228
229 protected void addCanonicalPath(List<String> paths, String path) {
230 Iterator<String> itr = paths.iterator();
231
232 while (itr.hasNext()) {
233 String curPath = itr.next();
234
235 if (curPath.startsWith(path) &&
236 (curPath.length() > path.length())) {
237
238 itr.remove();
239 }
240 else if (path.startsWith(curPath)) {
241 return;
242 }
243 }
244
245 path = StringUtil.replace(
246 path, StringPool.BACK_SLASH, StringPool.SLASH);
247
248 if (path.endsWith(StringPool.SLASH)) {
249 path = path + "-";
250 }
251
252 paths.add(path);
253 }
254
255 protected void addCanonicalPaths(List<String> paths, File directory)
256 throws IOException {
257
258 addCanonicalPath(
259 paths, directory.getCanonicalPath() + StringPool.SLASH);
260
261 File[] files = directory.listFiles();
262
263 if ((files == null) || (files.length == 0)) {
264 return;
265 }
266
267 for (File file : files) {
268 if (file.isDirectory()) {
269 addCanonicalPaths(paths, file);
270 }
271 else {
272 File canonicalFile = new File(file.getCanonicalPath());
273
274 File parentFile = canonicalFile.getParentFile();
275
276 addCanonicalPath(
277 paths, parentFile.getPath() + StringPool.SLASH);
278 }
279 }
280 }
281
282 protected void addDefaultReadPaths(List<String> paths, String selector) {
283 String[] pathsArray = PropsUtil.getArray(
284 PropsKeys.PORTAL_SECURITY_MANAGER_FILE_CHECKER_DEFAULT_READ_PATHS,
285 new Filter(selector));
286
287 for (String path : pathsArray) {
288 path = StringUtil.replace(
289 path, _defaultReadPathsFromArray, _defaultReadPathsToArray);
290
291 paths.add(path);
292 }
293 }
294
295 protected void addPermission(String path, String actions) {
296 if (_log.isDebugEnabled()) {
297 _log.debug("Allowing " + actions + " on " + path);
298 }
299
300 String unixPath = PathUtil.toUnixPath(path);
301
302 Permission unixPermission = new FilePermission(unixPath, actions);
303
304 _permissions.add(unixPermission);
305
306 String windowsPath = PathUtil.toWindowsPath(path);
307
308 Permission windowsPermission = new FilePermission(windowsPath, actions);
309
310 _permissions.add(windowsPermission);
311 }
312
313 protected void getPermissions(String key, String actions) {
314 String value = getProperty(key);
315
316 if (value != null) {
317 value = StringUtil.replace(
318 value, _defaultReadPathsFromArray, _defaultReadPathsToArray);
319
320 String[] paths = StringUtil.split(value);
321
322 if (value.contains("${comma}")) {
323 for (int i = 0; i < paths.length; i++) {
324 paths[i] = StringUtil.replace(
325 paths[i], "${comma}", StringPool.COMMA);
326 }
327 }
328
329 for (String path : paths) {
330 addPermission(path, actions);
331 }
332 }
333
334
335
336 String pathContext = ContextPathUtil.getContextPath(
337 PropsValues.PORTAL_CTX);
338
339 ServletContext servletContext = ServletContextPool.get(pathContext);
340
341 if (!actions.equals(FILE_PERMISSION_ACTION_EXECUTE) &&
342 (_workDir != null)) {
343
344 addPermission(_workDir, actions);
345 addPermission(_workDir + "/-", actions);
346
347 if (servletContext != null) {
348 File tempDir = (File)servletContext.getAttribute(
349 JavaConstants.JAVAX_SERVLET_CONTEXT_TEMPDIR);
350
351 String tempDirAbsolutePath = tempDir.getAbsolutePath();
352
353 if (_log.isDebugEnabled()) {
354 _log.debug("Temp directory " + tempDirAbsolutePath);
355 }
356
357 if (actions.equals(FILE_PERMISSION_ACTION_READ)) {
358 addPermission(tempDirAbsolutePath, actions);
359 }
360
361 addPermission(tempDirAbsolutePath + "/-", actions);
362 }
363 }
364
365 if (!actions.equals(FILE_PERMISSION_ACTION_READ)) {
366 return;
367 }
368
369 List<String> paths = new UniqueList<String>();
370
371
372
373
374
375
376 try {
377 File file = new File(System.getProperty("java.home") + "/lib");
378
379 addCanonicalPaths(paths, file);
380
381 ClassLoader classLoader = ClassLoader.getSystemClassLoader();
382
383 Enumeration<URL> enumeration = classLoader.getResources(
384 "META-INF/MANIFEST.MF");
385
386 while (enumeration.hasMoreElements()) {
387 URL url = enumeration.nextElement();
388
389 URLConnection urlConnection = url.openConnection();
390
391 if (urlConnection instanceof JarURLConnection) {
392 JarURLConnection jarURLConnection =
393 (JarURLConnection)url.openConnection();
394
395 URL jarFileURL = jarURLConnection.getJarFileURL();
396
397 String fileName = jarFileURL.getFile();
398
399 int pos = fileName.lastIndexOf(File.separatorChar);
400
401 if (pos != -1) {
402 fileName = fileName.substring(0, pos + 1);
403 }
404
405 addCanonicalPath(paths, fileName);
406 }
407 }
408 }
409 catch (IOException ioe) {
410 _log.error(ioe, ioe);
411 }
412
413
414
415 if (Validator.isNotNull(_globalSharedLibDir)) {
416 paths.add(_globalSharedLibDir + "-");
417 }
418
419
420
421 if (_rootDir != null) {
422 paths.add(_rootDir);
423 paths.add(_rootDir + "-");
424 }
425
426
427
428 addDefaultReadPaths(paths, ServerDetector.getServerId());
429
430 for (String path : paths) {
431 addPermission(path, actions);
432 }
433 }
434
435 protected void initPermissions() {
436 getPermissions(
437 "security-manager-files-delete", FILE_PERMISSION_ACTION_DELETE);
438 getPermissions(
439 "security-manager-files-execute", FILE_PERMISSION_ACTION_EXECUTE);
440 getPermissions(
441 "security-manager-files-read", FILE_PERMISSION_ACTION_READ);
442 getPermissions(
443 "security-manager-files-write", FILE_PERMISSION_ACTION_WRITE);
444 }
445
446 private static Log _log = LogFactoryUtil.getLog(FileChecker.class);
447
448 private String[] _defaultReadPathsFromArray;
449 private String[] _defaultReadPathsToArray;
450 private String _globalSharedLibDir =
451 PropsValues.LIFERAY_LIB_GLOBAL_SHARED_DIR;
452 private Permissions _permissions = new Permissions();
453 private String _portalDir = PropsValues.LIFERAY_WEB_PORTAL_DIR;
454 private String _rootDir;
455 private String _workDir;
456
457 }