1
17
18 package org.apache.catalina.core;
19
20
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import org.apache.catalina.Lifecycle;
27 import org.apache.catalina.LifecycleEvent;
28 import org.apache.catalina.LifecycleListener;
29 import org.apache.juli.logging.Log;
30 import org.apache.juli.logging.LogFactory;
31 import org.apache.tomcat.jni.Library;
32 import org.apache.tomcat.jni.LibraryNotFoundError;
33 import org.apache.tomcat.jni.SSL;
34 import org.apache.tomcat.util.ExceptionUtils;
35 import org.apache.tomcat.util.res.StringManager;
36
37
38
39
45 public class AprLifecycleListener
46 implements LifecycleListener {
47
48 private static final Log log = LogFactory.getLog(AprLifecycleListener.class);
49 private static boolean instanceCreated = false;
50
55 private static final List<String> initInfoLogMessages = new ArrayList<>(3);
56
57
60 protected static final StringManager sm =
61 StringManager.getManager(Constants.Package);
62
63
64
65
66
67 protected static final int TCN_REQUIRED_MAJOR = 1;
68 protected static final int TCN_REQUIRED_MINOR = 2;
69 protected static final int TCN_REQUIRED_PATCH = 14;
70 protected static final int TCN_RECOMMENDED_MINOR = 2;
71 protected static final int TCN_RECOMMENDED_PV = 23;
72
73
74
75 protected static String SSLEngine = "on";
76 protected static String FIPSMode = "off";
77 protected static String SSLRandomSeed = "builtin";
78 protected static boolean sslInitialized = false;
79 protected static boolean aprInitialized = false;
80 protected static boolean aprAvailable = false;
81 protected static boolean useAprConnector = false;
82 protected static boolean useOpenSSL = true;
83 protected static boolean fipsModeActive = false;
84
85
97 private static final int FIPS_ON = 1;
98
99 private static final int FIPS_OFF = 0;
100
101 protected static final Object lock = new Object();
102
103 public static boolean isAprAvailable() {
104
105 if (instanceCreated) {
106 synchronized (lock) {
107 init();
108 }
109 }
110 return aprAvailable;
111 }
112
113 public AprLifecycleListener() {
114 instanceCreated = true;
115 }
116
117
118
119
124 @Override
125 public void lifecycleEvent(LifecycleEvent event) {
126
127 if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
128 synchronized (lock) {
129 init();
130 for (String msg : initInfoLogMessages) {
131 log.info(msg);
132 }
133 initInfoLogMessages.clear();
134 if (aprAvailable) {
135 try {
136 initializeSSL();
137 } catch (Throwable t) {
138 t = ExceptionUtils.unwrapInvocationTargetException(t);
139 ExceptionUtils.handleThrowable(t);
140 log.error(sm.getString("aprListener.sslInit"), t);
141 }
142 }
143
144 if (!(null == FIPSMode || "off".equalsIgnoreCase(FIPSMode)) && !isFIPSModeActive()) {
145 String errorMessage = sm.getString("aprListener.initializeFIPSFailed");
146 Error e = new Error(errorMessage);
147
148 log.fatal(errorMessage, e);
149 throw e;
150 }
151 }
152 } else if (Lifecycle.AFTER_DESTROY_EVENT.equals(event.getType())) {
153 synchronized (lock) {
154 if (!aprAvailable) {
155 return;
156 }
157 try {
158 terminateAPR();
159 } catch (Throwable t) {
160 t = ExceptionUtils.unwrapInvocationTargetException(t);
161 ExceptionUtils.handleThrowable(t);
162 log.info(sm.getString("aprListener.aprDestroy"));
163 }
164 }
165 }
166
167 }
168
169 private static void terminateAPR()
170 throws ClassNotFoundException, NoSuchMethodException,
171 IllegalAccessException, InvocationTargetException
172 {
173 String methodName = "terminate";
174 Method method = Class.forName("org.apache.tomcat.jni.Library")
175 .getMethod(methodName, (Class [])null);
176 method.invoke(null, (Object []) null);
177 aprAvailable = false;
178 aprInitialized = false;
179 sslInitialized = false;
180 fipsModeActive = false;
181 }
182
183 private static void init()
184 {
185 int major = 0;
186 int minor = 0;
187 int patch = 0;
188 int apver = 0;
189 int rqver = TCN_REQUIRED_MAJOR * 1000 + TCN_REQUIRED_MINOR * 100 + TCN_REQUIRED_PATCH;
190 int rcver = TCN_REQUIRED_MAJOR * 1000 + TCN_RECOMMENDED_MINOR * 100 + TCN_RECOMMENDED_PV;
191
192 if (aprInitialized) {
193 return;
194 }
195 aprInitialized = true;
196
197 try {
198 Library.initialize(null);
199 major = Library.TCN_MAJOR_VERSION;
200 minor = Library.TCN_MINOR_VERSION;
201 patch = Library.TCN_PATCH_VERSION;
202 apver = major * 1000 + minor * 100 + patch;
203 } catch (LibraryNotFoundError lnfe) {
204
205 if (log.isDebugEnabled()) {
206 log.debug(sm.getString("aprListener.aprInitDebug",
207 lnfe.getLibraryNames(), System.getProperty("java.library.path"),
208 lnfe.getMessage()), lnfe);
209 }
210 initInfoLogMessages.add(sm.getString("aprListener.aprInit",
211 System.getProperty("java.library.path")));
212 return;
213 } catch (Throwable t) {
214
215 t = ExceptionUtils.unwrapInvocationTargetException(t);
216 ExceptionUtils.handleThrowable(t);
217 log.warn(sm.getString("aprListener.aprInitError", t.getMessage()), t);
218 return;
219 }
220 if (apver < rqver) {
221 log.error(sm.getString("aprListener.tcnInvalid", major + "."
222 + minor + "." + patch,
223 TCN_REQUIRED_MAJOR + "." +
224 TCN_REQUIRED_MINOR + "." +
225 TCN_REQUIRED_PATCH));
226 try {
227
228
229 terminateAPR();
230 } catch (Throwable t) {
231 t = ExceptionUtils.unwrapInvocationTargetException(t);
232 ExceptionUtils.handleThrowable(t);
233 }
234 return;
235 }
236 if (apver < rcver) {
237 initInfoLogMessages.add(sm.getString("aprListener.tcnVersion",
238 major + "." + minor + "." + patch,
239 TCN_REQUIRED_MAJOR + "." +
240 TCN_RECOMMENDED_MINOR + "." +
241 TCN_RECOMMENDED_PV));
242 }
243
244 initInfoLogMessages.add(sm.getString("aprListener.tcnValid",
245 major + "." + minor + "." + patch,
246 Library.APR_MAJOR_VERSION + "." +
247 Library.APR_MINOR_VERSION + "." +
248 Library.APR_PATCH_VERSION));
249
250
251 initInfoLogMessages.add(sm.getString("aprListener.flags",
252 Boolean.valueOf(Library.APR_HAVE_IPV6),
253 Boolean.valueOf(Library.APR_HAS_SENDFILE),
254 Boolean.valueOf(Library.APR_HAS_SO_ACCEPTFILTER),
255 Boolean.valueOf(Library.APR_HAS_RANDOM)));
256
257 initInfoLogMessages.add(sm.getString("aprListener.config",
258 Boolean.valueOf(useAprConnector),
259 Boolean.valueOf(useOpenSSL)));
260
261 aprAvailable = true;
262 }
263
264 private static void initializeSSL() throws Exception {
265
266 if ("off".equalsIgnoreCase(SSLEngine)) {
267 return;
268 }
269 if (sslInitialized) {
270
271 return;
272 }
273
274 sslInitialized = true;
275
276 String methodName = "randSet";
277 Class<?> paramTypes[] = new Class[1];
278 paramTypes[0] = String.class;
279 Object paramValues[] = new Object[1];
280 paramValues[0] = SSLRandomSeed;
281 Class<?> clazz = Class.forName("org.apache.tomcat.jni.SSL");
282 Method method = clazz.getMethod(methodName, paramTypes);
283 method.invoke(null, paramValues);
284
285
286 methodName = "initialize";
287 paramValues[0] = "on".equalsIgnoreCase(SSLEngine)?null:SSLEngine;
288 method = clazz.getMethod(methodName, paramTypes);
289 method.invoke(null, paramValues);
290
291 if (!(null == FIPSMode || "off".equalsIgnoreCase(FIPSMode))) {
292
293 fipsModeActive = false;
294
295 final boolean enterFipsMode;
296 int fipsModeState = SSL.fipsModeGet();
297
298 if(log.isDebugEnabled()) {
299 log.debug(sm.getString("aprListener.currentFIPSMode",
300 Integer.valueOf(fipsModeState)));
301 }
302
303 if ("on".equalsIgnoreCase(FIPSMode)) {
304 if (fipsModeState == FIPS_ON) {
305 log.info(sm.getString("aprListener.skipFIPSInitialization"));
306 fipsModeActive = true;
307 enterFipsMode = false;
308 } else {
309 enterFipsMode = true;
310 }
311 } else if ("require".equalsIgnoreCase(FIPSMode)) {
312 if (fipsModeState == FIPS_ON) {
313 fipsModeActive = true;
314 enterFipsMode = false;
315 } else {
316 throw new IllegalStateException(
317 sm.getString("aprListener.requireNotInFIPSMode"));
318 }
319 } else if ("enter".equalsIgnoreCase(FIPSMode)) {
320 if (fipsModeState == FIPS_OFF) {
321 enterFipsMode = true;
322 } else {
323 throw new IllegalStateException(sm.getString(
324 "aprListener.enterAlreadyInFIPSMode",
325 Integer.valueOf(fipsModeState)));
326 }
327 } else {
328 throw new IllegalArgumentException(sm.getString(
329 "aprListener.wrongFIPSMode", FIPSMode));
330 }
331
332 if (enterFipsMode) {
333 log.info(sm.getString("aprListener.initializingFIPS"));
334
335 fipsModeState = SSL.fipsModeSet(FIPS_ON);
336 if (fipsModeState != FIPS_ON) {
337
338
339 String message = sm.getString("aprListener.initializeFIPSFailed");
340 log.error(message);
341 throw new IllegalStateException(message);
342 }
343
344 fipsModeActive = true;
345 log.info(sm.getString("aprListener.initializeFIPSSuccess"));
346 }
347 }
348
349 log.info(sm.getString("aprListener.initializedOpenSSL", SSL.versionString()));
350 }
351
352 public String getSSLEngine() {
353 return SSLEngine;
354 }
355
356 public void setSSLEngine(String SSLEngine) {
357 if (!SSLEngine.equals(AprLifecycleListener.SSLEngine)) {
358
359 if (sslInitialized) {
360 throw new IllegalStateException(
361 sm.getString("aprListener.tooLateForSSLEngine"));
362 }
363
364 AprLifecycleListener.SSLEngine = SSLEngine;
365 }
366 }
367
368 public String getSSLRandomSeed() {
369 return SSLRandomSeed;
370 }
371
372 public void setSSLRandomSeed(String SSLRandomSeed) {
373 if (!SSLRandomSeed.equals(AprLifecycleListener.SSLRandomSeed)) {
374
375 if (sslInitialized) {
376 throw new IllegalStateException(
377 sm.getString("aprListener.tooLateForSSLRandomSeed"));
378 }
379
380 AprLifecycleListener.SSLRandomSeed = SSLRandomSeed;
381 }
382 }
383
384 public String getFIPSMode() {
385 return FIPSMode;
386 }
387
388 public void setFIPSMode(String FIPSMode) {
389 if (!FIPSMode.equals(AprLifecycleListener.FIPSMode)) {
390
391 if (sslInitialized) {
392 throw new IllegalStateException(
393 sm.getString("aprListener.tooLateForFIPSMode"));
394 }
395
396 AprLifecycleListener.FIPSMode = FIPSMode;
397 }
398 }
399
400 public boolean isFIPSModeActive() {
401 return fipsModeActive;
402 }
403
404 public void setUseAprConnector(boolean useAprConnector) {
405 if (useAprConnector != AprLifecycleListener.useAprConnector) {
406 AprLifecycleListener.useAprConnector = useAprConnector;
407 }
408 }
409
410 public static boolean getUseAprConnector() {
411 return useAprConnector;
412 }
413
414 public void setUseOpenSSL(boolean useOpenSSL) {
415 if (useOpenSSL != AprLifecycleListener.useOpenSSL) {
416 AprLifecycleListener.useOpenSSL = useOpenSSL;
417 }
418 }
419
420 public static boolean getUseOpenSSL() {
421 return useOpenSSL;
422 }
423
424 public static boolean isInstanceCreated() {
425 return instanceCreated;
426 }
427
428 }
429