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

Annotation of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.27 - (hide annotations)
Thu Mar 6 14:56:39 2003 UTC (21 years ago) by lefcha
Branch: MAIN
Changes since 1.26: +5 -5 lines
File MIME type: text/plain
Remove variable initialization from declaration.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26