/[imapfilter]/imapfilter/socket.c
ViewVC logotype

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.30 - (show annotations)
Sun Jul 27 10:10:03 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.29: +30 -17 lines
File MIME type: text/plain
Added STARTTLS support.

1 #include <string.h>
2 #include <errno.h>
3 #include <unistd.h>
4 #include <sys/time.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <netdb.h>
9 #include <fcntl.h>
10
11 #include "config.h"
12 #include "imapfilter.h"
13
14 #ifdef SSL_TLS
15 #include <openssl/ssl.h>
16 #include <openssl/err.h>
17 #include <openssl/x509.h>
18 #endif
19
20 extern unsigned int options;
21
22 long timeout = -1; /* Server non-response timeout in seconds. */
23
24 int sockpri = -1; /* Main socket used mostly. */
25 int sockaux = -1; /* Auxiliary socked used when another
26 * connection is needed. */
27
28 #ifdef SSL_TLS
29 static SSL *sslpri = NULL;
30 static SSL *sslaux = NULL;
31
32 #endif
33
34
35
36 /*
37 * Connect to mail server.
38 */
39 int
40 init_connection(int *sock, char *serv, unsigned short int port,
41 unsigned int protocol)
42 {
43 struct sockaddr_in sa;
44 struct hostent *he;
45
46 #ifdef SSL_TLS
47 SSL **ssl;
48
49 ssl = (sock == &sockpri ? &sslpri : &sslaux);
50 #else
51 if (protocol != SSL_DISABLED) {
52 error("SSL not supported by this build\n");
53 return ERROR_SSL;
54 }
55 #endif
56
57 memset((char *)&sa, 0, sizeof(struct sockaddr_in));
58
59 *sock = socket(PF_INET, SOCK_STREAM, 0);
60
61 if (*sock < 0) {
62 error("create socket; %s\n", strerror(errno));
63 return ERROR_NETWORK;
64 }
65 if (!(he = gethostbyname(serv))) {
66 error("get network host entry of %s; %s\n", serv,
67 strerror(errno));
68 close_connection(sock);
69 return ERROR_NETWORK;
70 }
71 sa.sin_family = AF_INET;
72 sa.sin_port = htons(port);
73 sa.sin_addr = *(struct in_addr *) he->h_addr;
74
75 if (connect(*sock, (struct sockaddr *) & sa, sizeof(struct sockaddr))) {
76 error("initiating connection to %s; %s\n", serv,
77 strerror(errno));
78 close_connection(sock);
79 return ERROR_NETWORK;
80 }
81 info("Connected to %s.\n", he->h_name);
82
83 #ifdef SSL_TLS
84 if (protocol != SSL_DISABLED)
85 if (!imf_ssl_init(sock, protocol))
86 return 0;
87 else
88 return ERROR_SSL;
89 else
90 *ssl = NULL;
91 #endif
92
93 return 0;
94 }
95
96
97 #ifdef SSL_TLS
98 /*
99 * Initialize Secure Socket Layer connection.
100 */
101 int
102 imf_ssl_init(int *sock, unsigned int protocol)
103 {
104 int e;
105 SSL_CTX *ctx;
106 SSL_METHOD *method;
107 SSL **ssl;
108 SSL_CIPHER *cipher;
109 char *ver;
110 const char *name;
111 int usebits, algbits;
112
113 method = NULL;
114 ssl = (sock == &sockpri ? &sslpri : &sslaux);
115
116 SSL_library_init();
117 SSL_load_error_strings();
118
119 switch (protocol) {
120 case SSL_TLS_V1:
121 method = TLSv1_client_method();
122 break;
123 case SSL_SSL_V2:
124 case SSL_SSL_V3:
125 method = SSLv23_client_method();
126 break;
127 }
128
129 if (!(ctx = SSL_CTX_new(method)))
130 goto fail;
131
132 if (!(*ssl = SSL_new(ctx)))
133 goto fail;
134
135 SSL_set_fd(*ssl, *sock);
136
137 if ((e = SSL_connect(*ssl)) <= 0) {
138 SSL_get_error(*ssl, e);
139 error("initiating SSL connection; %s\n",
140 ERR_error_string(ERR_get_error(), NULL));
141 goto fail;
142 }
143 cipher = SSL_get_current_cipher(*ssl);
144 ver = SSL_CIPHER_get_version(cipher);
145 name = SSL_CIPHER_get_name(cipher);
146 usebits = SSL_CIPHER_get_bits(cipher, &algbits);
147 verbose("SSL/TLS handshake completed: %s with cipher %s (%d/%d bits).\n",
148 ver, name, usebits, algbits);
149
150 if (imf_ssl_cert(*ssl))
151 goto fail;
152
153 SSL_CTX_free(ctx);
154
155 return 0;
156
157 fail:
158 *ssl = NULL;
159 SSL_CTX_free(ctx);
160
161 return ERROR_SSL;
162 }
163
164 #endif /* SSL_TLS */
165
166
167 /*
168 * Disconnect from mail server.
169 */
170 int
171 close_connection(int *sock)
172 {
173 #ifdef SSL_TLS
174 SSL **ssl;
175
176 ssl = (sock == &sockpri ? &sslpri : &sslaux);
177
178 if (*ssl) {
179 SSL_shutdown(*ssl);
180 SSL_free(*ssl);
181 *ssl = NULL;
182 }
183 #endif
184
185 if (*sock >= 0 && close(*sock) == -1) {
186 error("closing socket; %s\n", strerror(errno));
187 return ERROR_NETWORK;
188 } else {
189 *sock = -1;
190 return 0;
191 }
192 }
193
194
195 /*
196 * Read data from socket.
197 */
198 int
199 socket_read(int *sock, char *buf)
200 {
201 int f, e, s;
202 fd_set fds;
203 struct timeval tv;
204 struct timeval *tvp;
205
206 #ifdef SSL_TLS
207 SSL **ssl;
208
209 #endif
210
211 e = 0;
212 s = 1;
213 tvp = NULL;
214 #ifdef SSL_TLS
215 ssl = (sock == &sockpri ? &sslpri : &sslaux);
216 #endif
217
218 memset(buf, 0, RESPONSE_BUF + 1);
219
220 if (timeout >= 0) {
221 tv.tv_sec = timeout;
222 tv.tv_usec = 0;
223 tvp = &tv;
224 }
225 f = fcntl(*sock, F_GETFL, 0);
226 fcntl(*sock, F_SETFL, f | O_NONBLOCK);
227
228 FD_ZERO(&fds);
229 FD_SET(*sock, &fds);
230
231 #ifdef SSL_TLS
232 if (*ssl) {
233 while (SSL_pending(*ssl) > 0 ||
234 ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
235 FD_ISSET(*sock, &fds))) {
236 e = SSL_read(*ssl, buf, RESPONSE_BUF);
237
238 if (e > 0)
239 break;
240
241 switch (SSL_get_error(*ssl, e)) {
242 case SSL_ERROR_WANT_READ:
243 case SSL_ERROR_WANT_WRITE:
244 continue;
245 case SSL_ERROR_ZERO_RETURN:
246 return ERROR_NETWORK;
247 case SSL_ERROR_SYSCALL:
248 case SSL_ERROR_SSL:
249 fatal(ERROR_NETWORK, "reading data; %s\n",
250 ERR_error_string(ERR_get_error(), NULL));
251 default:
252 fatal(ERROR_NETWORK,
253 "undefined ssl error while reading data\n");
254 }
255 }
256 } else
257 #endif
258 {
259 if ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
260 FD_ISSET(*sock, &fds))
261 e = read(*sock, buf, RESPONSE_BUF);
262
263 if (e == -1)
264 fatal(ERROR_NETWORK, "reading data; %s",
265 strerror(errno));
266 else if (e == 0)
267 return ERROR_NETWORK;
268 }
269
270 fcntl(*sock, F_SETFL, f);
271
272 if (s == -1)
273 fatal(ERROR_NETWORK, "waiting to read from socket; %s\n",
274 strerror(errno));
275 else if (s == 0)
276 fatal(ERROR_NETWORK,
277 "timeout period expired while waiting to read "
278 "data\n");
279
280 return 0;
281 }
282
283
284 /*
285 * Write data to socket.
286 */
287 int
288 socket_write(int *sock, char *data)
289 {
290 int f, e, s;
291 fd_set fds;
292 struct timeval tv;
293 struct timeval *tvp = NULL;
294
295 #ifdef SSL_TLS
296 SSL **ssl;
297
298 #endif
299
300 e = 0;
301 s = 1;
302 #ifdef SSL_TLS
303 ssl = (sock == &sockpri ? &sslpri : &sslaux);
304 #endif
305
306 if (timeout >= 0) {
307 tv.tv_sec = timeout;
308 tv.tv_usec = 0;
309 tvp = &tv;
310 }
311 f = fcntl(*sock, F_GETFL, 0);
312 fcntl(*sock, F_SETFL, f | O_NONBLOCK);
313
314 FD_ZERO(&fds);
315 FD_SET(*sock, &fds);
316
317 #ifdef SSL_TLS
318 if (*ssl) {
319 while ((s = select(*sock + 1, NULL, &fds, NULL, tvp) > 0 &&
320 FD_ISSET(*sock, &fds))) {
321 e = SSL_write(*ssl, data, strlen(data));
322
323 if (e > 0)
324 break;
325
326 switch (SSL_get_error(*ssl, e)) {
327 case SSL_ERROR_WANT_READ:
328 case SSL_ERROR_WANT_WRITE:
329 continue;
330 case SSL_ERROR_ZERO_RETURN:
331 return ERROR_NETWORK;
332 case SSL_ERROR_SYSCALL:
333 case SSL_ERROR_SSL:
334 fatal(ERROR_NETWORK, "writing data; %s\n",
335 ERR_error_string(ERR_get_error(), NULL));
336 default:
337 fatal(ERROR_NETWORK,
338 "undefined ssl error while writing data\n");
339 }
340 }
341 } else
342 #endif
343 {
344 if ((s = select(*sock + 1, NULL, &fds, NULL, tvp)) > 0 &&
345 FD_ISSET(*sock, &fds))
346 e = write(*sock, data, strlen(data));
347
348 if (e == -1)
349 fatal(ERROR_NETWORK, "writing data; %s",
350 strerror(errno));
351 }
352
353 fcntl(*sock, F_SETFL, f);
354
355 if (s == -1)
356 fatal(ERROR_NETWORK, "waiting to write to socket; %s\n",
357 strerror(errno));
358 else if (s == 0)
359 fatal(ERROR_NETWORK,
360 "timeout period expired while waiting to write "
361 "data\n");
362
363 return 0;
364 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26