You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by cr...@apache.org on 2002/05/04 20:37:50 UTC

cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets ManagerServlet.java

craigmcc    02/05/04 11:37:50

  Modified:    catalina/src/share/org/apache/catalina/servlets
                        ManagerServlet.java
  Log:
  Make the "/deploy" command recognize a "META-INF/context.xml" file embedded
  inside the WAR, and process it as a context configuration file.  This allows
  deployment tool clients to customize the configuration of a webapp with
  exactly the same degree of freedom as those that use the "/install" command,
  with the added benefit of being able to deploy onto a Tomcat instance
  running on a different server.
  
  Revision  Changes    Path
  1.20      +193 -34   jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/ManagerServlet.java
  
  Index: ManagerServlet.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/ManagerServlet.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- ManagerServlet.java	8 Apr 2002 17:46:08 -0000	1.19
  +++ ManagerServlet.java	4 May 2002 18:37:49 -0000	1.20
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/ManagerServlet.java,v 1.19 2002/04/08 17:46:08 craigmcc Exp $
  - * $Revision: 1.19 $
  - * $Date: 2002/04/08 17:46:08 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/ManagerServlet.java,v 1.20 2002/05/04 18:37:49 craigmcc Exp $
  + * $Revision: 1.20 $
  + * $Date: 2002/05/04 18:37:49 $
    *
    * ====================================================================
    *
  @@ -74,6 +74,8 @@
   import java.net.URL;
   import java.util.Enumeration;
   import java.util.Iterator;
  +import java.util.jar.JarEntry;
  +import java.util.jar.JarFile;
   import javax.naming.InitialContext;
   import javax.naming.NameClassPair;
   import javax.naming.NamingEnumeration;
  @@ -196,7 +198,7 @@
    * </ul>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.19 $ $Date: 2002/04/08 17:46:08 $
  + * @version $Revision: 1.20 $ $Date: 2002/05/04 18:37:49 $
    */
   
   public class ManagerServlet
  @@ -219,6 +221,14 @@
   
   
       /**
  +     * File object representing the directory into which the deploy() command
  +     * will store the WAR and context configuration files that have been
  +     * uploaded.
  +     */
  +    protected File deployed = null;
  +
  +
  +    /**
        * The Deployer container that contains our own web application's Context,
        * along with the associated Contexts for web applications that we
        * are managing.
  @@ -435,6 +445,10 @@
               global = ((StandardServer) server).getGlobalNamingContext();
           }
   
  +        // Calculate the directory into which we will be deploying applications
  +        deployed = (File) getServletContext().getAttribute
  +            ("javax.servlet.context.tempdir");
  +
           // Log debugging messages as necessary
           if (debug >= 1) {
               log("init: Associated with Deployer '" +
  @@ -488,46 +502,52 @@
           }
   
           // Upload the web application archive to a local WAR file
  -        File tempDir = (File) getServletContext().getAttribute
  -            ("javax.servlet.context.tempdir");
  -        File localWar = new File(tempDir, basename + ".war");
  -        localWar.delete();
  +        File localWar = new File(deployed, basename + ".war");
  +        if (debug >= 2) {
  +            log("Uploading WAR file to " + localWar);
  +        }
           try {
  -            if (debug >= 2) {
  -                log("Uploading WAR file to " + localWar);
  -            }
  -            ServletInputStream istream = request.getInputStream();
  -            BufferedOutputStream ostream =
  -                new BufferedOutputStream(new FileOutputStream(localWar), 1024);
  -            byte buffer[] = new byte[1024];
  -            while (true) {
  -                int n = istream.read(buffer);
  -                if (n < 0) {
  -                    break;
  -                }
  -                ostream.write(buffer, 0, n);
  -            }
  -            ostream.flush();
  -            ostream.close();
  -            istream.close();
  +            uploadWar(request, localWar);
           } catch (IOException e) {
               log("managerServlet.upload[" + displayPath + "]", e);
               writer.println(sm.getString("managerServlet.exception",
                                           e.toString()));
  -            localWar.delete();
               return;
           }
   
  -        // Deploy the local WAR file
  +        // Extract the nested context deployment file (if any)
  +        File localXml = new File(deployed, basename + ".xml");
  +        if (debug >= 2) {
  +            log("Extracting XML file to " + localXml);
  +        }
           try {
  -            deployer.install(path,
  -                             new URL("jar:file:" +
  -                                     localWar.getAbsolutePath() + "!/"));
  +            extractXml(localWar, localXml);
  +        } catch (IOException e) {
  +            log("managerServlet.extract[" + displayPath + "]", e);
  +            writer.println(sm.getString("managerServlet.exception",
  +                                        e.toString()));
  +            return;
  +        }
  +
  +        // Deploy this web application
  +        try {
  +            URL warURL =
  +                new URL("jar:file:" + localWar.getAbsolutePath() + "!/");
  +            URL xmlURL = null;
  +            if (localXml.exists()) {
  +                xmlURL = new URL("file:" + localXml.getAbsolutePath());
  +            }
  +            if (xmlURL != null) {
  +                deployer.install(xmlURL, warURL);
  +            } else {
  +                deployer.install(path, warURL);
  +            }
           } catch (Throwable t) {
               log("ManagerServlet.deploy[" + displayPath + "]", t);
               writer.println(sm.getString("managerServlet.exception",
                                           t.toString()));
               localWar.delete();
  +            localXml.delete();
               return;
           }
   
  @@ -1034,16 +1054,14 @@
               }
   
               // Validate the docBase path of this application
  -            File tempDir = (File) getServletContext().getAttribute
  -                ("javax.servlet.context.tempdir");
  -            String tempDirPath = tempDir.getCanonicalPath();
  +            String deployedPath = deployed.getCanonicalPath();
               String docBase = context.getDocBase();
               File docBaseDir = new File(docBase);
               if (!docBaseDir.isAbsolute()) {
                   docBaseDir = new File(appBaseDir, docBase);
               }
               String docBasePath = docBaseDir.getCanonicalPath();
  -            if (!docBasePath.startsWith(tempDirPath)) {
  +            if (!docBasePath.startsWith(deployedPath)) {
                   writer.println(sm.getString("managerServlet.noDocBase",
                                               displayPath));
                   return;
  @@ -1059,6 +1077,10 @@
               } else {
                   docBaseDir.delete();  // Delete the WAR file
               }
  +            String docBaseXmlPath =
  +                docBasePath.substring(0, docBasePath.length() - 4) + ".xml";
  +            File docBaseXml = new File(docBaseXmlPath);
  +            docBaseXml.delete();
               writer.println(sm.getString("managerServlet.undeployed",
                                           displayPath));
   
  @@ -1071,6 +1093,86 @@
       }
   
   
  +    // -------------------------------------------------------- Support Methods
  +
  +
  +    /**
  +     * Extract the context configuration file from the specified WAR,
  +     * if it is present.  If it is not present, ensure that the corresponding
  +     * file does not exist.
  +     *
  +     * @param war File object representing the WAR
  +     * @param xml File object representing where to store the extracted
  +     *  context configuration file (if it exists)
  +     *
  +     * @exception IOException if an i/o error occurs
  +     */
  +    protected void extractXml(File war, File xml) throws IOException {
  +
  +        xml.delete();
  +        JarFile jar = null;
  +        JarEntry entry = null;
  +        InputStream istream = null;
  +        BufferedOutputStream ostream = null;
  +        try {
  +            jar = new JarFile(war);
  +            entry = jar.getJarEntry("META-INF/context.xml");
  +            if (entry == null) {
  +                return;
  +            }
  +            istream = jar.getInputStream(entry);
  +            ostream =
  +                new BufferedOutputStream(new FileOutputStream(xml), 1024);
  +            byte buffer[] = new byte[1024];
  +            while (true) {
  +                int n = istream.read(buffer);
  +                if (n < 0) {
  +                    break;
  +                }
  +                ostream.write(buffer, 0, n);
  +            }
  +            ostream.flush();
  +            ostream.close();
  +            ostream = null;
  +            istream.close();
  +            istream = null;
  +            entry = null;
  +            jar.close();
  +            jar = null;
  +        } catch (IOException e) {
  +            xml.delete();
  +            throw e;
  +        } finally {
  +            if (ostream != null) {
  +                try {
  +                    ostream.close();
  +                } catch (Throwable t) {
  +                    ;
  +                }
  +                ostream = null;
  +            }
  +            if (istream != null) {
  +                try {
  +                    istream.close();
  +                } catch (Throwable t) {
  +                    ;
  +                }
  +                istream = null;
  +            }
  +            entry = null;
  +            if (jar != null) {
  +                try {
  +                    jar.close();
  +                } catch (Throwable t) {
  +                    ;
  +                }
  +                jar = null;
  +            }
  +        }
  +
  +    }
  +
  +
       /**
        * Delete the specified directory, including all of its contents and
        * subdirectories recursively.
  @@ -1092,6 +1194,63 @@
               }
           }
           dir.delete();
  +
  +    }
  +
  +
  +    /**
  +     * Upload the WAR file included in this request, and store it at the
  +     * specified file location.
  +     *
  +     * @param request The servlet request we are processing
  +     * @param file The file into which we should store the uploaded WAR
  +     *
  +     * @exception IOException if an I/O error occurs during processing
  +     */
  +    protected void uploadWar(HttpServletRequest request, File war)
  +        throws IOException {
  +
  +        war.delete();
  +        ServletInputStream istream = null;
  +        BufferedOutputStream ostream = null;
  +        try {
  +            istream = request.getInputStream();
  +            ostream =
  +                new BufferedOutputStream(new FileOutputStream(war), 1024);
  +            byte buffer[] = new byte[1024];
  +            while (true) {
  +                int n = istream.read(buffer);
  +                if (n < 0) {
  +                    break;
  +                }
  +                ostream.write(buffer, 0, n);
  +            }
  +            ostream.flush();
  +            ostream.close();
  +            ostream = null;
  +            istream.close();
  +            istream = null;
  +        } catch (IOException e) {
  +            war.delete();
  +            throw e;
  +        } finally {
  +            if (ostream != null) {
  +                try {
  +                    ostream.close();
  +                } catch (Throwable t) {
  +                    ;
  +                }
  +                ostream = null;
  +            }
  +            if (istream != null) {
  +                try {
  +                    istream.close();
  +                } catch (Throwable t) {
  +                    ;
  +                }
  +                istream = null;
  +            }
  +        }
   
       }
   
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets ManagerServlet.java

