4 * @brief Implementation of fetcher_t.
9 * Copyright (C) 2007 Andreas Steffen
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <fetcher://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 #include <curl/curl.h>
28 #ifndef LDAP_DEPRECATED
29 #define LDAP_DEPRECATED 1
39 typedef struct private_fetcher_t private_fetcher_t
;
42 * @brief Private Data of a fetcher_t object.
44 struct private_fetcher_t
{
51 * URI of the information source
57 * we use libcurl from http://curl.haxx.se/ as a fetcher
64 * we use libldap from http://www.openssl.org/ as a fetcher
72 * writes data into a dynamically resizeable chunk_t
73 * needed for libcurl responses
75 static size_t curl_write_buffer(void *ptr
, size_t size
, size_t nmemb
, void *data
)
77 size_t realsize
= size
* nmemb
;
78 chunk_t
*mem
= (chunk_t
*)data
;
80 mem
->ptr
= (u_char
*)realloc(mem
->ptr
, mem
->len
+ realsize
);
82 memcpy(&(mem
->ptr
[mem
->len
]), ptr
, realsize
);
89 * Implements fetcher_t.get for curl methods
91 static chunk_t
curl_get(private_fetcher_t
*this)
93 chunk_t response
= chunk_empty
;
99 chunk_t curl_response
= chunk_empty
;
100 char curl_error_buffer
[CURL_ERROR_SIZE
];
102 curl_easy_setopt(this->curl
, CURLOPT_URL
, this->uri
);
103 curl_easy_setopt(this->curl
, CURLOPT_WRITEFUNCTION
, curl_write_buffer
);
104 curl_easy_setopt(this->curl
, CURLOPT_WRITEDATA
, (void *)&curl_response
);
105 curl_easy_setopt(this->curl
, CURLOPT_ERRORBUFFER
, &curl_error_buffer
);
106 curl_easy_setopt(this->curl
, CURLOPT_FAILONERROR
, TRUE
);
107 curl_easy_setopt(this->curl
, CURLOPT_CONNECTTIMEOUT
, FETCHER_TIMEOUT
);
108 curl_easy_setopt(this->curl
, CURLOPT_NOSIGNAL
, TRUE
);
110 DBG1("sending curl request to '%s'...", this->uri
);
111 res
= curl_easy_perform(this->curl
);
115 DBG1("received valid curl response");
116 response
= chunk_clone(curl_response
);
120 DBG1("curl request failed: %s", curl_error_buffer
);
122 curl_free(curl_response
.ptr
);
125 DBG1("warning: libcurl fetching not compiled in");
131 * Implements fetcher_t.post.
133 static chunk_t
http_post(private_fetcher_t
*this, const char *request_type
, chunk_t request
)
135 chunk_t response
= chunk_empty
;
141 struct curl_slist
*headers
= NULL
;
142 chunk_t curl_response
= chunk_empty
;
143 char curl_error_buffer
[CURL_ERROR_SIZE
];
144 char content_type
[BUF_LEN
];
146 /* set content type header */
147 snprintf(content_type
, BUF_LEN
, "Content-Type: %s", request_type
);
148 headers
= curl_slist_append(headers
, content_type
);
151 curl_easy_setopt(this->curl
, CURLOPT_HTTPHEADER
, headers
);
152 curl_easy_setopt(this->curl
, CURLOPT_URL
, this->uri
);
153 curl_easy_setopt(this->curl
, CURLOPT_WRITEFUNCTION
, curl_write_buffer
);
154 curl_easy_setopt(this->curl
, CURLOPT_WRITEDATA
, (void *)&curl_response
);
155 curl_easy_setopt(this->curl
, CURLOPT_POSTFIELDS
, request
.ptr
);
156 curl_easy_setopt(this->curl
, CURLOPT_POSTFIELDSIZE
, request
.len
);
157 curl_easy_setopt(this->curl
, CURLOPT_ERRORBUFFER
, &curl_error_buffer
);
158 curl_easy_setopt(this->curl
, CURLOPT_FAILONERROR
, TRUE
);
159 curl_easy_setopt(this->curl
, CURLOPT_CONNECTTIMEOUT
, FETCHER_TIMEOUT
);
160 curl_easy_setopt(this->curl
, CURLOPT_NOSIGNAL
, TRUE
);
162 DBG1("sending http post request to '%s'...", this->uri
);
163 res
= curl_easy_perform(this->curl
);
167 DBG1("received valid http response");
168 response
= chunk_clone(curl_response
);
172 DBG1("http post request using libcurl failed: %s", curl_error_buffer
);
174 curl_slist_free_all(headers
);
175 curl_free(curl_response
.ptr
);
178 DBG1("warning: libcurl fetching not compiled in");
185 * Parses the result returned by an ldap query
187 static chunk_t
ldap_parse(LDAP
*ldap
, LDAPMessage
*result
)
189 chunk_t response
= chunk_empty
;
192 LDAPMessage
*entry
= ldap_first_entry(ldap
, result
);
196 BerElement
*ber
= NULL
;
199 attr
= ldap_first_attribute(ldap
, entry
, &ber
);
203 struct berval
**values
= ldap_get_values_len(ldap
, entry
, attr
);
207 if (values
[0] != NULL
)
209 response
.len
= values
[0]->bv_len
;
210 response
.ptr
= malloc(response
.len
);
211 memcpy(response
.ptr
, values
[0]->bv_val
, response
.len
);
213 if (values
[1] != NULL
)
215 ugh
= "more than one value was fetched - first selected";
220 ugh
= "no values in attribute";
222 ldap_value_free_len(values
);
226 ugh
= ldap_err2string(ldap_result2error(ldap
, entry
, 0));
232 ugh
= ldap_err2string(ldap_result2error(ldap
, entry
, 0));
238 ugh
= ldap_err2string(ldap_result2error(ldap
, result
, 0));
242 DBG1("ldap request failed: %s", ugh
);
249 * Implements fetcher_t.get for curl methods
251 static chunk_t
ldap_get(private_fetcher_t
*this)
253 chunk_t response
= chunk_empty
;
260 int ldap_version
= LDAP_VERSION3
;
262 struct timeval timeout
;
264 timeout
.tv_sec
= FETCHER_TIMEOUT
;
267 ldap_set_option(this->ldap
, LDAP_OPT_PROTOCOL_VERSION
, &ldap_version
);
268 ldap_set_option(this->ldap
, LDAP_OPT_NETWORK_TIMEOUT
, &timeout
);
270 DBG1("sending ldap request to '%s'...", this->uri
);
272 rc
= ldap_simple_bind_s(this->ldap
, NULL
, NULL
);
273 if (rc
== LDAP_SUCCESS
)
277 timeout
.tv_sec
= FETCHER_TIMEOUT
;
280 rc
= ldap_search_st(this->ldap
, this->lurl
->lud_dn
,
281 this->lurl
->lud_scope
,
282 this->lurl
->lud_filter
,
283 this->lurl
->lud_attrs
,
284 0, &timeout
, &result
);
286 if (rc
== LDAP_SUCCESS
)
288 response
= ldap_parse(this->ldap
, result
);
291 DBG1("received valid ldap response");
293 ldap_msgfree(result
);
297 ugh
= ldap_err2string(rc
);
302 ugh
= ldap_err2string(rc
);
304 ldap_unbind_s(this->ldap
);
308 DBG1("ldap request failed: %s", ugh
);
312 DBG1("warning: libldap fetching not compiled in");
313 #endif /* !LIBLDAP */
318 * Implements fetcher_t.destroy
320 static void destroy(private_fetcher_t
*this)
325 curl_easy_cleanup(this->curl
);
332 ldap_free_urldesc(this->lurl
);
340 * Described in header.
342 fetcher_t
*fetcher_create(const char *uri
)
344 private_fetcher_t
*this = malloc_thing(private_fetcher_t
);
358 if (strlen(uri
) >= 4 && strncasecmp(uri
, "ldap", 4) == 0)
361 int rc
= ldap_url_parse(uri
, &this->lurl
);
363 if (rc
== LDAP_SUCCESS
)
365 this->ldap
= ldap_init(this->lurl
->lud_host
,
366 this->lurl
->lud_port
);
370 DBG1("ldap: %s", ldap_err2string(rc
));
374 this->public.get
= (chunk_t (*) (fetcher_t
*))ldap_get
;
379 this->curl
= curl_easy_init();
380 if (this->curl
== NULL
)
382 DBG1("curl_easy_init_failed()");
385 this->public.get
= (chunk_t (*) (fetcher_t
*))curl_get
;
388 /* public functions */
389 this->public.post
= (chunk_t (*) (fetcher_t
*,const char*,chunk_t
))http_post
;
390 this->public.destroy
= (void (*) (fetcher_t
*))destroy
;
392 return &this->public;
396 * Described in header.
398 void fetcher_initialize(void)
403 /* initialize libcurl */
404 DBG1("initializing libcurl");
405 res
= curl_global_init(CURL_GLOBAL_NOTHING
);
408 DBG1("libcurl could not be initialized: %s", curl_easy_strerror(res
));
414 * Described in header.
416 void fetcher_finalize(void)
419 /* finalize libcurl */
420 DBG1("finalizing libcurl");
421 curl_global_cleanup();