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