Mercurial > trustbridge > nss-cmake-static
view nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
line wrap: on
line source
/* 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_pl_ldapdefaultclient.c * * LDAPDefaultClient Function Definitions * */ /* We can't decode the length of a message without at least this many bytes */ #define MINIMUM_MSG_LENGTH 5 #include "pkix_pl_ldapdefaultclient.h" /* --Private-LdapDefaultClient-Message-Building-Functions---------------- */ /* * FUNCTION: pkix_pl_LdapDefaultClient_MakeBind * DESCRIPTION: * * This function creates and encodes a Bind message, using the arena pointed * to by "arena", the version number contained in "versionData", the * LDAPBindAPI pointed to by "bindAPI", and the messageID contained in * "msgNum", and stores a pointer to the encoded string at "pBindMsg". * * See pkix_pl_ldaptemplates.c for the ASN.1 description of a Bind message. * * This code is not used if the DefaultClient was created with a NULL pointer * supplied for the LDAPBindAPI structure. (Bind and Unbind do not seem to be * expected for anonymous Search requests.) * * PARAMETERS: * "arena" * The address of the PLArenaPool used in encoding the message. Must be * non-NULL. * "versionData" * The Int32 containing the version number to be encoded in the Bind * message. * "bindAPI" * The address of the LDAPBindAPI to be encoded in the Bind message. Must * be non-NULL. * "msgNum" * The Int32 containing the MessageID to be encoded in the Bind message. * "pBindMsg" * The address at which the encoded Bind message will be 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 a LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_MakeBind( PLArenaPool *arena, PKIX_Int32 versionData, LDAPBindAPI *bindAPI, PKIX_UInt32 msgNum, SECItem **pBindMsg, void *plContext) { LDAPMessage msg; char version = '\0'; SECItem *encoded = NULL; PKIX_UInt32 len = 0; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeBind"); PKIX_NULLCHECK_TWO(arena, pBindMsg); PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset, (&msg, 0, sizeof (LDAPMessage))); version = (char)versionData; msg.messageID.type = siUnsignedInteger; msg.messageID.data = (void*)&msgNum; msg.messageID.len = sizeof (msgNum); msg.protocolOp.selector = LDAP_BIND_TYPE; msg.protocolOp.op.bindMsg.version.type = siUnsignedInteger; msg.protocolOp.op.bindMsg.version.data = (void *)&version; msg.protocolOp.op.bindMsg.version.len = sizeof (char); /* * XXX At present we only know how to handle anonymous requests (no * authentication), and we are guessing how to do simple authentication. * This section will need to be revised and extended when other * authentication is needed. */ if (bindAPI->selector == SIMPLE_AUTH) { msg.protocolOp.op.bindMsg.bindName.type = siAsciiString; msg.protocolOp.op.bindMsg.bindName.data = (void *)bindAPI->chooser.simple.bindName; len = PL_strlen(bindAPI->chooser.simple.bindName); msg.protocolOp.op.bindMsg.bindName.len = len; msg.protocolOp.op.bindMsg.authentication.type = siAsciiString; msg.protocolOp.op.bindMsg.authentication.data = (void *)bindAPI->chooser.simple.authentication; len = PL_strlen(bindAPI->chooser.simple.authentication); msg.protocolOp.op.bindMsg.authentication.len = len; } PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem, (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate)); if (!encoded) { PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); } *pBindMsg = encoded; cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_MakeUnbind * DESCRIPTION: * * This function creates and encodes a Unbind message, using the arena pointed * to by "arena" and the messageID contained in "msgNum", and stores a pointer * to the encoded string at "pUnbindMsg". * * See pkix_pl_ldaptemplates.c for the ASN.1 description of an Unbind message. * * This code is not used if the DefaultClient was created with a NULL pointer * supplied for the LDAPBindAPI structure. (Bind and Unbind do not seem to be * expected for anonymous Search requests.) * * PARAMETERS: * "arena" * The address of the PLArenaPool used in encoding the message. Must be * non-NULL. * "msgNum" * The Int32 containing the MessageID to be encoded in the Unbind message. * "pUnbindMsg" * The address at which the encoded Unbind message will be 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 a LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_MakeUnbind( PLArenaPool *arena, PKIX_UInt32 msgNum, SECItem **pUnbindMsg, void *plContext) { LDAPMessage msg; SECItem *encoded = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeUnbind"); PKIX_NULLCHECK_TWO(arena, pUnbindMsg); PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset, (&msg, 0, sizeof (LDAPMessage))); msg.messageID.type = siUnsignedInteger; msg.messageID.data = (void*)&msgNum; msg.messageID.len = sizeof (msgNum); msg.protocolOp.selector = LDAP_UNBIND_TYPE; msg.protocolOp.op.unbindMsg.dummy.type = siBuffer; msg.protocolOp.op.unbindMsg.dummy.data = NULL; msg.protocolOp.op.unbindMsg.dummy.len = 0; PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem, (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate)); if (!encoded) { PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); } *pUnbindMsg = encoded; cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_MakeAbandon * DESCRIPTION: * * This function creates and encodes a Abandon message, using the arena pointed * to by "arena" and the messageID contained in "msgNum", and stores a pointer * to the encoded string at "pAbandonMsg". * * See pkix_pl_ldaptemplates.c for the ASN.1 description of an Abandon message. * * PARAMETERS: * "arena" * The address of the PLArenaPool used in encoding the message. Must be * non-NULL. * "msgNum" * The Int32 containing the MessageID to be encoded in the Abandon message. * "pAbandonMsg" * The address at which the encoded Abandon message will be 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 a LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_MakeAbandon( PLArenaPool *arena, PKIX_UInt32 msgNum, SECItem **pAbandonMsg, void *plContext) { LDAPMessage msg; SECItem *encoded = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeAbandon"); PKIX_NULLCHECK_TWO(arena, pAbandonMsg); PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset, (&msg, 0, sizeof (LDAPMessage))); msg.messageID.type = siUnsignedInteger; msg.messageID.data = (void*)&msgNum; msg.messageID.len = sizeof (msgNum); msg.protocolOp.selector = LDAP_ABANDONREQUEST_TYPE; msg.protocolOp.op.abandonRequestMsg.messageID.type = siBuffer; msg.protocolOp.op.abandonRequestMsg.messageID.data = (void*)&msgNum; msg.protocolOp.op.abandonRequestMsg.messageID.len = sizeof (msgNum); PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem, (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate)); if (!encoded) { PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); } *pAbandonMsg = encoded; cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_DecodeBindResponse * DESCRIPTION: * * This function decodes the encoded data pointed to by "src", using the arena * pointed to by "arena", storing the decoded LDAPMessage at "pBindResponse" * and the decoding status at "pStatus". * * PARAMETERS: * "arena" * The address of the PLArenaPool to be used in decoding the message. Must * be non-NULL. * "src" * The address of the SECItem containing the DER- (or BER-)encoded string. * Must be non-NULL. * "pBindResponse" * The address at which the LDAPMessage is stored, if the decoding is * successful (the returned status is SECSuccess). Must be non-NULL. * "pStatus" * The address at which the decoding status 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 a LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_DecodeBindResponse( PLArenaPool *arena, SECItem *src, LDAPMessage *pBindResponse, SECStatus *pStatus, void *plContext) { SECStatus rv = SECFailure; LDAPMessage response; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_DecodeBindResponse"); PKIX_NULLCHECK_FOUR(arena, src, pBindResponse, pStatus); PKIX_PL_NSSCALL (LDAPDEFAULTCLIENT, PORT_Memset, (&response, 0, sizeof (LDAPMessage))); PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, rv, SEC_ASN1DecodeItem, (arena, &response, PKIX_PL_LDAPMessageTemplate, src)); if (rv == SECSuccess) { *pBindResponse = response; } *pStatus = rv; PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_VerifyBindResponse * DESCRIPTION: * * This function verifies that the contents of the message in the rcvbuf of * the LdapDefaultClient object pointed to by "client", and whose length is * provided by "buflen", is a response to a successful Bind. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "buflen" * The value of the number of bytes in the receive buffer. * "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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_VerifyBindResponse( PKIX_PL_LdapDefaultClient *client, PKIX_UInt32 bufLen, void *plContext) { SECItem decode = {siBuffer, NULL, 0}; SECStatus rv = SECFailure; LDAPMessage msg; LDAPBindResponse *ldapBindResponse = NULL; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_VerifyBindResponse"); PKIX_NULLCHECK_TWO(client, client->rcvBuf); decode.data = (void *)(client->rcvBuf); decode.len = bufLen; PKIX_CHECK(pkix_pl_LdapDefaultClient_DecodeBindResponse (client->arena, &decode, &msg, &rv, plContext), PKIX_LDAPDEFAULTCLIENTDECODEBINDRESPONSEFAILED); if (rv == SECSuccess) { ldapBindResponse = &msg.protocolOp.op.bindResponseMsg; if (*(ldapBindResponse->resultCode.data) == SUCCESS) { client->connectStatus = BOUND; } else { PKIX_ERROR(PKIX_BINDREJECTEDBYSERVER); } } else { PKIX_ERROR(PKIX_CANTDECODEBINDRESPONSEFROMSERVER); } cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_RecvCheckComplete * DESCRIPTION: * * This function determines whether the current response in the * LdapDefaultClient pointed to by "client" is complete, in the sense that all * bytes required to satisfy the message length field in the encoding have been * received. If so, the pointer to input data is updated to reflect the number * of bytes consumed, provided by "bytesProcessed". The state machine flag * pointed to by "pKeepGoing" is updated to indicate whether processing can * continue without further input. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "bytesProcessed" * The UInt32 value of the number of bytes consumed from the current * buffer. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_RecvCheckComplete( PKIX_PL_LdapDefaultClient *client, PKIX_UInt32 bytesProcessed, PKIX_Boolean *pKeepGoing, void *plContext) { PKIX_Boolean complete = PKIX_FALSE; SECStatus rv = SECFailure; LDAPMessageType messageType = 0; LDAPResultCode resultCode = 0; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvCheckComplete"); PKIX_NULLCHECK_TWO(client, pKeepGoing); PKIX_CHECK(pkix_pl_LdapResponse_IsComplete (client->currentResponse, &complete, plContext), PKIX_LDAPRESPONSEISCOMPLETEFAILED); if (complete) { PKIX_CHECK(pkix_pl_LdapResponse_Decode (client->arena, client->currentResponse, &rv, plContext), PKIX_LDAPRESPONSEDECODEFAILED); if (rv != SECSuccess) { PKIX_ERROR(PKIX_CANTDECODESEARCHRESPONSEFROMSERVER); } PKIX_CHECK(pkix_pl_LdapResponse_GetMessageType (client->currentResponse, &messageType, plContext), PKIX_LDAPRESPONSEGETMESSAGETYPEFAILED); if (messageType == LDAP_SEARCHRESPONSEENTRY_TYPE) { if (client->entriesFound == NULL) { PKIX_CHECK(PKIX_List_Create (&(client->entriesFound), plContext), PKIX_LISTCREATEFAILED); } PKIX_CHECK(PKIX_List_AppendItem (client->entriesFound, (PKIX_PL_Object *)client->currentResponse, plContext), PKIX_LISTAPPENDITEMFAILED); PKIX_DECREF(client->currentResponse); /* current receive buffer empty? */ if (client->currentBytesAvailable == 0) { client->connectStatus = RECV; *pKeepGoing = PKIX_TRUE; } else { client->connectStatus = RECV_INITIAL; client->currentInPtr = &((char *) (client->currentInPtr))[bytesProcessed]; *pKeepGoing = PKIX_TRUE; } } else if (messageType == LDAP_SEARCHRESPONSERESULT_TYPE) { PKIX_CHECK(pkix_pl_LdapResponse_GetResultCode (client->currentResponse, &resultCode, plContext), PKIX_LDAPRESPONSEGETRESULTCODEFAILED); if ((client->entriesFound == NULL) && ((resultCode == SUCCESS) || (resultCode == NOSUCHOBJECT))) { PKIX_CHECK(PKIX_List_Create (&(client->entriesFound), plContext), PKIX_LISTCREATEFAILED); } else if (resultCode == SUCCESS) { PKIX_CHECK(PKIX_List_SetImmutable (client->entriesFound, plContext), PKIX_LISTSETIMMUTABLEFAILED); PKIX_CHECK(PKIX_PL_HashTable_Add (client->cachePtr, (PKIX_PL_Object *)client->currentRequest, (PKIX_PL_Object *)client->entriesFound, plContext), PKIX_HASHTABLEADDFAILED); } else { PKIX_ERROR(PKIX_UNEXPECTEDRESULTCODEINRESPONSE); } client->connectStatus = BOUND; *pKeepGoing = PKIX_FALSE; PKIX_DECREF(client->currentResponse); } else { PKIX_ERROR(PKIX_SEARCHRESPONSEPACKETOFUNKNOWNTYPE); } } else { client->connectStatus = RECV; *pKeepGoing = PKIX_TRUE; } cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* --Private-LdapDefaultClient-Object-Functions------------------------- */ static PKIX_Error * pkix_pl_LdapDefaultClient_InitiateRequest( PKIX_PL_LdapClient *client, LDAPRequestParams *requestParams, void **pPollDesc, PKIX_List **pResponse, void *plContext); static PKIX_Error * pkix_pl_LdapDefaultClient_ResumeRequest( PKIX_PL_LdapClient *client, void **pPollDesc, PKIX_List **pResponse, void *plContext); /* * FUNCTION: pkix_pl_LdapDefaultClient_CreateHelper * DESCRIPTION: * * This function creates a new LdapDefaultClient using the Socket pointed to * by "socket", the PRIntervalTime pointed to by "timeout", and the * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient". * * A value of zero for "timeout" means the LDAPClient will use non-blocking * I/O. * * PARAMETERS: * "socket" * Address of the Socket to be used for the client. Must be non-NULL. * "bindAPI" * The address of the LDAPBindAPI containing the Bind information to be * encoded in the Bind message. * "pClient" * The address at which the created LdapDefaultClient is to be 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 a LdapDefaultClient 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_LdapDefaultClient_CreateHelper( PKIX_PL_Socket *socket, LDAPBindAPI *bindAPI, PKIX_PL_LdapDefaultClient **pClient, void *plContext) { PKIX_PL_HashTable *ht; PKIX_PL_LdapDefaultClient *ldapDefaultClient = NULL; PKIX_PL_Socket_Callback *callbackList; PRFileDesc *fileDesc = NULL; PLArenaPool *arena = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_CreateHelper"); PKIX_NULLCHECK_TWO(socket, pClient); PKIX_CHECK(PKIX_PL_Object_Alloc (PKIX_LDAPDEFAULTCLIENT_TYPE, sizeof (PKIX_PL_LdapDefaultClient), (PKIX_PL_Object **)&ldapDefaultClient, plContext), PKIX_COULDNOTCREATELDAPDEFAULTCLIENTOBJECT); ldapDefaultClient->vtable.initiateFcn = pkix_pl_LdapDefaultClient_InitiateRequest; ldapDefaultClient->vtable.resumeFcn = pkix_pl_LdapDefaultClient_ResumeRequest; PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc (socket, &fileDesc, plContext), PKIX_SOCKETGETPRFILEDESCFAILED); ldapDefaultClient->pollDesc.fd = fileDesc; ldapDefaultClient->pollDesc.in_flags = 0; ldapDefaultClient->pollDesc.out_flags = 0; ldapDefaultClient->bindAPI = bindAPI; PKIX_CHECK(PKIX_PL_HashTable_Create (LDAP_CACHEBUCKETS, 0, &ht, plContext), PKIX_HASHTABLECREATEFAILED); ldapDefaultClient->cachePtr = ht; PKIX_CHECK(pkix_pl_Socket_GetCallbackList (socket, &callbackList, plContext), PKIX_SOCKETGETCALLBACKLISTFAILED); ldapDefaultClient->callbackList = callbackList; PKIX_INCREF(socket); ldapDefaultClient->clientSocket = socket; ldapDefaultClient->messageID = 0; ldapDefaultClient->bindAPI = bindAPI; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY); } ldapDefaultClient->arena = arena; ldapDefaultClient->sendBuf = NULL; ldapDefaultClient->bytesToWrite = 0; PKIX_CHECK(PKIX_PL_Malloc (RCVBUFSIZE, &ldapDefaultClient->rcvBuf, plContext), PKIX_MALLOCFAILED); ldapDefaultClient->capacity = RCVBUFSIZE; ldapDefaultClient->bindMsg = NULL; ldapDefaultClient->bindMsgLen = 0; ldapDefaultClient->entriesFound = NULL; ldapDefaultClient->currentRequest = NULL; ldapDefaultClient->currentResponse = NULL; *pClient = ldapDefaultClient; cleanup: if (PKIX_ERROR_RECEIVED) { PKIX_DECREF(ldapDefaultClient); } PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: PKIX_PL_LdapDefaultClient_Create * DESCRIPTION: * * This function creates a new LdapDefaultClient using the PRNetAddr pointed to * by "sockaddr", the PRIntervalTime pointed to by "timeout", and the * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient". * * A value of zero for "timeout" means the LDAPClient will use non-blocking * I/O. * * PARAMETERS: * "sockaddr" * Address of the PRNetAddr to be used for the socket connection. Must be * non-NULL. * "timeout" * The PRIntervalTime to be used in I/O requests for this client. * "bindAPI" * The address of the LDAPBindAPI containing the Bind information to be * encoded in the Bind message. * "pClient" * The address at which the created LdapDefaultClient is to be 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 a LdapDefaultClient 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_LdapDefaultClient_Create( PRNetAddr *sockaddr, PRIntervalTime timeout, LDAPBindAPI *bindAPI, PKIX_PL_LdapDefaultClient **pClient, void *plContext) { PRErrorCode status = 0; PKIX_PL_Socket *socket = NULL; PKIX_PL_LdapDefaultClient *client = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "PKIX_PL_LdapDefaultClient_Create"); PKIX_NULLCHECK_TWO(sockaddr, pClient); PKIX_CHECK(pkix_pl_Socket_Create (PKIX_FALSE, timeout, sockaddr, &status, &socket, plContext), PKIX_SOCKETCREATEFAILED); PKIX_CHECK(pkix_pl_LdapDefaultClient_CreateHelper (socket, bindAPI, &client, plContext), PKIX_LDAPDEFAULTCLIENTCREATEHELPERFAILED); /* Did Socket_Create say the connection was made? */ if (status == 0) { if (client->bindAPI != NULL) { client->connectStatus = CONNECTED; } else { client->connectStatus = BOUND; } } else { client->connectStatus = CONNECT_PENDING; } *pClient = client; cleanup: if (PKIX_ERROR_RECEIVED) { PKIX_DECREF(client); } PKIX_DECREF(socket); PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: PKIX_PL_LdapDefaultClient_CreateByName * DESCRIPTION: * * This function creates a new LdapDefaultClient using the hostname pointed to * by "hostname", the PRIntervalTime pointed to by "timeout", and the * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient". * * A value of zero for "timeout" means the LDAPClient will use non-blocking * I/O. * * PARAMETERS: * "hostname" * Address of the hostname to be used for the socket connection. Must be * non-NULL. * "timeout" * The PRIntervalTime to be used in I/O requests for this client. * "bindAPI" * The address of the LDAPBindAPI containing the Bind information to be * encoded in the Bind message. * "pClient" * The address at which the created LdapDefaultClient is to be 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 a LdapDefaultClient 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_LdapDefaultClient_CreateByName( char *hostname, PRIntervalTime timeout, LDAPBindAPI *bindAPI, PKIX_PL_LdapDefaultClient **pClient, void *plContext) { PRErrorCode status = 0; PKIX_PL_Socket *socket = NULL; PKIX_PL_LdapDefaultClient *client = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "PKIX_PL_LdapDefaultClient_CreateByName"); PKIX_NULLCHECK_TWO(hostname, pClient); PKIX_CHECK(pkix_pl_Socket_CreateByName (PKIX_FALSE, timeout, hostname, &status, &socket, plContext), PKIX_SOCKETCREATEBYNAMEFAILED); PKIX_CHECK(pkix_pl_LdapDefaultClient_CreateHelper (socket, bindAPI, &client, plContext), PKIX_LDAPDEFAULTCLIENTCREATEHELPERFAILED); /* Did Socket_Create say the connection was made? */ if (status == 0) { if (client->bindAPI != NULL) { client->connectStatus = CONNECTED; } else { client->connectStatus = BOUND; } } else { client->connectStatus = CONNECT_PENDING; } *pClient = client; cleanup: if (PKIX_ERROR_RECEIVED) { PKIX_DECREF(client); } PKIX_DECREF(socket); PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_Destroy * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_LdapDefaultClient_Destroy( PKIX_PL_Object *object, void *plContext) { PKIX_Int32 bytesWritten = 0; PKIX_PL_LdapDefaultClient *client = NULL; PKIX_PL_Socket_Callback *callbackList = NULL; SECItem *encoded = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Destroy"); PKIX_NULLCHECK_ONE(object); PKIX_CHECK(pkix_CheckType (object, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext), PKIX_OBJECTNOTANLDAPDEFAULTCLIENT); client = (PKIX_PL_LdapDefaultClient *)object; switch (client->connectStatus) { case CONNECT_PENDING: break; case CONNECTED: case BIND_PENDING: case BIND_RESPONSE: case BIND_RESPONSE_PENDING: case BOUND: case SEND_PENDING: case RECV: case RECV_PENDING: case RECV_INITIAL: case RECV_NONINITIAL: case ABANDON_PENDING: if (client->bindAPI != NULL) { PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeUnbind (client->arena, ++(client->messageID), &encoded, plContext), PKIX_LDAPDEFAULTCLIENTMAKEUNBINDFAILED); callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->sendCallback (client->clientSocket, encoded->data, encoded->len, &bytesWritten, plContext), PKIX_SOCKETSENDFAILED); } break; default: PKIX_ERROR(PKIX_LDAPDEFAULTCLIENTINILLEGALSTATE); } PKIX_DECREF(client->cachePtr); PKIX_DECREF(client->clientSocket); PKIX_DECREF(client->entriesFound); PKIX_DECREF(client->currentRequest); PKIX_DECREF(client->currentResponse); PKIX_CHECK(PKIX_PL_Free (client->rcvBuf, plContext), PKIX_FREEFAILED); PKIX_PL_NSSCALL (LDAPDEFAULTCLIENT, PORT_FreeArena, (client->arena, PR_FALSE)); cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_Hashcode * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_LdapDefaultClient_Hashcode( PKIX_PL_Object *object, PKIX_UInt32 *pHashcode, void *plContext) { PKIX_PL_LdapDefaultClient *ldapDefaultClient = NULL; PKIX_UInt32 tempHash = 0; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Hashcode"); PKIX_NULLCHECK_TWO(object, pHashcode); PKIX_CHECK(pkix_CheckType (object, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext), PKIX_OBJECTNOTANLDAPDEFAULTCLIENT); ldapDefaultClient = (PKIX_PL_LdapDefaultClient *)object; PKIX_CHECK(PKIX_PL_Object_Hashcode ((PKIX_PL_Object *)ldapDefaultClient->clientSocket, &tempHash, plContext), PKIX_SOCKETHASHCODEFAILED); if (ldapDefaultClient->bindAPI != NULL) { tempHash = (tempHash << 7) + ldapDefaultClient->bindAPI->selector; } *pHashcode = tempHash; cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_Equals * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_LdapDefaultClient_Equals( PKIX_PL_Object *firstObject, PKIX_PL_Object *secondObject, PKIX_Int32 *pResult, void *plContext) { PKIX_PL_LdapDefaultClient *firstClientContext = NULL; PKIX_PL_LdapDefaultClient *secondClientContext = NULL; PKIX_Int32 compare = 0; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Equals"); PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); *pResult = PKIX_FALSE; PKIX_CHECK(pkix_CheckTypes (firstObject, secondObject, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext), PKIX_OBJECTNOTANLDAPDEFAULTCLIENT); firstClientContext = (PKIX_PL_LdapDefaultClient *)firstObject; secondClientContext = (PKIX_PL_LdapDefaultClient *)secondObject; if (firstClientContext == secondClientContext) { *pResult = PKIX_TRUE; goto cleanup; } PKIX_CHECK(PKIX_PL_Object_Equals ((PKIX_PL_Object *)firstClientContext->clientSocket, (PKIX_PL_Object *)secondClientContext->clientSocket, &compare, plContext), PKIX_SOCKETEQUALSFAILED); if (!compare) { goto cleanup; } if (PKIX_EXACTLY_ONE_NULL (firstClientContext->bindAPI, secondClientContext->bindAPI)) { goto cleanup; } if (firstClientContext->bindAPI) { if (firstClientContext->bindAPI->selector != secondClientContext->bindAPI->selector) { goto cleanup; } } *pResult = PKIX_TRUE; cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_RegisterSelf * * DESCRIPTION: * Registers PKIX_PL_LDAPDEFAULTCLIENT_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_pl_LdapDefaultClient_RegisterSelf(void *plContext) { extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; pkix_ClassTable_Entry entry; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RegisterSelf"); entry.description = "LdapDefaultClient"; entry.objCounter = 0; entry.typeObjectSize = sizeof(PKIX_PL_LdapDefaultClient); entry.destructor = pkix_pl_LdapDefaultClient_Destroy; entry.equalsFunction = pkix_pl_LdapDefaultClient_Equals; entry.hashcodeFunction = pkix_pl_LdapDefaultClient_Hashcode; entry.toStringFunction = NULL; entry.comparator = NULL; entry.duplicateFunction = NULL; systemClasses[PKIX_LDAPDEFAULTCLIENT_TYPE] = entry; PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_GetPollDesc * DESCRIPTION: * * This function retrieves the PRPollDesc from the LdapDefaultClient * pointed to by "context" and stores the address at "pPollDesc". * * PARAMETERS: * "context" * The LdapDefaultClient whose PRPollDesc is desired. Must be non-NULL. * "pPollDesc" * Address where PRPollDesc will be 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 a Fatal Error if the function fails in an unrecoverable way. */ PKIX_Error * pkix_pl_LdapDefaultClient_GetPollDesc( PKIX_PL_LdapDefaultClient *context, PRPollDesc **pPollDesc, void *plContext) { PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_GetPollDesc"); PKIX_NULLCHECK_TWO(context, pPollDesc); *pPollDesc = &(context->pollDesc); PKIX_RETURN(LDAPDEFAULTCLIENT); } /* --Private-Ldap-CertStore-I/O-Functions---------------------------- */ /* * FUNCTION: pkix_pl_LdapDefaultClient_ConnectContinue * DESCRIPTION: * * This function determines whether a socket Connect initiated earlier for the * CertStore embodied in the LdapDefaultClient "client" has completed, and * stores in "pKeepGoing" a flag indicating whether processing can continue * without further input. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_ConnectContinue( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, void *plContext) { PKIX_PL_Socket_Callback *callbackList; PRErrorCode status; PKIX_Boolean keepGoing = PKIX_FALSE; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_ConnectContinue"); PKIX_NULLCHECK_ONE(client); callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->connectcontinueCallback (client->clientSocket, &status, plContext), PKIX_SOCKETCONNECTCONTINUEFAILED); if (status == 0) { if (client->bindAPI != NULL) { client->connectStatus = CONNECTED; } else { client->connectStatus = BOUND; } keepGoing = PKIX_FALSE; } else if (status != PR_IN_PROGRESS_ERROR) { PKIX_ERROR(PKIX_UNEXPECTEDERRORINESTABLISHINGCONNECTION); } PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)client, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); *pKeepGoing = keepGoing; cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_Bind * DESCRIPTION: * * This function creates and sends the LDAP-protocol Bind message for the * CertStore embodied in the LdapDefaultClient "client", and stores in * "pKeepGoing" a flag indicating whether processing can continue without * further input. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_Bind( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, void *plContext) { SECItem *encoded = NULL; PKIX_Int32 bytesWritten = 0; PKIX_PL_Socket_Callback *callbackList; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Bind"); PKIX_NULLCHECK_ONE(client); /* if we have not yet constructed the BIND message, build it now */ if (!(client->bindMsg)) { PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeBind (client->arena, 3, client->bindAPI, client->messageID, &encoded, plContext), PKIX_LDAPDEFAULTCLIENTMAKEBINDFAILED); client->bindMsg = encoded->data; client->bindMsgLen = encoded->len; } callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->sendCallback (client->clientSocket, client->bindMsg, client->bindMsgLen, &bytesWritten, plContext), PKIX_SOCKETSENDFAILED); client->lastIO = PR_Now(); if (bytesWritten < 0) { client->connectStatus = BIND_PENDING; *pKeepGoing = PKIX_FALSE; } else { client->connectStatus = BIND_RESPONSE; *pKeepGoing = PKIX_TRUE; } PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)client, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_BindContinue * DESCRIPTION: * * This function determines whether the LDAP-protocol Bind message for the * CertStore embodied in the LdapDefaultClient "client" has completed, and * stores in "pKeepGoing" a flag indicating whether processing can continue * without further input. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient 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_LdapDefaultClient_BindContinue( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, void *plContext) { PKIX_Int32 bytesWritten = 0; PKIX_PL_Socket_Callback *callbackList = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_BindContinue"); PKIX_NULLCHECK_ONE(client); *pKeepGoing = PKIX_FALSE; callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->pollCallback (client->clientSocket, &bytesWritten, NULL, plContext), PKIX_SOCKETPOLLFAILED); /* * If the send completed we can proceed to try for the * response. If the send did not complete we will have * continue to poll. */ if (bytesWritten >= 0) { client->connectStatus = BIND_RESPONSE; PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)client, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); *pKeepGoing = PKIX_TRUE; } cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_BindResponse * DESCRIPTION: * * This function attempts to read the LDAP-protocol BindResponse message for * the CertStore embodied in the LdapDefaultClient "client", and stores in * "pKeepGoing" a flag indicating whether processing can continue without * further input. * * If a BindResponse is received with a Result code of 0 (success), we * continue with the connection. If a non-zero Result code is received, * we throw an Error. Some more sophisticated handling of that condition * might be in order in the future. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_BindResponse( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, void *plContext) { PKIX_Int32 bytesRead = 0; PKIX_PL_Socket_Callback *callbackList = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_BindResponse"); PKIX_NULLCHECK_TWO(client, client->rcvBuf); callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->recvCallback (client->clientSocket, client->rcvBuf, client->capacity, &bytesRead, plContext), PKIX_SOCKETRECVFAILED); client->lastIO = PR_Now(); if (bytesRead > 0) { PKIX_CHECK(pkix_pl_LdapDefaultClient_VerifyBindResponse (client, bytesRead, plContext), PKIX_LDAPDEFAULTCLIENTVERIFYBINDRESPONSEFAILED); /* * XXX What should we do if failure? At present if * VerifyBindResponse throws an Error, we do too. */ client->connectStatus = BOUND; } else { client->connectStatus = BIND_RESPONSE_PENDING; } PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)client, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); *pKeepGoing = PKIX_TRUE; cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_BindResponseContinue * DESCRIPTION: * * This function determines whether the LDAP-protocol BindResponse message for * the CertStore embodied in the LdapDefaultClient "client" has completed, and * stores in "pKeepGoing" a flag indicating whether processing can continue * without further input. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_BindResponseContinue( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, void *plContext) { PKIX_Int32 bytesRead = 0; PKIX_PL_Socket_Callback *callbackList = NULL; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_BindResponseContinue"); PKIX_NULLCHECK_ONE(client); callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->pollCallback (client->clientSocket, NULL, &bytesRead, plContext), PKIX_SOCKETPOLLFAILED); if (bytesRead > 0) { PKIX_CHECK(pkix_pl_LdapDefaultClient_VerifyBindResponse (client, bytesRead, plContext), PKIX_LDAPDEFAULTCLIENTVERIFYBINDRESPONSEFAILED); client->connectStatus = BOUND; PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)client, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); *pKeepGoing = PKIX_TRUE; } else { *pKeepGoing = PKIX_FALSE; } cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_Send * DESCRIPTION: * * This function creates and sends an LDAP-protocol message for the * CertStore embodied in the LdapDefaultClient "client", and stores in * "pKeepGoing" a flag indicating whether processing can continue without * further input, and at "pBytesTransferred" the number of bytes sent. * * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use * and that transmission has not completed. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * Must be non-NULL. * "pBytesTransferred" * The address at which the number of bytes sent 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 a LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_Send( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, PKIX_UInt32 *pBytesTransferred, void *plContext) { PKIX_Int32 bytesWritten = 0; PKIX_PL_Socket_Callback *callbackList = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Send"); PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred); *pKeepGoing = PKIX_FALSE; /* Do we have anything waiting to go? */ if (client->sendBuf) { callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->sendCallback (client->clientSocket, client->sendBuf, client->bytesToWrite, &bytesWritten, plContext), PKIX_SOCKETSENDFAILED); client->lastIO = PR_Now(); /* * If the send completed we can proceed to try for the * response. If the send did not complete we will have * to poll for completion later. */ if (bytesWritten >= 0) { client->sendBuf = NULL; client->connectStatus = RECV; *pKeepGoing = PKIX_TRUE; } else { *pKeepGoing = PKIX_FALSE; client->connectStatus = SEND_PENDING; } } PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)client, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); *pBytesTransferred = bytesWritten; cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_SendContinue * DESCRIPTION: * * This function determines whether the sending of the LDAP-protocol message * for the CertStore embodied in the LdapDefaultClient "client" has completed, * and stores in "pKeepGoing" a flag indicating whether processing can continue * without further input, and at "pBytesTransferred" the number of bytes sent. * * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use * and that transmission has not completed. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * Must be non-NULL. * "pBytesTransferred" * The address at which the number of bytes sent 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 a LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_SendContinue( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, PKIX_UInt32 *pBytesTransferred, void *plContext) { PKIX_Int32 bytesWritten = 0; PKIX_PL_Socket_Callback *callbackList = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_SendContinue"); PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred); *pKeepGoing = PKIX_FALSE; callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->pollCallback (client->clientSocket, &bytesWritten, NULL, plContext), PKIX_SOCKETPOLLFAILED); /* * If the send completed we can proceed to try for the * response. If the send did not complete we will have * continue to poll. */ if (bytesWritten >= 0) { client->sendBuf = NULL; client->connectStatus = RECV; PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)client, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); *pKeepGoing = PKIX_TRUE; } *pBytesTransferred = bytesWritten; cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_Recv * DESCRIPTION: * * This function receives an LDAP-protocol message for the CertStore embodied * in the LdapDefaultClient "client", and stores in "pKeepGoing" a flag * indicating whether processing can continue without further input. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_Recv( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, void *plContext) { PKIX_Int32 bytesRead = 0; PKIX_UInt32 bytesToRead = 0; PKIX_PL_Socket_Callback *callbackList = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Recv"); PKIX_NULLCHECK_THREE(client, pKeepGoing, client->rcvBuf); callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); /* * If we attempt to fill our buffer with every read, we increase * the risk of an ugly situation: one or two bytes of a new message * left over at the end of processing one message. With such a * fragment, we can't decode a byte count and so won't know how much * space to allocate for the next LdapResponse. We try to avoid that * case by reading just enough to complete the current message, unless * there will be at least MINIMUM_MSG_LENGTH bytes left over. */ if (client->currentResponse) { PKIX_CHECK(pkix_pl_LdapResponse_GetCapacity (client->currentResponse, &bytesToRead, plContext), PKIX_LDAPRESPONSEGETCAPACITYFAILED); if ((bytesToRead > client->capacity) || ((bytesToRead + MINIMUM_MSG_LENGTH) < client->capacity)) { bytesToRead = client->capacity; } } else { bytesToRead = client->capacity; } client->currentBytesAvailable = 0; PKIX_CHECK(callbackList->recvCallback (client->clientSocket, (void *)client->rcvBuf, bytesToRead, &bytesRead, plContext), PKIX_SOCKETRECVFAILED); client->currentInPtr = client->rcvBuf; client->lastIO = PR_Now(); if (bytesRead > 0) { client->currentBytesAvailable = bytesRead; client->connectStatus = RECV_INITIAL; *pKeepGoing = PKIX_TRUE; } else { client->connectStatus = RECV_PENDING; *pKeepGoing = PKIX_FALSE; } PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)client, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_RecvContinue * DESCRIPTION: * * This function determines whether the receiving of the LDAP-protocol message * for the CertStore embodied in the LdapDefaultClient "client" has completed, * and stores in "pKeepGoing" a flag indicating whether processing can continue * without further input. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_RecvContinue( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, void *plContext) { PKIX_Int32 bytesRead = 0; PKIX_PL_Socket_Callback *callbackList = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvContinue"); PKIX_NULLCHECK_TWO(client, pKeepGoing); callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->pollCallback (client->clientSocket, NULL, &bytesRead, plContext), PKIX_SOCKETPOLLFAILED); if (bytesRead > 0) { client->currentBytesAvailable += bytesRead; client->connectStatus = RECV_INITIAL; *pKeepGoing = PKIX_TRUE; PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)client, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); } else { *pKeepGoing = PKIX_FALSE; } cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_AbandonContinue * DESCRIPTION: * * This function determines whether the abandon-message request of the * LDAP-protocol message for the CertStore embodied in the LdapDefaultClient * "client" has completed, and stores in "pKeepGoing" a flag indicating whether * processing can continue without further input. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_AbandonContinue( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, void *plContext) { PKIX_Int32 bytesWritten = 0; PKIX_PL_Socket_Callback *callbackList = NULL; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_AbandonContinue"); PKIX_NULLCHECK_TWO(client, pKeepGoing); callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->pollCallback (client->clientSocket, &bytesWritten, NULL, plContext), PKIX_SOCKETPOLLFAILED); if (bytesWritten > 0) { client->connectStatus = BOUND; *pKeepGoing = PKIX_TRUE; PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)client, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); } else { *pKeepGoing = PKIX_FALSE; } cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_RecvInitial * DESCRIPTION: * * This function processes the contents of the first buffer of a received * LDAP-protocol message for the CertStore embodied in the LdapDefaultClient * "client", and stores in "pKeepGoing" a flag indicating whether processing can * continue without further input. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_RecvInitial( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, void *plContext) { unsigned char *msgBuf = NULL; unsigned char *to = NULL; unsigned char *from = NULL; PKIX_UInt32 dataIndex = 0; PKIX_UInt32 messageIdLen = 0; PKIX_UInt32 messageLength = 0; PKIX_UInt32 sizeofLength = 0; PKIX_UInt32 bytesProcessed = 0; unsigned char messageChar = 0; LDAPMessageType messageType = 0; PKIX_Int32 bytesRead = 0; PKIX_PL_Socket_Callback *callbackList = NULL; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvInitial"); PKIX_NULLCHECK_TWO(client, pKeepGoing); /* * Is there an LDAPResponse in progress? I.e., have we * already processed the tag and length at the beginning of * the message? */ if (client->currentResponse) { client->connectStatus = RECV_NONINITIAL; *pKeepGoing = PKIX_TRUE; goto cleanup; } msgBuf = client->currentInPtr; /* Do we have enough of the message to decode the message length? */ if (client->currentBytesAvailable < MINIMUM_MSG_LENGTH) { /* * No! Move these few bytes to the beginning of rcvBuf * and hang another read. */ to = (unsigned char *)client->rcvBuf; from = client->currentInPtr; for (dataIndex = 0; dataIndex < client->currentBytesAvailable; dataIndex++) { *to++ = *from++; } callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->recvCallback (client->clientSocket, (void *)to, client->capacity - client->currentBytesAvailable, &bytesRead, plContext), PKIX_SOCKETRECVFAILED); client->currentInPtr = client->rcvBuf; client->lastIO = PR_Now(); if (bytesRead <= 0) { client->connectStatus = RECV_PENDING; *pKeepGoing = PKIX_FALSE; goto cleanup; } else { client->currentBytesAvailable += bytesRead; } } /* * We have to determine whether the response is an entry, with * application-specific tag LDAP_SEARCHRESPONSEENTRY_TYPE, or a * resultCode, with application tag LDAP_SEARCHRESPONSERESULT_TYPE. * First, we have to figure out where to look for the tag. */ /* Is the message length short form (one octet) or long form? */ if ((msgBuf[1] & 0x80) != 0) { sizeofLength = msgBuf[1] & 0x7F; for (dataIndex = 0; dataIndex < sizeofLength; dataIndex++) { messageLength = (messageLength << 8) + msgBuf[dataIndex + 2]; } } else { messageLength = msgBuf[1]; } /* How many bytes did the messageID require? */ messageIdLen = msgBuf[dataIndex + 3]; messageChar = msgBuf[dataIndex + messageIdLen + 4]; /* Are we looking at an Entry message or a ResultCode message? */ if ((SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_SEARCHRESPONSEENTRY_TYPE) == messageChar) { messageType = LDAP_SEARCHRESPONSEENTRY_TYPE; } else if ((SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_SEARCHRESPONSERESULT_TYPE) == messageChar) { messageType = LDAP_SEARCHRESPONSERESULT_TYPE; } else { PKIX_ERROR(PKIX_SEARCHRESPONSEPACKETOFUNKNOWNTYPE); } /* * messageLength is the length from (tag, length, value). * We have to allocate space for the tag and length bits too. */ PKIX_CHECK(pkix_pl_LdapResponse_Create (messageType, messageLength + dataIndex + 2, client->currentBytesAvailable, msgBuf, &bytesProcessed, &(client->currentResponse), plContext), PKIX_LDAPRESPONSECREATEFAILED); client->currentBytesAvailable -= bytesProcessed; PKIX_CHECK(pkix_pl_LdapDefaultClient_RecvCheckComplete (client, bytesProcessed, pKeepGoing, plContext), PKIX_LDAPDEFAULTCLIENTRECVCHECKCOMPLETEFAILED); cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_RecvNonInitial * DESCRIPTION: * * This function processes the contents of buffers, after the first, of a * received LDAP-protocol message for the CertStore embodied in the * LdapDefaultClient "client", and stores in "pKeepGoing" a flag indicating * whether processing can continue without further input. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pKeepGoing" * The address at which the Boolean state machine flag is stored to * indicate whether processing can continue without further input. * 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_RecvNonInitial( PKIX_PL_LdapDefaultClient *client, PKIX_Boolean *pKeepGoing, void *plContext) { PKIX_UInt32 bytesProcessed = 0; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvNonInitial"); PKIX_NULLCHECK_TWO(client, pKeepGoing); PKIX_CHECK(pkix_pl_LdapResponse_Append (client->currentResponse, client->currentBytesAvailable, client->currentInPtr, &bytesProcessed, plContext), PKIX_LDAPRESPONSEAPPENDFAILED); client->currentBytesAvailable -= bytesProcessed; PKIX_CHECK(pkix_pl_LdapDefaultClient_RecvCheckComplete (client, bytesProcessed, pKeepGoing, plContext), PKIX_LDAPDEFAULTCLIENTRECVCHECKCOMPLETEFAILED); cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_Dispatch * DESCRIPTION: * * This function is the state machine dispatcher for the CertStore embodied in * the LdapDefaultClient pointed to by "client". Results are returned by * changes to various fields in the context. * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. 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 LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_Dispatch( PKIX_PL_LdapDefaultClient *client, void *plContext) { PKIX_UInt32 bytesTransferred = 0; PKIX_Boolean keepGoing = PKIX_TRUE; PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Dispatch"); PKIX_NULLCHECK_ONE(client); while (keepGoing) { switch (client->connectStatus) { case CONNECT_PENDING: PKIX_CHECK (pkix_pl_LdapDefaultClient_ConnectContinue (client, &keepGoing, plContext), PKIX_LDAPDEFAULTCLIENTCONNECTCONTINUEFAILED); break; case CONNECTED: PKIX_CHECK (pkix_pl_LdapDefaultClient_Bind (client, &keepGoing, plContext), PKIX_LDAPDEFAULTCLIENTBINDFAILED); break; case BIND_PENDING: PKIX_CHECK (pkix_pl_LdapDefaultClient_BindContinue (client, &keepGoing, plContext), PKIX_LDAPDEFAULTCLIENTBINDCONTINUEFAILED); break; case BIND_RESPONSE: PKIX_CHECK (pkix_pl_LdapDefaultClient_BindResponse (client, &keepGoing, plContext), PKIX_LDAPDEFAULTCLIENTBINDRESPONSEFAILED); break; case BIND_RESPONSE_PENDING: PKIX_CHECK (pkix_pl_LdapDefaultClient_BindResponseContinue (client, &keepGoing, plContext), PKIX_LDAPDEFAULTCLIENTBINDRESPONSECONTINUEFAILED); break; case BOUND: PKIX_CHECK (pkix_pl_LdapDefaultClient_Send (client, &keepGoing, &bytesTransferred, plContext), PKIX_LDAPDEFAULTCLIENTSENDFAILED); break; case SEND_PENDING: PKIX_CHECK (pkix_pl_LdapDefaultClient_SendContinue (client, &keepGoing, &bytesTransferred, plContext), PKIX_LDAPDEFAULTCLIENTSENDCONTINUEFAILED); break; case RECV: PKIX_CHECK (pkix_pl_LdapDefaultClient_Recv (client, &keepGoing, plContext), PKIX_LDAPDEFAULTCLIENTRECVFAILED); break; case RECV_PENDING: PKIX_CHECK (pkix_pl_LdapDefaultClient_RecvContinue (client, &keepGoing, plContext), PKIX_LDAPDEFAULTCLIENTRECVCONTINUEFAILED); break; case RECV_INITIAL: PKIX_CHECK (pkix_pl_LdapDefaultClient_RecvInitial (client, &keepGoing, plContext), PKIX_LDAPDEFAULTCLIENTRECVINITIALFAILED); break; case RECV_NONINITIAL: PKIX_CHECK (pkix_pl_LdapDefaultClient_RecvNonInitial (client, &keepGoing, plContext), PKIX_LDAPDEFAULTCLIENTRECVNONINITIALFAILED); break; case ABANDON_PENDING: PKIX_CHECK (pkix_pl_LdapDefaultClient_AbandonContinue (client, &keepGoing, plContext), PKIX_LDAPDEFAULTCLIENTABANDONCONTINUEFAILED); break; default: PKIX_ERROR(PKIX_LDAPCERTSTOREINILLEGALSTATE); } } cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_MakeAndFilter * DESCRIPTION: * * This function allocates space from the arena pointed to by "arena" to * construct a filter that will match components of the X500Name pointed to by * XXX... * * PARAMETERS: * "arena" * The address of the PLArenaPool used in creating the filter. Must be * non-NULL. * "nameComponent" * The address of a NULL-terminated list of LDAPNameComponents * Must be non-NULL. * "pFilter" * The address at which the result is stored. * "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 CertStore Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_MakeAndFilter( PLArenaPool *arena, LDAPNameComponent **nameComponents, LDAPFilter **pFilter, void *plContext) { LDAPFilter **setOfFilter; LDAPFilter *andFilter = NULL; LDAPFilter *currentFilter = NULL; PKIX_UInt32 componentsPresent = 0; void *v = NULL; unsigned char *component = NULL; LDAPNameComponent **componentP = NULL; PKIX_ENTER(CERTSTORE, "pkix_pl_LdapDefaultClient_MakeAndFilter"); PKIX_NULLCHECK_THREE(arena, nameComponents, pFilter); /* count how many components we were provided */ for (componentP = nameComponents, componentsPresent = 0; *(componentP++) != NULL; componentsPresent++) {} /* Space for (componentsPresent + 1) pointers to LDAPFilter */ PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZAlloc, (arena, (componentsPresent + 1)*sizeof(LDAPFilter *))); setOfFilter = (LDAPFilter **)v; /* Space for AndFilter and <componentsPresent> EqualFilters */ PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZNewArray, (arena, LDAPFilter, componentsPresent + 1)); setOfFilter[0] = (LDAPFilter *)v; /* Claim the first array element for the ANDFilter */ andFilter = setOfFilter[0]; /* Set ANDFilter to point to the first EqualFilter pointer */ andFilter->selector = LDAP_ANDFILTER_TYPE; andFilter->filter.andFilter.filters = setOfFilter; currentFilter = andFilter + 1; for (componentP = nameComponents, componentsPresent = 0; *(componentP) != NULL; componentP++) { setOfFilter[componentsPresent++] = currentFilter; currentFilter->selector = LDAP_EQUALFILTER_TYPE; component = (*componentP)->attrType; currentFilter->filter.equalFilter.attrType.data = component; currentFilter->filter.equalFilter.attrType.len = PL_strlen((const char *)component); component = (*componentP)->attrValue; currentFilter->filter.equalFilter.attrValue.data = component; currentFilter->filter.equalFilter.attrValue.len = PL_strlen((const char *)component); currentFilter++; } setOfFilter[componentsPresent] = NULL; *pFilter = andFilter; PKIX_RETURN(CERTSTORE); } /* * FUNCTION: pkix_pl_LdapDefaultClient_InitiateRequest * DESCRIPTION: * * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "requestParams" * The address of an LdapClientParams object. Must be non-NULL. * "pPollDesc" * The location where the address of the PRPollDesc is stored, if the * client returns with I/O pending. * "pResponse" * The address where the List of LDAPResponses, or NULL for an * unfinished request, 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 a LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_InitiateRequest( PKIX_PL_LdapClient *genericClient, LDAPRequestParams *requestParams, void **pPollDesc, PKIX_List **pResponse, void *plContext) { PKIX_List *searchResponseList = NULL; SECItem *encoded = NULL; LDAPFilter *filter = NULL; PKIX_PL_LdapDefaultClient *client = 0; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_InitiateRequest"); PKIX_NULLCHECK_FOUR(genericClient, requestParams, pPollDesc, pResponse); PKIX_CHECK(pkix_CheckType ((PKIX_PL_Object *)genericClient, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext), PKIX_GENERICCLIENTNOTANLDAPDEFAULTCLIENT); client = (PKIX_PL_LdapDefaultClient *)genericClient; PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeAndFilter (client->arena, requestParams->nc, &filter, plContext), PKIX_LDAPDEFAULTCLIENTMAKEANDFILTERFAILED); PKIX_CHECK(pkix_pl_LdapRequest_Create (client->arena, client->messageID++, requestParams->baseObject, requestParams->scope, requestParams->derefAliases, requestParams->sizeLimit, requestParams->timeLimit, PKIX_FALSE, /* attrs only */ filter, requestParams->attributes, &client->currentRequest, plContext), PKIX_LDAPREQUESTCREATEFAILED); /* check hashtable for matching request */ PKIX_CHECK(PKIX_PL_HashTable_Lookup (client->cachePtr, (PKIX_PL_Object *)(client->currentRequest), (PKIX_PL_Object **)&searchResponseList, plContext), PKIX_HASHTABLELOOKUPFAILED); if (searchResponseList != NULL) { *pPollDesc = NULL; *pResponse = searchResponseList; PKIX_DECREF(client->currentRequest); goto cleanup; } /* It wasn't cached. We'll have to actually send it. */ PKIX_CHECK(pkix_pl_LdapRequest_GetEncoded (client->currentRequest, &encoded, plContext), PKIX_LDAPREQUESTGETENCODEDFAILED); client->sendBuf = encoded->data; client->bytesToWrite = encoded->len; PKIX_CHECK(pkix_pl_LdapDefaultClient_Dispatch(client, plContext), PKIX_LDAPDEFAULTCLIENTDISPATCHFAILED); /* * It's not enough that we may be done with a particular read. * We're still processing the transaction until we've gotten the * SearchResponseResult message and returned to the BOUND state. * Otherwise we must still have a read pending, and must hold off * on returning results. */ if ((client->connectStatus == BOUND) && (client->entriesFound != NULL)) { *pPollDesc = NULL; *pResponse = client->entriesFound; client->entriesFound = NULL; PKIX_DECREF(client->currentRequest); } else { *pPollDesc = &client->pollDesc; *pResponse = NULL; } cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* * FUNCTION: pkix_pl_LdapDefaultClient_ResumeRequest * DESCRIPTION: * * * PARAMETERS: * "client" * The address of the LdapDefaultClient object. Must be non-NULL. * "pPollDesc" * The location where the address of the PRPollDesc is stored, if the * client returns with I/O pending. * "pResponse" * The address where the List of LDAPResponses, or NULL for an * unfinished request, 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 a LdapDefaultClient Error if the function fails in a * non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_LdapDefaultClient_ResumeRequest( PKIX_PL_LdapClient *genericClient, void **pPollDesc, PKIX_List **pResponse, void *plContext) { PKIX_PL_LdapDefaultClient *client = 0; PKIX_ENTER (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_ResumeRequest"); PKIX_NULLCHECK_THREE(genericClient, pPollDesc, pResponse); PKIX_CHECK(pkix_CheckType ((PKIX_PL_Object *)genericClient, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext), PKIX_GENERICCLIENTNOTANLDAPDEFAULTCLIENT); client = (PKIX_PL_LdapDefaultClient *)genericClient; PKIX_CHECK(pkix_pl_LdapDefaultClient_Dispatch(client, plContext), PKIX_LDAPDEFAULTCLIENTDISPATCHFAILED); /* * It's not enough that we may be done with a particular read. * We're still processing the transaction until we've gotten the * SearchResponseResult message and returned to the BOUND state. * Otherwise we must still have a read pending, and must hold off * on returning results. */ if ((client->connectStatus == BOUND) && (client->entriesFound != NULL)) { *pPollDesc = NULL; *pResponse = client->entriesFound; client->entriesFound = NULL; PKIX_DECREF(client->currentRequest); } else { *pPollDesc = &client->pollDesc; *pResponse = NULL; } cleanup: PKIX_RETURN(LDAPDEFAULTCLIENT); } /* --Public-LdapDefaultClient-Functions----------------------------------- */ /* * FUNCTION: PKIX_PL_LdapDefaultClient_AbandonRequest * DESCRIPTION: * * This function creates and sends an LDAP-protocol "Abandon" message to the * server connected to the LdapDefaultClient pointed to by "client". * * PARAMETERS: * "client" * The LdapDefaultClient whose connection is to be abandoned. 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_LdapDefaultClient_AbandonRequest( PKIX_PL_LdapDefaultClient *client, void *plContext) { PKIX_Int32 bytesWritten = 0; PKIX_PL_Socket_Callback *callbackList = NULL; SECItem *encoded = NULL; PKIX_ENTER(CERTSTORE, "PKIX_PL_LdapDefaultClient_AbandonRequest"); PKIX_NULLCHECK_ONE(client); if (client->connectStatus == RECV_PENDING) { PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeAbandon (client->arena, (client->messageID) - 1, &encoded, plContext), PKIX_LDAPDEFAULTCLIENTMAKEABANDONFAILED); callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList); PKIX_CHECK(callbackList->sendCallback (client->clientSocket, encoded->data, encoded->len, &bytesWritten, plContext), PKIX_SOCKETSENDFAILED); if (bytesWritten < 0) { client->connectStatus = ABANDON_PENDING; } else { client->connectStatus = BOUND; } } PKIX_DECREF(client->entriesFound); PKIX_DECREF(client->currentRequest); PKIX_DECREF(client->currentResponse); cleanup: PKIX_DECREF(client); PKIX_RETURN(CERTSTORE); }