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_pl_ldapresponse.c andre@0: * andre@0: */ andre@0: andre@0: #include andre@0: #include "pkix_pl_ldapresponse.h" andre@0: andre@0: /* --Private-LdapResponse-Functions------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_Destroy andre@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_LdapResponse_Destroy( andre@0: PKIX_PL_Object *object, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_LdapResponse *ldapRsp = NULL; andre@0: LDAPMessage *m = NULL; andre@0: LDAPSearchResponseEntry *entry = NULL; andre@0: LDAPSearchResponseResult *result = NULL; andre@0: LDAPSearchResponseAttr **attributes = NULL; andre@0: LDAPSearchResponseAttr *attr = NULL; andre@0: SECItem **valp = NULL; andre@0: SECItem *val = NULL; andre@0: andre@0: PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Destroy"); andre@0: PKIX_NULLCHECK_ONE(object); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPRESPONSE_TYPE, plContext), andre@0: PKIX_OBJECTNOTLDAPRESPONSE); andre@0: andre@0: ldapRsp = (PKIX_PL_LdapResponse *)object; andre@0: andre@0: m = &ldapRsp->decoded; andre@0: andre@0: if (m->messageID.data != NULL) { andre@0: PR_Free(m->messageID.data); andre@0: } andre@0: andre@0: if (m->protocolOp.selector == andre@0: LDAP_SEARCHRESPONSEENTRY_TYPE) { andre@0: entry = &m->protocolOp.op.searchResponseEntryMsg; andre@0: if (entry->objectName.data != NULL) { andre@0: PR_Free(entry->objectName.data); andre@0: } andre@0: if (entry->attributes != NULL) { andre@0: for (attributes = entry->attributes; andre@0: *attributes != NULL; andre@0: attributes++) { andre@0: attr = *attributes; andre@0: PR_Free(attr->attrType.data); andre@0: for (valp = attr->val; *valp != NULL; valp++) { andre@0: val = *valp; andre@0: if (val->data != NULL) { andre@0: PR_Free(val->data); andre@0: } andre@0: PR_Free(val); andre@0: } andre@0: PR_Free(attr->val); andre@0: PR_Free(attr); andre@0: } andre@0: PR_Free(entry->attributes); andre@0: } andre@0: } else if (m->protocolOp.selector == andre@0: LDAP_SEARCHRESPONSERESULT_TYPE) { andre@0: result = &m->protocolOp.op.searchResponseResultMsg; andre@0: if (result->resultCode.data != NULL) { andre@0: PR_Free(result->resultCode.data); andre@0: } andre@0: } andre@0: andre@0: PKIX_FREE(ldapRsp->derEncoded.data); andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_Hashcode andre@0: * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_LdapResponse_Hashcode( andre@0: PKIX_PL_Object *object, andre@0: PKIX_UInt32 *pHashcode, andre@0: void *plContext) andre@0: { andre@0: PKIX_UInt32 dataLen = 0; andre@0: PKIX_UInt32 dindex = 0; andre@0: PKIX_UInt32 sizeOfLength = 0; andre@0: PKIX_UInt32 idLen = 0; andre@0: const unsigned char *msgBuf = NULL; andre@0: PKIX_PL_LdapResponse *ldapRsp = NULL; andre@0: andre@0: PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Hashcode"); andre@0: PKIX_NULLCHECK_TWO(object, pHashcode); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPRESPONSE_TYPE, plContext), andre@0: PKIX_OBJECTNOTLDAPRESPONSE); andre@0: andre@0: ldapRsp = (PKIX_PL_LdapResponse *)object; andre@0: andre@0: *pHashcode = 0; andre@0: andre@0: /* andre@0: * Two responses that differ only in msgnum are a match! Therefore, andre@0: * start hashcoding beyond the encoded messageID field. andre@0: */ andre@0: if (ldapRsp->derEncoded.data) { andre@0: msgBuf = (const unsigned char *)ldapRsp->derEncoded.data; andre@0: /* Is message length short form (one octet) or long form? */ andre@0: if ((msgBuf[1] & 0x80) != 0) { andre@0: sizeOfLength = msgBuf[1] & 0x7F; andre@0: for (dindex = 0; dindex < sizeOfLength; dindex++) { andre@0: dataLen = (dataLen << 8) + msgBuf[dindex + 2]; andre@0: } andre@0: } else { andre@0: dataLen = msgBuf[1]; andre@0: } andre@0: andre@0: /* How many bytes for the messageID? (Assume short form) */ andre@0: idLen = msgBuf[dindex + 3] + 2; andre@0: dindex += idLen; andre@0: dataLen -= idLen; andre@0: msgBuf = &msgBuf[dindex + 2]; andre@0: andre@0: PKIX_CHECK(pkix_hash(msgBuf, dataLen, pHashcode, plContext), andre@0: PKIX_HASHFAILED); andre@0: } andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_Equals andre@0: * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_LdapResponse_Equals( andre@0: PKIX_PL_Object *firstObj, andre@0: PKIX_PL_Object *secondObj, andre@0: PKIX_Boolean *pResult, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_LdapResponse *rsp1 = NULL; andre@0: PKIX_PL_LdapResponse *rsp2 = NULL; andre@0: PKIX_UInt32 secondType = 0; andre@0: PKIX_UInt32 firstLen = 0; andre@0: const unsigned char *firstData = NULL; andre@0: const unsigned char *secondData = NULL; andre@0: PKIX_UInt32 sizeOfLength = 0; andre@0: PKIX_UInt32 dindex = 0; andre@0: PKIX_UInt32 i = 0; andre@0: andre@0: PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Equals"); andre@0: PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult); andre@0: andre@0: /* test that firstObj is a LdapResponse */ andre@0: PKIX_CHECK(pkix_CheckType(firstObj, PKIX_LDAPRESPONSE_TYPE, plContext), andre@0: PKIX_FIRSTOBJARGUMENTNOTLDAPRESPONSE); andre@0: andre@0: /* andre@0: * Since we know firstObj is a LdapResponse, if both references are andre@0: * identical, they must be equal andre@0: */ andre@0: if (firstObj == secondObj){ andre@0: *pResult = PKIX_TRUE; andre@0: goto cleanup; andre@0: } andre@0: andre@0: /* andre@0: * If secondObj isn't a LdapResponse, we don't throw an error. andre@0: * We simply return a Boolean result of FALSE andre@0: */ andre@0: *pResult = PKIX_FALSE; andre@0: PKIX_CHECK(PKIX_PL_Object_GetType(secondObj, &secondType, plContext), andre@0: PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); andre@0: if (secondType != PKIX_LDAPRESPONSE_TYPE) { andre@0: goto cleanup; andre@0: } andre@0: andre@0: rsp1 = (PKIX_PL_LdapResponse *)firstObj; andre@0: rsp2 = (PKIX_PL_LdapResponse *)secondObj; andre@0: andre@0: /* If either lacks an encoded string, they cannot be compared */ andre@0: if (!(rsp1->derEncoded.data) || !(rsp2->derEncoded.data)) { andre@0: goto cleanup; andre@0: } andre@0: andre@0: if (rsp1->derEncoded.len != rsp2->derEncoded.len) { andre@0: goto cleanup; andre@0: } andre@0: andre@0: firstData = (const unsigned char *)rsp1->derEncoded.data; andre@0: secondData = (const unsigned char *)rsp2->derEncoded.data; andre@0: andre@0: /* andre@0: * Two responses that differ only in msgnum are equal! Therefore, andre@0: * start the byte comparison beyond the encoded messageID field. andre@0: */ andre@0: andre@0: /* Is message length short form (one octet) or long form? */ andre@0: if ((firstData[1] & 0x80) != 0) { andre@0: sizeOfLength = firstData[1] & 0x7F; andre@0: for (dindex = 0; dindex < sizeOfLength; dindex++) { andre@0: firstLen = (firstLen << 8) + firstData[dindex + 2]; andre@0: } andre@0: } else { andre@0: firstLen = firstData[1]; andre@0: } andre@0: andre@0: /* How many bytes for the messageID? (Assume short form) */ andre@0: i = firstData[dindex + 3] + 2; andre@0: dindex += i; andre@0: firstLen -= i; andre@0: firstData = &firstData[dindex + 2]; andre@0: andre@0: /* andre@0: * In theory, we have to calculate where the second message data andre@0: * begins by checking its length encodings. But if these messages andre@0: * are equal, we can re-use the calculation we already did. If they andre@0: * are not equal, the byte comparisons will surely fail. andre@0: */ andre@0: andre@0: secondData = &secondData[dindex + 2]; andre@0: andre@0: for (i = 0; i < firstLen; i++) { andre@0: if (firstData[i] != secondData[i]) { andre@0: goto cleanup; andre@0: } andre@0: } andre@0: andre@0: *pResult = PKIX_TRUE; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_RegisterSelf andre@0: * DESCRIPTION: andre@0: * Registers PKIX_LDAPRESPONSE_TYPE and its related functions with andre@0: * systemClasses[] andre@0: * PARAMETERS: andre@0: * "plContext" andre@0: * Platform-specific context pointer. 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_pl_LdapResponse_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(LDAPRESPONSE, "pkix_pl_LdapResponse_RegisterSelf"); andre@0: andre@0: entry.description = "LdapResponse"; andre@0: entry.objCounter = 0; andre@0: entry.typeObjectSize = sizeof(PKIX_PL_LdapResponse); andre@0: entry.destructor = pkix_pl_LdapResponse_Destroy; andre@0: entry.equalsFunction = pkix_pl_LdapResponse_Equals; andre@0: entry.hashcodeFunction = pkix_pl_LdapResponse_Hashcode; andre@0: entry.toStringFunction = NULL; andre@0: entry.comparator = NULL; andre@0: entry.duplicateFunction = pkix_duplicateImmutable; andre@0: andre@0: systemClasses[PKIX_LDAPRESPONSE_TYPE] = entry; andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* --Public-Functions------------------------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_Create andre@0: * DESCRIPTION: andre@0: * andre@0: * This function creates an LdapResponse for the LDAPMessageType provided in andre@0: * "responseType" and a buffer capacity provided by "totalLength". It copies andre@0: * into its buffer either "totalLength" or "bytesAvailable" bytes, whichever andre@0: * is less, from the buffer pointed to by "partialData", storing the number of andre@0: * bytes copied at "pBytesConsumed" and storing the address of the LdapResponse andre@0: * at "pLdapResponse". andre@0: * andre@0: * If a message is complete in a single I/O buffer, the LdapResponse will be andre@0: * complete when this function returns. If the message carries over into andre@0: * additional buffers, their contents will be added to the LdapResponse by andre@0: * susequent calls to pkix_pl_LdapResponse_Append. andre@0: * andre@0: * PARAMETERS andre@0: * "responseType" andre@0: * The value of the message type (LDAP_SEARCHRESPONSEENTRY_TYPE or andre@0: * LDAP_SEARCHRESPONSERESULT_TYPE) for the LdapResponse being created andre@0: * "totalLength" andre@0: * The UInt32 value for the total length of the encoded message to be andre@0: * stored in the LdapResponse andre@0: * "bytesAvailable" andre@0: * The UInt32 value for the number of bytes of data available in the andre@0: * current buffer. andre@0: * "partialData" andre@0: * The address from which data is to be copied. andre@0: * "pBytesConsumed" andre@0: * The address at which is stored the UInt32 number of bytes taken from the andre@0: * current buffer. If this number is less than "bytesAvailable", then bytes andre@0: * remain in the buffer for the next LdapResponse. Must be non-NULL. andre@0: * "pLdapResponse" andre@0: * The address where the created LdapResponse is stored. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an LdapResponse Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_LdapResponse_Create( andre@0: LDAPMessageType responseType, andre@0: PKIX_UInt32 totalLength, andre@0: PKIX_UInt32 bytesAvailable, andre@0: void *partialData, andre@0: PKIX_UInt32 *pBytesConsumed, andre@0: PKIX_PL_LdapResponse **pLdapResponse, andre@0: void *plContext) andre@0: { andre@0: PKIX_UInt32 bytesConsumed = 0; andre@0: PKIX_PL_LdapResponse *ldapResponse = NULL; andre@0: void *data = NULL; andre@0: andre@0: PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Create"); andre@0: PKIX_NULLCHECK_ONE(pLdapResponse); andre@0: andre@0: if (bytesAvailable <= totalLength) { andre@0: bytesConsumed = bytesAvailable; andre@0: } else { andre@0: bytesConsumed = totalLength; andre@0: } andre@0: andre@0: /* create a PKIX_PL_LdapResponse object */ andre@0: PKIX_CHECK(PKIX_PL_Object_Alloc andre@0: (PKIX_LDAPRESPONSE_TYPE, andre@0: sizeof (PKIX_PL_LdapResponse), andre@0: (PKIX_PL_Object **)&ldapResponse, andre@0: plContext), andre@0: PKIX_COULDNOTCREATEOBJECT); andre@0: andre@0: ldapResponse->decoded.protocolOp.selector = responseType; andre@0: ldapResponse->totalLength = totalLength; andre@0: ldapResponse->partialLength = bytesConsumed; andre@0: andre@0: if (totalLength != 0){ andre@0: /* Alloc space for array */ andre@0: PKIX_NULLCHECK_ONE(partialData); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Malloc andre@0: (totalLength, andre@0: &data, andre@0: plContext), andre@0: PKIX_MALLOCFAILED); andre@0: andre@0: PKIX_PL_NSSCALL andre@0: (LDAPRESPONSE, andre@0: PORT_Memcpy, andre@0: (data, partialData, bytesConsumed)); andre@0: } andre@0: andre@0: ldapResponse->derEncoded.type = siBuffer; andre@0: ldapResponse->derEncoded.data = data; andre@0: ldapResponse->derEncoded.len = totalLength; andre@0: *pBytesConsumed = bytesConsumed; andre@0: *pLdapResponse = ldapResponse; andre@0: andre@0: cleanup: andre@0: andre@0: if (PKIX_ERROR_RECEIVED){ andre@0: PKIX_DECREF(ldapResponse); andre@0: } andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_Append andre@0: * DESCRIPTION: andre@0: * andre@0: * This function updates the LdapResponse pointed to by "response" with up to andre@0: * "incrLength" from the buffer pointer to by "incrData", storing the number of andre@0: * bytes copied at "pBytesConsumed". andre@0: * andre@0: * PARAMETERS andre@0: * "response" andre@0: * The address of the LdapResponse being updated. Must be non-zero. andre@0: * "incrLength" andre@0: * The UInt32 value for the number of bytes of data available in the andre@0: * current buffer. andre@0: * "incrData" andre@0: * The address from which data is to be copied. andre@0: * "pBytesConsumed" andre@0: * The address at which is stored the UInt32 number of bytes taken from the andre@0: * current buffer. If this number is less than "incrLength", then bytes andre@0: * remain in the buffer for the next LdapResponse. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an LdapResponse Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_LdapResponse_Append( andre@0: PKIX_PL_LdapResponse *response, andre@0: PKIX_UInt32 incrLength, andre@0: void *incrData, andre@0: PKIX_UInt32 *pBytesConsumed, andre@0: void *plContext) andre@0: { andre@0: PKIX_UInt32 newPartialLength = 0; andre@0: PKIX_UInt32 bytesConsumed = 0; andre@0: void *dest = NULL; andre@0: andre@0: PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Append"); andre@0: PKIX_NULLCHECK_TWO(response, pBytesConsumed); andre@0: andre@0: if (incrLength > 0) { andre@0: andre@0: /* Calculate how many bytes we have room for. */ andre@0: bytesConsumed = andre@0: response->totalLength - response->partialLength; andre@0: andre@0: if (bytesConsumed > incrLength) { andre@0: bytesConsumed = incrLength; andre@0: } andre@0: andre@0: newPartialLength = response->partialLength + bytesConsumed; andre@0: andre@0: PKIX_NULLCHECK_ONE(incrData); andre@0: andre@0: dest = &(((char *)response->derEncoded.data)[ andre@0: response->partialLength]); andre@0: andre@0: PKIX_PL_NSSCALL andre@0: (LDAPRESPONSE, andre@0: PORT_Memcpy, andre@0: (dest, incrData, bytesConsumed)); andre@0: andre@0: response->partialLength = newPartialLength; andre@0: } andre@0: andre@0: *pBytesConsumed = bytesConsumed; andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_IsComplete andre@0: * DESCRIPTION: andre@0: * andre@0: * This function determines whether the LdapResponse pointed to by "response" andre@0: * contains all the data called for by the "totalLength" parameter provided andre@0: * when it was created, storing PKIX_TRUE at "pIsComplete" if so, and andre@0: * PKIX_FALSE otherwise. andre@0: * andre@0: * PARAMETERS andre@0: * "response" andre@0: * The address of the LdapResponse being evaluaTED. Must be non-zero. andre@0: * "incrLength" andre@0: * The UInt32 value for the number of bytes of data available in the andre@0: * current buffer. andre@0: * "incrData" andre@0: * The address from which data is to be copied. andre@0: * "pIsComplete" andre@0: * The address at which is stored the Boolean indication of whether the andre@0: * LdapResponse is complete. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an LdapResponse Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_LdapResponse_IsComplete( andre@0: PKIX_PL_LdapResponse *response, andre@0: PKIX_Boolean *pIsComplete, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_IsComplete"); andre@0: PKIX_NULLCHECK_TWO(response, pIsComplete); andre@0: andre@0: if (response->totalLength == response->partialLength) { andre@0: *pIsComplete = PKIX_TRUE; andre@0: } else { andre@0: *pIsComplete = PKIX_FALSE; andre@0: } andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_Decode andre@0: * DESCRIPTION: andre@0: * andre@0: * This function decodes the DER data contained in the LdapResponse pointed to andre@0: * by "response", using the arena pointed to by "arena", and storing at andre@0: * "pStatus" SECSuccess if the decoding was successful and SECFailure andre@0: * otherwise. The decoded message is stored in an element of "response". andre@0: * andre@0: * PARAMETERS andre@0: * "arena" andre@0: * The address of the PLArenaPool to be used in the decoding. Must be andre@0: * non-NULL. andre@0: * "response" andre@0: * The address of the LdapResponse whose DER data is to be decoded. Must andre@0: * be non-NULL. andre@0: * "pStatus" andre@0: * The address at which is stored the status from the decoding, SECSuccess andre@0: * if successful, SECFailure otherwise. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an LdapResponse Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_LdapResponse_Decode( andre@0: PLArenaPool *arena, andre@0: PKIX_PL_LdapResponse *response, andre@0: SECStatus *pStatus, andre@0: void *plContext) andre@0: { andre@0: LDAPMessage *msg; andre@0: SECStatus rv = SECFailure; andre@0: andre@0: PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Decode"); andre@0: PKIX_NULLCHECK_THREE(arena, response, pStatus); andre@0: andre@0: if (response->totalLength != response->partialLength) { andre@0: PKIX_ERROR(PKIX_ATTEMPTTODECODEANINCOMPLETERESPONSE); andre@0: } andre@0: andre@0: msg = &(response->decoded); andre@0: andre@0: PKIX_PL_NSSCALL andre@0: (LDAPRESPONSE, PORT_Memset, (msg, 0, sizeof (LDAPMessage))); andre@0: andre@0: PKIX_PL_NSSCALLRV(LDAPRESPONSE, rv, SEC_ASN1DecodeItem, andre@0: (NULL, msg, PKIX_PL_LDAPMessageTemplate, &(response->derEncoded))); andre@0: andre@0: *pStatus = rv; andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_GetMessage andre@0: * DESCRIPTION: andre@0: * andre@0: * This function obtains the decoded message from the LdapResponse pointed to andre@0: * by "response", storing the result at "pMessage". andre@0: * andre@0: * PARAMETERS andre@0: * "response" andre@0: * The address of the LdapResponse whose decoded message is to be andre@0: * retrieved. Must be non-NULL. andre@0: * "pMessage" andre@0: * The address at which is stored the address of the decoded message. Must andre@0: * be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_LdapResponse_GetMessage( andre@0: PKIX_PL_LdapResponse *response, andre@0: LDAPMessage **pMessage, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetMessage"); andre@0: PKIX_NULLCHECK_TWO(response, pMessage); andre@0: andre@0: *pMessage = &response->decoded; andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_GetCapacity andre@0: * DESCRIPTION: andre@0: * andre@0: * This function obtains from the LdapResponse pointed to by "response" the andre@0: * number of bytes remaining to be read, based on the totalLength that was andre@0: * provided to LdapResponse_Create and the data subsequently provided to andre@0: * LdapResponse_Append, storing the result at "pMessage". andre@0: * andre@0: * PARAMETERS andre@0: * "response" andre@0: * The address of the LdapResponse whose remaining capacity is to be andre@0: * retrieved. Must be non-NULL. andre@0: * "pCapacity" andre@0: * The address at which is stored the address of the decoded message. Must andre@0: * be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an LdapResponse Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_LdapResponse_GetCapacity( andre@0: PKIX_PL_LdapResponse *response, andre@0: PKIX_UInt32 *pCapacity, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetCapacity"); andre@0: PKIX_NULLCHECK_TWO(response, pCapacity); andre@0: andre@0: *pCapacity = response->totalLength - response->partialLength; andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_GetMessageType andre@0: * DESCRIPTION: andre@0: * andre@0: * This function obtains the message type from the LdapResponse pointed to andre@0: * by "response", storing the result at "pMessageType". andre@0: * andre@0: * PARAMETERS andre@0: * "response" andre@0: * The address of the LdapResponse whose message type is to be andre@0: * retrieved. Must be non-NULL. andre@0: * "pMessageType" andre@0: * The address at which is stored the type of the response message. Must andre@0: * be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_LdapResponse_GetMessageType( andre@0: PKIX_PL_LdapResponse *response, andre@0: LDAPMessageType *pMessageType, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetMessageType"); andre@0: PKIX_NULLCHECK_TWO(response, pMessageType); andre@0: andre@0: *pMessageType = response->decoded.protocolOp.selector; andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_GetResultCode andre@0: * DESCRIPTION: andre@0: * andre@0: * This function obtains the result code from the LdapResponse pointed to andre@0: * by "response", storing the result at "pResultCode". andre@0: * andre@0: * PARAMETERS andre@0: * "response" andre@0: * The address of the LdapResponse whose result code is to be andre@0: * retrieved. Must be non-NULL. andre@0: * "pResultCode" andre@0: * The address at which is stored the address of the decoded message. Must andre@0: * be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an LdapResponse Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_LdapResponse_GetResultCode( andre@0: PKIX_PL_LdapResponse *response, andre@0: LDAPResultCode *pResultCode, andre@0: void *plContext) andre@0: { andre@0: LDAPMessageType messageType = 0; andre@0: LDAPSearchResponseResult *resultMsg = NULL; andre@0: andre@0: PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetResultCode"); andre@0: PKIX_NULLCHECK_TWO(response, pResultCode); andre@0: andre@0: messageType = response->decoded.protocolOp.selector; andre@0: andre@0: if (messageType != LDAP_SEARCHRESPONSERESULT_TYPE) { andre@0: PKIX_ERROR(PKIX_GETRESULTCODECALLEDFORNONRESULTMESSAGE); andre@0: } andre@0: andre@0: resultMsg = &response->decoded.protocolOp.op.searchResponseResultMsg; andre@0: andre@0: *pResultCode = *(char *)(resultMsg->resultCode.data); andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_LdapResponse_GetAttributes andre@0: * DESCRIPTION: andre@0: * andre@0: * This function obtains the attributes from the LdapResponse pointed to andre@0: * by "response", storing the result at "pAttributes". andre@0: * andre@0: * PARAMETERS andre@0: * "response" andre@0: * The address of the LdapResponse whose decoded message is to be andre@0: * retrieved. Must be non-NULL. andre@0: * "pAttributes" andre@0: * The address at which is stored the attributes of the message. Must be andre@0: * non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an LdapResponse Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_LdapResponse_GetAttributes( andre@0: PKIX_PL_LdapResponse *response, andre@0: LDAPSearchResponseAttr ***pAttributes, andre@0: void *plContext) andre@0: { andre@0: LDAPMessageType messageType = 0; andre@0: andre@0: PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetResultCode"); andre@0: PKIX_NULLCHECK_TWO(response, pAttributes); andre@0: andre@0: messageType = response->decoded.protocolOp.selector; andre@0: andre@0: if (messageType != LDAP_SEARCHRESPONSEENTRY_TYPE) { andre@0: PKIX_ERROR(PKIX_GETATTRIBUTESCALLEDFORNONENTRYMESSAGE); andre@0: } andre@0: andre@0: *pAttributes = response-> andre@0: decoded.protocolOp.op.searchResponseEntryMsg.attributes; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(LDAPRESPONSE); andre@0: }