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

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.25 - (show annotations)
Fri Feb 21 18:54:18 2003 UTC (21 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.24: +23 -12 lines
File MIME type: text/plain
Fix network bug when server aborts connection.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26