summaryrefslogtreecommitdiffstats
path: root/pki/base/common/src/com/netscape/cms/logging/LogFile.java
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/common/src/com/netscape/cms/logging/LogFile.java')
-rw-r--r--pki/base/common/src/com/netscape/cms/logging/LogFile.java1492
1 files changed, 1492 insertions, 0 deletions
diff --git a/pki/base/common/src/com/netscape/cms/logging/LogFile.java b/pki/base/common/src/com/netscape/cms/logging/LogFile.java
new file mode 100644
index 000000000..8c9a38410
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/logging/LogFile.java
@@ -0,0 +1,1492 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.logging;
+
+
+import java.lang.*;
+import java.io.*;
+import java.io.File.*;
+import java.util.*;
+import java.text.*;
+import java.security.*;
+import java.security.Security;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.common.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.cmsutil.util.*;
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.util.Base64OutputStream;
+import java.io.CharConversionException;
+
+/**
+ * A log event listener which write logs to log files
+ *
+ * @version $Revision$, $Date$
+ **/
+public class LogFile implements ILogEventListener, IExtendedPluginInfo {
+ public static final String PROP_TYPE = "type";
+ public static final String PROP_REGISTER = "register";
+ public static final String PROP_ON = "enable";
+ public static final String PROP_TRACE = "trace";
+ public static final String PROP_SIGNED_AUDIT_LOG_SIGNING = "logSigning";
+ public static final String PROP_SIGNED_AUDIT_CERT_NICKNAME =
+ "signedAuditCertNickname";
+ public static final String PROP_SIGNED_AUDIT_EVENTS = "events";
+ public static final String PROP_LEVEL = "level";
+ static final String PROP_FILE_NAME = "fileName";
+ static final String PROP_LAST_HASH_FILE_NAME = "lastHashFileName";
+ static final String PROP_BUFFER_SIZE = "bufferSize";
+ static final String PROP_FLUSH_INTERVAL = "flushInterval";
+
+ private final static String LOGGING_SIGNED_AUDIT_AUDIT_LOG_STARTUP =
+ "LOGGING_SIGNED_AUDIT_AUDIT_LOG_STARTUP_2";
+ private final static String LOGGING_SIGNED_AUDIT_SIGNING =
+ "LOGGING_SIGNED_AUDIT_SIGNING_3";
+ private final static String LOGGING_SIGNED_AUDIT_AUDIT_LOG_SHUTDOWN =
+ "LOGGING_SIGNED_AUDIT_AUDIT_LOG_SHUTDOWN_2";
+ private final static String LOG_SIGNED_AUDIT_EXCEPTION =
+ "LOG_SIGNED_AUDIT_EXCEPTION_1";
+
+ protected ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+ protected IConfigStore mConfig = null;
+
+ /**
+ * The date string used in the log file name
+ */
+ static final String DATE_PATTERN = "yyyyMMddHHmmss";
+
+ //It may be interesting to make this flexable someday....
+ protected SimpleDateFormat mLogFileDateFormat = new SimpleDateFormat(DATE_PATTERN);
+
+ /**
+ * The default output stream buffer size in bytes
+ */
+ static final int BUFFER_SIZE = 512;
+
+ /**
+ * The default output flush interval in seconds
+ */
+ static final int FLUSH_INTERVAL = 5;
+
+ /**
+ * The log file
+ */
+ protected File mFile = null;
+
+ /**
+ * The log file name
+ */
+ protected String mFileName = null;
+
+ /**
+ * The log file output stream
+ */
+ protected BufferedWriter mLogWriter = null;
+
+ /**
+ * The log date entry format pattern
+ */
+ protected String mDatePattern = "dd/MMM/yyyy:HH:mm:ss z";
+
+ /**
+ * The log date entry format
+ */
+ protected SimpleDateFormat mLogDateFormat = new SimpleDateFormat(mDatePattern);
+
+ /**
+ * The date object used for log entries
+ */
+ protected Date mDate = new Date();
+
+ /**
+ * The number of bytes written to the current log file
+ */
+ protected int mBytesWritten = 0;
+
+ /**
+ * The output buffer size in bytes
+ */
+ protected int mBufferSize = BUFFER_SIZE;
+
+ /**
+ * The output buffer flush interval
+ */
+ protected int mFlushInterval = FLUSH_INTERVAL;
+
+ /**
+ * The number of unflushed bytes
+ */
+ protected int mBytesUnflushed = 0;
+
+ /**
+ * The output buffer flush interval thread
+ */
+ private Thread mFlushThread = null;
+
+ /**
+ * The current pid for the log entries
+ */
+ protected int mPid = CMS.getpid();
+
+ /**
+ * The selected log event types
+ */
+ protected String mSelectedEventsList = null;
+ protected Vector mSelectedEvents = null;
+
+ /**
+ * The eventType that this log is triggered
+ */
+ protected String mType = null;
+
+ /**
+ * The log is turned on/off
+ */
+ protected boolean mOn = false;
+
+ /**
+ * Should this log listener self-register or not
+ */
+ protected boolean mRegister = false;
+
+ protected boolean mTrace = false;
+
+ /**
+ * Log signing is on/off
+ */
+ protected boolean mLogSigning = false;
+
+ /**
+ * Nickname of certificate to use to sign log.
+ */
+ private String mSAuditCertNickName = "";
+
+ /**
+ * The provider used by the KeyGenerator and Mac
+ */
+ static final String CRYPTO_PROVIDER = "Mozilla-JSS";
+
+ /**
+ * The log level threshold
+ * Only logs with level greater or equal than this value will be written
+ */
+ protected long mLevel = 1;
+
+ /**
+ * Constructor for a LogFile.
+ *
+ */
+ public LogFile() {
+ }
+
+ public void init(ISubsystem owner, IConfigStore config)
+ throws EBaseException {
+ mConfig = config;
+
+ try {
+ mOn = config.getBoolean(PROP_ON, true);
+ } catch (EBaseException e) {
+ throw new ELogException(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED",
+ config.getName() + "." + PROP_ON));
+ }
+
+ try {
+ mLogSigning = config.getBoolean(PROP_SIGNED_AUDIT_LOG_SIGNING,
+ false);
+ } catch (EBaseException e) {
+ throw new ELogException(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED",
+ config.getName() + "." + PROP_SIGNED_AUDIT_LOG_SIGNING));
+ }
+
+ if (mOn && mLogSigning) {
+ try {
+ mSAuditCertNickName = config.getString(
+ PROP_SIGNED_AUDIT_CERT_NICKNAME);
+ CMS.debug("LogFile: init(): audit log signing enabled. signedAuditCertNickname="+ mSAuditCertNickName);
+ } catch (EBaseException e) {
+ throw new ELogException(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED",
+ config.getName() + "."
+ + PROP_SIGNED_AUDIT_CERT_NICKNAME));
+ }
+ if (mSAuditCertNickName == null ||
+ mSAuditCertNickName.trim().equals("")) {
+ throw new ELogException(CMS.getUserMessage(
+ "CMS_BASE_GET_PROPERTY_FAILED",
+ config.getName() + "."
+ + PROP_SIGNED_AUDIT_CERT_NICKNAME));
+ }
+ }
+
+ // selective logging
+ mSelectedEventsList = null;
+ try {
+ mSelectedEventsList = config.getString(PROP_SIGNED_AUDIT_EVENTS);
+ } catch (EBaseException e) {
+ // when not specified, ALL are selected by default
+ }
+ mSelectedEvents = string2Vector(mSelectedEventsList);
+
+ try {
+ init(config);
+ } catch (IOException e) {
+ throw new ELogException(CMS.getUserMessage("CMS_LOG_UNEXPECTED_EXCEPTION", e.toString()));
+ }
+ }
+
+ /**
+ * turns a comma-separated String into a Vector
+ */
+ protected Vector string2Vector(String theString) {
+ Vector theVector = new Vector();
+ if (theString == null) {
+ return theVector;
+ }
+
+ StringTokenizer tokens = new StringTokenizer(theString,
+ ",");
+ while (tokens.hasMoreTokens()) {
+ String eventId = tokens.nextToken().trim();
+
+ theVector.addElement(eventId);
+ CMS.debug("LogFile: log event type selected: "+eventId);
+ }
+ return theVector;
+ }
+
+ /**
+ * add the event to the selected events list
+ * @param event to be selected
+ */
+ public void selectEvent(String event) {
+ if (!mSelectedEvents.contains(event))
+ mSelectedEvents.addElement(event);
+ }
+
+ /**
+ * remove the event from the selected events list
+ * @param event to be de-selected
+ */
+ public void deselectEvent(String event) {
+ if (mSelectedEvents.contains(event))
+ mSelectedEvents.removeElement(event);
+ }
+
+ /**
+ * replace the selected events list
+ * @param events comma-separated event list
+ */
+ public void replaceEvents(String events) {
+ Vector v = string2Vector(events);
+ mSelectedEvents.removeAllElements();
+ mSelectedEvents = v;
+ }
+
+ public static String base64Encode(byte[] bytes) throws IOException {
+ // All this streaming is lame, but Base64OutputStream needs a
+ // PrintStream
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Base64OutputStream b64 = new Base64OutputStream(new
+ PrintStream(new
+ FilterOutputStream(output)
+ )
+ );
+
+ b64.write(bytes);
+ b64.flush();
+
+ // This is internationally safe because Base64 chars are
+ // contained within 8859_1
+ return output.toString("8859_1");
+ }
+
+ private static boolean mInSignedAuditLogFailureMode = false;
+
+ private static synchronized void shutdownCMS() {
+ if( mInSignedAuditLogFailureMode == false ) {
+
+ // Set signed audit log failure mode true
+ // No, this isn't a race condition, because the method is
+ // synchronized. We just want to avoid an infinite loop.
+ mInSignedAuditLogFailureMode = true;
+
+ // Block all new incoming requests
+ if( CMS.areRequestsDisabled() == false ) {
+ // XXX is this a race condition?
+ CMS.disableRequests();
+ }
+
+ // Terminate all requests in process
+ CMS.terminateRequests();
+
+ // Call graceful shutdown of the CMS server
+ // Call force shutdown to get added functionality of
+ // making sure to kill the web server.
+
+ CMS.forceShutdown();
+ }
+ }
+
+ /**
+ * Initialize and open the log using the parameters from a config store
+ *
+ * @param config The property config store to find values in
+ */
+ public void init(IConfigStore config) throws IOException,
+ EBaseException {
+ String fileName = null;
+ String defaultFileName = null;
+ String signedAuditDefaultFileName = "";
+
+ mConfig = config;
+
+ try {
+ mTrace = config.getBoolean(PROP_TRACE, false);
+ } catch (EBaseException e) {
+ throw new ELogException(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED",
+ config.getName() + "." + PROP_TRACE));
+ }
+
+ try {
+ mType = config.getString(PROP_TYPE, "system");
+ } catch (EBaseException e) {
+ throw new ELogException(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED",
+ config.getName() + "." + PROP_TYPE));
+ }
+
+ try {
+ mRegister = config.getBoolean(PROP_REGISTER, true);
+ } catch (EBaseException e) {
+ throw new ELogException(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED",
+ config.getName() + "." + PROP_REGISTER));
+ }
+
+ if (mOn) {
+ if (mRegister) {
+ CMS.getLogger().getLogQueue().addLogEventListener(this);
+ }
+ } else {
+ // shutdown the listener, remove the listener
+ if (mRegister) {
+ CMS.getLogger().getLogQueue().removeLogEventListener(this);
+ shutdown();
+ }
+ }
+
+ try {
+ mLevel = config.getInteger(PROP_LEVEL, 3);
+ } catch (EBaseException e) {
+ e.printStackTrace();
+ throw new ELogException(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED",
+ config.getName() + "." + PROP_LEVEL));
+ }
+
+ try {
+ // retrieve the subsystem
+ String subsystem = "";
+
+ ISubsystem caSubsystem = CMS.getSubsystem( "ca" );
+ if( caSubsystem != null ) {
+ subsystem = "ca";
+ }
+
+ ISubsystem raSubsystem = CMS.getSubsystem( "ra" );
+ if( raSubsystem != null ) {
+ subsystem = "ra";
+ }
+
+ ISubsystem kraSubsystem = CMS.getSubsystem( "kra" );
+ if( kraSubsystem != null ) {
+ subsystem = "kra";
+ }
+
+ ISubsystem ocspSubsystem = CMS.getSubsystem( "ocsp" );
+ if( ocspSubsystem != null ) {
+ subsystem = "ocsp";
+ }
+
+ // retrieve the instance name
+ String instIDPath = CMS.getInstanceDir();
+ int index = instIDPath.lastIndexOf( "/" );
+ String instID = instIDPath.substring( index + 1 );
+
+ // build the default signedAudit file name
+ signedAuditDefaultFileName = subsystem + "_"
+ + instID + "_" + "audit";
+
+ } catch( Exception e2 ) {
+ throw new ELogException(
+ CMS.getUserMessage( "CMS_BASE_GET_PROPERTY_FAILED",
+ config.getName() + "." +
+ PROP_FILE_NAME ) );
+ }
+
+ // the default value is determined by the eventType.
+ if (mType.equals(ILogger.PROP_SIGNED_AUDIT)) {
+ defaultFileName = "logs/signedAudit/" + signedAuditDefaultFileName;
+ }else if (mType.equals(ILogger.PROP_SYSTEM)) {
+ defaultFileName = "logs/system";
+ }else if (mType.equals(ILogger.PROP_AUDIT)) {
+ defaultFileName = "logs/transactions";
+ }else {
+ //wont get here
+ throw new ELogException(CMS.getUserMessage("CMS_LOG_INVALID_LOG_TYPE",
+ config.getName()));
+ }
+
+ try {
+ fileName = config.getString(PROP_FILE_NAME, defaultFileName);
+ } catch (EBaseException e) {
+ throw new ELogException(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED",
+ config.getName() + "." + PROP_FILE_NAME));
+ }
+
+ if (mOn) {
+ init(fileName, config.getInteger(PROP_BUFFER_SIZE, BUFFER_SIZE),
+ config.getInteger(PROP_FLUSH_INTERVAL, FLUSH_INTERVAL));
+ }
+ }
+
+ /**
+ * Initialize and open the log
+ *
+ * @param bufferSize The buffer size for the output stream in bytes
+ * @param flushInterval The interval in seconds to flush the log
+ */
+ public void init(String fileName, int bufferSize, int flushInterval) throws IOException,ELogException {
+
+ if (fileName == null)
+ throw new ELogException(CMS.getUserMessage("CMS_LOG_INVALID_FILE_NAME", "null"));
+
+ //If we want to reuse the old log files
+ //mFileName = fileName + "." + mLogFileDateFormat.format(mDate);
+ mFileName = fileName;
+ if( !Utils.isNT() ) {
+ // Always insure that a physical file exists!
+ Utils.exec( "touch " + mFileName );
+ Utils.exec( "chmod 00640 " + mFileName );
+ }
+ mFile = new File(mFileName);
+ mBufferSize = bufferSize;
+ setFlushInterval(flushInterval);
+ open();
+ }
+
+ private PrivateKey mSigningKey = null;
+ private Signature mSignature = null;
+
+ private void setupSigning() throws EBaseException {
+ try {
+
+ Provider[] providers = java.security.Security.getProviders();
+ int ps = providers.length;
+ for (int i = 0; i<ps; i++) {
+ CMS.debug("LogFile: provider "+i+"= "+providers[i].getName());
+ }
+
+ CryptoManager cm = CryptoManager.getInstance();
+
+ // find CertServer's private key
+ X509Certificate cert = cm.findCertByNickname( mSAuditCertNickName );
+ if (cert != null) {
+ CMS.debug("LogFile: setupSignig(): found cert:"+mSAuditCertNickName);
+ } else {
+ CMS.debug("LogFile: setupSignig(): cert not found:"+mSAuditCertNickName);
+ }
+ mSigningKey = cm.findPrivKeyByCert(cert);
+
+ String sigAlgorithm;
+ if( mSigningKey instanceof RSAPrivateKey ) {
+ sigAlgorithm = "SHA-256/RSA";
+ } else if( mSigningKey instanceof DSAPrivateKey ) {
+ sigAlgorithm = "SHA-256/DSA";
+ } else {
+ throw new NoSuchAlgorithmException("Unknown private key type");
+ }
+
+ CryptoToken savedToken = cm.getThreadToken();
+ try {
+ CryptoToken keyToken =
+ ((org.mozilla.jss.pkcs11.PK11PrivKey)mSigningKey)
+ .getOwningToken();
+ cm.setThreadToken(keyToken);
+ mSignature = java.security.Signature.getInstance(sigAlgorithm,
+ CRYPTO_PROVIDER);
+ } finally {
+ cm.setThreadToken(savedToken);
+ }
+
+ mSignature.initSign(mSigningKey);
+
+ // get the last signature from the currently-opened file
+ String entry = getLastSignature(mFile);
+ if( entry != null ) {
+ mSignature.update(entry.getBytes("UTF-8"));
+ mSignature.update(LINE_SEP_BYTE);
+ }
+
+ // Always start off with a signature. That way, even if there
+ // were problems with the log file we inherited, we will
+ // get a fresh start with this instance.
+ pushSignature();
+
+ } catch (CryptoManager.NotInitializedException nie) {
+ setupSigningFailure("BASE_CRYPTOMANAGER_UNINITIALIZED", nie);
+ } catch (ObjectNotFoundException onfe) {
+ setupSigningFailure("LOG_SIGNING_CERT_NOT_FOUND", onfe);
+ } catch (TokenException te) {
+ setupSigningFailure("BASE_TOKEN_ERROR_0", te);
+ } catch (NoSuchAlgorithmException nsae) {
+ setupSigningFailure("LOG_NO_SUCH_ALGORITHM_0", nsae);
+ } catch (NoSuchProviderException nspe) {
+ setupSigningFailure("BASE_PROVIDER_NOT_SUPPORTED", nspe);
+ } catch (InvalidKeyException ike) {
+ setupSigningFailure("BASE_INVALID_KEY", ike);
+ } catch (SignatureException se) {
+ setupSigningFailure("LOG_SIGNING_OP_FAILED", se);
+ } catch (UnsupportedEncodingException uee) {
+ setupSigningFailure("LOG_UNEXPECTED_EXCEPTION", uee);
+ } catch (IOException ioe) {
+ setupSigningFailure("LOG_UNEXPECTED_EXCEPTION", ioe);
+ } catch (Exception e) {
+ setupSigningFailure("LOG_UNEXPECTED_EXCEPTION", e);
+ }
+ }
+
+ private static void setupSigningFailure(String logMessageCode, Exception e)
+ throws EBaseException
+ {
+ try {
+ ConsoleError.send( new SystemEvent(
+ CMS.getLogMessage(logMessageCode)));
+ } catch(Exception e2) {
+ // don't allow an exception while printing to the console
+ // prevent us from running the rest of this function.
+ e2.printStackTrace();
+ }
+ e.printStackTrace();
+ shutdownCMS();
+ throw new EBaseException(e.toString());
+ }
+
+ /**
+ * Startup the instance
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_AUDIT_LOG_STARTUP used at audit
+ * function startup
+ * </ul>
+ * @exception EBaseException if an internal error occurred
+ */
+ public void startup() throws EBaseException {
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ CMS.debug("LogFile: entering LogFile.startup()");
+ if( mOn && mLogSigning ) {
+ try {
+ setupSigning();
+ audit( CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_AUDIT_LOG_STARTUP,
+ ILogger.SYSTEM_UID,
+ ILogger.SUCCESS) );
+ } catch(EBaseException e) {
+ audit( CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_AUDIT_LOG_STARTUP,
+ ILogger.SYSTEM_UID,
+ ILogger.FAILURE) );
+ throw e;
+ }
+ }
+
+ }
+
+
+ /**
+ * Retrieves the eventType this log is triggered.
+ */
+ public String getType() {
+ return mType;
+ }
+
+ /**
+ * Retrieves the log on/off.
+ */
+ public String getOn() {
+ String logStatus = null;
+ return logStatus.valueOf( mOn );
+ }
+
+ /**
+ * Retrieves the log level threshold.
+ */
+ public long getLevel() {
+ return mLevel;
+ }
+
+ /**
+ * Retrieves the base log file name.
+ */
+ public String getName() {
+ return mFileName;
+ }
+
+ private boolean firstOpen = true;
+
+ /**
+ * Record that the signed audit log has been signed
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_SIGNING used when a signature on the
+ * audit log is generated (same as "flush" time)
+ * </ul>
+ * @exception IOException for input/output problems
+ * @exception ELogException when plugin implementation fails
+ * @exception SignatureException when signing fails
+ * @exception InvalidKeyException when an invalid key is utilized
+ */
+ private void pushSignature() throws IOException, ELogException,
+ SignatureException, InvalidKeyException
+ {
+ byte[] sigBytes = null;
+
+ if( mSignature == null ) {
+ return;
+ }
+
+ sigBytes = mSignature.sign();
+ mSignature.initSign(mSigningKey);
+
+ Object o[] = new Object[1];
+ o[0] = null;
+
+ // cook up a signed audit log message to record mac
+ // so as to avoid infinite recursiveness of calling
+ // the log() method
+ String auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_SIGNING,
+ ILogger.SYSTEM_UID,
+ ILogger.SUCCESS,
+ base64Encode( sigBytes ) );
+
+ if( mSignedAuditLogger == null ) {
+ return;
+ }
+
+ ILogEvent ev = mSignedAuditLogger.create(
+ ILogger.EV_SIGNED_AUDIT,
+ ( Properties ) null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ auditMessage,
+ o,
+ ILogger.L_SINGLELINE );
+
+ String logMesg = logEvt2String(ev);
+ doLog(logMesg, true);
+ }
+
+ private static String getLastSignature(File f) throws IOException {
+ BufferedReader r = new BufferedReader( new FileReader(f) );
+ String lastSig = null;
+ String curLine = null;
+ while( (curLine = r.readLine()) != null ) {
+ if( curLine.indexOf("AUDIT_LOG_SIGNING") != -1 ) {
+ lastSig = curLine;
+ }
+ }
+ r.close();
+ return lastSig;
+ }
+
+ /**
+ * Open the log file. This creates the buffered FileWriter
+ *
+ */
+ protected synchronized void open() throws IOException {
+ RandomAccessFile out;
+
+ try {
+ out = new RandomAccessFile(mFile, "rw");
+ out.seek(out.length());
+ //XXX int or long?
+ mBytesWritten = (int) out.length();
+ if( !Utils.isNT() ) {
+ try {
+ Utils.exec( "chmod 00640 " + mFile.getCanonicalPath() );
+ } catch( IOException e ) {
+ CMS.debug( "Unable to change file permissions on "
+ + mFile.toString() );
+ }
+ }
+ mLogWriter = new BufferedWriter(
+ new FileWriter(out.getFD()), mBufferSize);
+
+ // The first time we open, mSignature will not have been
+ // initialized yet. That's ok, we will push our first signature
+ // in setupSigning().
+ if( mLogSigning && (mSignature != null)) {
+ try {
+ pushSignature();
+ } catch (ELogException le) {
+ ConsoleError.send(
+ new SystemEvent(CMS.getUserMessage("CMS_LOG_ILLEGALARGUMENT",
+ mFileName)));
+ }
+ }
+ } catch (IllegalArgumentException iae) {
+ ConsoleError.send(
+ new SystemEvent(CMS.getUserMessage("CMS_LOG_ILLEGALARGUMENT",
+ mFileName)));
+ } catch(GeneralSecurityException gse) {
+ // error with signed audit log, shutdown CMS
+ gse.printStackTrace();
+ shutdownCMS();
+ }
+
+ mBytesUnflushed = 0;
+ }
+
+ /**
+ * Flush the log file. Also update the MAC for hash protected logs
+ *
+ */
+ public synchronized void flush() {
+ try {
+ if( mLogSigning ) {
+ try {
+ pushSignature();
+ } catch (ELogException le) {
+ ConsoleError.send(new SystemEvent(CMS.getUserMessage("CMS_LOG_FLUSH_LOG_FAILED", mFileName, le.toString())));
+ }
+ }
+
+ if (mLogWriter != null) {
+ mLogWriter.flush();
+ }
+ } catch (IOException e) {
+ ConsoleError.send(new SystemEvent(CMS.getUserMessage("CMS_LOG_FLUSH_LOG_FAILED", mFileName, e.toString())));
+ } catch(GeneralSecurityException gse) {
+ // error with signed audit log, shutdown CMS
+ gse.printStackTrace();
+ shutdownCMS();
+ }
+
+ mBytesUnflushed = 0;
+ }
+
+ /**
+ * Close the log file
+ *
+ */
+ protected synchronized void close() {
+ try {
+ flush();
+ if (mLogWriter != null) {
+ mLogWriter.close();
+ }
+ } catch (IOException e) {
+ ConsoleError.send(new SystemEvent(CMS.getUserMessage("CMS_LOG_CLOSE_FAILED", mFileName, e.toString())));
+ }
+ mLogWriter = null;
+ }
+
+ /**
+ * Shutdown this log file.
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_AUDIT_LOG_SHUTDOWN used at audit
+ * function shutdown
+ * </ul>
+ */
+ public synchronized void shutdown() {
+ String auditMessage = null;
+
+ CMS.debug("LogFile:In log shutdown");
+
+ setFlushInterval(0);
+
+ // log signed audit shutdown success
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_AUDIT_LOG_SHUTDOWN,
+ ILogger.SYSTEM_UID,
+ ILogger.SUCCESS );
+
+ audit( auditMessage );
+
+ close();
+ }
+
+ /**
+ * Set the flush interval
+ * <P>
+ * @param flushInterval The amount of time in seconds until the log
+ * is flush. A value of 0 will disable autoflush. This will also set
+ * the update period for hash protected logs.
+ **/
+ public synchronized void setFlushInterval(int flushInterval) {
+ mFlushInterval = flushInterval * 1000;
+
+ if ((mFlushThread == null) && (mFlushInterval > 0)) {
+ mFlushThread = new FlushThread();
+ mFlushThread.setDaemon(true);
+ mFlushThread.start();
+ }
+
+ this.notify();
+ }
+
+ /**
+ * Log flush thread. Sleep for the flush interval and flush the
+ * log. Changing flush interval to 0 will cause this thread to exit.
+ */
+ final class FlushThread extends Thread {
+
+ /**
+ * Flush thread constructor including thread name
+ */
+ public FlushThread() {
+ super();
+ super.setName(mFileName + ".flush-" + (Thread.activeCount() + 1));
+ }
+
+ public void run() {
+ while (mFlushInterval > 0) {
+ // Sleep for the interval and then flush the log
+ synchronized (LogFile.this) {
+ try {
+ LogFile.this.wait(mFlushInterval);
+ } catch (InterruptedException e) {
+ // This shouldn't happen very often
+ ConsoleError.send(new
+ SystemEvent(CMS.getUserMessage("CMS_LOG_THREAD_INTERRUPT", "flush")));
+ }
+ }
+
+ if (mFlushInterval == 0) {
+ break;
+ }
+
+ if (mBytesUnflushed > 0) {
+ flush();
+ }
+ }
+ mFlushThread = null;
+ }
+ }
+
+ /**
+ * Synchronized method to write a string to the log file. All I18N
+ * should take place before this call.
+ *
+ * @param entry The log entry string
+ */
+ protected synchronized void log(String entry) throws ELogException {
+ doLog(entry, false);
+ }
+
+ // Standard line separator byte. We always sign this line separator,
+ // regardless of what we actually write to the file, so that signature
+ // verification is platform-independent.
+ private static final byte LINE_SEP_BYTE = 0x0a;
+
+ /**
+ * This method actually does the logging, and is not overridden
+ * by subclasses, so you can call it and know that it will do exactly
+ * what you see below.
+ */
+ private synchronized void doLog(String entry, boolean noFlush)
+ throws ELogException {
+ if (mLogWriter == null) {
+ String[] params = { mFileName, entry };
+
+ throw new ELogException(CMS.getUserMessage("CMS_LOG_LOGFILE_CLOSED", params));
+ } else {
+ try {
+ mLogWriter.write(entry, 0/*offset*/, entry.length());
+
+ if (mLogSigning==true) {
+ if(mSignature != null) {
+ // include newline for calculating MAC
+ mSignature.update(entry.getBytes("UTF-8"));
+ } else {
+ CMS.debug("LogFile: mSignature is not yet ready... null in log()");
+ }
+ }
+ if (mTrace) {
+ CharArrayWriter cw = new CharArrayWriter(200);
+ PrintWriter pw = new PrintWriter(cw);
+ Exception e = new Exception();
+ e.printStackTrace(pw);
+ char[] c = cw.toCharArray();
+ cw.close();
+ pw.close();
+
+ CharArrayReader cr = new CharArrayReader(c);
+ LineNumberReader lr = new LineNumberReader(cr);
+
+ String text = null;
+ String method = null;
+ String fileAndLine = null;
+ if (lr.ready()) {
+ text = lr.readLine();
+ do {
+ text = lr.readLine();
+ } while (text.indexOf("logging") != -1);
+ int p = text.indexOf("(");
+ fileAndLine = text.substring(p);
+
+ String classandmethod = text.substring(0, p);
+ int q = classandmethod.lastIndexOf(".");
+ method = classandmethod.substring(q + 1);
+ mLogWriter.write(fileAndLine, 0/*offset*/, fileAndLine.length());
+ mLogWriter.write(" ", 0/*offset*/, " ".length());
+ mLogWriter.write(method, 0/*offset*/, method.length());
+ }
+ }
+ mLogWriter.newLine();
+
+ if (mLogSigning==true){
+ if(mSignature != null) {
+ mSignature.update(LINE_SEP_BYTE);
+ } else {
+ CMS.debug("LogFile: mSignature is null in log() 2");
+ }
+ }
+ } catch (IOException e) {
+ ConsoleError.send(new SystemEvent(CMS.getUserMessage("CMS_LOG_WRITE_FAILED", mFileName, entry, e.toString())));
+ } catch (IllegalStateException e) {
+ CMS.debug("LogFile: exception thrown in log(): "+e.toString());
+ ConsoleError.send(new SignedAuditEvent(CMS.getLogMessage(LOG_SIGNED_AUDIT_EXCEPTION,e.toString())));
+ } catch( GeneralSecurityException gse ) {
+ // DJN: handle error
+ CMS.debug("LogFile: exception thrown in log(): "
+ + gse.toString());
+ gse.printStackTrace();
+ ConsoleError.send(new SignedAuditEvent(CMS.getLogMessage(
+ LOG_SIGNED_AUDIT_EXCEPTION,gse.toString())));
+ }
+
+
+ // XXX
+ // Although length will be in Unicode dual-bytes, the PrintWriter
+ // will only print out 1 byte per character. I suppose this could
+ // be dependent on the encoding of your log file, but it ain't that
+ // smart yet. Also, add one for the newline. (hmm, on NT, CR+LF)
+ int nBytes = entry.length() + 1;
+
+ mBytesWritten += nBytes;
+ mBytesUnflushed += nBytes;
+
+ if (mBufferSize > 0 && mBytesUnflushed > mBufferSize && !noFlush) {
+ flush();
+ }
+ }
+ }
+
+ /**
+ * Write an event to the log file
+ *
+ * @param ev The event to be logged.
+ */
+ public void log(ILogEvent ev) throws ELogException {
+ if (ev instanceof AuditEvent) {
+ if (!mType.equals("transaction") || (!mOn) || mLevel > ev.getLevel()) {
+ return;
+ }
+ } else if (ev instanceof SystemEvent) {
+ if (!mType.equals("system") || (!mOn) || mLevel > ev.getLevel()) {
+ return;
+ }
+ } else if (ev instanceof SignedAuditEvent) {
+ if (!mType.equals("signedAudit") || (!mOn) || mLevel > ev.getLevel()) {
+ return;
+ }
+ }
+
+ // Is the event type selected?
+ // If no selection specified in configuration, then all are selected
+ // If no type specified in propertity file, then treated as selected
+ if (mSelectedEvents.size() > 0) {
+ String type = ev.getEventType();
+ if (type != null) {
+ if (!mSelectedEvents.contains(type)) {
+ CMS.debug("LogFile: event type not selected: "+type);
+ return;
+ }
+ }
+ }
+
+ String entry = logEvt2String(ev);
+
+ log(entry);
+ }
+
+ public String logEvt2String(ILogEvent ev) {
+ String entry = null;
+
+ // Hmm.. multiple threads could hit this and reset the time.
+ // Do we care?
+ mDate.setTime(ev.getTimeStamp());
+
+ // XXX
+ // This should follow the Common Log Format which still needs
+ // some work.
+ if (ev.getMultiline() == ILogger.L_MULTILINE) {
+ entry = mPid + "." + Thread.currentThread().getName() + " - ["
+ + mLogDateFormat.format(mDate) + "] [" +
+ Integer.toString(ev.getSource()) + "] [" + Integer.toString(ev.getLevel())
+ + "] " + prepareMultiline(ev.toString());
+ } else {
+ entry = mPid + "." + Thread.currentThread().getName() + " - ["
+ + mLogDateFormat.format(mDate) + "] [" +
+ Integer.toString(ev.getSource()) + "] [" + Integer.toString(ev.getLevel())
+ + "] " + ev.toString();
+ }
+
+ return entry;
+ }
+
+ /**
+ * change multi-line log entry by replace "\n" with "\n "
+ *
+ * @param original The original multi-line log entry.
+ */
+ private String prepareMultiline(String original) {
+ int i, last = 0;
+
+ //NT: \r\n, unix: \n
+ while ((i = original.indexOf("\n", last)) != -1) {
+ last = i + 1;
+ original = original.substring(0, i + 1) + " " + original.substring(i + 1);
+ }
+ return original;
+ }
+
+ /**
+ * Read all entries whose logLevel>=lowLevel && log source = source
+ * to at most maxLine entries(from end)
+ * If the parameter is -1, it's ignored and return all entries
+ *
+ * @param maxLine The maximum lines to be returned
+ * @param lowLevel The lowest log level to be returned
+ * @param source The particular log source to be returned
+ * @param fName The log file name to be read. If it's null, read the current
+ * log file
+ */
+ public Vector readEntry(int maxLine, int lowLevel, int source, String fName) {
+ Vector mEntries = new Vector();
+ String fileName = mFileName;
+ BufferedReader fBuffer;
+ int lineNo = 0; // lineNo of the current entry in the log file
+ int line = 0; // line of readed valid entries
+ String firstLine = null; // line buffer
+ String nextLine = null;
+ String entry = null;
+ LogEntry logEntry = null;
+
+ /*
+ this variable is added to accormodate misplaced multiline entries
+ write out buffered log entry when next entry is parsed successfully
+ this implementation is assuming parsing is more time consuming than
+ condition check
+ */
+ LogEntry preLogEntry = null;
+
+ if (fName != null) {
+ fileName = fName;
+ }
+ try {
+ //XXX think about this
+ fBuffer = new BufferedReader(new FileReader(fileName));
+ do {
+ try {
+ nextLine = fBuffer.readLine();
+ if (nextLine != null) {
+ if ((nextLine.length() == 0) || (nextLine.charAt(0) == ' ')) {
+ // It's a continuous line
+ entry = null;
+ if (nextLine.length() > 1)
+ firstLine = firstLine + "\n" + nextLine.substring(1);
+ else
+ firstLine = firstLine + "\n";
+
+ } else {
+ // It's a new entry
+ entry = firstLine;
+ firstLine = nextLine;
+ }
+ // parse the previous entry, the current one is buffered
+ if (entry != null) {
+ try {
+ logEntry = new LogEntry(entry);
+ // if parse succeed, write out previous entry
+ if (preLogEntry != null) {
+ if ((Integer.parseInt(preLogEntry.getLevel()) >= lowLevel) &&
+ ((Integer.parseInt(preLogEntry.getSource()) == source) ||
+ (source == ILogger.S_ALL)
+ )) {
+ mEntries.addElement(preLogEntry);
+ if (maxLine == -1) {
+ line++;
+ } else if (line < maxLine) {
+ line++;
+ } else {
+ mEntries.removeElementAt(0);
+ }
+ }
+ }
+ preLogEntry = logEntry;
+ } catch (ParseException e) {
+ if (preLogEntry != null) {
+ preLogEntry.appendDetail(entry);
+ } else {
+ firstLine = firstLine + "\n" + nextLine;
+ }
+ entry = null;
+ logEntry = null;
+ }
+ }
+ }
+ lineNo++;
+
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_FAILURE,
+ CMS.getLogMessage("LOGGING_READ_ERROR", fileName,
+ Integer.toString(lineNo)));
+ }
+
+ }
+ while (nextLine != null);
+
+ // need to process the last 2 entries of the file
+ if (firstLine != null) {
+ if (logEntry != null) {
+ preLogEntry = logEntry;
+ }
+ entry = firstLine;
+ try {
+ logEntry = new LogEntry(entry);
+
+ /* System.out.println(
+ Integer.toString(Integer.parseInt(logEntry.getLevel()))
+ +","+Integer.toString(lowLevel)+","+
+ Integer.toString(Integer.parseInt(logEntry.getSource()))
+ +","+Integer.toString(source) );
+ */
+ if (preLogEntry != null) {
+ if ((Integer.parseInt(preLogEntry.getLevel()) >= lowLevel) &&
+ ((Integer.parseInt(preLogEntry.getSource()) == source) ||
+ (source == ILogger.S_ALL)
+ )) {
+ mEntries.addElement(preLogEntry);
+ if (maxLine == -1) {
+ line++;
+ } else if (line < maxLine) {
+ line++;
+ } else {
+ mEntries.removeElementAt(0);
+ }
+ }
+ }
+ preLogEntry = logEntry;
+ } catch (ParseException e) {
+ preLogEntry.appendDetail(entry);
+ }
+
+ if (preLogEntry != null) {
+ if ((Integer.parseInt(preLogEntry.getLevel()) >= lowLevel)
+ &&
+ ((Integer.parseInt(preLogEntry.getSource()) == source)
+ ||
+ (source == ILogger.S_ALL)
+ )) {
+ // parse the entry, pass to UI
+ mEntries.addElement(preLogEntry);
+ if (maxLine == -1) {
+ line++;
+ } else if (line < maxLine) {
+ line++;
+ } else {
+ mEntries.removeElementAt(0);
+ }
+ }
+ }
+
+ }// end: last entry
+
+ try {
+ fBuffer.close();
+ } catch (IOException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_FAILURE, "logging:" + fileName +
+ " failed to close for reading");
+ }
+
+ } catch (FileNotFoundException e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_FAILURE,
+ CMS.getLogMessage("LOGGING_FILE_NOT_FOUND",
+ fileName));
+ }
+ return mEntries;
+ }
+
+ /**
+ * Retrieves the configuration store of this subsystem.
+ * <P>
+ *
+ * @return configuration store
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ /**
+ * Retrieve last "maxLine" number of system log with log lever >"level"
+ * and from source "source". If the parameter is omitted. All entries
+ * are sent back.
+ */
+ public synchronized NameValuePairs retrieveLogContent(Hashtable req) throws ServletException,
+ IOException, EBaseException {
+ NameValuePairs params = new NameValuePairs();
+ String tmp, fName = null;
+ int maxLine = -1, level = -1, source = -1;
+ Vector entries = null;
+
+ if ((tmp = (String)req.get(Constants.PR_LOG_ENTRY)) != null) {
+ maxLine = Integer.parseInt(tmp);
+ }
+ if ((tmp = (String)req.get(Constants.PR_LOG_LEVEL)) != null) {
+ level = Integer.parseInt(tmp);
+ }
+ if ((tmp = (String)req.get(Constants.PR_LOG_SOURCE)) != null) {
+ source = Integer.parseInt(tmp);
+ }
+ tmp = (String)req.get(Constants.PR_LOG_NAME);
+ if (!(tmp.equals(Constants.PR_CURRENT_LOG))) {
+ fName = tmp;
+ } else {
+ flush();
+ }
+
+ try {
+ entries = readEntry(maxLine, level, source, fName);
+ for (int i = 0; i < entries.size(); i++) {
+ params.add(Integer.toString(i) +
+ ((LogEntry) entries.elementAt(i)).getEntry(), "");
+ }
+ } catch (Exception e) {
+ CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_WARN,
+ "System log parse error");
+ }
+ return params;
+ }
+
+ /**
+ * Retrieve log file list.
+ */
+ public synchronized NameValuePairs retrieveLogList(Hashtable req) throws ServletException,
+ IOException, EBaseException {
+ return null;
+ }
+
+ public String getImplName() {
+ return "LogFile";
+ }
+
+ public String getDescription() {
+ return "LogFile";
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement(PROP_TYPE + "=");
+ v.addElement(PROP_ON + "=");
+ v.addElement(PROP_LEVEL + "=");
+ v.addElement(PROP_FILE_NAME + "=");
+ v.addElement(PROP_BUFFER_SIZE + "=");
+ v.addElement(PROP_FLUSH_INTERVAL + "=");
+
+ // needs to find a way to determine what type you want. if this
+ // is not for the signed audit type, then we should not show the
+ // following parameters.
+ //if( mType.equals( ILogger.PROP_SIGNED_AUDIT ) ) {
+ v.addElement( PROP_SIGNED_AUDIT_LOG_SIGNING + "=" );
+ v.addElement( PROP_SIGNED_AUDIT_CERT_NICKNAME + "=" );
+ v.addElement( PROP_SIGNED_AUDIT_EVENTS + "=" );
+ //}
+
+ return v;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ try {
+ String logStatus = null;
+
+ if (mType == null) {
+ v.addElement(PROP_TYPE + "=");
+ }else {
+ v.addElement(PROP_TYPE + "=" +
+ mConfig.getString(PROP_TYPE));
+ }
+ v.addElement(PROP_ON + "=" + logStatus.valueOf( mOn ) );
+ if (mLevel == 0)
+ v.addElement(PROP_LEVEL + "=" + ILogger.LL_DEBUG_STRING);
+ else if (mLevel == 1)
+ v.addElement(PROP_LEVEL + "=" + ILogger.LL_INFO_STRING);
+ else if (mLevel == 2)
+ v.addElement(PROP_LEVEL + "=" + ILogger.LL_WARN_STRING);
+ else if (mLevel == 3)
+ v.addElement(PROP_LEVEL + "=" + ILogger.LL_FAILURE_STRING);
+ else if (mLevel == 4)
+ v.addElement(PROP_LEVEL + "=" + ILogger.LL_MISCONF_STRING);
+ else if (mLevel == 5)
+ v.addElement(PROP_LEVEL + "=" + ILogger.LL_CATASTRPHE_STRING);
+ else if (mLevel == 6)
+ v.addElement(PROP_LEVEL + "=" + ILogger.LL_SECURITY_STRING);
+
+ if (mFileName == null) {
+ v.addElement(PROP_FILE_NAME + "=");
+ }else {
+ v.addElement(PROP_FILE_NAME + "=" +
+ mFileName);
+ }
+ v.addElement(PROP_BUFFER_SIZE + "=" + mBufferSize);
+ v.addElement(PROP_FLUSH_INTERVAL + "=" + mFlushInterval / 1000);
+
+ if( (mType != null) && mType.equals( ILogger.PROP_SIGNED_AUDIT ) ) {
+ String logSigning = null;
+
+ v.addElement( PROP_SIGNED_AUDIT_LOG_SIGNING + "="
+ + logSigning.valueOf( mLogSigning ) );
+
+ if( mSAuditCertNickName == null ) {
+ v.addElement( PROP_SIGNED_AUDIT_CERT_NICKNAME + "=" );
+ } else {
+ v.addElement( PROP_SIGNED_AUDIT_CERT_NICKNAME + "="
+ + mSAuditCertNickName );
+ }
+
+ if( mSelectedEventsList == null ) {
+ v.addElement( PROP_SIGNED_AUDIT_EVENTS + "=" );
+ } else {
+ v.addElement( PROP_SIGNED_AUDIT_EVENTS + "="
+ + mSelectedEventsList );
+ }
+ }
+ } catch (Exception e) {
+ }
+ return v;
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ if( mType.equals( ILogger.PROP_SIGNED_AUDIT ) ) {
+ String[] params = {
+ PROP_TYPE + ";choice(transaction,signedAudit,system);The log event type this instance is listening to",
+ PROP_ON + ";boolean;Turn on the listener",
+ PROP_LEVEL + ";choice(" + ILogger.LL_DEBUG_STRING + "," +
+ ILogger.LL_INFO_STRING + "," +
+ ILogger.LL_WARN_STRING + "," +
+ ILogger.LL_FAILURE_STRING + "," +
+ ILogger.LL_MISCONF_STRING + "," +
+ ILogger.LL_CATASTRPHE_STRING + "," +
+ ILogger.LL_SECURITY_STRING + ");Only log message with level higher than this filter will be written by this listener",
+ PROP_FILE_NAME + ";string;The name of the file the log is written to",
+ PROP_BUFFER_SIZE + ";integer;The size of the buffer to receive log messages in kilobytes(KB)",
+ PROP_FLUSH_INTERVAL + ";integer;The maximum time in seconds before the buffer is flushed to the file",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-logrules-logfile",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";Write the log messages to a file",
+ PROP_SIGNED_AUDIT_LOG_SIGNING +
+ ";boolean;Enable audit logs to be signed",
+ PROP_SIGNED_AUDIT_CERT_NICKNAME +
+ ";string;The nickname of the certificate to be used to sign audit logs",
+ PROP_SIGNED_AUDIT_EVENTS +
+ ";string;A comma-separated list of strings used to specify particular signed audit log events",
+ };
+
+ return params;
+ } else {
+ // mType.equals( ILogger.PROP_AUDIT ) ||
+ // mType.equals( ILogger.PROP_SYSTEM )
+ String[] params = {
+ PROP_TYPE + ";choice(transaction,signedAudit,system);The log event type this instance is listening to",
+ PROP_ON + ";boolean;Turn on the listener",
+ PROP_LEVEL + ";choice(" + ILogger.LL_DEBUG_STRING + "," +
+ ILogger.LL_INFO_STRING + "," +
+ ILogger.LL_WARN_STRING + "," +
+ ILogger.LL_FAILURE_STRING + "," +
+ ILogger.LL_MISCONF_STRING + "," +
+ ILogger.LL_CATASTRPHE_STRING + "," +
+ ILogger.LL_SECURITY_STRING + ");Only log message with level higher than this filter will be written by this listener",
+ PROP_FILE_NAME + ";string;The name of the file the log is written to",
+ PROP_BUFFER_SIZE + ";integer;The size of the buffer to receive log messages in kilobytes(KB)",
+ PROP_FLUSH_INTERVAL + ";integer;The maximum time in seconds before the buffer is flushed to the file",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-logrules-logfile",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";Write the log messages to a file"
+ };
+
+ return params;
+ }
+ }
+
+ /**
+ * Signed Audit Log
+ *
+ * This method is inherited by all classes that extend this "LogFile"
+ * class, and is called to store messages to the signed audit log.
+ * <P>
+ *
+ * @param msg signed audit log message
+ */
+ protected void audit( String msg )
+ {
+ // in this case, do NOT strip preceding/trailing whitespace
+ // from passed-in String parameters
+
+ if( mSignedAuditLogger == null ) {
+ return;
+ }
+
+ mSignedAuditLogger.log( ILogger.EV_SIGNED_AUDIT,
+ null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ msg );
+ }
+}
+