diff options
Diffstat (limited to 'security/nss/lib/libpkix/pkix/util/pkix_logger.c')
-rw-r--r-- | security/nss/lib/libpkix/pkix/util/pkix_logger.c | 1088 |
1 files changed, 1088 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix/util/pkix_logger.c b/security/nss/lib/libpkix/pkix/util/pkix_logger.c new file mode 100644 index 000000000..a916e6e4f --- /dev/null +++ b/security/nss/lib/libpkix/pkix/util/pkix_logger.c @@ -0,0 +1,1088 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_logger.c + * + * Logger Object Functions + * + */ + +#include "pkix_logger.h" +#ifndef PKIX_ERROR_DESCRIPTION +#include "prprf.h" +#endif + +/* Global variable to keep PKIX_Logger List */ +PKIX_List *pkixLoggers = NULL; + +/* + * Once the Logger has been set, for any logging related operations, we have + * to go through the List to find a match, and if found, issue the + * corresponding callback. The overhead to check for DEBUG and TRACE in each + * PKIX function entering and exiting is very expensive (400X), and redundant + * if they are not the interest of the Logger. Therefore, the PKIX_Logger List + * pkixLoggers is separated into two lists based on its Loggers' trace level. + * + * Whenever the pkixLoggers List is updated by PKIX_Logger_AddLogger() or + * PKIX_Logger_SetLoggers(), we destroy and reconstruct pkixLoggersErrors + * and pkixLoggersDebugTrace Logger Lists. The ERROR, FATAL_ERROR and + * WARNING goes to pkixLoggersErrors and the DEBUG and TRACE goes to + * pkixLoggersDebugTrace. + * + * Currently we provide five logging levels and the default setting are by: + * + * PKIX_FATAL_ERROR() macro invokes pkix_Logger_Check of FATAL_ERROR level + * PKIX_ERROR() macro invokes pkix_Logger_Check of ERROR level + * WARNING is not invoked as default + * PKIX_DEBUG() macro invokes pkix_Logger_Check of DEBUG level. This needs + * compilation -DPKIX_<component>DEBUG flag to turn on + * PKIX_ENTER() and PKIX_RETURN() macros invoke pkix_Logger_Check of TRACE + * level. TRACE provides duplicate information of DEBUG, but needs no + * recompilation and cannot choose component. To allow application + * to use DEBUG level, TRACE is put as last. + * + */ +PKIX_List *pkixLoggersErrors = NULL; +PKIX_List *pkixLoggersDebugTrace = NULL; + +/* To ensure atomic update on pkixLoggers lists */ +PKIX_PL_MonitorLock *pkixLoggerLock = NULL; + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_Logger_CheckErrors + * DESCRIPTION: + * + * This function goes through each PKIX_Logger at "pkixLoggersList" and + * checks if "maxLevel" and "logComponent" satisfies what is specified in the + * PKIX_Logger. If satisfies, it invokes the callback in PKIX_Logger and + * passes a PKIX_PL_String that is the concatenation of "message" and + * "message2" to the application for processing. + * Since this call is inserted into a handful of PKIX macros, no macros are + * applied in this function, to avoid infinite recursion. + * If an error occurs, this call is aborted. + * + * PARAMETERS: + * "pkixLoggersList" + * A list of PKIX_Loggers to be examined for invoking callback. Must be + * non-NULL. + * "message" + * Address of "message" to be logged. Must be non-NULL. + * "message2" + * Address of "message2" to be concatenated and logged. May be NULL. + * "logComponent" + * A PKIX_UInt32 that indicates the component the message is from. + * "maxLevel" + * A PKIX_UInt32 that represents the level of severity of the message. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_Logger_Check( + PKIX_List *pkixLoggersList, + const char *message, + const char *message2, + PKIX_ERRORCLASS logComponent, + PKIX_UInt32 currentLevel, + void *plContext) +{ + PKIX_Logger *logger = NULL; + PKIX_List *savedPkixLoggersErrors = NULL; + PKIX_List *savedPkixLoggersDebugTrace = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *messageString = NULL; + PKIX_PL_String *message2String = NULL; + PKIX_PL_String *msgString = NULL; + PKIX_Error *error = NULL; + PKIX_Boolean needLogging = PKIX_FALSE; + PKIX_UInt32 i, length; + + /* + * We cannot use any the PKIX_ macros here, since this function is + * called from some of these macros. It can create infinite recursion. + */ + + if ((pkixLoggersList == NULL) || (message == NULL)) { + return(NULL); + } + + /* + * Disable all subsequent loggings to avoid recursion. The result is + * if other thread is calling this function at the same time, there + * won't be any logging because the pkixLoggersErrors and + * pkixLoggersDebugTrace are set to null. + * It would be nice if we provide control per thread (e.g. make + * plContext threadable) then we can avoid the recursion by setting + * flag at plContext. Then other thread's logging won't be affected. + * + * Also we need to use a reentrant Lock. Although we avoid recursion + * for TRACE. When there is an ERROR occurs in subsequent call, this + * function will be called. + */ + + error = PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext); + if (error) { return(NULL); } + + savedPkixLoggersDebugTrace = pkixLoggersDebugTrace; + pkixLoggersDebugTrace = NULL; + savedPkixLoggersErrors = pkixLoggersErrors; + pkixLoggersErrors = NULL; + + /* Convert message and message2 to String */ + error = PKIX_PL_String_Create + (PKIX_ESCASCII, message, 0, &messageString, plContext); + if (error) { goto cleanup; } + + if (message2) { + error = PKIX_PL_String_Create + (PKIX_ESCASCII, message2, 0, &message2String, plContext); + if (error) { goto cleanup; } + error = PKIX_PL_String_Create + (PKIX_ESCASCII, "%s %s", 0, &formatString, plContext); + if (error) { goto cleanup; } + + } else { + error = PKIX_PL_String_Create + (PKIX_ESCASCII, "%s", 0, &formatString, plContext); + if (error) { goto cleanup; } + + } + + error = PKIX_PL_Sprintf + (&msgString, + plContext, + formatString, + messageString, + message2String); + if (error) { goto cleanup; } + + /* Go through the Logger list */ + + error = PKIX_List_GetLength(pkixLoggersList, &length, plContext); + if (error) { goto cleanup; } + + for (i = 0; i < length; i++) { + + error = PKIX_List_GetItem + (pkixLoggersList, + i, + (PKIX_PL_Object **) &logger, + plContext); + if (error) { goto cleanup; } + + /* Intended logging level less or equal than the max */ + needLogging = (currentLevel <= logger->maxLevel); + + if (needLogging && (logger->callback)) { + + /* + * We separate Logger into two lists based on log level + * but log level is not modified. We need to check here to + * avoid logging the higher log level (lower value) twice. + */ + if (pkixLoggersList == pkixLoggersErrors) { + needLogging = needLogging && + (currentLevel <= PKIX_LOGGER_LEVEL_WARNING); + } else if (pkixLoggersList == pkixLoggersDebugTrace) { + needLogging = needLogging && + (currentLevel > PKIX_LOGGER_LEVEL_WARNING); + } + + if (needLogging) { + if (logComponent == logger->logComponent) { + needLogging = PKIX_TRUE; + } else { + needLogging = PKIX_FALSE; + } + } + + if (needLogging) { + error = logger->callback + (logger, + msgString, + currentLevel, + logComponent, + plContext); + if (error) { goto cleanup; } + } + } + + error = PKIX_PL_Object_DecRef + ((PKIX_PL_Object *)logger, plContext); + logger = NULL; + if (error) { goto cleanup; } + + } + +cleanup: + + if (formatString) { + error = PKIX_PL_Object_DecRef + ((PKIX_PL_Object *)formatString, plContext); + } + + if (messageString) { + error = PKIX_PL_Object_DecRef + ((PKIX_PL_Object *)messageString, plContext); + } + + if (message2String) { + error = PKIX_PL_Object_DecRef + ((PKIX_PL_Object *)message2String, plContext); + } + + if (msgString) { + error = PKIX_PL_Object_DecRef + ((PKIX_PL_Object *)msgString, plContext); + } + + if (logger) { + error = PKIX_PL_Object_DecRef + ((PKIX_PL_Object *)logger, plContext); + } + + if (pkixLoggersErrors == NULL && savedPkixLoggersErrors != NULL) { + pkixLoggersErrors = savedPkixLoggersErrors; + } + + if (pkixLoggersDebugTrace == NULL && + savedPkixLoggersDebugTrace != NULL) { + pkixLoggersDebugTrace = savedPkixLoggersDebugTrace; + } + + error = PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext); + if (error) { return(NULL); } + + return(NULL); +} + +PKIX_Error * +pkix_Logger_CheckWithCode( + PKIX_List *pkixLoggersList, + PKIX_UInt32 errorCode, + const char *message2, + PKIX_ERRORCLASS logComponent, + PKIX_UInt32 currentLevel, + void *plContext) +{ + char error[32]; + char *errorString = NULL; + + PKIX_ENTER(LOGGER, "pkix_Logger_CheckWithCode"); +#if defined PKIX_ERROR_DESCRIPTION + errorString = PKIX_ErrorText[errorCode]; +#else + PR_snprintf(error, 32, "Error code: %d", errorCode); + errorString = error; +#endif /* PKIX_ERROR_DESCRIPTION */ + + pkixErrorResult = pkix_Logger_Check(pkixLoggersList, errorString, + message2, logComponent, + currentLevel, plContext); + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: pkix_Logger_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_Logger_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_Logger *logger = NULL; + + PKIX_ENTER(LOGGER, "pkix_Logger_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Check that this object is a logger */ + PKIX_CHECK(pkix_CheckType(object, PKIX_LOGGER_TYPE, plContext), + PKIX_OBJECTNOTLOGGER); + + logger = (PKIX_Logger *)object; + + /* We have a valid logger. DecRef its item and recurse on next */ + + logger->callback = NULL; + PKIX_DECREF(logger->context); + logger->logComponent = (PKIX_ERRORCLASS)NULL; + +cleanup: + + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: pkix_Logger_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_Logger_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_Logger *logger = NULL; + char *asciiFormat = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *contextString = NULL; + PKIX_PL_String *componentString = NULL; + PKIX_PL_String *loggerString = NULL; + + PKIX_ENTER(LOGGER, "pkix_Logger_ToString_Helper"); + PKIX_NULLCHECK_TWO(object, pString); + + /* Check that this object is a logger */ + PKIX_CHECK(pkix_CheckType(object, PKIX_LOGGER_TYPE, plContext), + PKIX_OBJECTNOTLOGGER); + + logger = (PKIX_Logger *)object; + + asciiFormat = + "[\n" + "\tLogger: \n" + "\tContext: %s\n" + "\tMaximum Level: %d\n" + "\tComponent Name: %s\n" + "]\n"; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiFormat, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_TOSTRING(logger->context, &contextString, plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + (void *)PKIX_ERRORCLASSNAMES[logger->logComponent], + 0, + &componentString, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&loggerString, + plContext, + formatString, + contextString, + logger->maxLevel, + componentString), + PKIX_SPRINTFFAILED); + + *pString = loggerString; + +cleanup: + + PKIX_DECREF(formatString); + PKIX_DECREF(contextString); + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: pkix_Logger_Equals + * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_Logger_Equals( + PKIX_PL_Object *first, + PKIX_PL_Object *second, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_UInt32 secondType; + PKIX_Boolean cmpResult; + PKIX_Logger *firstLogger = NULL; + PKIX_Logger *secondLogger = NULL; + + PKIX_ENTER(LOGGER, "pkix_Logger_Equals"); + PKIX_NULLCHECK_THREE(first, second, pResult); + + /* test that first is a Logger */ + PKIX_CHECK(pkix_CheckType(first, PKIX_LOGGER_TYPE, plContext), + PKIX_FIRSTOBJECTNOTLOGGER); + + /* + * Since we know first is a Logger, if both references are + * identical, they must be equal + */ + if (first == second){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If second isn't a Logger, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_LOGGER_TYPE) goto cleanup; + + firstLogger = (PKIX_Logger *)first; + secondLogger = (PKIX_Logger *)second; + + cmpResult = PKIX_FALSE; + + if (firstLogger->callback != secondLogger->callback) { + goto cleanup; + } + + if (firstLogger->logComponent != secondLogger->logComponent) { + goto cleanup; + } + + PKIX_EQUALS + (firstLogger->context, + secondLogger->context, + &cmpResult, + plContext, + PKIX_OBJECTEQUALSFAILED); + + if (cmpResult == PKIX_FALSE) { + goto cleanup; + } + + if (firstLogger->maxLevel != secondLogger->maxLevel) { + goto cleanup; + } + + *pResult = cmpResult; + +cleanup: + + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: pkix_Logger_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_Logger_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_Logger *logger = NULL; + PKIX_UInt32 hash = 0; + PKIX_UInt32 tempHash = 0; + + PKIX_ENTER(LOGGER, "pkix_Logger_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_LOGGER_TYPE, plContext), + PKIX_OBJECTNOTLOGGER); + + logger = (PKIX_Logger *)object; + + PKIX_HASHCODE(logger->context, &tempHash, plContext, + PKIX_OBJECTHASHCODEFAILED); + + hash = (((((PKIX_UInt32)((char *)logger->callback - (char *)NULL) + tempHash) << 7) + + logger->maxLevel) << 7) + (PKIX_UInt32)logger->logComponent; + + *pHashcode = hash; + +cleanup: + + PKIX_RETURN(LOGGER); +} + + +/* + * FUNCTION: pkix_Logger_Duplicate + * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_Logger_Duplicate( + PKIX_PL_Object *object, + PKIX_PL_Object **pNewObject, + void *plContext) +{ + PKIX_Logger *logger = NULL; + PKIX_Logger *dupLogger = NULL; + + PKIX_ENTER(LOGGER, "pkix_Logger_Duplicate"); + PKIX_NULLCHECK_TWO(object, pNewObject); + + PKIX_CHECK(pkix_CheckType + ((PKIX_PL_Object *)object, PKIX_LOGGER_TYPE, plContext), + PKIX_OBJECTNOTLOGGER); + + logger = (PKIX_Logger *) object; + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_LOGGER_TYPE, + sizeof (PKIX_Logger), + (PKIX_PL_Object **)&dupLogger, + plContext), + PKIX_COULDNOTCREATELOGGEROBJECT); + + dupLogger->callback = logger->callback; + dupLogger->maxLevel = logger->maxLevel; + + PKIX_DUPLICATE + (logger->context, + &dupLogger->context, + plContext, + PKIX_OBJECTDUPLICATEFAILED); + + dupLogger->logComponent = logger->logComponent; + + *pNewObject = (PKIX_PL_Object *) dupLogger; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(dupLogger); + } + + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: pkix_Logger_RegisterSelf + * DESCRIPTION: + * Registers PKIX_LOGGER_TYPE and its related functions with systemClasses[] + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_Logger_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(LOGGER, "pkix_Logger_RegisterSelf"); + + entry.description = "Logger"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_Logger); + entry.destructor = pkix_Logger_Destroy; + entry.equalsFunction = pkix_Logger_Equals; + entry.hashcodeFunction = pkix_Logger_Hashcode; + entry.toStringFunction = pkix_Logger_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_Logger_Duplicate; + + systemClasses[PKIX_LOGGER_TYPE] = entry; + + PKIX_RETURN(LOGGER); +} + +/* --Public-Logger-Functions--------------------------------------------- */ + +/* + * FUNCTION: PKIX_Logger_Create (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_Logger_Create( + PKIX_Logger_LogCallback callback, + PKIX_PL_Object *loggerContext, + PKIX_Logger **pLogger, + void *plContext) +{ + PKIX_Logger *logger = NULL; + + PKIX_ENTER(LOGGER, "PKIX_Logger_Create"); + PKIX_NULLCHECK_ONE(pLogger); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_LOGGER_TYPE, + sizeof (PKIX_Logger), + (PKIX_PL_Object **)&logger, + plContext), + PKIX_COULDNOTCREATELOGGEROBJECT); + + logger->callback = callback; + logger->maxLevel = 0; + logger->logComponent = (PKIX_ERRORCLASS)NULL; + + PKIX_INCREF(loggerContext); + logger->context = loggerContext; + + *pLogger = logger; + logger = NULL; + +cleanup: + + PKIX_DECREF(logger); + + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: PKIX_Logger_GetLogCallback (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_Logger_GetLogCallback( + PKIX_Logger *logger, + PKIX_Logger_LogCallback *pCallback, + void *plContext) +{ + PKIX_ENTER(LOGGER, "PKIX_Logger_GetLogCallback"); + PKIX_NULLCHECK_TWO(logger, pCallback); + + *pCallback = logger->callback; + + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: PKIX_Logger_GetLoggerContext (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_Logger_GetLoggerContext( + PKIX_Logger *logger, + PKIX_PL_Object **pLoggerContext, + void *plContext) +{ + PKIX_ENTER(LOGGER, "PKIX_Logger_GetLoggerContex"); + PKIX_NULLCHECK_TWO(logger, pLoggerContext); + + PKIX_INCREF(logger->context); + *pLoggerContext = logger->context; + +cleanup: + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: PKIX_Logger_GetMaxLoggingLevel (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_Logger_GetMaxLoggingLevel( + PKIX_Logger *logger, + PKIX_UInt32 *pLevel, + void *plContext) +{ + PKIX_ENTER(LOGGER, "PKIX_Logger_GetMaxLoggingLevel"); + PKIX_NULLCHECK_TWO(logger, pLevel); + + *pLevel = logger->maxLevel; + + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: PKIX_Logger_SetMaxLoggingLevel (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_Logger_SetMaxLoggingLevel( + PKIX_Logger *logger, + PKIX_UInt32 level, + void *plContext) +{ + PKIX_ENTER(LOGGER, "PKIX_Logger_SetMaxLoggingLevel"); + PKIX_NULLCHECK_ONE(logger); + + if (level > PKIX_LOGGER_LEVEL_MAX) { + PKIX_ERROR(PKIX_LOGGINGLEVELEXCEEDSMAXIMUM); + } else { + logger->maxLevel = level; + } + +cleanup: + + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: PKIX_Logger_GetLoggingComponent (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_Logger_GetLoggingComponent( + PKIX_Logger *logger, + PKIX_ERRORCLASS *pComponent, + void *plContext) +{ + PKIX_ENTER(LOGGER, "PKIX_Logger_GetLoggingComponent"); + PKIX_NULLCHECK_TWO(logger, pComponent); + + *pComponent = logger->logComponent; + + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: PKIX_Logger_SetLoggingComponent (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_Logger_SetLoggingComponent( + PKIX_Logger *logger, + PKIX_ERRORCLASS component, + void *plContext) +{ + PKIX_ENTER(LOGGER, "PKIX_Logger_SetLoggingComponent"); + PKIX_NULLCHECK_ONE(logger); + + logger->logComponent = component; + + PKIX_RETURN(LOGGER); +} + + +/* + * Following PKIX_GetLoggers(), PKIX_SetLoggers() and PKIX_AddLogger() are + * documented as not thread-safe. However they are thread-safe now. We need + * the lock when accessing the logger lists. + */ + +/* + * FUNCTION: PKIX_Logger_GetLoggers (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_GetLoggers( + PKIX_List **pLoggers, /* list of PKIX_Logger */ + void *plContext) +{ + PKIX_List *list = NULL; + PKIX_List *savedPkixLoggersDebugTrace = NULL; + PKIX_List *savedPkixLoggersErrors = NULL; + PKIX_Logger *logger = NULL; + PKIX_Logger *dupLogger = NULL; + PKIX_UInt32 i, length; + PKIX_Boolean locked = PKIX_FALSE; + + PKIX_ENTER(LOGGER, "PKIX_Logger_GetLoggers"); + PKIX_NULLCHECK_ONE(pLoggers); + + PKIX_CHECK(PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext), + PKIX_MONITORLOCKENTERFAILED); + locked = PKIX_TRUE; + + /* + * Temporarily disable DEBUG/TRACE Logging to avoid possible + * deadlock: + * When the Logger List is being accessed, e.g. by PKIX_ENTER or + * PKIX_DECREF, pkix_Logger_Check may check whether logging + * is requested, creating a deadlock situation. + */ + savedPkixLoggersDebugTrace = pkixLoggersDebugTrace; + pkixLoggersDebugTrace = NULL; + savedPkixLoggersErrors = pkixLoggersErrors; + pkixLoggersErrors = NULL; + + if (pkixLoggers == NULL) { + length = 0; + } else { + PKIX_CHECK(PKIX_List_GetLength + (pkixLoggers, &length, plContext), + PKIX_LISTGETLENGTHFAILED); + } + + /* Create a list and copy the pkixLoggers item to the list */ + PKIX_CHECK(PKIX_List_Create(&list, plContext), + PKIX_LISTCREATEFAILED); + + for (i = 0; i < length; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (pkixLoggers, + i, + (PKIX_PL_Object **) &logger, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_Logger_Duplicate + ((PKIX_PL_Object *)logger, + (PKIX_PL_Object **)&dupLogger, + plContext), + PKIX_LOGGERDUPLICATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (list, + (PKIX_PL_Object *) dupLogger, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(logger); + PKIX_DECREF(dupLogger); + } + + /* Set the list to be immutable */ + PKIX_CHECK(PKIX_List_SetImmutable(list, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + *pLoggers = list; + +cleanup: + + PKIX_DECREF(logger); + + /* Restore logging capability */ + pkixLoggersDebugTrace = savedPkixLoggersDebugTrace; + pkixLoggersErrors = savedPkixLoggersErrors; + + if (locked) { + PKIX_CHECK(PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext), + PKIX_MONITORLOCKEXITFAILED); + } + + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: PKIX_Logger_SetLoggers (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_SetLoggers( + PKIX_List *loggers, /* list of PKIX_Logger */ + void *plContext) +{ + PKIX_List *list = NULL; + PKIX_List *savedPkixLoggersErrors = NULL; + PKIX_List *savedPkixLoggersDebugTrace = NULL; + PKIX_Logger *logger = NULL; + PKIX_Logger *dupLogger = NULL; + PKIX_Boolean locked = PKIX_FALSE; + PKIX_UInt32 i, length; + + PKIX_ENTER(LOGGER, "PKIX_SetLoggers"); + + PKIX_CHECK(PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext), + PKIX_MONITORLOCKENTERFAILED); + locked = PKIX_TRUE; + + /* Disable tracing, etc. to avoid recursion and deadlock */ + savedPkixLoggersDebugTrace = pkixLoggersDebugTrace; + pkixLoggersDebugTrace = NULL; + savedPkixLoggersErrors = pkixLoggersErrors; + pkixLoggersErrors = NULL; + + /* discard any prior loggers */ + PKIX_DECREF(pkixLoggers); + PKIX_DECREF(savedPkixLoggersErrors); + PKIX_DECREF(savedPkixLoggersDebugTrace); + + if (loggers != NULL) { + + PKIX_CHECK(PKIX_List_Create(&list, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK(PKIX_List_GetLength(loggers, &length, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (i = 0; i < length; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (loggers, + i, + (PKIX_PL_Object **) &logger, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_Logger_Duplicate + ((PKIX_PL_Object *)logger, + (PKIX_PL_Object **)&dupLogger, + plContext), + PKIX_LOGGERDUPLICATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (list, + (PKIX_PL_Object *) dupLogger, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + /* Make two lists */ + + /* Put in pkixLoggersErrors in any case*/ + + if (savedPkixLoggersErrors == NULL) { + + PKIX_CHECK(PKIX_List_Create + (&savedPkixLoggersErrors, + plContext), + PKIX_LISTCREATEFAILED); + } + + PKIX_CHECK(PKIX_List_AppendItem + (savedPkixLoggersErrors, + (PKIX_PL_Object *) dupLogger, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + if (logger->maxLevel > PKIX_LOGGER_LEVEL_WARNING) { + + /* Put in pkixLoggersDebugTrace */ + + if (savedPkixLoggersDebugTrace == NULL) { + + PKIX_CHECK(PKIX_List_Create + (&savedPkixLoggersDebugTrace, + plContext), + PKIX_LISTCREATEFAILED); + } + + PKIX_CHECK(PKIX_List_AppendItem + (savedPkixLoggersDebugTrace, + (PKIX_PL_Object *) dupLogger, + plContext), + PKIX_LISTAPPENDITEMFAILED); + } + PKIX_DECREF(logger); + PKIX_DECREF(dupLogger); + + } + + pkixLoggers = list; + } + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(list); + PKIX_DECREF(savedPkixLoggersErrors); + PKIX_DECREF(savedPkixLoggersDebugTrace); + pkixLoggers = NULL; + } + + PKIX_DECREF(logger); + + /* Reenable logging capability with new lists */ + pkixLoggersErrors = savedPkixLoggersErrors; + pkixLoggersDebugTrace = savedPkixLoggersDebugTrace; + + if (locked) { + PKIX_CHECK(PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext), + PKIX_MONITORLOCKEXITFAILED); + } + + PKIX_RETURN(LOGGER); +} + +/* + * FUNCTION: PKIX_Logger_AddLogger (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_AddLogger( + PKIX_Logger *logger, + void *plContext) +{ + PKIX_Logger *dupLogger = NULL; + PKIX_Logger *addLogger = NULL; + PKIX_List *savedPkixLoggersErrors = NULL; + PKIX_List *savedPkixLoggersDebugTrace = NULL; + PKIX_Boolean locked = PKIX_FALSE; + PKIX_UInt32 i, length; + + PKIX_ENTER(LOGGER, "PKIX_Logger_AddLogger"); + PKIX_NULLCHECK_ONE(logger); + + PKIX_CHECK(PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext), + PKIX_MONITORLOCKENTERFAILED); + locked = PKIX_TRUE; + + savedPkixLoggersDebugTrace = pkixLoggersDebugTrace; + pkixLoggersDebugTrace = NULL; + savedPkixLoggersErrors = pkixLoggersErrors; + pkixLoggersErrors = NULL; + + PKIX_DECREF(savedPkixLoggersErrors); + PKIX_DECREF(savedPkixLoggersDebugTrace); + + if (pkixLoggers == NULL) { + + PKIX_CHECK(PKIX_List_Create(&pkixLoggers, plContext), + PKIX_LISTCREATEFAILED); + } + + PKIX_CHECK(pkix_Logger_Duplicate + ((PKIX_PL_Object *)logger, + (PKIX_PL_Object **)&dupLogger, + plContext), + PKIX_LOGGERDUPLICATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (pkixLoggers, + (PKIX_PL_Object *) dupLogger, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_CHECK(PKIX_List_GetLength(pkixLoggers, &length, plContext), + PKIX_LISTGETLENGTHFAILED); + + /* Reconstruct pkixLoggersErrors and pkixLoggersDebugTrace */ + for (i = 0; i < length; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (pkixLoggers, + i, + (PKIX_PL_Object **) &addLogger, + plContext), + PKIX_LISTGETITEMFAILED); + + + /* Put in pkixLoggersErrors */ + + if (savedPkixLoggersErrors == NULL) { + + PKIX_CHECK(PKIX_List_Create + (&savedPkixLoggersErrors, + plContext), + PKIX_LISTCREATEFAILED); + } + + PKIX_CHECK(PKIX_List_AppendItem + (savedPkixLoggersErrors, + (PKIX_PL_Object *) addLogger, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + if (addLogger->maxLevel > PKIX_LOGGER_LEVEL_WARNING) { + + /* Put in pkixLoggersDebugTrace */ + + if (savedPkixLoggersDebugTrace == NULL) { + + PKIX_CHECK(PKIX_List_Create + (&savedPkixLoggersDebugTrace, + plContext), + PKIX_LISTCREATEFAILED); + } + + PKIX_CHECK(PKIX_List_AppendItem + (savedPkixLoggersDebugTrace, + (PKIX_PL_Object *) addLogger, + plContext), + PKIX_LISTAPPENDITEMFAILED); + } + + PKIX_DECREF(addLogger); + + } + +cleanup: + + PKIX_DECREF(dupLogger); + PKIX_DECREF(addLogger); + + /* Restore logging capability */ + pkixLoggersErrors = savedPkixLoggersErrors; + pkixLoggersDebugTrace = savedPkixLoggersDebugTrace; + + if (locked) { + PKIX_CHECK(PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext), + PKIX_MONITORLOCKEXITFAILED); + } + + PKIX_RETURN(LOGGER); +} |