Posted by co...@covalent.net.
On Mon, 6 May 2002, Glenn Nielsen wrote:

> I agree, I added a Host config flag called "deployXML" which can disable this
> for context.xml files in the webapps dir.  As long as this flag works for
> /META-INF/context.xml we are covered.

Wouldn't be better to just separate the 'sensitive' config information 
from the sandboxed config ? 

The webapps/ ( including static and dynamic files, web.xml ) can be made 
accessible to users safely - i.e. give write permission in the
 webapp dir ( based on group, etc ). 

All sensitive informations should only be accessible to admins, 
so conf/ can/should be more restrictive.

Costin


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets ManagerServlet.java

Posted by "Craig R. McClanahan" <cr...@apache.org>.

On Mon, 6 May 2002, Glenn Nielsen wrote:

> Date: Mon, 06 May 2002 14:00:33 -0500
> From: Glenn Nielsen <gl...@voyager.apg.more.net>
> Reply-To: Tomcat Developers List <to...@jakarta.apache.org>
> To: Tomcat Developers List <to...@jakarta.apache.org>
> Subject: Re: cvs commit:
>     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets
>     ManagerServlet.java
>
>
>
> costinm@covalent.net wrote:
>
> > On 4 May 2002 craigmcc@apache.org wrote:
> >
> >
> >>  Make the "/deploy" command recognize a "META-INF/context.xml" file embedded
> >>  inside the WAR, and process it as a context configuration file.  This allows
> >>  deployment tool clients to customize the configuration of a webapp with
> >>  exactly the same degree of freedom as those that use the "/install" command,
> >>  with the added benefit of being able to deploy onto a Tomcat instance
> >>  running on a different server.
> >>
> >
> > This is a very dangerous path... Having server-config info in the webapp
> > is extremely dangerous, it may (easily) break the sandbox.
> >
> > Unless there's something I'm missing, context.xml will allow loading of
> > valves and other modules that have access to the server internal objects.
> > This is a huge security hole.
> >
> > Well, having the config files in webapps/ is dangerous too - IMHO
> > all potentially dangerous configs should be in conf/, since webapps
> > may be writtable to more groups. But this is far worse.
> >
> > At least add a check to disable this if a security manager is present.
> >
> >
>
>
> I agree, I added a Host config flag called "deployXML" which can disable this
> for context.xml files in the webapps dir.  As long as this flag works for
> /META-INF/context.xml we are covered.
>

