1
/* ------------------------------------------------------------------
3
* Copyright (C) 2002-2007 Novell/SUSE
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of version 2 of the GNU General Public
7
* License published by the Free Software Foundation.
9
* ------------------------------------------------------------------ */
11
package com.novell.apparmor.catalina.valves;
13
import com.novell.apparmor.JNIChangeHat;
14
import java.io.IOException;
15
import javax.servlet.ServletException;
16
import org.apache.catalina.Container;
17
import org.apache.catalina.valves.ValveBase;
18
import java.security.SecureRandom;
21
public final class ChangeHatValve extends ValveBase {
22
// JNI interface class for AppArmor change_hat
23
private static JNIChangeHat changehat_wrapper = new JNIChangeHat();
24
private static SecureRandom randomNumberGenerator = null;
25
private static String DEFAULT_HAT = "DEFAULT";
26
private static int SERVLET_PATH_MEDIATION = 0;
27
private static int URI_MEDIATION = 1;
29
private int mediationType = ChangeHatValve.SERVLET_PATH_MEDIATION;
33
* Property setter called during the parsing of the server.xml.
34
* If the <code>mediationType</code> is an attribute of the
35
* Valve definition for
36
* <code>com.novell.apparmor.catalina.valves.ChangeHatValve</code>
37
* then this setter will be called to set the value for this property.
39
* @param type <b>URI|ServletPath<b>
41
* Controls what granularity of security confinement when used with
42
* AppArmor change_hat(2). Either based upon <code>getServletPath()</code>
43
* or <code>getRequestURI()</code> called against on the request.
46
public void setMediationType( String type ) {
47
if ( type.equalsIgnoreCase("URI") ) {
48
this.mediationType = ChangeHatValve.URI_MEDIATION;
49
} else if ( type.equalsIgnoreCase("servletPath") ) {
50
this.mediationType = ChangeHatValve.SERVLET_PATH_MEDIATION;
56
* Return an int value representing the currently configured
57
* <code>mediationType</code> for this instance.
60
public int getMediationType() {
61
return this.mediationType;
67
* Return an instance of <code>SecureRandom</code> creating one if necessary
70
SecureRandom getRndGen() {
71
if ( ChangeHatValve.randomNumberGenerator == null) {
72
ChangeHatValve.randomNumberGenerator = new java.security.SecureRandom();
74
return ChangeHatValve.randomNumberGenerator;
79
* Call to return a random cookie from the <code>SecureRandom</code> PRNG
83
SecureRandom rnd = getRndGen();
85
this.getContainer().getLogger().error(
86
"[APPARMOR] can't initialize SecureRandom for cookie" +
87
" generation for change_hat() call.");
96
* Call out to AppArmor change_hat(2) to change the security
97
* context for the processing of the request by subsequent valves.
98
* Returns to the current security context when processing is complete.
99
* The security context that is chosen is govern by the
100
* <code>mediationType</code> property - which can be set in the
101
* <code>server.xml</code> file.
103
* @param request Request being processed
104
* @param response Response being processed
105
* @param context The valve context used to invoke the next valve
106
* in the current processing pipeline
108
* @exception IOException if an input/output error has occurred
109
* @exception ServletException if a servlet error has occurred
112
public void invoke( org.apache.catalina.connector.Request request,
113
org.apache.catalina.connector.Response response )
114
throws IOException, ServletException {
116
Container container = this.getContainer();
118
boolean inSubHat = false;
120
container.getLogger().debug(this.getClass().toString() +
121
"[APPARMOR] Request received [" + request.getInfo()
124
String hatname = ChangeHatValve.DEFAULT_HAT;;
125
if ( getMediationType() == ChangeHatValve.SERVLET_PATH_MEDIATION ) {
126
hatname = request.getServletPath();
127
} else if ( getMediationType() == ChangeHatValve.URI_MEDIATION ) {
128
hatname = request.getRequestURI();
132
* Select the AppArmor container for this request:
134
* 1. try hat name from either URI or ServletPath
135
* (based on configuration)
137
* 2. try hat name of the defined DEFAULT_HAT
139
* 3. run in the current AppArmor context
142
cookie = getCookie();
143
if ( hatname == null || "".equals(hatname) ) {
144
hatname = ChangeHatValve.DEFAULT_HAT;
146
container.getLogger().debug("[APPARMOR] ChangeHat to [" + hatname
147
+ "] cookie [" + cookie + "]");
149
result = changehat_wrapper.changehat_in(hatname, cookie);
151
if ( result == JNIChangeHat.EPERM ) {
152
container.getLogger().error("[APPARMOR] change_hat valve " +
153
"configured but Tomcat process is not confined by an " +
154
"AppArmor profile.");
155
getNext().invoke(request, response);
157
if ( result == JNIChangeHat.EACCES ) {
158
changehat_wrapper.changehat_out(cookie);
159
result = changehat_wrapper.changehat_in(ChangeHatValve.DEFAULT_HAT,
162
changehat_wrapper.changehat_out(cookie);
163
container.getLogger().error("[APPARMOR] ChangeHat to [" + hatname
164
+ "] failed. Running in parent context.");
168
} else if ( result != 0 ) {
169
changehat_wrapper.changehat_out(cookie);
170
container.getLogger().error("[APPARMOR] ChangeHat to [" + hatname
171
+ "] failed. Running in parent context.");
175
getNext().invoke(request, response);
176
if ( inSubHat ) changehat_wrapper.changehat_out(cookie);