diff --git a/configuration.txt b/configuration.txt index 6124e527..740f120a 100644 --- a/configuration.txt +++ b/configuration.txt @@ -106,6 +106,9 @@ webserver-port: 8123 # Disables Webserver portion of Dynmap (Advanced users only) disable-webserver: false +# Enable/disable having the web server allow symbolic links (true=compatible with existing code, false=more secure (default)) +allow-symlinks: true + # Period between tile renders for fullrender, in seconds (non-zero to pace fullrenders, lessen CPU load) timesliceinterval: 0.0 diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index 5dde9505..d769b975 100644 --- a/src/main/java/org/dynmap/DynmapPlugin.java +++ b/src/main/java/org/dynmap/DynmapPlugin.java @@ -136,10 +136,14 @@ public class DynmapPlugin extends JavaPlugin { } } int port = configuration.getInteger("webserver-port", 8123); - + boolean allow_symlinks = configuration.getBoolean("allow-symlinks", false); + if(allow_symlinks) + Log.verboseinfo("Web server is permitting symbolic links"); + else + Log.verboseinfo("Web server is not permitting symbolic links"); webServer = new HttpServer(bindAddress, port); - webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web")))); - webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory)); + webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web")), allow_symlinks)); + webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory, allow_symlinks)); webServer.handlers.put("/up/configuration", new ClientConfigurationHandler(this)); } diff --git a/src/main/java/org/dynmap/web/handlers/FilesystemHandler.java b/src/main/java/org/dynmap/web/handlers/FilesystemHandler.java index 07bc089a..d20b217c 100644 --- a/src/main/java/org/dynmap/web/handlers/FilesystemHandler.java +++ b/src/main/java/org/dynmap/web/handlers/FilesystemHandler.java @@ -5,6 +5,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import org.dynmap.Log; import org.dynmap.utils.FileLockManager; @@ -15,21 +16,33 @@ import org.dynmap.web.HttpResponse; public class FilesystemHandler extends FileHandler { private File root; - public FilesystemHandler(File root) { + private boolean allow_symlinks = false; + private String root_path; + public FilesystemHandler(File root, boolean allow_symlinks) { if (!root.isDirectory()) throw new IllegalArgumentException(); this.root = root; + this.allow_symlinks = allow_symlinks; + this.root_path = root.getAbsolutePath(); } @Override protected InputStream getFileInput(String path, HttpRequest request, HttpResponse response) { + path = getNormalizedPath(path); /* Resolve out relative stuff - nothing allowed above webroot */ File file = new File(root, path); + if(!file.isFile()) + return null; if(!FileLockManager.getReadLock(file, 5000)) { /* Wait up to 5 seconds for lock */ Log.severe("Timeout waiting for lock on file " + file.getPath()); return null; } FileInputStream result = null; try { - if (file.getCanonicalPath().startsWith(root.getAbsolutePath()) && file.isFile()) { + String fpath; + if(allow_symlinks) + fpath = file.getAbsolutePath(); + else + fpath = file.getCanonicalPath(); + if (fpath.startsWith(root_path)) { try { result = new FileInputStream(file); } catch (FileNotFoundException e) { @@ -46,6 +59,7 @@ public class FilesystemHandler extends FileHandler { return null; } protected void closeFileInput(String path, InputStream in) throws IOException { + path = getNormalizedPath(path); try { super.closeFileInput(path, in); } finally { @@ -53,4 +67,28 @@ public class FilesystemHandler extends FileHandler { FileLockManager.releaseReadLock(file); } } + public static String getNormalizedPath(String p) { + p = p.replace('\\', '/'); + String[] tok = p.split("/"); + int i, j; + for(i = 0, j = 0; i < tok.length; i++) { + if((tok[i] == null) || (tok[i].length() == 0) || (tok[i].equals("."))) { + tok[i] = null; + } + else if(tok[i].equals("..")) { + if(j > 0) { j--; tok[j] = null; } + tok[i] = null; + } + else { + tok[j] = tok[i]; + j++; + } + } + String path = ""; + for(i = 0; i < j; i++) { + if(tok[i] != null) + path = path + "/" + tok[i]; + } + return path; + } }