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_aiamgr.c
andre@0:  *
andre@0:  * AIAMgr Object Definitions
andre@0:  *
andre@0:  */
andre@0: 
andre@0: #include "pkix_pl_aiamgr.h"
andre@0: extern PKIX_PL_HashTable *aiaConnectionCache;
andre@0: 
andre@0: #ifndef NSS_PKIX_NO_LDAP
andre@0: /* --Virtual-LdapClient-Functions------------------------------------ */
andre@0: 
andre@0: PKIX_Error *
andre@0: PKIX_PL_LdapClient_InitiateRequest(
andre@0:         PKIX_PL_LdapClient *client,
andre@0:         LDAPRequestParams *requestParams,
andre@0:         void **pNBIO,
andre@0:         PKIX_List **pResponse,
andre@0:         void *plContext)
andre@0: {
andre@0:         PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_InitiateRequest");
andre@0:         PKIX_NULLCHECK_TWO(client, client->initiateFcn);
andre@0: 
andre@0:         PKIX_CHECK(client->initiateFcn
andre@0:                 (client, requestParams, pNBIO, pResponse, plContext),
andre@0:                 PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
andre@0: cleanup:
andre@0: 
andre@0:         PKIX_RETURN(LDAPCLIENT);
andre@0: 
andre@0: }
andre@0: 
andre@0: PKIX_Error *
andre@0: PKIX_PL_LdapClient_ResumeRequest(
andre@0:         PKIX_PL_LdapClient *client,
andre@0:         void **pNBIO,
andre@0:         PKIX_List **pResponse,
andre@0:         void *plContext)
andre@0: {
andre@0:         PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_ResumeRequest");
andre@0:         PKIX_NULLCHECK_TWO(client, client->resumeFcn);
andre@0: 
andre@0:         PKIX_CHECK(client->resumeFcn
andre@0:                 (client, pNBIO, pResponse, plContext),
andre@0:                 PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
andre@0: cleanup:
andre@0: 
andre@0:         PKIX_RETURN(LDAPCLIENT);
andre@0: 
andre@0: }
andre@0: #endif /* !NSS_PKIX_NO_LDAP */
andre@0: 
andre@0: /* --Private-AIAMgr-Functions----------------------------------*/
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: pkix_pl_AIAMgr_Destroy
andre@0:  * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h)
andre@0:  */
andre@0: static PKIX_Error *
andre@0: pkix_pl_AIAMgr_Destroy(
andre@0:         PKIX_PL_Object *object,
andre@0:         void *plContext)
andre@0: {
andre@0:         PKIX_PL_AIAMgr *aiaMgr = NULL;
andre@0: 
andre@0:         PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_Destroy");
andre@0:         PKIX_NULLCHECK_ONE(object);
andre@0: 
andre@0:         PKIX_CHECK(pkix_CheckType(object, PKIX_AIAMGR_TYPE, plContext),
andre@0:                 PKIX_OBJECTNOTAIAMGR);
andre@0: 
andre@0:         aiaMgr = (PKIX_PL_AIAMgr *)object;
andre@0: 
andre@0:         /* pointer to cert cache */
andre@0:         /* pointer to crl cache */
andre@0:         aiaMgr->method = 0;
andre@0:         aiaMgr->aiaIndex = 0;
andre@0:         aiaMgr->numAias = 0;
andre@0:         PKIX_DECREF(aiaMgr->aia);
andre@0:         PKIX_DECREF(aiaMgr->location);
andre@0:         PKIX_DECREF(aiaMgr->results);
andre@0: #ifndef NSS_PKIX_NO_LDAP
andre@0:         PKIX_DECREF(aiaMgr->client.ldapClient);
andre@0: #endif
andre@0: 
andre@0: cleanup:
andre@0: 
andre@0:         PKIX_RETURN(AIAMGR);
andre@0: }
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: pkix_pl_AIAMgr_RegisterSelf
andre@0:  * DESCRIPTION:
andre@0:  *  Registers PKIX_AIAMGR_TYPE and its related functions with systemClasses[]
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_AIAMgr_RegisterSelf(void *plContext)
andre@0: {
andre@0:         extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
andre@0:         pkix_ClassTable_Entry *entry = &systemClasses[PKIX_AIAMGR_TYPE];
andre@0: 
andre@0:         PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_RegisterSelf");
andre@0: 
andre@0:         entry->description = "AIAMgr";
andre@0:         entry->typeObjectSize = sizeof(PKIX_PL_AIAMgr);
andre@0:         entry->destructor = pkix_pl_AIAMgr_Destroy;
andre@0: 
andre@0:         PKIX_RETURN(AIAMGR);
andre@0: }
andre@0: 
andre@0: #ifndef NSS_PKIX_NO_LDAP
andre@0: /*
andre@0:  * FUNCTION: pkix_pl_AiaMgr_FindLDAPClient
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  *  This function checks the collection of LDAPClient connections held by the
andre@0:  *  AIAMgr pointed to by "aiaMgr" for one matching the domain name given by
andre@0:  *  "domainName". The string may include a port number: e.g., "betty.nist.gov"
andre@0:  *  or "nss.red.iplanet.com:1389". If a match is found, that LDAPClient is
andre@0:  *  stored at "pClient". Otherwise, an LDAPClient is created and added to the
andre@0:  *  collection, and then stored at "pClient".
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "aiaMgr"
andre@0:  *      The AIAMgr whose LDAPClient connected are to be managed. Must be
andre@0:  *      non-NULL.
andre@0:  *  "domainName"
andre@0:  *      Address of a string pointing to a server name. Must be non-NULL.
andre@0:  *      An empty string (which means no <host> is given in the LDAP URL) is
andre@0:  *      not supported.
andre@0:  *  "pClient"
andre@0:  *      Address at which the returned LDAPClient is stored. Must be non-NULL.
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns an AIAMgr 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_AiaMgr_FindLDAPClient(
andre@0:         PKIX_PL_AIAMgr *aiaMgr,
andre@0:         char *domainName,
andre@0:         PKIX_PL_LdapClient **pClient,
andre@0:         void *plContext)
andre@0: {
andre@0:         PKIX_PL_String *domainString = NULL;
andre@0:         PKIX_PL_LdapDefaultClient *client = NULL;
andre@0: 
andre@0:         PKIX_ENTER(AIAMGR, "pkix_pl_AiaMgr_FindLDAPClient");
andre@0:         PKIX_NULLCHECK_THREE(aiaMgr, domainName, pClient);
andre@0: 
andre@0:         /*
andre@0:          * An LDAP URL may not have a <host> part, for example,
andre@0:          *     ldap:///o=University%20of%20Michigan,c=US
andre@0:          * PKIX_PL_LdapDefaultClient doesn't know how to discover the default
andre@0:          * LDAP server, so we don't support this kind of LDAP URL.
andre@0:          */
andre@0:         if (*domainName == '\0') {
andre@0:                 /* Simulate a PKIX_PL_LdapDefaultClient_CreateByName failure. */
andre@0:                 PKIX_ERROR(PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED);
andre@0:         }
andre@0: 
andre@0:         /* create PKIX_PL_String from domain name */
andre@0:         PKIX_CHECK(PKIX_PL_String_Create
andre@0:                 (PKIX_ESCASCII, domainName, 0, &domainString, plContext),
andre@0:                 PKIX_STRINGCREATEFAILED);
andre@0: 
andre@0:         /* Is this domainName already in cache? */
andre@0:         PKIX_CHECK(PKIX_PL_HashTable_Lookup
andre@0:                 (aiaConnectionCache,
andre@0:                 (PKIX_PL_Object *)domainString,
andre@0:                 (PKIX_PL_Object **)&client,
andre@0:                 plContext),
andre@0:                 PKIX_HASHTABLELOOKUPFAILED);
andre@0: 
andre@0:         if (client == NULL) {
andre@0: 
andre@0:                 /* No, create a connection (and cache it) */
andre@0:                 PKIX_CHECK(PKIX_PL_LdapDefaultClient_CreateByName
andre@0:                         (domainName,
andre@0:                          /* Do not use NBIO until we verify, that
andre@0:                           * it is working. For now use 1 min timeout. */
andre@0:                         PR_SecondsToInterval(
andre@0:                             ((PKIX_PL_NssContext*)plContext)->timeoutSeconds),
andre@0:                         NULL,
andre@0:                         &client,
andre@0:                         plContext),
andre@0:                         PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED);
andre@0: 
andre@0:                 PKIX_CHECK(PKIX_PL_HashTable_Add
andre@0:                         (aiaConnectionCache,
andre@0:                         (PKIX_PL_Object *)domainString,
andre@0:                         (PKIX_PL_Object *)client,
andre@0:                         plContext),
andre@0:                         PKIX_HASHTABLEADDFAILED);
andre@0: 
andre@0:         }
andre@0: 
andre@0:         *pClient = (PKIX_PL_LdapClient *)client;
andre@0: 
andre@0: cleanup:
andre@0: 
andre@0:         PKIX_DECREF(domainString);
andre@0: 
andre@0:         PKIX_RETURN(AIAMGR);
andre@0: }
andre@0: #endif /* !NSS_PKIX_NO_LDAP */
andre@0: 
andre@0: PKIX_Error *
andre@0: pkix_pl_AIAMgr_GetHTTPCerts(
andre@0:         PKIX_PL_AIAMgr *aiaMgr,
andre@0: 	PKIX_PL_InfoAccess *ia,
andre@0: 	void **pNBIOContext,
andre@0: 	PKIX_List **pCerts,
andre@0:         void *plContext)
andre@0: {
andre@0:         PKIX_PL_GeneralName *location = NULL;
andre@0:         PKIX_PL_String *locationString = NULL;
andre@0: 	PKIX_UInt32 len = 0;
andre@0: 	PRUint16 port = 0;
andre@0: 	const SEC_HttpClientFcn *httpClient = NULL;
andre@0: 	const SEC_HttpClientFcnV1 *hcv1 = NULL;
andre@0: 	SECStatus rv = SECFailure;
andre@0: 	SEC_HTTP_SERVER_SESSION serverSession = NULL;
andre@0: 	SEC_HTTP_REQUEST_SESSION requestSession = NULL;	
andre@0: 	char *path = NULL;
andre@0: 	char *hostname = NULL;
andre@0: 	char *locationAscii = NULL;
andre@0: 	void *nbio = NULL;
andre@0: 	PRUint16 responseCode = 0;
andre@0: 	const char *responseContentType = NULL;
andre@0: 	const char *responseData = NULL;
andre@0: 
andre@0:         PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetHTTPCerts");
andre@0:         PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts);
andre@0: 
andre@0:         nbio = *pNBIOContext;
andre@0:         *pNBIOContext = NULL;
andre@0:         *pCerts = NULL;
andre@0: 
andre@0:         if (nbio == NULL) { /* a new request */
andre@0: 
andre@0:                 PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
andre@0:                         (ia, &location, plContext),
andre@0:                        PKIX_INFOACCESSGETLOCATIONFAILED);
andre@0: 
andre@0:                 /* find or create httpClient = default client */
andre@0: 		httpClient = SEC_GetRegisteredHttpClient();
andre@0: 		aiaMgr->client.hdata.httpClient = httpClient;
andre@0: 		if (!httpClient)
andre@0: 		    PKIX_ERROR(PKIX_OUTOFMEMORY);
andre@0: 
andre@0: 		if (httpClient->version == 1) {
andre@0: 
andre@0:                         PKIX_UInt32 timeout =
andre@0:                              ((PKIX_PL_NssContext*)plContext)->timeoutSeconds;
andre@0: 
andre@0: 			hcv1 = &(httpClient->fcnTable.ftable1);
andre@0: 
andre@0: 			/* create server session */
andre@0: 			PKIX_TOSTRING(location, &locationString, plContext,
andre@0: 				PKIX_GENERALNAMETOSTRINGFAILED);
andre@0: 
andre@0: 			PKIX_CHECK(PKIX_PL_String_GetEncoded
andre@0: 				(locationString,
andre@0: 				PKIX_ESCASCII,
andre@0: 				(void **)&locationAscii,
andre@0: 				&len,
andre@0: 				plContext),
andre@0: 				PKIX_STRINGGETENCODEDFAILED);
andre@0: 
andre@0:                         rv = CERT_ParseURL(locationAscii, &hostname, &port,
andre@0:                                             &path);
andre@0: 			if ((rv != SECSuccess) ||
andre@0: 			    (hostname == NULL) ||
andre@0: 			    (path == NULL)) {
andre@0: 				PKIX_ERROR(PKIX_URLPARSINGFAILED);
andre@0: 			}
andre@0: 
andre@0:                         rv = (*hcv1->createSessionFcn)(hostname, port, 
andre@0:                                                        &serverSession);
andre@0: 	                if (rv != SECSuccess) {
andre@0: 				PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED);
andre@0: 			}
andre@0: 
andre@0: 			aiaMgr->client.hdata.serverSession = serverSession;
andre@0: 
andre@0: 			/* create request session */
andre@0:                         rv = (*hcv1->createFcn)(serverSession, "http", path,
andre@0:                         	"GET", PR_SecondsToInterval(timeout),
andre@0:                                  &requestSession);
andre@0:                 	if (rv != SECSuccess) {
andre@0:                         	PKIX_ERROR(PKIX_HTTPSERVERERROR);
andre@0:                 	}
andre@0: 
andre@0: 			aiaMgr->client.hdata.requestSession = requestSession;
andre@0: 		} else {
andre@0: 			PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
andre@0: 		}
andre@0: 	}
andre@0: 
andre@0: 	httpClient = aiaMgr->client.hdata.httpClient;
andre@0: 
andre@0: 	if (httpClient->version == 1) {
andre@0:                 PRUint32 responseDataLen = 
andre@0:                    ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
andre@0: 
andre@0: 		hcv1 = &(httpClient->fcnTable.ftable1);
andre@0: 		requestSession = aiaMgr->client.hdata.requestSession;
andre@0: 
andre@0: 		/* trySendAndReceive */
andre@0:                 rv = (*hcv1->trySendAndReceiveFcn)(requestSession,
andre@0:                                  (PRPollDesc **)&nbio,
andre@0:                                  &responseCode,
andre@0:                                  (const char **)&responseContentType,
andre@0:                                  NULL, /* &responseHeaders */
andre@0:                                  (const char **)&responseData,
andre@0:                                  &responseDataLen);
andre@0: 
andre@0:                 if (rv != SECSuccess) {
andre@0:                         PKIX_ERROR(PKIX_HTTPSERVERERROR);
andre@0:                 }
andre@0: 
andre@0:                 if (nbio != 0) {
andre@0:                         *pNBIOContext = nbio;
andre@0:                         goto cleanup;
andre@0:                 }
andre@0: 
andre@0: 		PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse
andre@0: 	                (responseCode,
andre@0: 	                responseContentType,
andre@0: 	                responseData,
andre@0: 	                responseDataLen,
andre@0: 	                pCerts,
andre@0: 	                plContext),
andre@0: 	                PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED);
andre@0:                 
andre@0:                 /* Session and request cleanup in case of success */
andre@0:                 if (aiaMgr->client.hdata.requestSession != NULL) {
andre@0:                     (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession);
andre@0:                     aiaMgr->client.hdata.requestSession = NULL;
andre@0:                 }
andre@0:                 if (aiaMgr->client.hdata.serverSession != NULL) {
andre@0:                     (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession);
andre@0:                     aiaMgr->client.hdata.serverSession = NULL;
andre@0:                 }
andre@0:                 aiaMgr->client.hdata.httpClient = 0; /* callback fn */
andre@0: 
andre@0:         } else  {
andre@0: 		PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
andre@0: 	}
andre@0: 
andre@0: cleanup:
andre@0:         /* Session and request cleanup in case of error. Passing through without cleanup
andre@0:          * if interrupted by blocked IO. */
andre@0:         if (PKIX_ERROR_RECEIVED && aiaMgr) {
andre@0:             if (aiaMgr->client.hdata.requestSession != NULL) {
andre@0:                 (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession);
andre@0:                 aiaMgr->client.hdata.requestSession = NULL;
andre@0:             }
andre@0:             if (aiaMgr->client.hdata.serverSession != NULL) {
andre@0:                 (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession);
andre@0:                 aiaMgr->client.hdata.serverSession = NULL;
andre@0:             }
andre@0:             aiaMgr->client.hdata.httpClient = 0; /* callback fn */
andre@0:         }
andre@0: 
andre@0:         PKIX_DECREF(location);
andre@0:         PKIX_DECREF(locationString);
andre@0: 
andre@0:         if (locationAscii) {
andre@0:             PORT_Free(locationAscii);
andre@0:         }
andre@0:         if (hostname) {
andre@0:             PORT_Free(hostname);
andre@0:         }
andre@0:         if (path) {
andre@0:             PORT_Free(path);
andre@0:         }
andre@0: 
andre@0:         PKIX_RETURN(AIAMGR);
andre@0: }
andre@0: 
andre@0: #ifndef NSS_PKIX_NO_LDAP
andre@0: PKIX_Error *
andre@0: pkix_pl_AIAMgr_GetLDAPCerts(
andre@0:         PKIX_PL_AIAMgr *aiaMgr,
andre@0: 	PKIX_PL_InfoAccess *ia,
andre@0: 	void **pNBIOContext,
andre@0: 	PKIX_List **pCerts,
andre@0:         void *plContext)
andre@0: {
andre@0:         PKIX_List *result = NULL;
andre@0:         PKIX_PL_GeneralName *location = NULL;
andre@0:         PKIX_PL_LdapClient *client = NULL;
andre@0:         LDAPRequestParams request;
andre@0:         PLArenaPool *arena = NULL;
andre@0:         char *domainName = NULL;
andre@0: 	void *nbio = NULL;
andre@0: 
andre@0:         PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetLDAPCerts");
andre@0:         PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts);
andre@0: 
andre@0:         nbio = *pNBIOContext;
andre@0:         *pNBIOContext = NULL;
andre@0:         *pCerts = NULL;
andre@0: 
andre@0:         if (nbio == NULL) { /* a new request */
andre@0: 
andre@0:                 /* Initiate an LDAP request */
andre@0: 
andre@0:                 request.scope = WHOLE_SUBTREE;
andre@0:                 request.derefAliases = NEVER_DEREF;
andre@0:                 request.sizeLimit = 0;
andre@0:                 request.timeLimit = 0;
andre@0: 
andre@0:                 PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
andre@0:                         (ia, &location, plContext),
andre@0:                         PKIX_INFOACCESSGETLOCATIONFAILED);
andre@0: 
andre@0:                 /*
andre@0:                  * Get a short-lived arena. We'll be done with
andre@0:                  * this space once the request is encoded.
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: 
andre@0:                 PKIX_CHECK(pkix_pl_InfoAccess_ParseLocation
andre@0:                         (location, arena, &request, &domainName, plContext),
andre@0:                         PKIX_INFOACCESSPARSELOCATIONFAILED);
andre@0: 
andre@0:                 PKIX_DECREF(location);
andre@0: 
andre@0:                 /* Find or create a connection to LDAP server */
andre@0:                 PKIX_CHECK(pkix_pl_AiaMgr_FindLDAPClient
andre@0:                         (aiaMgr, domainName, &client, plContext),
andre@0:                         PKIX_AIAMGRFINDLDAPCLIENTFAILED);
andre@0: 
andre@0:                 aiaMgr->client.ldapClient = client;
andre@0: 
andre@0:                 PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
andre@0:                         (aiaMgr->client.ldapClient,
andre@0: 			&request,
andre@0: 			&nbio,
andre@0: 			&result,
andre@0: 			plContext),
andre@0:                         PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
andre@0: 
andre@0:                 PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));
andre@0: 
andre@0:         } else {
andre@0: 
andre@0:                 PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
andre@0:                         (aiaMgr->client.ldapClient, &nbio, &result, plContext),
andre@0:                         PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
andre@0: 
andre@0:         }
andre@0: 
andre@0:         if (nbio != NULL) { /* WOULDBLOCK */
andre@0:                 *pNBIOContext = nbio;
andre@0:                 *pCerts = NULL;
andre@0:                 goto cleanup;
andre@0:         }
andre@0: 
andre@0: 	PKIX_DECREF(aiaMgr->client.ldapClient);
andre@0: 
andre@0: 	if (result == NULL) {
andre@0: 		*pCerts = NULL;
andre@0: 	} else {
andre@0: 		PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
andre@0: 			(result, pCerts, plContext),
andre@0: 			PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
andre@0: 	}
andre@0: 
andre@0: 	*pNBIOContext = nbio;
andre@0: 
andre@0: cleanup:
andre@0: 
andre@0:         if (arena && (PKIX_ERROR_RECEIVED)) {
andre@0:                 PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));
andre@0:         }
andre@0: 
andre@0:         if (PKIX_ERROR_RECEIVED) {
andre@0: 	        PKIX_DECREF(aiaMgr->client.ldapClient);
andre@0: 	}
andre@0: 
andre@0:         PKIX_DECREF(location);
andre@0: 
andre@0:         PKIX_RETURN(AIAMGR);
andre@0: }
andre@0: #endif /* !NSS_PKIX_NO_LDAP */
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: PKIX_PL_AIAMgr_Create
andre@0:  * DESCRIPTION:
andre@0:  *
andre@0:  *  This function creates an AIAMgr, storing the result at "pAIAMgr".
andre@0:  *
andre@0:  * PARAMETERS:
andre@0:  *  "pAIAMGR"
andre@0:  *      Address at which the returned AIAMgr is stored. Must be non-NULL.
andre@0:  *  "plContext"
andre@0:  *      Platform-specific context pointer.
andre@0:  * THREAD SAFETY:
andre@0:  *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
andre@0:  * RETURNS:
andre@0:  *  Returns NULL if the function succeeds.
andre@0:  *  Returns an AIAMgr Error if the function fails in a non-fatal way
andre@0:  *  Returns a Fatal Error if the function fails in an unrecoverable way.
andre@0:  */
andre@0: PKIX_Error *
andre@0: PKIX_PL_AIAMgr_Create(
andre@0:         PKIX_PL_AIAMgr **pAIAMgr,
andre@0:         void *plContext)
andre@0: {
andre@0:         PKIX_PL_AIAMgr *aiaMgr = NULL;
andre@0: 
andre@0:         PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_Create");
andre@0:         PKIX_NULLCHECK_ONE(pAIAMgr);
andre@0: 
andre@0:         PKIX_CHECK(PKIX_PL_Object_Alloc
andre@0:                 (PKIX_AIAMGR_TYPE,
andre@0:                 sizeof(PKIX_PL_AIAMgr),
andre@0:                 (PKIX_PL_Object **)&aiaMgr,
andre@0:                 plContext),
andre@0:                 PKIX_COULDNOTCREATEAIAMGROBJECT);
andre@0:         /* pointer to cert cache */
andre@0:         /* pointer to crl cache */
andre@0:         aiaMgr->method = 0;
andre@0:         aiaMgr->aiaIndex = 0;
andre@0:         aiaMgr->numAias = 0;
andre@0:         aiaMgr->aia = NULL;
andre@0:         aiaMgr->location = NULL;
andre@0:         aiaMgr->results = NULL;
andre@0:         aiaMgr->client.hdata.httpClient = NULL;
andre@0: 	aiaMgr->client.hdata.serverSession = NULL;
andre@0: 	aiaMgr->client.hdata.requestSession = NULL;
andre@0: 
andre@0:         *pAIAMgr = aiaMgr;
andre@0: 
andre@0: cleanup:
andre@0: 
andre@0:         PKIX_RETURN(AIAMGR);
andre@0: }
andre@0: 
andre@0: /* --Public-Functions------------------------------------------------------- */
andre@0: 
andre@0: /*
andre@0:  * FUNCTION: PKIX_PL_AIAMgr_GetAIACerts (see description in pkix_pl_pki.h)
andre@0:  */
andre@0: PKIX_Error *
andre@0: PKIX_PL_AIAMgr_GetAIACerts(
andre@0:         PKIX_PL_AIAMgr *aiaMgr,
andre@0:         PKIX_PL_Cert *prevCert,
andre@0:         void **pNBIOContext,
andre@0:         PKIX_List **pCerts,
andre@0:         void *plContext)
andre@0: {
andre@0:         PKIX_UInt32 numAias = 0;
andre@0:         PKIX_UInt32 aiaIndex = 0;
andre@0:         PKIX_UInt32 iaType = PKIX_INFOACCESS_LOCATION_UNKNOWN;
andre@0:         PKIX_List *certs = NULL;
andre@0:         PKIX_PL_InfoAccess *ia = NULL;
andre@0:         void *nbio = NULL;
andre@0: 
andre@0:         PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_GetAIACerts");
andre@0:         PKIX_NULLCHECK_FOUR(aiaMgr, prevCert, pNBIOContext, pCerts);
andre@0: 
andre@0:         nbio = *pNBIOContext;
andre@0:         *pCerts = NULL;
andre@0:         *pNBIOContext = NULL;
andre@0: 
andre@0:         if (nbio == NULL) { /* a new request */
andre@0: 
andre@0:                 /* Does this Cert have an AIA extension? */
andre@0:                 PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess
andre@0:                         (prevCert, &aiaMgr->aia, plContext),
andre@0:                         PKIX_CERTGETAUTHORITYINFOACCESSFAILED);
andre@0: 
andre@0:                 if (aiaMgr->aia != NULL) {
andre@0:                         PKIX_CHECK(PKIX_List_GetLength
andre@0:                                 (aiaMgr->aia, &numAias, plContext),
andre@0:                                 PKIX_LISTGETLENGTHFAILED);
andre@0:                 }
andre@0: 
andre@0:                 /* And if so, does it have any entries? */
andre@0:                 if ((aiaMgr->aia == NULL) || (numAias == 0)) {
andre@0:                         *pCerts = NULL;
andre@0:                         goto cleanup;
andre@0:                 }
andre@0: 
andre@0:                 aiaMgr->aiaIndex = 0;
andre@0:                 aiaMgr->numAias = numAias;
andre@0:                 aiaMgr->results = NULL;
andre@0: 
andre@0:         }
andre@0: 
andre@0:         for (aiaIndex = aiaMgr->aiaIndex;
andre@0:                 aiaIndex < aiaMgr->numAias;
andre@0:                 aiaIndex ++) {
andre@0:                 PKIX_UInt32 method = 0;
andre@0: 
andre@0:                 PKIX_CHECK(PKIX_List_GetItem
andre@0:                         (aiaMgr->aia,
andre@0:                         aiaIndex,
andre@0:                         (PKIX_PL_Object **)&ia,
andre@0:                         plContext),
andre@0:                         PKIX_LISTGETITEMFAILED);
andre@0: 
andre@0:                 PKIX_CHECK(PKIX_PL_InfoAccess_GetMethod
andre@0:                         (ia, &method, plContext),
andre@0:                         PKIX_INFOACCESSGETMETHODFAILED);
andre@0: 
andre@0:                 if (method != PKIX_INFOACCESS_CA_ISSUERS &&
andre@0:                     method != PKIX_INFOACCESS_CA_REPOSITORY) {
andre@0:                     PKIX_DECREF(ia);
andre@0:                     continue;
andre@0:                 }
andre@0:                 
andre@0:                 PKIX_CHECK(PKIX_PL_InfoAccess_GetLocationType
andre@0:                         (ia, &iaType, plContext),
andre@0:                         PKIX_INFOACCESSGETLOCATIONTYPEFAILED);
andre@0: 
andre@0:                 if (iaType == PKIX_INFOACCESS_LOCATION_HTTP) {
andre@0: 			PKIX_CHECK(pkix_pl_AIAMgr_GetHTTPCerts
andre@0: 				(aiaMgr, ia, &nbio, &certs, plContext),
andre@0: 				PKIX_AIAMGRGETHTTPCERTSFAILED);
andre@0: #ifndef NSS_PKIX_NO_LDAP
andre@0:                 } else if (iaType == PKIX_INFOACCESS_LOCATION_LDAP) {
andre@0: 			PKIX_CHECK(pkix_pl_AIAMgr_GetLDAPCerts
andre@0: 				(aiaMgr, ia, &nbio, &certs, plContext),
andre@0: 				PKIX_AIAMGRGETLDAPCERTSFAILED);
andre@0: #endif
andre@0:                 } else {
andre@0:                         /* We only support http and ldap requests. */
andre@0:                         PKIX_DECREF(ia);
andre@0:                         continue;
andre@0:                 }
andre@0: 
andre@0:                 if (nbio != NULL) { /* WOULDBLOCK */
andre@0:                         aiaMgr->aiaIndex = aiaIndex;
andre@0:                         *pNBIOContext = nbio;
andre@0:                         *pCerts = NULL;
andre@0:                         goto cleanup;
andre@0:                 }
andre@0: 
andre@0:                 /*
andre@0:                  * We can't just use and modify the List we received.
andre@0:                  * Because it's cached, it's set immutable.
andre@0:                  */
andre@0:                 if (aiaMgr->results == NULL) {
andre@0:                         PKIX_CHECK(PKIX_List_Create
andre@0:                                 (&(aiaMgr->results), plContext),
andre@0:                                 PKIX_LISTCREATEFAILED);
andre@0:                 }
andre@0:                 PKIX_CHECK(pkix_List_AppendList
andre@0:                         (aiaMgr->results, certs, plContext),
andre@0:                         PKIX_APPENDLISTFAILED);
andre@0:                 PKIX_DECREF(certs);
andre@0: 
andre@0:                 PKIX_DECREF(ia);
andre@0:         }
andre@0: 
andre@0:         PKIX_DECREF(aiaMgr->aia);
andre@0: 
andre@0:         *pNBIOContext = NULL;
andre@0:         *pCerts = aiaMgr->results;
andre@0:         aiaMgr->results = NULL;
andre@0: 
andre@0: cleanup:
andre@0: 
andre@0:         if (PKIX_ERROR_RECEIVED) {
andre@0:                 PKIX_DECREF(aiaMgr->aia);
andre@0:                 PKIX_DECREF(aiaMgr->results);
andre@0: #ifndef NSS_PKIX_NO_LDAP
andre@0:                 PKIX_DECREF(aiaMgr->client.ldapClient);
andre@0: #endif
andre@0:         }
andre@0: 
andre@0:         PKIX_DECREF(certs);
andre@0:         PKIX_DECREF(ia);
andre@0: 
andre@0:         PKIX_RETURN(AIAMGR);
andre@0: }