summaryrefslogtreecommitdiff
path: root/src/libstrongswan/utils/fetcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/utils/fetcher.c')
-rw-r--r--src/libstrongswan/utils/fetcher.c421
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 */
+}
+