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