diff options
Diffstat (limited to 'src/libstrongswan/utils/fetcher.c')
-rw-r--r-- | src/libstrongswan/utils/fetcher.c | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/src/libstrongswan/utils/fetcher.c b/src/libstrongswan/utils/fetcher.c new file mode 100644 index 000000000..6165cc1e1 --- /dev/null +++ b/src/libstrongswan/utils/fetcher.c @@ -0,0 +1,421 @@ +/** + * @file fetcher.c + * + * @brief Implementation of fetcher_t. + * + */ + +/* + * Copyright (C) 2007 Andreas Steffen + * Hochschule fuer Technik Rapperswil + * + * 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 <fetcher://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. + */ + +#ifdef LIBCURL +#include <curl/curl.h> +#endif /* LIBCURL */ + +#ifdef LIBLDAP +#include <ldap.h> +#endif /* LIBLDAP */ + +#include <library.h> +#include <debug.h> + +#include "fetcher.h" + +typedef struct private_fetcher_t private_fetcher_t; + +/** + * @brief Private Data of a fetcher_t object. + */ +struct private_fetcher_t { + /** + * Public data + */ + fetcher_t public; + + /** + * URI of the information source + */ + const char *uri; + +#ifdef LIBCURL + /** + * we use libcurl from http://curl.haxx.se/ as a fetcher + */ + CURL* curl; +#endif /* LIBCURL */ + +#ifdef LIBLDAP + /** + * we use libldap from http://www.openssl.org/ as a fetcher + */ + LDAP *ldap; + LDAPURLDesc *lurl; +#endif /* LIBLDAP */ +}; + +/** + * writes data into a dynamically resizeable chunk_t + * needed for libcurl responses + */ +static size_t curl_write_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; +} + +/** + * Implements fetcher_t.get for curl methods + */ +static chunk_t curl_get(private_fetcher_t *this) +{ + chunk_t response = chunk_empty; + +#ifdef LIBCURL + if (this->curl) + { + CURLcode res; + chunk_t curl_response = chunk_empty; + char curl_error_buffer[CURL_ERROR_SIZE]; + + curl_easy_setopt(this->curl, CURLOPT_URL, this->uri); + curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, curl_write_buffer); + curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, (void *)&curl_response); + curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, &curl_error_buffer); + curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, TRUE); + curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, FETCHER_TIMEOUT); + curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE); + + DBG1("sending curl request to '%s'...", this->uri); + res = curl_easy_perform(this->curl); + + if (res == CURLE_OK) + { + DBG1("received valid curl response"); + response = chunk_clone(curl_response); + } + else + { + DBG1("curl request failed: %s", curl_error_buffer); + } + curl_free(curl_response.ptr); + } +#else + DBG1("warning: libcurl fetching not compiled in"); +#endif /* LIBCURL */ + return response; +} + +/** + * Implements fetcher_t.post. + */ +static chunk_t http_post(private_fetcher_t *this, const char *request_type, chunk_t request) +{ + chunk_t response = chunk_empty; + +#ifdef LIBCURL + if (this->curl) + { + CURLcode res; + struct curl_slist *headers = NULL; + chunk_t curl_response = chunk_empty; + char curl_error_buffer[CURL_ERROR_SIZE]; + char content_type[BUF_LEN]; + + /* set content type header */ + snprintf(content_type, BUF_LEN, "Content-Type: %s", request_type); + headers = curl_slist_append(headers, content_type); + + /* set options */ + curl_easy_setopt(this->curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(this->curl, CURLOPT_URL, this->uri); + curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, curl_write_buffer); + curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, (void *)&curl_response); + curl_easy_setopt(this->curl, CURLOPT_POSTFIELDS, request.ptr); + curl_easy_setopt(this->curl, CURLOPT_POSTFIELDSIZE, request.len); + curl_easy_setopt(this->curl, CURLOPT_ERRORBUFFER, &curl_error_buffer); + curl_easy_setopt(this->curl, CURLOPT_FAILONERROR, TRUE); + curl_easy_setopt(this->curl, CURLOPT_CONNECTTIMEOUT, FETCHER_TIMEOUT); + curl_easy_setopt(this->curl, CURLOPT_NOSIGNAL, TRUE); + + DBG1("sending http post request to '%s'...", this->uri); + res = curl_easy_perform(this->curl); + + if (res == CURLE_OK) + { + DBG1("received valid http response"); + response = chunk_clone(curl_response); + } + else + { + DBG1("http post request using libcurl failed: %s", curl_error_buffer); + } + curl_slist_free_all(headers); + curl_free(curl_response.ptr); + } +#else + DBG1("warning: libcurl fetching not compiled in"); +#endif /* LIBCURL */ + return response; +} + +#ifdef LIBLDAP +/** + * Parses the result returned by an ldap query + */ +static chunk_t ldap_parse(LDAP *ldap, LDAPMessage *result) +{ + chunk_t response = chunk_empty; + 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) + { + response.len = values[0]->bv_len; + response.ptr = malloc(response.len); + memcpy(response.ptr, values[0]->bv_val, response.len); + + if (values[1] != NULL) + { + ugh = "more than one value was fetched - first selected"; + } + } + 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)); + } + if (ugh) + { + DBG1("ldap request failed: %s", ugh); + } + return response; +} +#endif /* LIBLDAP */ + +/** + * Implements fetcher_t.get for curl methods + */ +static chunk_t ldap_get(private_fetcher_t *this) +{ + chunk_t response = chunk_empty; + +#ifdef LIBLDAP + if (this->ldap) + { + err_t ugh = NULL; + int rc; + int ldap_version = LDAP_VERSION3; + + struct timeval timeout; + + timeout.tv_sec = FETCHER_TIMEOUT; + timeout.tv_usec = 0; + + ldap_set_option(this->ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version); + ldap_set_option(this->ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout); + + DBG1("sending ldap request to '%s'...", this->uri); + + rc = ldap_simple_bind_s(this->ldap, NULL, NULL); + if (rc == LDAP_SUCCESS) + { + LDAPMessage *result; + + timeout.tv_sec = FETCHER_TIMEOUT; + timeout.tv_usec = 0; + + rc = ldap_search_st(this->ldap, this->lurl->lud_dn, + this->lurl->lud_scope, + this->lurl->lud_filter, + this->lurl->lud_attrs, + 0, &timeout, &result); + + if (rc == LDAP_SUCCESS) + { + response = ldap_parse(this->ldap, result); + if (response.ptr) + { + DBG1("received valid ldap response"); + } + ldap_msgfree(result); + } + else + { + ugh = ldap_err2string(rc); + } + } + else + { + ugh = ldap_err2string(rc); + } + ldap_unbind_s(this->ldap); + + if (ugh) + { + DBG1("ldap request failed: %s", ugh); + } + } +#else /* !LIBLDAP */ + DBG1("warning: libldap fetching not compiled in"); +#endif /* !LIBLDAP */ + return response; +} + +/** + * Implements fetcher_t.destroy + */ +static void destroy(private_fetcher_t *this) +{ +#ifdef LIBCURL + if (this->curl) + { + curl_easy_cleanup(this->curl); + } +#endif /* LIBCURL */ + +#ifdef LIBLDAP + if (this->lurl) + { + ldap_free_urldesc(this->lurl); + } +#endif /* LIBLDAP */ + + free(this); +} + +/* + * Described in header. + */ +fetcher_t *fetcher_create(const char *uri) +{ + private_fetcher_t *this = malloc_thing(private_fetcher_t); + + /* initialize */ + this->uri = uri; + +#ifdef LIBCURL + this->curl = NULL; +#endif /* LIBCURL */ + +#ifdef LIBLDAP + this->lurl = NULL; + this->ldap = NULL; +#endif /* LIBLDAP */ + + if (strlen(uri) >= 4 && strncasecmp(uri, "ldap", 4) == 0) + { +#ifdef LIBLDAP + int rc = ldap_url_parse(uri, &this->lurl); + + if (rc == LDAP_SUCCESS) + { + this->ldap = ldap_init(this->lurl->lud_host, + this->lurl->lud_port); + } + else + { + DBG1("ldap: %s", ldap_err2string(rc)); + this->ldap = NULL; + } +#endif /* LIBLDAP */ + this->public.get = (chunk_t (*) (fetcher_t*))ldap_get; + } + else + { +#ifdef LIBCURL + this->curl = curl_easy_init(); + if (this->curl == NULL) + { + DBG1("curl_easy_init_failed()"); + } +#endif /* LIBCURL */ + this->public.get = (chunk_t (*) (fetcher_t*))curl_get; + } + + /* public functions */ + this->public.post = (chunk_t (*) (fetcher_t*,const char*,chunk_t))http_post; + this->public.destroy = (void (*) (fetcher_t*))destroy; + + return &this->public; +} + +/** + * Described in header. + */ +void fetcher_initialize(void) +{ +#ifdef LIBCURL + CURLcode res; + + /* initialize libcurl */ + DBG1("initializing libcurl"); + res = curl_global_init(CURL_GLOBAL_NOTHING); + if (res != CURLE_OK) + { + DBG1("libcurl could not be initialized: %s", curl_easy_strerror(res)); + } +#endif /* LIBCURL */ +} + +/** + * Described in header. + */ +void fetcher_finalize(void) +{ +#ifdef LIBCURL + /* finalize libcurl */ + DBG1("finalizing libcurl"); + curl_global_cleanup(); +#endif /* LIBCURL */ +} + |