After reviewing the code, this protection is already in place.

The manager webapp handles any /install or /deploy command that has a
context XML file via the install(URL config, URL war) method of
StandardHostDeployer -- and this method is sensitive to the state of the
"deployXML" property already.

>
> Regards,
>
> Glenn

Craig


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets ManagerServlet.java

Posted by Glenn Nielsen <gl...@voyager.apg.more.net>.

costinm@covalent.net wrote:

> On 4 May 2002 craigmcc@apache.org wrote:
> 
> 
>>  Make the "/deploy" command recognize a "META-INF/context.xml" file embedded
>>  inside the WAR, and process it as a context configuration file.  This allows
>>  deployment tool clients to customize the configuration of a webapp with
>>  exactly the same degree of freedom as those that use the "/install" command,
>>  with the added benefit of being able to deploy onto a Tomcat instance
>>  running on a different server.
>>
> 
> This is a very dangerous path... Having server-config info in the webapp 
> is extremely dangerous, it may (easily) break the sandbox. 
> 
> Unless there's something I'm missing, context.xml will allow loading of
> valves and other modules that have access to the server internal objects.
> This is a huge security hole.
> 
> Well, having the config files in webapps/ is dangerous too - IMHO 
> all potentially dangerous configs should be in conf/, since webapps
> may be writtable to more groups. But this is far worse.
> 
> At least add a check to disable this if a security manager is present. 
> 
> 


