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 <fcntl.h>
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: }