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

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26