Author: markt
Date: Wed Feb 23 19:23:59 2011
New Revision: 1073891
URL: http://svn.apache.org/viewvc?rev=1073891&view=rev
Log:
Add the SecurityListener (disabled by default) that prevents Tomcat from
starting if configured insecurely.
Added:
tomcat/trunk/java/org/apache/catalina/security/Constants.java (with props)
tomcat/trunk/java/org/apache/catalina/security/SecurityListener.java
(with props)
Modified:
tomcat/trunk/bin/catalina.sh
tomcat/trunk/conf/server.xml
tomcat/trunk/java/org/apache/catalina/security/LocalStrings.properties
tomcat/trunk/java/org/apache/catalina/security/SecurityUtil.java
tomcat/trunk/res/confinstall/server_1.xml
tomcat/trunk/webapps/docs/changelog.xml
tomcat/trunk/webapps/docs/config/listeners.xml
tomcat/trunk/webapps/docs/setup.xml
Modified: tomcat/trunk/bin/catalina.sh
URL:
http://svn.apache.org/viewvc/tomcat/trunk/bin/catalina.sh?rev=1073891&r1=1073890&r2=1073891&view=diff
==============================================================================
--- tomcat/trunk/bin/catalina.sh (original)
+++ tomcat/trunk/bin/catalina.sh Wed Feb 23 19:23:59 2011
@@ -225,6 +225,10 @@ else
JAVA_OPTS="$JAVA_OPTS $LOGGING_MANAGER"
fi
+# Uncomment the following line to make the umask available when using the
+# org.apache.catalina.security.SecurityListener
+#JAVA_OPTS="$JAVA_OPTS
-Dorg.apache.catalina.security.SecurityListener.UMASK=`umask`"
+
# ----- Execute The Requested Command -----------------------------------------
# Bugzilla 37848: only output this if we have a TTY
Modified: tomcat/trunk/conf/server.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/conf/server.xml?rev=1073891&r1=1073890&r2=1073891&view=diff
==============================================================================
--- tomcat/trunk/conf/server.xml (original)
+++ tomcat/trunk/conf/server.xml Wed Feb 23 19:23:59 2011
@@ -20,7 +20,9 @@
Documentation at /docs/config/server.html
-->
<Server port="8005" shutdown="SHUTDOWN">
-
+ <!-- Security listener. Documentation at /docs/config/listeners.html
+ <Listener className="org.apache.catalina.security.SecurityListener" />
+ -->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener"
SSLEngine="on" />
<!--Initialize Jasper prior to webapps are loaded. Documentation at
/docs/jasper-howto.html -->
Added: tomcat/trunk/java/org/apache/catalina/security/Constants.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/security/Constants.java?rev=1073891&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/security/Constants.java (added)
+++ tomcat/trunk/java/org/apache/catalina/security/Constants.java Wed Feb 23
19:23:59 2011
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.security;
+
+public class Constants {
+
+ public static final String PACKAGE = "org.apache.catalina.security";
+
+ public static final String LINE_SEP = System.getProperty("line.separator");
+ public static final String CRLF = "\r\n";
+}
Propchange: tomcat/trunk/java/org/apache/catalina/security/Constants.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/trunk/java/org/apache/catalina/security/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/security/LocalStrings.properties?rev=1073891&r1=1073890&r2=1073891&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/security/LocalStrings.properties
(original)
+++ tomcat/trunk/java/org/apache/catalina/security/LocalStrings.properties Wed
Feb 23 19:23:59 2011
@@ -14,4 +14,8 @@
# limitations under the License.
SecurityUtil.doAsPrivilege=An exception occurs when running the
PrivilegedExceptionAction block.
-
+SecurityListener.checkUmaskFail=Start attempted with umask setting of [{0}].
Running Tomcat without a umask at least as restrictive as [{1}] has been
blocked by the Lifecycle listener org.apache.catalina.security.SecurityListener
(usually configured in CATALINA_BASE/conf/server.xml)
+SecurityListener.checkUmaskNone=No umask setting was found in system property
[{0}]. However, it appears Tomcat is running on a platform that supports umask.
The system property is typically set in CATALINA_HOME/bin/catalina.sh. The
Lifecycle listener org.apache.catalina.security.SecurityListener (usually
configured in CATALINA_BASE/conf/server.xml) expects a umask at least as
restrictive as [{1}]
+SecurityListener.checkUmaskParseFail=Failed to parse value [{0}] as a valid
umask.
+SecurityListener.checkUmaskSkip=Unable to determine umask. It appears Tomcat
is running on Windows so skip the umask check.
+SecurityListener.checkUserWarning=Start attempted while running as user [{0}].
Running Tomcat as this user has been blocked by the Lifecycle listener
org.apache.catalina.security.SecurityListener (usually configured in
CATALINA_BASE/conf/server.xml)
\ No newline at end of file
Added: tomcat/trunk/java/org/apache/catalina/security/SecurityListener.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/security/SecurityListener.java?rev=1073891&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/security/SecurityListener.java (added)
+++ tomcat/trunk/java/org/apache/catalina/security/SecurityListener.java Wed
Feb 23 19:23:59 2011
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.security;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.res.StringManager;
+
+public class SecurityListener implements LifecycleListener {
+
+ private static final Log log = LogFactory.getLog(SecurityListener.class);
+
+ private static final StringManager sm =
+ StringManager.getManager(Constants.PACKAGE);
+
+ private static final String UMASK_PROPERTY_NAME =
+ Constants.PACKAGE + ".SecurityListener.UMASK";
+
+ private static final String UMASK_FORMAT = "%04o";
+
+ /**
+ * The list of operating system users not permitted to run Tomcat.
+ */
+ private Set<String> checkedOsUsers = new HashSet<String>();
+
+ /**
+ * The minimum umask that must be configured for the operating system user
+ * running Tomcat. The umask is handled as an octal.
+ */
+ private Integer minimumUmask = Integer.valueOf(7);
+
+
+ public SecurityListener() {
+ checkedOsUsers.add("root");
+ }
+
+
+ @Override
+ public void lifecycleEvent(LifecycleEvent event) {
+ // This is the earliest event in Lifecycle
+ if (event.getType().equals(Lifecycle.BEFORE_INIT_EVENT)) {
+ doChecks();
+ }
+ }
+
+
+ /**
+ * Set the list of operating system users not permitted to run Tomcat. By
+ * default, only root is prevented from running Tomcat. Calling this method
+ * with null or the empty string will clear the list of users and
+ * effectively disables this check. User names will always be checked in a
+ * case insensitive manner.
+ *
+ * @param userList A comma separated list of operating system users not
+ * permitted to run Tomcat
+ */
+ public void setCheckedOsUsers(String userNameList) {
+ if (userNameList == null || userNameList.length() == 0) {
+ checkedOsUsers.clear();
+ } else {
+ String[] userNames = userNameList.split(",");
+ for (String userName : userNames) {
+ if (userName.length() > 0) {
+ checkedOsUsers.add(userName);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Returns the current list of operating system users not permitted to run
+ * Tomcat.
+ *
+ * @return A comma separated list of operating sytem user names.
+ */
+ public String getCheckedOsUsers() {
+ if (checkedOsUsers.size() == 0) {
+ return "";
+ }
+
+ StringBuilder result = new StringBuilder();
+ Iterator<String> iter = checkedOsUsers.iterator();
+ result.append(iter.next());
+ while (iter.hasNext()) {
+ result.append(',');
+ result.append(iter.next());
+ }
+ return result.toString();
+ }
+
+
+ /**
+ * Set the minimum umask that must be configured before Tomcat will start.
+ *
+ * @param umask The 4-digit umask as returned by the OS command
<i>umask</i>
+ */
+ public void setMinimumUmask(String umask) {
+ if (umask == null || umask.length() == 0) {
+ minimumUmask = Integer.valueOf(0);
+ } else {
+ minimumUmask = Integer.valueOf(umask, 8);
+ }
+ }
+
+
+ /**
+ * Get the minimum umask that must be configured before Tomcat will start.
+ *
+ * @return The 4-digit umask as used by the OS command <i>umask</i>
+ */
+ public String getMinimumUmask() {
+ return String.format(UMASK_FORMAT, minimumUmask);
+ }
+
+
+ /**
+ * Execute the security checks. Each check should be in a separate method.
+ */
+ protected void doChecks() {
+ checkOsUser();
+ checkUmask();
+ }
+
+
+ protected void checkOsUser() {
+ String userName = System.getProperty("user.name");
+ if (userName != null) {
+ String userNameLC = userName.toLowerCase();
+
+ if (checkedOsUsers.contains(userNameLC)) {
+ // Have to throw Error to force start process to be aborted
+ throw new Error(sm.getString(
+ "SecurityListener.checkUserWarning", userName));
+ }
+ }
+ }
+
+
+ protected void checkUmask() {
+ String prop = System.getProperty(UMASK_PROPERTY_NAME);
+ Integer umask = null;
+ if (prop != null) {
+ try {
+ umask = Integer.valueOf(prop, 8);
+ } catch (NumberFormatException nfe) {
+ log.warn(sm.getString("SecurityListener.checkUmaskParseFail",
+ prop));
+ }
+ }
+ if (umask == null) {
+ if (Constants.CRLF.equals(Constants.LINE_SEP)) {
+ // Probably running on Windows so no umask
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("SecurityListener.checkUmaskSkip"));
+ }
+ return;
+ } else {
+ if (minimumUmask.intValue() > 0) {
+ log.warn(sm.getString(
+ "SecurityListener.checkUmaskNone",
+ UMASK_PROPERTY_NAME, getMinimumUmask()));
+ }
+ return;
+ }
+ }
+
+ if ((umask.intValue() & minimumUmask.intValue()) !=
+ minimumUmask.intValue()) {
+ throw new Error(sm.getString("SecurityListener.checkUmaskFail",
+ String.format(UMASK_FORMAT, umask), getMinimumUmask()));
+ }
+ }
+}
Propchange: tomcat/trunk/java/org/apache/catalina/security/SecurityListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/trunk/java/org/apache/catalina/security/SecurityUtil.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/security/SecurityUtil.java?rev=1073891&r1=1073890&r2=1073891&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/security/SecurityUtil.java (original)
+++ tomcat/trunk/java/org/apache/catalina/security/SecurityUtil.java Wed Feb 23
19:23:59 2011
@@ -73,8 +73,6 @@ public final class SecurityUtil{
private static final org.apache.juli.logging.Log log=
org.apache.juli.logging.LogFactory.getLog( SecurityUtil.class );
- private static String PACKAGE = "org.apache.catalina.security";
-
private static boolean packageDefinitionEnabled =
(System.getProperty("package.definition") == null &&
System.getProperty("package.access") == null) ? false : true;
@@ -83,7 +81,7 @@ public final class SecurityUtil{
* The string resources for this package.
*/
private static final StringManager sm =
- StringManager.getManager(PACKAGE);
+ StringManager.getManager(Constants.PACKAGE);
/**
Modified: tomcat/trunk/res/confinstall/server_1.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/res/confinstall/server_1.xml?rev=1073891&r1=1073890&r2=1073891&view=diff
==============================================================================
--- tomcat/trunk/res/confinstall/server_1.xml (original)
+++ tomcat/trunk/res/confinstall/server_1.xml Wed Feb 23 19:23:59 2011
@@ -20,7 +20,9 @@
Documentation at /docs/config/server.html
-->
<Server port="8005" shutdown="SHUTDOWN">
-
+ <!-- Security Listener. Documentation at /docs/config/listeners.html
+ <Listener className="org.apache.catalina.security.SecurityListener" />
+ -->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener"
SSLEngine="on" />
<!--Initialize Jasper prior to webapps are loaded. Documentation at
/docs/jasper-howto.html -->
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1073891&r1=1073890&r2=1073891&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Wed Feb 23 19:23:59 2011
@@ -53,6 +53,14 @@
<bug>21669</bug>: Add the ability to specify the roleBase for the JNDI
Realm as relative to the users DN. Based on a patch by Art W. (markt)
</add>
+ <add>
+ <bug>22405</bug>: Add a new Lifecycle listener,
+ <code>org.apache.catalina.security.SecurityListener</code> that
prevents
+ Tomcat from starting insecurely. It requires that Tomcat is not started
+ as root and that a umask at least as restrictive as 0007 is used. This
+ new listener is not enabled by default.
+ (markt)
+ </add>
<fix>
<bug>48863</bug>: Better logging when specifying an invalid directory
for a class loader. Based on a patch by Ralf Hauser. (markt)
Modified: tomcat/trunk/webapps/docs/config/listeners.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/listeners.xml?rev=1073891&r1=1073890&r2=1073891&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/listeners.xml (original)
+++ tomcat/trunk/webapps/docs/config/listeners.xml Wed Feb 23 19:23:59 2011
@@ -310,6 +310,39 @@ service:jmx:rmi://<hostname>:10002
</attributes>
+ <h3>Security Lifecycle Listener
(org.apache.catalina.security.SecurityListener)</h3>
+
+ <p>The <strong>Security Lifecycle Listener</strong> performs a number of
+ security checks when Tomcat starts and prevents Tomcat from starting if
they
+ fail. The listener is not enabled by default. To enabled it uncomment the
+ listener in $CATALINA_BASE/conf/server.xml. If the operating system
supports
+ umask then the line in $CATALINA_HOME/bin/catalina.sh that obtains the
umask
+ also needs to be uncommented.</p>
+
+ <p>This listener must only be nested within <a
href="server.html">Server</a>
+ elements.</p>
+
+ <p>The following additional attributes are supported by the
<strong>Security
+ Lifecycle Listener</strong>:</p>
+
+ <attributes>
+
+ <attribute name="checkedOsUsers" required="false">
+ <p>A comma separated list of OS users that must not be used to start
+ Tomcat. If not specified, the default value of <b>root</b> is used. To
+ disable this check, set the attribute to the empty string. Usernames
+ are checked in a case-insensitive manner.</p>
+ </attribute>
+
+ <attribute name="minimumUmask" required="false">
+ <p>The least rectrictive umask that must be configured before Tomcat
+ will start. If not specified, the default value of <b>0007</b> is used.
+ To disable this check, set the attribute to the empty string. The check
+ is not performed on Windows platforms.</p>
+ </attribute>
+
+ </attributes>
+
</subsection>
</section>
Modified: tomcat/trunk/webapps/docs/setup.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/setup.xml?rev=1073891&r1=1073890&r2=1073891&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/setup.xml (original)
+++ tomcat/trunk/webapps/docs/setup.xml Wed Feb 23 19:23:59 2011
@@ -131,8 +131,12 @@
<p>jsvc has other useful parameters, such as <code>-user</code> which
causes it to switch to another user after the daemon initialization is
complete. This allows, for example, running Tomcat as a non privileged
- user while still being able to use privileged ports.
- <code>jsvc --help</code> will return the full jsvc usage
+ user while still being able to use privileged ports. Note that if you
+ use this option and start Tomcat as root, you'll need to disable
the
+ <code>org.apache.catalina.security.SecurityListener</code> check that
+ prevents Tomcat starting when running as root.</p>
+
+ <p><code>jsvc --help</code> will return the full jsvc usage
information. In particular, the <code>-debug</code> option is useful
to debug issues running jsvc.</p>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]