diff --git a/i18n/src/main/resources/openfire_i18n.properties b/i18n/src/main/resources/openfire_i18n.properties index 7e5a7f34ac..caa14d7464 100644 --- a/i18n/src/main/resources/openfire_i18n.properties +++ b/i18n/src/main/resources/openfire_i18n.properties @@ -1626,6 +1626,7 @@ system_property.xmpp.muc.muclumbus.v1-0.enabled=Determine is the multi-user chat system_property.ldap.pagedResultsSize=The maximum number of records to retrieve from LDAP in a single page. \ The default value of -1 means rely on the paging of the LDAP server itself. \ Note that if using ActiveDirectory, this should not be left at the default, and should not be set to more than the value of the ActiveDirectory MaxPageSize; 1,000 by default. +plugins.servlet.allowLocalFileReading=Determines if the plugin servlets can be used to access files outside of Openfire's home directory. system_property.cert.storewatcher.enabled=Automatically reloads certificate stores when they're modified on disk. # Server properties Page diff --git a/xmppserver/src/main/java/org/jivesoftware/openfire/container/PluginServlet.java b/xmppserver/src/main/java/org/jivesoftware/openfire/container/PluginServlet.java index a723a0540e..c9f90c8656 100644 --- a/xmppserver/src/main/java/org/jivesoftware/openfire/container/PluginServlet.java +++ b/xmppserver/src/main/java/org/jivesoftware/openfire/container/PluginServlet.java @@ -22,7 +22,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.net.URLConnection; +import java.nio.file.Path; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; @@ -48,6 +48,7 @@ import org.jivesoftware.admin.PluginFilter; import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.StringUtils; +import org.jivesoftware.util.SystemProperty; import org.jivesoftware.util.WebXmlUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -77,6 +78,12 @@ public class PluginServlet extends HttpServlet { private static final Logger Log = LoggerFactory.getLogger(PluginServlet.class); + public static final SystemProperty ALLOW_LOCAL_FILE_READING = SystemProperty.Builder.ofType( Boolean.class ) + .setKey( "plugins.servlet.allowLocalFileReading" ) + .setDynamic( true ) + .setDefaultValue( false ) + .build(); + private static Map servlets; // mapped using lowercase path (OF-1105) private static PluginManager pluginManager; private static ServletConfig servletConfig; @@ -480,7 +487,21 @@ private void handleOtherRequest(String pathInfo, HttpServletResponse response) t if (environment != null) { file = new File(environment.getWebRoot(), contextPath); + } else { + if ( !ALLOW_LOCAL_FILE_READING.getValue() ) { + // If _not_ in a DEV environment, ensure that the file that's being served is a + // file that is part of Openfire. This guards against accessing files from the + // operating system, or other files that shouldn't be accessible via the web (OF-1886). + final Path absoluteHome = new File( JiveGlobals.getHomeDirectory() ).toPath().normalize().toAbsolutePath(); + final Path absoluteLookup = file.toPath().normalize().toAbsolutePath(); + if ( !absoluteLookup.startsWith( absoluteHome ) ) + { + response.setStatus( HttpServletResponse.SC_FORBIDDEN ); + return; + } + } } + if (!file.exists()) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return;