Author: markt
Date: Sun Sep 16 22:18:54 2012
New Revision: 1385387
URL: http://svn.apache.org/viewvc?rev=1385387&view=rev
Log:
Add in support for allowLinking option.
Note: this restores the case sensitivity checks on Windows closing a large
security hole in the new resources implementation.
Modified:
tomcat/sandbox/trunk-resources/java/org/apache/catalina/WebResourceRoot.java
tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/DirResourceSet.java
tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java
tomcat/sandbox/trunk-resources/test/org/apache/catalina/webresources/TesterWebResourceRoot.java
Modified:
tomcat/sandbox/trunk-resources/java/org/apache/catalina/WebResourceRoot.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/WebResourceRoot.java?rev=1385387&r1=1385386&r2=1385387&view=diff
==============================================================================
---
tomcat/sandbox/trunk-resources/java/org/apache/catalina/WebResourceRoot.java
(original)
+++
tomcat/sandbox/trunk-resources/java/org/apache/catalina/WebResourceRoot.java
Sun Sep 16 22:18:54 2012
@@ -223,6 +223,7 @@ public interface WebResourceRoot extends
boolean getAddWebinfClassesResources();
void setAllowLinking(boolean allowLinking);
+ boolean getAllowLinking();
public static enum ResourceSetType {
PRE,
Modified:
tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/DirResourceSet.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/DirResourceSet.java?rev=1385387&r1=1385386&r2=1385387&view=diff
==============================================================================
---
tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/DirResourceSet.java
(original)
+++
tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/DirResourceSet.java
Sun Sep 16 22:18:54 2012
@@ -27,6 +27,7 @@ import org.apache.catalina.WebResourceRo
import org.apache.catalina.WebResourceRoot.ResourceSetType;
import org.apache.catalina.util.IOTools;
import org.apache.catalina.util.ResourceSet;
+import org.apache.tomcat.util.http.RequestUtil;
/**
* Represents a {@link WebResourceSet} based on a directory.
@@ -37,6 +38,8 @@ public class DirResourceSet extends Abst
private final WebResourceRoot root;
private final File base;
+ private final String absoluteBase;
+ private final String canonicalBase;
private final String webAppMount;
/**
@@ -63,6 +66,19 @@ public class DirResourceSet extends Abst
"TODO-i18n: base/internalPath is not a directory");
}
this.base = base;
+
+ String absolutePath = base.getAbsolutePath();
+ if (absolutePath.endsWith(".")) {
+ absolutePath = absolutePath + "/";
+ }
+ this.absoluteBase = normalize(absolutePath);
+
+ try {
+ this.canonicalBase = base.getCanonicalPath();
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+
this.webAppMount = webAppMount;
if (root.getAddWebinfClassesResources()) {
@@ -80,7 +96,10 @@ public class DirResourceSet extends Abst
public WebResource getResource(String path) {
checkPath(path);
if (path.startsWith(webAppMount)) {
- File f = new File(base, path.substring(webAppMount.length()));
+ File f = file(path.substring(webAppMount.length()), true);
+ if (f == null) {
+ return new EmptyResource(root, path);
+ }
if (f.isDirectory() && path.charAt(path.length() - 1) != '/') {
path = path += '/';
}
@@ -94,7 +113,10 @@ public class DirResourceSet extends Abst
public String[] list(String path) {
checkPath(path);
if (path.startsWith(webAppMount)) {
- File f = new File(base, path.substring(webAppMount.length()));
+ File f = file(path.substring(webAppMount.length()), true);
+ if (f == null) {
+ return EMPTY_STRING_ARRAY;
+ }
String[] result = f.list();
if (result == null) {
return EMPTY_STRING_ARRAY;
@@ -111,19 +133,21 @@ public class DirResourceSet extends Abst
checkPath(path);
ResourceSet<String> result = new ResourceSet<>();
if (path.startsWith(webAppMount)) {
- File f = new File(base, path.substring(webAppMount.length()));
- File[] list = f.listFiles();
- if (list != null) {
- for (File entry : list) {
- StringBuilder sb = new StringBuilder(path);
- if (path.charAt(path.length() - 1) != '/') {
- sb.append('/');
- }
- sb.append(entry.getName());
- if (entry.isDirectory()) {
- sb.append('/');
+ File f = file(path.substring(webAppMount.length()), true);
+ if (f != null) {
+ File[] list = f.listFiles();
+ if (list != null) {
+ for (File entry : list) {
+ StringBuilder sb = new StringBuilder(path);
+ if (path.charAt(path.length() - 1) != '/') {
+ sb.append('/');
+ }
+ sb.append(entry.getName());
+ if (entry.isDirectory()) {
+ sb.append('/');
+ }
+ result.add(sb.toString());
}
- result.add(sb.toString());
}
}
}
@@ -135,7 +159,10 @@ public class DirResourceSet extends Abst
public boolean mkdir(String path) {
checkPath(path);
if (path.startsWith(webAppMount)) {
- File f = new File(base, path.substring(webAppMount.length()));
+ File f = file(path.substring(webAppMount.length()), false);
+ if (f == null) {
+ return false;
+ }
return f.mkdir();
} else {
return false;
@@ -153,7 +180,10 @@ public class DirResourceSet extends Abst
File dest = null;
if (path.startsWith(webAppMount)) {
- dest = new File(base, path.substring(webAppMount.length()));
+ dest = file(path.substring(webAppMount.length()), false);
+ if (dest == null) {
+ return false;
+ }
} else {
return false;
}
@@ -170,4 +200,67 @@ public class DirResourceSet extends Abst
return true;
}
+
+ private File file(String name, boolean mustExist) {
+
+ File file = new File(base, name);
+ if (file.exists() && file.canRead() || !mustExist) {
+
+ if (root.getAllowLinking()) {
+ return file;
+ }
+
+ // Check that this file is located under the WebResourceSet's base
+ String canPath = null;
+ try {
+ canPath = file.getCanonicalPath();
+ } catch (IOException e) {
+ // Ignore
+ }
+ if (canPath == null)
+ return null;
+
+ if (!canPath.startsWith(canonicalBase)) {
+ return null;
+ }
+
+ // Case sensitivity check
+ // Note: We know the resource is located somewhere under base at
+ // point. The purpose of this code is to check in a case
+ // sensitive manner, the path to the resource under base
+ // agrees with what was requested
+ String fileAbsPath = file.getAbsolutePath();
+ if (fileAbsPath.endsWith("."))
+ fileAbsPath = fileAbsPath + "/";
+ String absPath = normalize(fileAbsPath);
+ if ((absoluteBase.length() < absPath.length())
+ && (canonicalBase.length() < canPath.length())) {
+ absPath = absPath.substring(absoluteBase.length() + 1);
+ if (absPath.equals(""))
+ absPath = "/";
+ canPath = canPath.substring(canonicalBase.length() + 1);
+ if (canPath.equals(""))
+ canPath = "/";
+ if (!canPath.equals(absPath))
+ return null;
+ }
+
+ } else {
+ return null;
+ }
+ return file;
+ }
+
+ /**
+ * Return a context-relative path, beginning with a "/", that represents
+ * the canonical version of the specified path after ".." and "." elements
+ * are resolved out. If the specified path attempts to go outside the
+ * boundaries of the current context (i.e. too many ".." path elements
+ * are present), return <code>null</code> instead.
+ *
+ * @param path Path to be normalized
+ */
+ protected String normalize(String path) {
+ return RequestUtil.normalize(path, File.separatorChar == '/');
+ }
}
Modified:
tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java?rev=1385387&r1=1385386&r2=1385387&view=diff
==============================================================================
---
tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java
(original)
+++
tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java
Sun Sep 16 22:18:54 2012
@@ -48,6 +48,7 @@ public class StandardRoot extends Lifecy
StringManager.getManager(Constants.Package);
private final Context context;
+ private boolean allowLinking = false;
private ArrayList<WebResourceSet> preResources = new ArrayList<>();
private WebResourceSet main;
private ArrayList<WebResourceSet> jarResources = new ArrayList<>();
@@ -182,7 +183,11 @@ public class StandardRoot extends Lifecy
String[] resources = list(path);
WebResource[] result = new WebResource[resources.length];
for (int i = 0; i < resources.length; i++) {
- result[i] = getResource(path + "/" + resources[i]);
+ if (path.charAt(path.length() - 1) == '/') {
+ result[i] = getResource(path + resources[i]);
+ } else {
+ result[i] = getResource(path + '/' + resources[i]);
+ }
}
return result;
}
@@ -237,7 +242,12 @@ public class StandardRoot extends Lifecy
@Override
public void setAllowLinking(boolean allowLinking) {
- // TODO Implement this feature
+ this.allowLinking = allowLinking;
+ }
+
+ @Override
+ public boolean getAllowLinking() {
+ return allowLinking;
}
@Override
Modified:
tomcat/sandbox/trunk-resources/test/org/apache/catalina/webresources/TesterWebResourceRoot.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/test/org/apache/catalina/webresources/TesterWebResourceRoot.java?rev=1385387&r1=1385386&r2=1385387&view=diff
==============================================================================
---
tomcat/sandbox/trunk-resources/test/org/apache/catalina/webresources/TesterWebResourceRoot.java
(original)
+++
tomcat/sandbox/trunk-resources/test/org/apache/catalina/webresources/TesterWebResourceRoot.java
Sun Sep 16 22:18:54 2012
@@ -138,4 +138,9 @@ public class TesterWebResourceRoot imple
public void setAllowLinking(boolean allowLinking) {
// NO-OP
}
+
+ @Override
+ public boolean getAllowLinking() {
+ return false;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]