📄 fetch.c
字号:
/* Dynamic fetching of X.509 CRLs * Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com> * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: fetch.c,v 1.6 2004/06/14 02:01:32 mcr Exp $ */#include <stdlib.h>#include <errno.h>#include <sys/time.h>#include <pthread.h>#include <string.h>#ifdef LIBCURL#include <curl/curl.h>#endif#include <openswan.h>#ifdef LDAP_VER#include <ldap.h>#endif#include "constants.h"#include "defs.h"#include "log.h"#include "id.h"#include "asn1.h"#include "pem.h"#include "x509.h"#include "whack.h"#include "ocsp.h"#include "fetch.h"#ifdef LIBCURL#define LIBCURL_UNUSED #else#define LIBCURL_UNUSED UNUSED#endif#define FETCH_CMD_TIMEOUT 5 /* seconds */typedef struct fetch_req fetch_req_t;struct fetch_req { fetch_req_t *next; time_t installed; int trials; chunk_t issuer; generalName_t *distributionPoints;};fetch_req_t empty_fetch_req = { NULL , /* next */ 0 , /* installed */ 0 , /* trials */ {NULL, 0}, /* issuer */ NULL /* distributionPoints */};/* chained list of crl fetch requests */static fetch_req_t *crl_fetch_reqs = NULL;/* chained list of ocsp fetch requests */static ocsp_location_t *ocsp_fetch_reqs = NULL;static pthread_t thread;static pthread_mutex_t certs_and_keys_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_mutex_t authcert_list_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_mutex_t crl_list_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_mutex_t ocsp_cache_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_mutex_t crl_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_mutex_t ocsp_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_mutex_t fetch_wake_mutex = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t fetch_wake_cond = PTHREAD_COND_INITIALIZER;#define BUF_LEN 512/* * lock access to my certs and keys */voidlock_certs_and_keys(const char *who){ pthread_mutex_lock(&certs_and_keys_mutex); DBG(DBG_CONTROLMORE, DBG_log("certs and keys locked by '%s'", who) )}/* * unlock access to my certs and keys */voidunlock_certs_and_keys(const char *who){ DBG(DBG_CONTROLMORE, DBG_log("certs and keys unlocked by '%s'", who) ) pthread_mutex_unlock(&certs_and_keys_mutex);}/* * lock access to the chained authcert list */voidlock_authcert_list(const char *who){ pthread_mutex_lock(&authcert_list_mutex); DBG(DBG_CONTROLMORE, DBG_log("authcert list locked by '%s'", who) )}/* * unlock access to the chained authcert list */voidunlock_authcert_list(const char *who){ DBG(DBG_CONTROLMORE, DBG_log("authcert list unlocked by '%s'", who) ) pthread_mutex_unlock(&authcert_list_mutex);}/* * lock access to the chained crl list */voidlock_crl_list(const char *who){ pthread_mutex_lock(&crl_list_mutex); DBG(DBG_CONTROLMORE, DBG_log("crl list locked by '%s'", who) )}/* * unlock access to the chained crl list */voidunlock_crl_list(const char *who){ DBG(DBG_CONTROLMORE, DBG_log("crl list unlocked by '%s'", who) ) pthread_mutex_unlock(&crl_list_mutex);}/* * lock access to the ocsp cache */extern voidlock_ocsp_cache(const char *who){ pthread_mutex_lock(&ocsp_cache_mutex); DBG(DBG_CONTROLMORE, DBG_log("ocsp cache locked by '%s'", who) )}/* * unlock access to the ocsp cache */extern voidunlock_ocsp_cache(const char *who){ DBG(DBG_CONTROLMORE, DBG_log("ocsp cache unlocked by '%s'", who) ) pthread_mutex_unlock(&ocsp_cache_mutex);}/* * lock access to the chained crl fetch request list */static voidlock_crl_fetch_list(const char *who){ pthread_mutex_lock(&crl_fetch_list_mutex); DBG(DBG_CONTROLMORE, DBG_log("crl fetch request list locked by '%s'", who) )}/* * unlock access to the chained crl fetch request list */static voidunlock_crl_fetch_list(const char *who){ DBG(DBG_CONTROLMORE, DBG_log("crl fetch request list unlocked by '%s'", who) ) pthread_mutex_unlock(&crl_fetch_list_mutex);}/* * lock access to the chained ocsp fetch request list */static voidlock_ocsp_fetch_list(const char *who){ pthread_mutex_lock(&ocsp_fetch_list_mutex); DBG(DBG_CONTROLMORE, DBG_log("ocsp fetch request list locked by '%s'", who) )}/* * unlock access to the chained ocsp fetch request list */static voidunlock_ocsp_fetch_list(const char *who){ DBG(DBG_CONTROLMORE, DBG_log("ocsp fetch request list unlocked by '%s'", who) ) pthread_mutex_unlock(&ocsp_fetch_list_mutex);}/* * wakes up the sleeping fetch thread */voidwake_fetch_thread(const char *who){ if (crl_check_interval > 0) { DBG(DBG_CONTROLMORE, DBG_log("fetch thread wake call by '%s'", who) )#ifdef HAVE_THREADS pthread_mutex_lock(&fetch_wake_mutex); pthread_cond_signal(&fetch_wake_cond); pthread_mutex_unlock(&fetch_wake_mutex);#endif }}/* * free the dynamic memory used to store fetch requests */static voidfree_fetch_request(fetch_req_t *req){ pfree(req->issuer.ptr); free_generalNames(req->distributionPoints, TRUE); pfree(req);}#ifdef LIBCURL/* * writes data into a buffer * needed for libcurl */static size_twrite_buffer(void *ptr, size_t size, size_t nmemb, void *data){ size_t realsize = size * nmemb; chunk_t *mem = (chunk_t*)data; mem->ptr = (u_char *)realloc(mem->ptr, mem->len + realsize); if (mem->ptr) { memcpy(&(mem->ptr[mem->len]), ptr, realsize); mem->len += realsize; } return realsize;}#endif/* * fetches a binary blob from a url with libcurl */static err_t fetch_curl(chunk_t url LIBCURL_UNUSED, chunk_t *blob LIBCURL_UNUSED){#ifdef LIBCURL char errorbuffer[CURL_ERROR_SIZE] = ""; char *uri; chunk_t response = empty_chunk; CURLcode res; /* get it with libcurl */ CURL *curl = curl_easy_init(); if (curl != NULL) { /* we need a null terminated string for curl */ uri = alloc_bytes(url.len + 1, "null terminated url"); memcpy(uri, url.ptr, url.len); *(uri + url.len) = '\0'; DBG(DBG_CONTROL, DBG_log("Trying cURL '%s'", uri) ) curl_easy_setopt(curl, CURLOPT_URL, uri); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer); curl_easy_setopt(curl, CURLOPT_FILE, (void *)&response); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &errorbuffer); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT); res = curl_easy_perform(curl); if (res == CURLE_OK) { blob->len = response.len; blob->ptr = alloc_bytes(response.len, "curl blob"); memcpy(blob->ptr, response.ptr, response.len); } else { plog("fetching uri (%s) with libcurl failed: %s", uri, errorbuffer); } curl_easy_cleanup(curl); pfree(uri); /* not using freeanychunk because of realloc (no leak detective) */ free(response.ptr); } return strlen(errorbuffer) > 0 ? "libcurl error" : NULL;#else return "not compiled with libcurl support";#endif }#ifdef LDAP_VER/* * parses the result returned by an ldap query */static err_tparse_ldap_result(LDAP * ldap, LDAPMessage *result, chunk_t *blob){ err_t ugh = NULL; LDAPMessage * entry = ldap_first_entry(ldap, result); if (entry != NULL) { BerElement *ber = NULL; char *attr; attr = ldap_first_attribute(ldap, entry, &ber); if (attr != NULL) { struct berval **values = ldap_get_values_len(ldap, entry, attr); if (values != NULL) { if (values[0] != NULL) { blob->len = values[0]->bv_len; blob->ptr = alloc_bytes(blob->len, "ldap blob"); memcpy(blob->ptr, values[0]->bv_val, blob->len); if (values[1] != NULL) { plog("warning: more than one value was fetched from LDAP URL"); } } else { ugh = "no values in attribute"; } ldap_value_free_len(values); } else { ugh = ldap_err2string(ldap_result2error(ldap, entry, 0)); } ldap_memfree(attr); } else { ugh = ldap_err2string(ldap_result2error(ldap, entry, 0)); } ber_free(ber, 0); } else { ugh = ldap_err2string(ldap_result2error(ldap, result, 0)); } return ugh;}/* * fetches a binary blob from an ldap url */static err_tfetch_ldap_url(chunk_t url, chunk_t *blob){ LDAPURLDesc *lurl; err_t ugh = NULL; int rc; char *ldap_url = alloc_bytes(url.len + 1, "ldap query"); sprintf(ldap_url,"%.*s", (int)url.len, url.ptr); DBG(DBG_CONTROL, DBG_log("Trying LDAP URL '%s'", ldap_url) ) rc = ldap_url_parse(ldap_url, &lurl); pfree(ldap_url); if (rc == LDAP_SUCCESS) { LDAP *ldap = ldap_init(lurl->lud_host, lurl->lud_port); if (ldap != NULL) { int ldap_version = (LDAP_VER == 2)? LDAP_VERSION2 : LDAP_VERSION3; struct timeval timeout; timeout.tv_sec = FETCH_CMD_TIMEOUT; timeout.tv_usec = 0; ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version); ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout); rc = ldap_simple_bind_s(ldap, NULL, NULL); if (rc == LDAP_SUCCESS) { LDAPMessage *result; timeout.tv_sec = FETCH_CMD_TIMEOUT; timeout.tv_usec = 0; rc = ldap_search_st(ldap, lurl->lud_dn , lurl->lud_scope , lurl->lud_filter , lurl->lud_attrs , 0, &timeout, &result); if (rc == LDAP_SUCCESS) { ugh = parse_ldap_result(ldap, result, blob); ldap_msgfree(result); } else { ugh = ldap_err2string(rc); } } else { ugh = ldap_err2string(rc); } ldap_unbind_s(ldap); } else { ugh = "ldap init"; } ldap_free_urldesc(lurl); } else { ugh = ldap_err2string(rc); } return ugh;}#elsestatic err_tfetch_ldap_url(chunk_t url UNUSED , chunk_t *blob UNUSED){ return "LDAP URL fetching not activated in pluto source code";}#endif/* * fetch an ASN.1 blob coded in PEM or DER format from a URL */static err_tfetch_asn1_blob(chunk_t url, chunk_t *blob)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -