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