I agree, I added a Host config flag called "deployXML" which can disable this
for context.xml files in the webapps dir.  As long as this flag works for
/META-INF/context.xml we are covered.


Regards,

Glenn


----------------------------------------------------------------------
Glenn Nielsen             glenn@more.net | /* Spelin donut madder    |
MOREnet System Programming               |  * if iz ina coment.      |
Missouri Research and Education Network  |  */                       |
----------------------------------------------------------------------


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets ManagerServlet.java

Posted by co...@covalent.net.
On Mon, 6 May 2002, Craig R. McClanahan wrote:

> Context XML files are like the app config files in 3.3 -- they can contain
> any config parameters that could be found in server.xml inside a <Context>
> element.  However, any <Valve> implementation classes you try to specify
> must exist in the server's classloader (i.e. in server/classes or
> server/lib) already to actually take any effect.  They will not be loaded
> from the webapp's /WEB-INF directory.

There's a lot that can be done only by using the internal classes
to hook in some untrusted code. Messing with loggers for example 
would allow to override any file that tomcat core has access to.
( probably a bit hard to push content into it, but you get my point).

The sandbox can protect you as long as you keep priviledged code 
separated. 


> It seems unlikely to me (in general) that untrusted users would have
> any more access to the "webapps" directory than to the "conf" directory.
> It seems even more unlikely to me that untrusted users would be allowed to
> issue the Manager /deploy (or /install, which has the same level of
> flexibility) commands, both of which are password protected.


