summaryrefslogtreecommitdiffabout
path: root/libetpan/src/data-types/mailstream_ssl.c
Unidiff
Diffstat (limited to 'libetpan/src/data-types/mailstream_ssl.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/data-types/mailstream_ssl.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/libetpan/src/data-types/mailstream_ssl.c b/libetpan/src/data-types/mailstream_ssl.c
new file mode 100644
index 0000000..e57fa22
--- a/dev/null
+++ b/libetpan/src/data-types/mailstream_ssl.c
@@ -0,0 +1,320 @@
1/*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36/*
37 NOTE :
38
39 The user has to call himself SSL_library_init() if he wants to
40 use SSL.
41*/
42
43#include "mailstream_ssl.h"
44#include <unistd.h>
45#include <fcntl.h>
46
47#ifndef CONFIG_H
48#define CONFIG_H
49#include "config.h"
50#endif
51
52/*
53 these 3 headers MUST be included before <sys/select.h>
54 to insure compatibility with Mac OS X (this is true for 10.2)
55*/
56#include <sys/time.h>
57#include <sys/types.h>
58#include <unistd.h>
59#include <sys/select.h>
60
61/* mailstream_low, ssl */
62
63#ifdef USE_SSL
64#include <openssl/ssl.h>
65#ifdef LIBETPAN_REENTRANT
66#include <pthread.h>
67#endif
68#endif
69
70#ifdef USE_SSL
71struct mailstream_ssl_data {
72 int fd;
73 SSL * ssl_conn;
74 SSL_CTX * ssl_ctx;
75};
76#endif
77
78#ifdef USE_SSL
79#ifdef LIBETPAN_REENTRANT
80static pthread_mutex_t ssl_lock = PTHREAD_MUTEX_INITIALIZER;
81#endif
82static int ssl_init_done = 0;
83#endif
84
85#ifdef USE_SSL
86static int mailstream_low_ssl_close(mailstream_low * s);
87static ssize_t mailstream_low_ssl_read(mailstream_low * s,
88 void * buf, size_t count);
89static ssize_t mailstream_low_ssl_write(mailstream_low * s,
90 const void * buf, size_t count);
91static void mailstream_low_ssl_free(mailstream_low * s);
92static int mailstream_low_ssl_get_fd(mailstream_low * s);
93
94static mailstream_low_driver local_mailstream_ssl_driver = {
95 mailstream_read: mailstream_low_ssl_read,
96 mailstream_write: mailstream_low_ssl_write,
97 mailstream_close: mailstream_low_ssl_close,
98 mailstream_free: mailstream_low_ssl_free,
99 mailstream_get_fd: mailstream_low_ssl_get_fd,
100};
101
102mailstream_low_driver * mailstream_ssl_driver = &local_mailstream_ssl_driver;
103#endif
104
105/* file descriptor must be given in (default) blocking-mode */
106
107#ifdef USE_SSL
108static struct mailstream_ssl_data * ssl_data_new(int fd)
109{
110 struct mailstream_ssl_data * ssl_data;
111 SSL * ssl_conn;
112 int r;
113 SSL_CTX * tmp_ctx;
114 int fd_flags;
115 int old_fd_flags;
116
117#ifdef LIBETPAN_REENTRANT
118 pthread_mutex_lock(&ssl_lock);
119#endif
120 if (!ssl_init_done) {
121 SSL_library_init();
122 ssl_init_done = 1;
123 }
124#ifdef LIBETPAN_REENTRANT
125 pthread_mutex_unlock(&ssl_lock);
126#endif
127
128 tmp_ctx = SSL_CTX_new(TLSv1_client_method());
129 if (tmp_ctx == NULL)
130 goto err;
131
132 ssl_conn = (SSL *) SSL_new(tmp_ctx);
133 if (ssl_conn == NULL)
134 goto free_ctx;
135
136 if (SSL_set_fd(ssl_conn, fd) == 0)
137 goto free_ssl_conn;
138
139 SSL_set_read_ahead(ssl_conn, 1);
140
141 r = SSL_connect(ssl_conn);
142 if (r <= 0)
143 goto free_ssl_conn;
144
145 fd_flags = fcntl(fd, F_GETFL, 0);
146 old_fd_flags = fd_flags;
147 fd_flags |= O_NDELAY;
148 r = fcntl(fd, F_SETFL, fd_flags);
149 if (r < 0)
150 goto free_ssl_conn;
151
152 ssl_data = malloc(sizeof(* ssl_data));
153 if (ssl_data == NULL)
154 goto reset_fd_flags;
155
156 ssl_data->fd = fd;
157 ssl_data->ssl_conn = ssl_conn;
158 ssl_data->ssl_ctx = tmp_ctx;
159
160 return ssl_data;
161
162 reset_fd_flags:
163 fcntl(fd, F_SETFL, old_fd_flags);
164 free_ctx:
165 SSL_CTX_free(tmp_ctx);
166 free_ssl_conn:
167 SSL_free(ssl_conn);
168 err:
169 return NULL;
170}
171
172static void ssl_data_free(struct mailstream_ssl_data * ssl_data)
173{
174 free(ssl_data);
175}
176
177static void ssl_data_close(struct mailstream_ssl_data * ssl_data)
178{
179 SSL_free(ssl_data->ssl_conn);
180 ssl_data->ssl_conn = NULL;
181 SSL_CTX_free(ssl_data->ssl_ctx);
182 ssl_data->ssl_ctx = NULL;
183 close(ssl_data->fd);
184 ssl_data->fd = -1;
185}
186#endif
187
188mailstream_low * mailstream_low_ssl_open(int fd)
189{
190#ifdef USE_SSL
191 mailstream_low * s;
192 struct mailstream_ssl_data * ssl_data;
193
194 ssl_data = ssl_data_new(fd);
195 if (ssl_data == NULL)
196 goto err;
197
198 s = mailstream_low_new(ssl_data, mailstream_ssl_driver);
199 if (s == NULL)
200 goto free_ssl_data;
201
202 return s;
203
204 free_ssl_data:
205 ssl_data_free(ssl_data);
206 err:
207 return NULL;
208#else
209 return NULL;
210#endif
211}
212
213#ifdef USE_SSL
214static int mailstream_low_ssl_close(mailstream_low * s)
215{
216 struct mailstream_ssl_data * ssl_data;
217
218 ssl_data = (struct mailstream_ssl_data *) s->data;
219 ssl_data_close(ssl_data);
220
221 return 0;
222}
223
224static void mailstream_low_ssl_free(mailstream_low * s)
225{
226 struct mailstream_ssl_data * ssl_data;
227
228 ssl_data = (struct mailstream_ssl_data *) s->data;
229 ssl_data_free(ssl_data);
230 s->data = NULL;
231
232 free(s);
233}
234
235static int mailstream_low_ssl_get_fd(mailstream_low * s)
236{
237 struct mailstream_ssl_data * ssl_data;
238
239 ssl_data = (struct mailstream_ssl_data *) s->data;
240 return ssl_data->fd;
241}
242
243static ssize_t mailstream_low_ssl_read(mailstream_low * s,
244 void * buf, size_t count)
245{
246 struct mailstream_ssl_data * ssl_data;
247 int r;
248
249 ssl_data = (struct mailstream_ssl_data *) s->data;
250
251 while (1) {
252 int ssl_r;
253 fd_set fds_read;
254 struct timeval timeout;
255
256 r = SSL_read(ssl_data->ssl_conn, buf, count);
257 if (r > 0)
258 return r;
259
260 ssl_r = SSL_get_error(ssl_data->ssl_conn, r);
261 switch (ssl_r) {
262 case SSL_ERROR_NONE:
263 return r;
264
265 case SSL_ERROR_ZERO_RETURN:
266 return r;
267
268 case SSL_ERROR_WANT_READ:
269 timeout = mailstream_network_delay;
270
271 FD_ZERO(&fds_read);
272 FD_SET(ssl_data->fd, &fds_read);
273 r = select(ssl_data->fd + 1, &fds_read, NULL, NULL, &timeout);
274 if (r == 0)
275 return -1;
276 break;
277
278 default:
279 return r;
280 }
281 }
282}
283
284static ssize_t mailstream_low_ssl_write(mailstream_low * s,
285 const void * buf, size_t count)
286{
287 struct mailstream_ssl_data * ssl_data;
288
289 ssl_data = (struct mailstream_ssl_data *) s->data;
290 return SSL_write(ssl_data->ssl_conn, buf, count);
291}
292#endif
293
294/* mailstream */
295
296mailstream * mailstream_ssl_open(int fd)
297{
298#ifdef USE_SSL
299 mailstream_low * low;
300 mailstream * s;
301
302 low = mailstream_low_ssl_open(fd);
303 if (low == NULL)
304 goto err;
305
306 s = mailstream_new(low, 8192);
307 if (s == NULL)
308 goto free_low;
309
310 return s;
311
312 free_low:
313 mailstream_low_close(low);
314 err:
315 return NULL;
316#else
317 return NULL;
318#endif
319}
320