diff options
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.java | 1534 |
1 files changed, 0 insertions, 1534 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 deleted file mode 100644 index 5144bf16d..000000000 --- a/pki/base/common/src/com/netscape/cms/logging/LogFile.java +++ /dev/null @@ -1,1534 +0,0 @@ -// --- 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.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.CharArrayReader; -import java.io.CharArrayWriter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.LineNumberReader; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.RandomAccessFile; -import java.io.UnsupportedEncodingException; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.Signature; -import java.security.SignatureException; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.RSAPrivateKey; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Hashtable; -import java.util.Locale; -import java.util.Properties; -import java.util.StringTokenizer; -import java.util.Vector; - -import javax.servlet.ServletException; - -import org.mozilla.jss.CryptoManager; -import org.mozilla.jss.crypto.CryptoToken; -import org.mozilla.jss.crypto.ObjectNotFoundException; -import org.mozilla.jss.crypto.TokenException; -import org.mozilla.jss.crypto.X509Certificate; -import org.mozilla.jss.util.Base64OutputStream; - -import com.netscape.certsrv.apps.CMS; -import com.netscape.certsrv.base.EBaseException; -import com.netscape.certsrv.base.IConfigStore; -import com.netscape.certsrv.base.IExtendedPluginInfo; -import com.netscape.certsrv.base.ISubsystem; -import com.netscape.certsrv.common.Constants; -import com.netscape.certsrv.common.NameValuePairs; -import com.netscape.certsrv.logging.AuditEvent; -import com.netscape.certsrv.logging.ConsoleError; -import com.netscape.certsrv.logging.ELogException; -import com.netscape.certsrv.logging.ILogEvent; -import com.netscape.certsrv.logging.ILogEventListener; -import com.netscape.certsrv.logging.ILogger; -import com.netscape.certsrv.logging.SignedAuditEvent; -import com.netscape.certsrv.logging.SystemEvent; -import com.netscape.cmsutil.util.Utils; - -/** - * 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 selected log event types - */ - protected String mSelectedEventsList = null; - protected Vector<String> 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<String> string2Vector(String theString) { - Vector<String> theVector = new Vector<String>(); - 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<String> 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() { - return String.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()))); - if (mLogSigning) { - //error in writing to signed audit log, shut down CMS - e.printStackTrace(); - shutdownCMS(); - } - } 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()))); - if (mLogSigning) { - // Failed to write to audit log, shut down CMS - e.printStackTrace(); - shutdownCMS(); - } - } 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 = CMS.getPID() + "." + Thread.currentThread().getName() + " - [" - + mLogDateFormat.format(mDate) + "] [" + - Integer.toString(ev.getSource()) + "] [" + Integer.toString(ev.getLevel()) - + "] " + prepareMultiline(ev.toString()); - } else { - entry = CMS.getPID() + "." + 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<LogEntry> readEntry(int maxLine, int lowLevel, int source, String fName) { - Vector<LogEntry> mEntries = new Vector<LogEntry>(); - 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<String, String> req) throws ServletException, - IOException, EBaseException { - NameValuePairs params = new NameValuePairs(); - String tmp, fName = null; - int maxLine = -1, level = -1, source = -1; - Vector<LogEntry> 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.put(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<String, String> req) throws ServletException, - IOException, EBaseException { - return null; - } - - public String getImplName() { - return "LogFile"; - } - - public String getDescription() { - return "LogFile"; - } - - public Vector<String> getDefaultParams() { - Vector<String> v = new Vector<String>(); - - 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<String> getInstanceParams() { - Vector<String> v = new Vector<String>(); - - try { - - if (mType == null) { - v.addElement(PROP_TYPE + "="); - } else { - v.addElement(PROP_TYPE + "=" + - mConfig.getString(PROP_TYPE)); - } - v.addElement(PROP_ON + "=" + String.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)) { - v.addElement(PROP_SIGNED_AUDIT_LOG_SIGNING + "=" - + String.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); - } -} |