curl: For SSL features, depend on thread-safety provided by our crypto plugins
[strongswan.git] / src / libstrongswan / plugins / curl / curl_plugin.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "curl_plugin.h"
17
18 #include <library.h>
19 #include <utils/debug.h>
20 #include "curl_fetcher.h"
21
22 #include <curl/curl.h>
23
24 typedef struct private_curl_plugin_t private_curl_plugin_t;
25
26 /**
27 * private data of curl_plugin
28 */
29 struct private_curl_plugin_t {
30
31 /**
32 * public functions
33 */
34 curl_plugin_t public;
35
36 /**
37 * Supported features, CURL protocols + 1
38 */
39 plugin_feature_t *features;
40
41 /**
42 * Number of supported features
43 */
44 int count;
45 };
46
47 /**
48 * Append a feature to supported feature list
49 */
50 static void add_feature(private_curl_plugin_t *this, plugin_feature_t f)
51 {
52 this->features = realloc(this->features, ++this->count * sizeof(f));
53 this->features[this->count - 1] = f;
54 }
55
56 /**
57 * Try to add a feature, and the appropriate SSL dependencies
58 */
59 static void add_feature_with_ssl(private_curl_plugin_t *this, const char *ssl,
60 char *proto, plugin_feature_t f)
61 {
62 /* http://curl.haxx.se/libcurl/c/libcurl-tutorial.html#Multi-threading */
63 if (strpfx(ssl, "OpenSSL"))
64 {
65 add_feature(this, f);
66 add_feature(this, PLUGIN_DEPENDS(CUSTOM, "openssl-threading"));
67 }
68 else if (strpfx(ssl, "GnuTLS"))
69 {
70 add_feature(this, f);
71 add_feature(this, PLUGIN_DEPENDS(CUSTOM, "gcrypt-threading"));
72 }
73 else if (strpfx(ssl, "NSS"))
74 {
75 add_feature(this, f);
76 }
77 else
78 {
79 DBG1(DBG_LIB, "curl SSL backend '%s' not supported, %s disabled",
80 ssl, proto);
81 }
82 }
83
84 /**
85 * Get supported protocols, build plugin feature set
86 */
87 static bool query_protocols(private_curl_plugin_t *this)
88 {
89
90 struct {
91 /* protocol we are interested in, suffixed with "://" */
92 char *name;
93 /* require SSL library initialization? */
94 bool ssl;
95 } protos[] = {
96 { "file://", FALSE, },
97 { "http://", FALSE, },
98 { "https://", TRUE, },
99 { "ftp://", FALSE, },
100 };
101 curl_version_info_data *info;
102 char *name;
103 int i, j;
104
105 add_feature(this, PLUGIN_REGISTER(FETCHER, curl_fetcher_create));
106
107 info = curl_version_info(CURLVERSION_NOW);
108
109 for (i = 0; info->protocols[i]; i++)
110 {
111 for (j = 0; j < countof(protos); j++)
112 {
113 name = protos[j].name;
114 if (strlen(info->protocols[i]) == strlen(name) - strlen("://"))
115 {
116 if (strneq(info->protocols[i], name,
117 strlen(name) - strlen("://")))
118 {
119 if (protos[j].ssl)
120 {
121 add_feature_with_ssl(this, info->ssl_version, name,
122 PLUGIN_PROVIDE(FETCHER, name));
123 }
124 else
125 {
126 add_feature(this, PLUGIN_PROVIDE(FETCHER, name));
127 }
128 }
129 }
130 }
131 }
132
133 return this->count > 1;
134 }
135
136 METHOD(plugin_t, get_name, char*,
137 private_curl_plugin_t *this)
138 {
139 return "curl";
140 }
141
142 METHOD(plugin_t, get_features, int,
143 private_curl_plugin_t *this, plugin_feature_t *features[])
144 {
145 *features = this->features;
146 return this->count;
147 }
148
149 METHOD(plugin_t, destroy, void,
150 private_curl_plugin_t *this)
151 {
152 curl_global_cleanup();
153 free(this->features);
154 free(this);
155 }
156
157 /*
158 * see header file
159 */
160 plugin_t *curl_plugin_create()
161 {
162 CURLcode res;
163 private_curl_plugin_t *this;
164
165 INIT(this,
166 .public = {
167 .plugin = {
168 .get_name = _get_name,
169 .get_features = _get_features,
170 .destroy = _destroy,
171 },
172 },
173 );
174
175 res = curl_global_init(CURL_GLOBAL_SSL);
176 if (res != CURLE_OK)
177 {
178 /* no SSL support? Try without */
179 res = curl_global_init(CURL_GLOBAL_NOTHING);
180 }
181 if (res != CURLE_OK)
182 {
183 DBG1(DBG_LIB, "global libcurl initializing failed: %s",
184 curl_easy_strerror(res));
185 destroy(this);
186 return NULL;
187 }
188
189 if (!query_protocols(this))
190 {
191 DBG1(DBG_LIB, "no usable CURL protocols found, curl disabled");
192 destroy(this);
193 return NULL;
194 }
195
196 return &this->public.plugin;
197 }