andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: /* andre@0: * pkix_error.c andre@0: * andre@0: * Error Object Functions andre@0: * andre@0: */ andre@0: andre@0: #include "pkix_error.h" andre@0: andre@0: #undef PKIX_ERRORENTRY andre@0: andre@0: #define PKIX_ERRORENTRY(name,desc,nsserr) #desc andre@0: andre@0: #if defined PKIX_ERROR_DESCRIPTION andre@0: andre@0: const char * const PKIX_ErrorText[] = andre@0: { andre@0: #include "pkix_errorstrings.h" andre@0: }; andre@0: andre@0: #else andre@0: andre@0: #include "prprf.h" andre@0: andre@0: #endif /* PKIX_ERROR_DESCRIPTION */ andre@0: andre@0: extern const PKIX_Int32 PKIX_PLErrorIndex[]; andre@0: andre@0: /* --Private-Functions-------------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: pkix_Error_Equals andre@0: * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_Error_Equals( andre@0: PKIX_PL_Object *firstObject, andre@0: PKIX_PL_Object *secondObject, andre@0: PKIX_Boolean *pResult, andre@0: void *plContext) andre@0: { andre@0: PKIX_Error *firstError = NULL; andre@0: PKIX_Error *secondError = NULL; andre@0: PKIX_Error *firstCause = NULL; andre@0: PKIX_Error *secondCause = NULL; andre@0: PKIX_PL_Object *firstInfo = NULL; andre@0: PKIX_PL_Object *secondInfo = NULL; andre@0: PKIX_ERRORCLASS firstClass, secondClass; andre@0: PKIX_UInt32 secondType; andre@0: PKIX_Boolean boolResult, unequalFlag; andre@0: andre@0: PKIX_ENTER(ERROR, "pkix_Error_Equals"); andre@0: PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); andre@0: andre@0: unequalFlag = PKIX_FALSE; andre@0: andre@0: /* First just compare pointer values to save time */ andre@0: if (firstObject == secondObject) { andre@0: *pResult = PKIX_TRUE; andre@0: goto cleanup; andre@0: } else { andre@0: /* Result will only be set to true if all tests pass */ andre@0: *pResult = PKIX_FALSE; andre@0: } andre@0: andre@0: PKIX_CHECK(pkix_CheckType(firstObject, PKIX_ERROR_TYPE, plContext), andre@0: PKIX_FIRSTOBJECTNOTANERROROBJECT); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Object_GetType andre@0: (secondObject, &secondType, plContext), andre@0: PKIX_ERRORGETTINGSECONDOBJECTTYPE); andre@0: andre@0: /* If types differ, then return false. Result is already set */ andre@0: if (secondType != PKIX_ERROR_TYPE) goto cleanup; andre@0: andre@0: /* It is safe to cast to PKIX_Error */ andre@0: firstError = (PKIX_Error *) firstObject; andre@0: secondError = (PKIX_Error *) secondObject; andre@0: andre@0: /* Compare error codes */ andre@0: firstClass = firstError->errClass; andre@0: secondClass = secondError->errClass; andre@0: andre@0: /* If codes differ, return false. Result is already set */ andre@0: if (firstClass != secondClass) goto cleanup; andre@0: andre@0: /* Compare causes */ andre@0: firstCause = firstError->cause; andre@0: secondCause = secondError->cause; andre@0: andre@0: /* Ensure that either both or none of the causes are NULL */ andre@0: if (((firstCause != NULL) && (secondCause == NULL))|| andre@0: ((firstCause == NULL) && (secondCause != NULL))) andre@0: unequalFlag = PKIX_TRUE; andre@0: andre@0: if ((firstCause != NULL) && (secondCause != NULL)) { andre@0: PKIX_CHECK(PKIX_PL_Object_Equals andre@0: ((PKIX_PL_Object*)firstCause, andre@0: (PKIX_PL_Object*)secondCause, andre@0: &boolResult, andre@0: plContext), andre@0: PKIX_ERRORINRECURSIVEEQUALSCALL); andre@0: andre@0: /* Set the unequalFlag so that we return after dec refing */ andre@0: if (boolResult == 0) unequalFlag = PKIX_TRUE; andre@0: } andre@0: andre@0: /* If the cause errors are not equal, return null */ andre@0: if (unequalFlag) goto cleanup; andre@0: andre@0: /* Compare info fields */ andre@0: firstInfo = firstError->info; andre@0: secondInfo = secondError->info; andre@0: andre@0: if (firstInfo != secondInfo) goto cleanup; andre@0: andre@0: /* Ensure that either both or none of the infos are NULL */ andre@0: if (((firstInfo != NULL) && (secondInfo == NULL))|| andre@0: ((firstInfo == NULL) && (secondInfo != NULL))) andre@0: unequalFlag = PKIX_TRUE; andre@0: andre@0: if ((firstInfo != NULL) && (secondInfo != NULL)) { andre@0: andre@0: PKIX_CHECK(PKIX_PL_Object_Equals andre@0: ((PKIX_PL_Object*)firstInfo, andre@0: (PKIX_PL_Object*)secondInfo, andre@0: &boolResult, andre@0: plContext), andre@0: PKIX_ERRORINRECURSIVEEQUALSCALL); andre@0: andre@0: /* Set the unequalFlag so that we return after dec refing */ andre@0: if (boolResult == 0) unequalFlag = PKIX_TRUE; andre@0: } andre@0: andre@0: /* If the infos are not equal, return null */ andre@0: if (unequalFlag) goto cleanup; andre@0: andre@0: andre@0: /* Compare descs */ andre@0: if (firstError->errCode != secondError->errCode) { andre@0: unequalFlag = PKIX_TRUE; andre@0: } andre@0: andre@0: if (firstError->plErr != secondError->plErr) { andre@0: unequalFlag = PKIX_TRUE; andre@0: } andre@0: andre@0: /* If the unequalFlag was set, return false */ andre@0: if (unequalFlag) goto cleanup; andre@0: andre@0: /* Errors are equal in all fields at this point */ andre@0: *pResult = PKIX_TRUE; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(ERROR); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_Error_Destroy andre@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_Error_Destroy( andre@0: PKIX_PL_Object *object, andre@0: void *plContext) andre@0: { andre@0: PKIX_Error *error = NULL; andre@0: andre@0: PKIX_ENTER(ERROR, "pkix_Error_Destroy"); andre@0: PKIX_NULLCHECK_ONE(object); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_ERROR_TYPE, plContext), andre@0: PKIX_OBJECTNOTANERROR); andre@0: andre@0: error = (PKIX_Error *)object; andre@0: andre@0: PKIX_DECREF(error->cause); andre@0: andre@0: PKIX_DECREF(error->info); andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(ERROR); andre@0: } andre@0: andre@0: andre@0: /* XXX This is not thread safe */ andre@0: static PKIX_UInt32 pkix_error_cause_depth = 1; andre@0: andre@0: /* andre@0: * FUNCTION: pkix_Error_ToString andre@0: * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_Error_ToString( andre@0: PKIX_PL_Object *object, andre@0: PKIX_PL_String **pString, andre@0: void *plContext) andre@0: { andre@0: PKIX_Error *error = NULL; andre@0: PKIX_Error *cause = NULL; andre@0: PKIX_PL_String *desc = NULL; andre@0: PKIX_PL_String *formatString = NULL; andre@0: PKIX_PL_String *causeString = NULL; andre@0: PKIX_PL_String *optCauseString = NULL; andre@0: PKIX_PL_String *errorNameString = NULL; andre@0: char *format = NULL; andre@0: PKIX_ERRORCLASS errClass; andre@0: andre@0: PKIX_ENTER(ERROR, "pkix_Error_ToString"); andre@0: PKIX_NULLCHECK_TWO(object, pString); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_ERROR_TYPE, plContext), andre@0: PKIX_OBJECTNOTANERROR); andre@0: andre@0: error = (PKIX_Error *)object; andre@0: andre@0: /* Get this error's errClass, description and the string of its cause */ andre@0: errClass = error->errClass; andre@0: andre@0: /* Get the description string */ andre@0: PKIX_Error_GetDescription(error, &desc, plContext); andre@0: andre@0: /* Get the cause */ andre@0: cause = error->cause; andre@0: andre@0: /* Get the causes's description string */ andre@0: if (cause != NULL) { andre@0: pkix_error_cause_depth++; andre@0: andre@0: /* Get the cause string */ andre@0: PKIX_CHECK(PKIX_PL_Object_ToString andre@0: ((PKIX_PL_Object*)cause, &causeString, plContext), andre@0: PKIX_ERRORGETTINGCAUSESTRING); andre@0: andre@0: format = "\n*** Cause (%d): %s"; andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: format, andre@0: 0, andre@0: &formatString, andre@0: plContext), andre@0: PKIX_STRINGCREATEFAILED); andre@0: andre@0: /* Create the optional Cause String */ andre@0: PKIX_CHECK(PKIX_PL_Sprintf andre@0: (&optCauseString, andre@0: plContext, andre@0: formatString, andre@0: pkix_error_cause_depth, andre@0: causeString), andre@0: PKIX_SPRINTFFAILED); andre@0: andre@0: PKIX_DECREF(formatString); andre@0: andre@0: pkix_error_cause_depth--; andre@0: } andre@0: andre@0: /* Create the Format String */ andre@0: if (optCauseString != NULL) { andre@0: format = "*** %s Error- %s%s"; andre@0: } else { andre@0: format = "*** %s Error- %s"; andre@0: } andre@0: andre@0: /* Ensure that error errClass is known, otherwise default to Object */ andre@0: if (errClass >= PKIX_NUMERRORCLASSES) { andre@0: errClass = 0; andre@0: } andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: (void *)PKIX_ERRORCLASSNAMES[errClass], andre@0: 0, andre@0: &errorNameString, andre@0: plContext), andre@0: PKIX_STRINGCREATEFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: format, andre@0: 0, andre@0: &formatString, andre@0: plContext), andre@0: PKIX_STRINGCREATEFAILED); andre@0: andre@0: /* Create the output String */ andre@0: PKIX_CHECK(PKIX_PL_Sprintf andre@0: (pString, andre@0: plContext, andre@0: formatString, andre@0: errorNameString, andre@0: desc, andre@0: optCauseString), andre@0: PKIX_SPRINTFFAILED); andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_DECREF(desc); andre@0: PKIX_DECREF(causeString); andre@0: PKIX_DECREF(formatString); andre@0: PKIX_DECREF(optCauseString); andre@0: PKIX_DECREF(errorNameString); andre@0: andre@0: PKIX_RETURN(ERROR); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_Error_Hashcode andre@0: * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_Error_Hashcode( andre@0: PKIX_PL_Object *object, andre@0: PKIX_UInt32 *pResult, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(ERROR, "pkix_Error_Hashcode"); andre@0: PKIX_NULLCHECK_TWO(object, pResult); andre@0: andre@0: /* XXX Unimplemented */ andre@0: /* XXX Need to make hashcodes equal when two errors are equal */ andre@0: *pResult = (PKIX_UInt32)object; andre@0: andre@0: PKIX_RETURN(ERROR); andre@0: } andre@0: andre@0: /* --Initializers------------------------------------------------- */ andre@0: andre@0: /* andre@0: * PKIX_ERRORCLASSNAMES is an array of strings, with each string holding a andre@0: * descriptive name for an error errClass. This is used by the default andre@0: * PKIX_PL_Error_ToString function. andre@0: * andre@0: * Note: PKIX_ERRORCLASSES is defined in pkixt.h as a list of error types. andre@0: * (More precisely, as a list of invocations of ERRMACRO(type).) The andre@0: * macro is expanded in pkixt.h to define error numbers, and here to andre@0: * provide corresponding strings. For example, since the fifth ERRMACRO andre@0: * entry is MUTEX, then PKIX_MUTEX_ERROR is defined in pkixt.h as 4, and andre@0: * PKIX_ERRORCLASSNAMES[4] is initialized here with the value "MUTEX". andre@0: */ andre@0: #undef ERRMACRO andre@0: #define ERRMACRO(type) #type andre@0: andre@0: const char * andre@0: PKIX_ERRORCLASSNAMES[PKIX_NUMERRORCLASSES] = andre@0: { andre@0: PKIX_ERRORCLASSES andre@0: }; andre@0: andre@0: /* andre@0: * FUNCTION: pkix_Error_RegisterSelf andre@0: * DESCRIPTION: andre@0: * Registers PKIX_ERROR_TYPE and its related functions with systemClasses[] andre@0: * THREAD SAFETY: andre@0: * Not Thread Safe - for performance and complexity reasons andre@0: * andre@0: * Since this function is only called by PKIX_PL_Initialize, which should andre@0: * only be called once, it is acceptable that this function is not andre@0: * thread-safe. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_Error_RegisterSelf(void *plContext) andre@0: { andre@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; andre@0: pkix_ClassTable_Entry entry; andre@0: andre@0: PKIX_ENTER(ERROR, "pkix_Error_RegisterSelf"); andre@0: andre@0: entry.description = "Error"; andre@0: entry.objCounter = 0; andre@0: entry.typeObjectSize = sizeof(PKIX_Error); andre@0: entry.destructor = pkix_Error_Destroy; andre@0: entry.equalsFunction = pkix_Error_Equals; andre@0: entry.hashcodeFunction = pkix_Error_Hashcode; andre@0: entry.toStringFunction = pkix_Error_ToString; andre@0: entry.comparator = NULL; andre@0: entry.duplicateFunction = pkix_duplicateImmutable; andre@0: andre@0: systemClasses[PKIX_ERROR_TYPE] = entry; andre@0: andre@0: PKIX_RETURN(ERROR); andre@0: } andre@0: andre@0: /* --Public-Functions--------------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_Error_Create (see comments in pkix_util.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_Error_Create( andre@0: PKIX_ERRORCLASS errClass, andre@0: PKIX_Error *cause, andre@0: PKIX_PL_Object *info, andre@0: PKIX_ERRORCODE errCode, andre@0: PKIX_Error **pError, andre@0: void *plContext) andre@0: { andre@0: PKIX_Error *tempCause = NULL; andre@0: PKIX_Error *error = NULL; andre@0: andre@0: PKIX_ENTER(ERROR, "PKIX_Error_Create"); andre@0: andre@0: PKIX_NULLCHECK_ONE(pError); andre@0: andre@0: /* andre@0: * when called here, if PKIX_PL_Object_Alloc returns an error, andre@0: * it must be a PKIX_ALLOC_ERROR andre@0: */ andre@0: pkixErrorResult = PKIX_PL_Object_Alloc andre@0: (PKIX_ERROR_TYPE, andre@0: ((PKIX_UInt32)(sizeof (PKIX_Error))), andre@0: (PKIX_PL_Object **)&error, andre@0: plContext); andre@0: andre@0: if (pkixErrorResult) return (pkixErrorResult); andre@0: andre@0: error->errClass = errClass; andre@0: andre@0: /* Ensure we don't have a loop. Follow causes until NULL */ andre@0: for (tempCause = cause; andre@0: tempCause != NULL; andre@0: tempCause = tempCause->cause) { andre@0: /* If we detect a loop, throw a new error */ andre@0: if (tempCause == error) { andre@0: PKIX_ERROR(PKIX_LOOPOFERRORCAUSEDETECTED); andre@0: } andre@0: } andre@0: andre@0: PKIX_INCREF(cause); andre@0: error->cause = cause; andre@0: andre@0: PKIX_INCREF(info); andre@0: error->info = info; andre@0: andre@0: error->errCode = errCode; andre@0: andre@0: error->plErr = PKIX_PLErrorIndex[error->errCode]; andre@0: andre@0: *pError = error; andre@0: error = NULL; andre@0: andre@0: cleanup: andre@0: /* PKIX-XXX Fix for leak during error creation */ andre@0: PKIX_DECREF(error); andre@0: andre@0: PKIX_RETURN(ERROR); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_Error_GetErrorClass (see comments in pkix_util.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_Error_GetErrorClass( andre@0: PKIX_Error *error, andre@0: PKIX_ERRORCLASS *pClass, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(ERROR, "PKIX_Error_GetErrorClass"); andre@0: PKIX_NULLCHECK_TWO(error, pClass); andre@0: andre@0: *pClass = error->errClass; andre@0: andre@0: PKIX_RETURN(ERROR); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_Error_GetErrorCode (see comments in pkix_util.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_Error_GetErrorCode( andre@0: PKIX_Error *error, andre@0: PKIX_ERRORCODE *pCode, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(ERROR, "PKIX_Error_GetErrorCode"); andre@0: PKIX_NULLCHECK_TWO(error, pCode); andre@0: andre@0: *pCode = error->errCode; andre@0: andre@0: PKIX_RETURN(ERROR); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_Error_GetCause (see comments in pkix_util.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_Error_GetCause( andre@0: PKIX_Error *error, andre@0: PKIX_Error **pCause, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(ERROR, "PKIX_Error_GetCause"); andre@0: PKIX_NULLCHECK_TWO(error, pCause); andre@0: andre@0: if (error->cause != PKIX_ALLOC_ERROR()){ andre@0: PKIX_INCREF(error->cause); andre@0: } andre@0: andre@0: *pCause = error->cause; andre@0: andre@0: cleanup: andre@0: PKIX_RETURN(ERROR); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_Error_GetSupplementaryInfo (see comments in pkix_util.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_Error_GetSupplementaryInfo( andre@0: PKIX_Error *error, andre@0: PKIX_PL_Object **pInfo, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(ERROR, "PKIX_Error_GetSupplementaryInfo"); andre@0: PKIX_NULLCHECK_TWO(error, pInfo); andre@0: andre@0: PKIX_INCREF(error->info); andre@0: andre@0: *pInfo = error->info; andre@0: andre@0: cleanup: andre@0: PKIX_RETURN(ERROR); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_Error_GetDescription (see comments in pkix_util.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_Error_GetDescription( andre@0: PKIX_Error *error, andre@0: PKIX_PL_String **pDesc, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_String *descString = NULL; andre@0: #ifndef PKIX_ERROR_DESCRIPTION andre@0: char errorStr[32]; andre@0: #endif andre@0: andre@0: PKIX_ENTER(ERROR, "PKIX_Error_GetDescription"); andre@0: PKIX_NULLCHECK_TWO(error, pDesc); andre@0: andre@0: #ifndef PKIX_ERROR_DESCRIPTION andre@0: PR_snprintf(errorStr, 32, "Error code: %d", error->errCode); andre@0: #endif andre@0: andre@0: PKIX_PL_String_Create(PKIX_ESCASCII, andre@0: #if defined PKIX_ERROR_DESCRIPTION andre@0: (void *)PKIX_ErrorText[error->errCode], andre@0: #else andre@0: errorStr, andre@0: #endif andre@0: 0, andre@0: &descString, andre@0: plContext); andre@0: andre@0: *pDesc = descString; andre@0: andre@0: PKIX_RETURN(ERROR); andre@0: }