Hi, the problem that Tomcat can be shut down by any local user via AJP12 has been discussed on this list quite some time ago. It was fixed on the 3.3 branch, but iirc the fix was considered to big a change for the 3.2 branch. Since this is a rather painful problem on multiuser systems, I did a crude fix for 3.2.2 along the lines of what went into 3.3. It does change the shutdown behaviour, but here's the patch anyway in case it's useful for anyone. -- Stephan Seyboth - Developer Caldera (Deutschland) GmbH http://www.caldera.de/
? jakarta-tomcat-3.2.2-shutdown.patch Index: src/share/org/apache/tomcat/service/connector/Ajp12ConnectionHandler.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Attic/Ajp12ConnectionHandler.java,v retrieving revision 1.28.2.4 diff -u -r1.28.2.4 Ajp12ConnectionHandler.java --- src/share/org/apache/tomcat/service/connector/Ajp12ConnectionHandler.java 2001/05/11 22:37:23 1.28.2.4 +++ src/share/org/apache/tomcat/service/connector/Ajp12ConnectionHandler.java 2001/06/27 17:05:25 @@ -83,11 +83,14 @@ static StringManager sm = StringManager.getManager("org.apache.tomcat.service"); ContextManager contextM; + private static String secret; public Ajp12ConnectionHandler() { } public Object[] init() { + if(secret==null) + setSecret(contextM); Object thData[]=new Object[2]; AJP12RequestAdapter reqA=new AJP12RequestAdapter(); AJP12ResponseAdapter resA=new AJP12ResponseAdapter(); @@ -98,6 +101,38 @@ return thData; } + /* Produce a cookie file that is used to authorize shutdown + * requests so they can not be triggered by anyone + */ + public static void setSecret(ContextManager contextM) { + secret=Double.toString(Math.random()); + try { + PrintWriter stopF=new PrintWriter + (new FileWriter(contextM.getHome() + "/conf/ajp12.id")); + stopF.println( secret ); + stopF.close(); + } catch( IOException ex ) { + contextM.log( "Can't create " + contextM.getHome() + + "/conf/ajp12.id " + ex ); + } + } + + public static String getSecret(ContextManager contextM) { + if (secret!=null) + return secret; + try { + BufferedReader stopF=new BufferedReader + ( new FileReader(contextM.getHome() + "/conf/ajp12.id")); + secret=stopF.readLine(); + stopF.close(); + } catch( IOException ex ) { + contextM.log("Can't read " + contextM.getHome() + + "/conf/ajp12.id"); + secret=null; + } + return secret; + } + public void setAttribute(String name, Object value ) { if("context.manager".equals(name) ) { contextM=(ContextManager)value; @@ -390,13 +425,20 @@ } else { try { // close the socket connection before handling any signal - // but get the addresses first so they are not corrupted + // but get the addresses and secret first so they are not corrupted InetAddress serverAddr = socket.getLocalAddress(); InetAddress clientAddr = socket.getInetAddress(); + String cookie=ajpin.readString(""); sin.close(); + String secret=Ajp12ConnectionHandler.getSecret(contextM); if ( (signal== 15) && isSameAddress(serverAddr, clientAddr) ) { // Shutdown - probably apache was stoped with apachectl stop + // check cookie to make sure shutdown is legitimate + if( !secret.equals( cookie)) { + contextM.log("Attempt to stop Tomcat with the wrong secret!"); + return; + } contextM.stop(); // same behavior as in past, because it seems that // stopping everything doesn't work - need to figure Index: src/share/org/apache/tomcat/task/StopTomcat.java =================================================================== RCS file: /home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/task/Attic/StopTomcat.java,v retrieving revision 1.2 diff -u -r1.2 StopTomcat.java --- src/share/org/apache/tomcat/task/StopTomcat.java 2000/06/23 02:16:27 1.2 +++ src/share/org/apache/tomcat/task/StopTomcat.java 2001/06/27 17:05:31 @@ -99,6 +99,12 @@ } } + // Read the secret cookie + String secret=Ajp12ConnectionHandler.getSecret(cm); + if (secret==null) { + System.out.println("Can't read secret for shutdown, aborting!"); + System.exit(1); + } // use Ajp12 to stop the server... try { Socket socket = new Socket("localhost", portInt); @@ -107,6 +113,10 @@ stopMessage[0]=(byte)254; stopMessage[1]=(byte)15; os.write( stopMessage ); + int len=secret.length(); + os.write( len/256 ); + os.write( len%256 ); + os.write( secret.getBytes() );// works only for ascii socket.close(); } catch(Exception ex ) { ex.printStackTrace();