I think this was accidentally changed in revision
[pidgin-git.git] / libpurple / sslconn.c
blobe6365d390eb12014e2c56672694e8e1e445d22e2
1 /**
2 * @file sslconn.c SSL API
3 * @ingroup core
4 */
6 /* purple
8 * Purple is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 #define _PURPLE_SSLCONN_C_
28 #include "internal.h"
30 #include "certificate.h"
31 #include "debug.h"
32 #include "request.h"
33 #include "sslconn.h"
35 static gboolean _ssl_initialized = FALSE;
36 static PurpleSslOps *_ssl_ops = NULL;
38 static gboolean
39 ssl_init(void)
41 PurplePlugin *plugin;
42 PurpleSslOps *ops;
44 if (_ssl_initialized)
45 return FALSE;
47 plugin = purple_plugins_find_with_id("core-ssl");
49 if (plugin != NULL && !purple_plugin_is_loaded(plugin))
50 purple_plugin_load(plugin);
52 ops = purple_ssl_get_ops();
53 if ((ops == NULL) || (ops->init == NULL) || (ops->uninit == NULL) ||
54 (ops->connectfunc == NULL) || (ops->close == NULL) ||
55 (ops->read == NULL) || (ops->write == NULL))
57 return FALSE;
60 return (_ssl_initialized = ops->init());
63 gboolean
64 purple_ssl_is_supported(void)
66 #ifdef HAVE_SSL
67 ssl_init();
68 return (purple_ssl_get_ops() != NULL);
69 #else
70 return FALSE;
71 #endif
74 static void
75 purple_ssl_connect_cb(gpointer data, gint source, const gchar *error_message)
77 PurpleSslConnection *gsc;
78 PurpleSslOps *ops;
80 gsc = data;
81 gsc->connect_data = NULL;
83 if (source < 0)
85 if (gsc->error_cb != NULL)
86 gsc->error_cb(gsc, PURPLE_SSL_CONNECT_FAILED, gsc->connect_cb_data);
88 purple_ssl_close(gsc);
89 return;
92 gsc->fd = source;
94 ops = purple_ssl_get_ops();
95 ops->connectfunc(gsc);
98 PurpleSslConnection *
99 purple_ssl_connect(PurpleAccount *account, const char *host, int port,
100 PurpleSslInputFunction func, PurpleSslErrorFunction error_func,
101 void *data)
103 return purple_ssl_connect_with_ssl_cn(account, host, port, func, error_func,
104 NULL, data);
107 PurpleSslConnection *
108 purple_ssl_connect_with_ssl_cn(PurpleAccount *account, const char *host, int port,
109 PurpleSslInputFunction func, PurpleSslErrorFunction error_func,
110 const char *ssl_cn, void *data)
112 PurpleSslConnection *gsc;
114 g_return_val_if_fail(host != NULL, NULL);
115 g_return_val_if_fail(port != 0 && port != -1, NULL);
116 g_return_val_if_fail(func != NULL, NULL);
117 g_return_val_if_fail(purple_ssl_is_supported(), NULL);
119 if (!_ssl_initialized)
121 if (!ssl_init())
122 return NULL;
125 gsc = g_new0(PurpleSslConnection, 1);
127 gsc->fd = -1;
128 gsc->host = ssl_cn ? g_strdup(ssl_cn) : g_strdup(host);
129 gsc->port = port;
130 gsc->connect_cb_data = data;
131 gsc->connect_cb = func;
132 gsc->error_cb = error_func;
134 /* TODO: Move this elsewhere */
135 gsc->verifier = purple_certificate_find_verifier("x509","tls_cached");
137 gsc->connect_data = purple_proxy_connect(NULL, account, host, port, purple_ssl_connect_cb, gsc);
139 if (gsc->connect_data == NULL)
141 g_free(gsc->host);
142 g_free(gsc);
144 return NULL;
147 return (PurpleSslConnection *)gsc;
150 static void
151 recv_cb(gpointer data, gint source, PurpleInputCondition cond)
153 PurpleSslConnection *gsc = data;
155 gsc->recv_cb(gsc->recv_cb_data, gsc, cond);
158 void
159 purple_ssl_input_add(PurpleSslConnection *gsc, PurpleSslInputFunction func,
160 void *data)
162 g_return_if_fail(func != NULL);
163 g_return_if_fail(purple_ssl_is_supported());
165 gsc->recv_cb_data = data;
166 gsc->recv_cb = func;
168 gsc->inpa = purple_input_add(gsc->fd, PURPLE_INPUT_READ, recv_cb, gsc);
171 const gchar *
172 purple_ssl_strerror(PurpleSslErrorType error)
174 switch(error) {
175 case PURPLE_SSL_CONNECT_FAILED:
176 return _("SSL Connection Failed");
177 case PURPLE_SSL_HANDSHAKE_FAILED:
178 return _("SSL Handshake Failed");
179 case PURPLE_SSL_CERTIFICATE_INVALID:
180 return _("SSL peer presented an invalid certificate");
181 default:
182 purple_debug_warning("sslconn", "Unknown SSL error code %d\n", error);
183 return _("Unknown SSL error");
187 PurpleSslConnection *
188 purple_ssl_connect_fd(PurpleAccount *account, int fd,
189 PurpleSslInputFunction func,
190 PurpleSslErrorFunction error_func,
191 void *data)
193 return purple_ssl_connect_with_host_fd(account, fd, func, error_func, NULL, data);
196 PurpleSslConnection *
197 purple_ssl_connect_with_host_fd(PurpleAccount *account, int fd,
198 PurpleSslInputFunction func,
199 PurpleSslErrorFunction error_func,
200 const char *host,
201 void *data)
203 PurpleSslConnection *gsc;
204 PurpleSslOps *ops;
206 g_return_val_if_fail(fd != -1, NULL);
207 g_return_val_if_fail(func != NULL, NULL);
208 g_return_val_if_fail(purple_ssl_is_supported(), NULL);
210 if (!_ssl_initialized)
212 if (!ssl_init())
213 return NULL;
216 gsc = g_new0(PurpleSslConnection, 1);
218 gsc->connect_cb_data = data;
219 gsc->connect_cb = func;
220 gsc->error_cb = error_func;
221 gsc->fd = fd;
222 if(host)
223 gsc->host = g_strdup(host);
225 /* TODO: Move this elsewhere */
226 gsc->verifier = purple_certificate_find_verifier("x509","tls_cached");
229 ops = purple_ssl_get_ops();
230 ops->connectfunc(gsc);
232 return (PurpleSslConnection *)gsc;
235 void
236 purple_ssl_close(PurpleSslConnection *gsc)
238 PurpleSslOps *ops;
240 g_return_if_fail(gsc != NULL);
242 purple_request_close_with_handle(gsc);
243 purple_notify_close_with_handle(gsc);
245 ops = purple_ssl_get_ops();
246 (ops->close)(gsc);
248 if (gsc->connect_data != NULL)
249 purple_proxy_connect_cancel(gsc->connect_data);
251 if (gsc->inpa > 0)
252 purple_input_remove(gsc->inpa);
254 if (gsc->fd >= 0)
255 close(gsc->fd);
257 g_free(gsc->host);
258 g_free(gsc);
261 size_t
262 purple_ssl_read(PurpleSslConnection *gsc, void *data, size_t len)
264 PurpleSslOps *ops;
266 g_return_val_if_fail(gsc != NULL, 0);
267 g_return_val_if_fail(data != NULL, 0);
268 g_return_val_if_fail(len > 0, 0);
270 ops = purple_ssl_get_ops();
271 return (ops->read)(gsc, data, len);
274 size_t
275 purple_ssl_write(PurpleSslConnection *gsc, const void *data, size_t len)
277 PurpleSslOps *ops;
279 g_return_val_if_fail(gsc != NULL, 0);
280 g_return_val_if_fail(data != NULL, 0);
281 g_return_val_if_fail(len > 0, 0);
283 ops = purple_ssl_get_ops();
284 return (ops->write)(gsc, data, len);
287 GList *
288 purple_ssl_get_peer_certificates(PurpleSslConnection *gsc)
290 PurpleSslOps *ops;
292 g_return_val_if_fail(gsc != NULL, NULL);
294 ops = purple_ssl_get_ops();
295 return (ops->get_peer_certificates)(gsc);
298 void
299 purple_ssl_set_ops(PurpleSslOps *ops)
301 _ssl_ops = ops;
304 PurpleSslOps *
305 purple_ssl_get_ops(void)
307 return _ssl_ops;
310 void
311 purple_ssl_init(void)
313 /* Although purple_ssl_is_supported will do the initialization on
314 command, SSL plugins tend to register CertificateSchemes as well
315 as providing SSL ops. */
316 if (!ssl_init()) {
317 purple_debug_error("sslconn", "Unable to initialize SSL.\n");
321 void
322 purple_ssl_uninit(void)
324 PurpleSslOps *ops;
326 if (!_ssl_initialized)
327 return;
329 ops = purple_ssl_get_ops();
330 ops->uninit();
332 _ssl_initialized = FALSE;