added #define LDAP_DEPRECATED in order to use old ldap_init() function
[strongswan.git] / src / libstrongswan / utils / fetcher.c
1 /**
2 * @file fetcher.c
3 *
4 * @brief Implementation of fetcher_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 Andreas Steffen
10 * Hochschule fuer Technik Rapperswil
11 *
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>.
16 *
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
20 * for more details.
21 */
22
23 #ifdef LIBCURL
24 #include <curl/curl.h>
25 #endif /* LIBCURL */
26
27 #ifdef LIBLDAP
28 #ifndef LDAP_DEPRECATED
29 #define LDAP_DEPRECATED 1
30 #endif
31 #include <ldap.h>
32 #endif /* LIBLDAP */
33
34 #include <library.h>
35 #include <debug.h>
36
37 #include "fetcher.h"
38
39 typedef struct private_fetcher_t private_fetcher_t;
40
41 /**
42 * @brief Private Data of a fetcher_t object.
43 */
44 struct private_fetcher_t {
45 /**
46 * Public data
47 */
48 fetcher_t public;
49
50 /**
51 * URI of the information source
52 */
53 const char *uri;
54
55 #ifdef LIBCURL
56 /**
57 * we use libcurl from http://curl.haxx.se/ as a fetcher
58 */
59 CURL* curl;
60 #endif /* LIBCURL */
61
62 #ifdef LIBLDAP
63 /**
64 * we use libldap from http://www.openssl.org/ as a fetcher
65 */
66 LDAP *ldap;
67 LDAPURLDesc *lurl;
68 #endif /* LIBLDAP */
69 };
70
71 /**
72 * writes data into a dynamically resizeable chunk_t
73 * needed for libcurl responses
74 */
75 static size_t curl_write_buffer(void *ptr, size_t size, size_t nmemb, void *data)
76 {
77 size_t realsize = size * nmemb;
78 chunk_t *mem = (chunk_t*)data;
79
80 mem->ptr = (u_char *)realloc(mem->ptr, mem->len + realsize);
81 if (mem->ptr) {
82 memcpy(&(mem->ptr[mem->len]), ptr, realsize);
83 mem->len += realsize;
84 }
85 return realsize;
86 }
87
88 /**
89 * Implements fetcher_t.get for curl methods
90 */
91 static chunk_t curl_get(private_fetcher_t *this)
92 {
93 chunk_t response = chunk_empty;
94
95 #ifdef LIBCURL
96 if (this->curl)
97 {
98 CURLcode res;
99 chunk_t curl_response = chunk_empty;
100 char curl_error_buffer[CURL_ERROR_SIZE];
101
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);
109
110 DBG1("sending curl request to '%s'...", this->uri);
111 res = curl_easy_perform(this->curl);
112
113 if (res == CURLE_OK)
114 {
115 DBG1("received valid curl response");
116 response = chunk_clone(curl_response);
117 }
118 else
119 {
120 DBG1("curl request failed: %s", curl_error_buffer);
121 }
122 curl_free(curl_response.ptr);
123 }
124 #else
125 DBG1("warning: libcurl fetching not compiled in");
126 #endif /* LIBCURL */
127 return response;
128 }
129
130 /**
131 * Implements fetcher_t.post.
132 */
133 static chunk_t http_post(private_fetcher_t *this, const char *request_type, chunk_t request)
134 {
135 chunk_t response = chunk_empty;
136
137 #ifdef LIBCURL
138 if (this->curl)
139 {
140 CURLcode res;
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];
145
146 /* set content type header */
147 snprintf(content_type, BUF_LEN, "Content-Type: %s", request_type);
148 headers = curl_slist_append(headers, content_type);
149
150 /* set options */
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);
161
162 DBG1("sending http post request to '%s'...", this->uri);
163 res = curl_easy_perform(this->curl);
164
165 if (res == CURLE_OK)
166 {
167 DBG1("received valid http response");
168 response = chunk_clone(curl_response);
169 }
170 else
171 {
172 DBG1("http post request using libcurl failed: %s", curl_error_buffer);
173 }
174 curl_slist_free_all(headers);
175 curl_free(curl_response.ptr);
176 }
177 #else
178 DBG1("warning: libcurl fetching not compiled in");
179 #endif /* LIBCURL */
180 return response;
181 }
182
183 #ifdef LIBLDAP
184 /**
185 * Parses the result returned by an ldap query
186 */
187 static chunk_t ldap_parse(LDAP *ldap, LDAPMessage *result)
188 {
189 chunk_t response = chunk_empty;
190 err_t ugh = NULL;
191
192 LDAPMessage *entry = ldap_first_entry(ldap, result);
193
194 if (entry != NULL)
195 {
196 BerElement *ber = NULL;
197 char *attr;
198
199 attr = ldap_first_attribute(ldap, entry, &ber);
200
201 if (attr != NULL)
202 {
203 struct berval **values = ldap_get_values_len(ldap, entry, attr);
204
205 if (values != NULL)
206 {
207 if (values[0] != NULL)
208 {
209 response.len = values[0]->bv_len;
210 response.ptr = malloc(response.len);
211 memcpy(response.ptr, values[0]->bv_val, response.len);
212
213 if (values[1] != NULL)
214 {
215 ugh = "more than one value was fetched - first selected";
216 }
217 }
218 else
219 {
220 ugh = "no values in attribute";
221 }
222 ldap_value_free_len(values);
223 }
224 else
225 {
226 ugh = ldap_err2string(ldap_result2error(ldap, entry, 0));
227 }
228 ldap_memfree(attr);
229 }
230 else
231 {
232 ugh = ldap_err2string(ldap_result2error(ldap, entry, 0));
233 }
234 ber_free(ber, 0);
235 }
236 else
237 {
238 ugh = ldap_err2string(ldap_result2error(ldap, result, 0));
239 }
240 if (ugh)
241 {
242 DBG1("ldap request failed: %s", ugh);
243 }
244 return response;
245 }
246 #endif /* LIBLDAP */
247
248 /**
249 * Implements fetcher_t.get for curl methods
250 */
251 static chunk_t ldap_get(private_fetcher_t *this)
252 {
253 chunk_t response = chunk_empty;
254
255 #ifdef LIBLDAP
256 if (this->ldap)
257 {
258 err_t ugh = NULL;
259 int rc;
260 int ldap_version = LDAP_VERSION3;
261
262 struct timeval timeout;
263
264 timeout.tv_sec = FETCHER_TIMEOUT;
265 timeout.tv_usec = 0;
266
267 ldap_set_option(this->ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
268 ldap_set_option(this->ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
269
270 DBG1("sending ldap request to '%s'...", this->uri);
271
272 rc = ldap_simple_bind_s(this->ldap, NULL, NULL);
273 if (rc == LDAP_SUCCESS)
274 {
275 LDAPMessage *result;
276
277 timeout.tv_sec = FETCHER_TIMEOUT;
278 timeout.tv_usec = 0;
279
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);
285
286 if (rc == LDAP_SUCCESS)
287 {
288 response = ldap_parse(this->ldap, result);
289 if (response.ptr)
290 {
291 DBG1("received valid ldap response");
292 }
293 ldap_msgfree(result);
294 }
295 else
296 {
297 ugh = ldap_err2string(rc);
298 }
299 }
300 else
301 {
302 ugh = ldap_err2string(rc);
303 }
304 ldap_unbind_s(this->ldap);
305
306 if (ugh)
307 {
308 DBG1("ldap request failed: %s", ugh);
309 }
310 }
311 #else /* !LIBLDAP */
312 DBG1("warning: libldap fetching not compiled in");
313 #endif /* !LIBLDAP */
314 return response;
315 }
316
317 /**
318 * Implements fetcher_t.destroy
319 */
320 static void destroy(private_fetcher_t *this)
321 {
322 #ifdef LIBCURL
323 if (this->curl)
324 {
325 curl_easy_cleanup(this->curl);
326 }
327 #endif /* LIBCURL */
328
329 #ifdef LIBLDAP
330 if (this->lurl)
331 {
332 ldap_free_urldesc(this->lurl);
333 }
334 #endif /* LIBLDAP */
335
336 free(this);
337 }
338
339 /*
340 * Described in header.
341 */
342 fetcher_t *fetcher_create(const char *uri)
343 {
344 private_fetcher_t *this = malloc_thing(private_fetcher_t);
345
346 /* initialize */
347 this->uri = uri;
348
349 #ifdef LIBCURL
350 this->curl = NULL;
351 #endif /* LIBCURL */
352
353 #ifdef LIBLDAP
354 this->lurl = NULL;
355 this->ldap = NULL;
356 #endif /* LIBLDAP */
357
358 if (strlen(uri) >= 4 && strncasecmp(uri, "ldap", 4) == 0)
359 {
360 #ifdef LIBLDAP
361 int rc = ldap_url_parse(uri, &this->lurl);
362
363 if (rc == LDAP_SUCCESS)
364 {
365 this->ldap = ldap_init(this->lurl->lud_host,
366 this->lurl->lud_port);
367 }
368 else
369 {
370 DBG1("ldap: %s", ldap_err2string(rc));
371 this->ldap = NULL;
372 }
373 #endif /* LIBLDAP */
374 this->public.get = (chunk_t (*) (fetcher_t*))ldap_get;
375 }
376 else
377 {
378 #ifdef LIBCURL
379 this->curl = curl_easy_init();
380 if (this->curl == NULL)
381 {
382 DBG1("curl_easy_init_failed()");
383 }
384 #endif /* LIBCURL */
385 this->public.get = (chunk_t (*) (fetcher_t*))curl_get;
386 }
387
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;
391
392 return &this->public;
393 }
394
395 /**
396 * Described in header.
397 */
398 void fetcher_initialize(void)
399 {
400 #ifdef LIBCURL
401 CURLcode res;
402
403 /* initialize libcurl */
404 DBG1("initializing libcurl");
405 res = curl_global_init(CURL_GLOBAL_NOTHING);
406 if (res != CURLE_OK)
407 {
408 DBG1("libcurl could not be initialized: %s", curl_easy_strerror(res));
409 }
410 #endif /* LIBCURL */
411 }
412
413 /**
414 * Described in header.
415 */
416 void fetcher_finalize(void)
417 {
418 #ifdef LIBCURL
419 /* finalize libcurl */
420 DBG1("finalizing libcurl");
421 curl_global_cleanup();
422 #endif /* LIBCURL */
423 }
424