I think it is a typical use-case to delegate the admin of applications,
while keeping the main server config under control.

The webapp is designed to work in sandbox, with 'webapp deployer'
role different from 'server admin' role. A large site may have 
hundreds of webapps, each with different 'managers' ( with 
web hosting beeing the extreme case ).

Having conf/ writable by the 'server admin' group while webapp/
( or each virtual host's webapp dir ) writable by the 'webapp deployer'
group is usually a good idea ( and the main reason for using conf/apps- 
in 3.3, instead of webapps/apps-xml ).

Costin 





--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets ManagerServlet.java

Posted by "Craig R. McClanahan" <cr...@apache.org>.

On Mon, 6 May 2002 costinm@covalent.net wrote:

> Date: Mon, 6 May 2002 11:16:24 -0700 (PDT)
> From: costinm@covalent.net
> Reply-To: Tomcat Developers List <to...@jakarta.apache.org>
> To: Tomcat Developers List <to...@jakarta.apache.org>
> Cc: jakarta-tomcat-4.0-cvs@apache.org
> Subject: Re: cvs commit:
>     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets
>     ManagerServlet.java
>
> On 4 May 2002 craigmcc@apache.org wrote:
>
> >   Make the "/deploy" command recognize a "META-INF/context.xml" file embedded
> >   inside the WAR, and process it as a context configuration file.  This allows
> >   deployment tool clients to customize the configuration of a webapp with
> >   exactly the same degree of freedom as those that use the "/install" command,
> >   with the added benefit of being able to deploy onto a Tomcat instance
> >   running on a different server.
>
> This is a very dangerous path... Having server-config info in the webapp
> is extremely dangerous, it may (easily) break the sandbox.
>
> Unless there's something I'm missing, context.xml will allow loading of
> valves and other modules that have access to the server internal objects.
> This is a huge security hole.
>

Context XML files are like the app config files in 3.3 -- they can contain
any config parameters that could be found in server.xml inside a <Context>
element.  However, any <Valve> implementation classes you try to specify
must exist in the server's classloader (i.e. in server/classes or
server/lib) already to actually take any effect.  They will not be loaded
from the webapp's /WEB-INF directory.

It seems unlikely to me (in general) that untrusted users would have
any more access to the "webapps" directory than to the "conf" directory.
It seems even more unlikely to me that untrusted users would be allowed to
issue the Manager /deploy (or /install, which has the same level of
flexibility) commands, both of which are password protected.

> Well, having the config files in webapps/ is dangerous too - IMHO
> all potentially dangerous configs should be in conf/, since webapps
> may be writtable to more groups. But this is far worse.
>
> At least add a check to disable this if a security manager is present.
>

There's an existing "deployXML" property that can turn off context config
files -- I can extend it to cover the dynamic deployment cases as well.

>
> Costin

Craig


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets ManagerServlet.java

Posted by co...@covalent.net.
On 4 May 2002 craigmcc@apache.org wrote:

>   Make the "/deploy" command recognize a "META-INF/context.xml" file embedded
>   inside the WAR, and process it as a context configuration file.  This allows
>   deployment tool clients to customize the configuration of a webapp with
>   exactly the same degree of freedom as those that use the "/install" command,
>   with the added benefit of being able to deploy onto a Tomcat instance
>   running on a different server.

This is a very dangerous path... Having server-config info in the webapp 
is extremely dangerous, it may (easily) break the sandbox. 

Unless there's something I'm missing, context.xml will allow loading of
valves and other modules that have access to the server internal objects.
This is a huge security hole.

Well, having the config files in webapps/ is dangerous too - IMHO 
all potentially dangerous configs should be in conf/, since webapps
may be writtable to more groups. But this is far worse.

At least add a check to disable this if a security manager is present. 


Costin






--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>