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

Annotation of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.30 - (hide 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 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.28 extern unsigned int options;
21 lefcha 1.1
22 lefcha 1.14 long timeout = -1; /* Server non-response timeout in seconds. */
23 lefcha 1.1
24 lefcha 1.18 int sockpri = -1; /* Main socket used mostly. */
25     int sockaux = -1; /* Auxiliary socked used when another
26 lefcha 1.26 * connection is needed. */
27    
28 lefcha 1.13 #ifdef SSL_TLS
29 lefcha 1.20 static SSL *sslpri = NULL;
30     static SSL *sslaux = NULL;
31 lefcha 1.26
32 lefcha 1.1 #endif
33    
34    
35 lefcha 1.25
36 lefcha 1.1 /*
37     * Connect to mail server.
38     */
39 lefcha 1.26 int
40     init_connection(int *sock, char *serv, unsigned short int port,
41     unsigned int protocol)
42 lefcha 1.1 {
43 lefcha 1.26 struct sockaddr_in sa;
44     struct hostent *he;
45    
46 lefcha 1.20 #ifdef SSL_TLS
47 lefcha 1.26 SSL **ssl;
48    
49     ssl = (sock == &sockpri ? &sslpri : &sslaux);
50 lefcha 1.20 #else
51 lefcha 1.26 if (protocol != SSL_DISABLED) {
52     error("SSL not supported by this build\n");
53     return ERROR_SSL;
54     }
55 lefcha 1.17 #endif
56 lefcha 1.1
57 lefcha 1.26 memset((char *)&sa, 0, sizeof(struct sockaddr_in));
58 lefcha 1.1
59 lefcha 1.26 *sock = socket(PF_INET, SOCK_STREAM, 0);
60 lefcha 1.2
61 lefcha 1.26 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 lefcha 1.28 info("Connected to %s.\n", he->h_name);
82    
83 lefcha 1.1 #ifdef SSL_TLS
84 lefcha 1.26 if (protocol != SSL_DISABLED)
85 lefcha 1.30 if (!imf_ssl_init(sock, protocol))
86 lefcha 1.26 return 0;
87 lefcha 1.28 else
88 lefcha 1.26 return ERROR_SSL;
89     else
90     *ssl = NULL;
91 lefcha 1.1 #endif
92    
93 lefcha 1.26 return 0;
94 lefcha 1.1 }
95    
96    
97     #ifdef SSL_TLS
98     /*
99     * Initialize Secure Socket Layer connection.
100     */
101 lefcha 1.26 int
102 lefcha 1.30 imf_ssl_init(int *sock, unsigned int protocol)
103 lefcha 1.1 {
104 lefcha 1.26 int e;
105     SSL_CTX *ctx;
106     SSL_METHOD *method;
107     SSL **ssl;
108 lefcha 1.30 SSL_CIPHER *cipher;
109     char *ver;
110     const char *name;
111     int usebits, algbits;
112 lefcha 1.26
113     method = NULL;
114     ssl = (sock == &sockpri ? &sslpri : &sslaux);
115    
116     SSL_library_init();
117 lefcha 1.30 SSL_load_error_strings();
118 lefcha 1.26
119     switch (protocol) {
120 lefcha 1.30 case SSL_TLS_V1:
121     method = TLSv1_client_method();
122     break;
123 lefcha 1.26 case SSL_SSL_V2:
124     case SSL_SSL_V3:
125 lefcha 1.30 method = SSLv23_client_method();
126 lefcha 1.26 break;
127     }
128 lefcha 1.3
129 lefcha 1.26 if (!(ctx = SSL_CTX_new(method)))
130 lefcha 1.30 goto fail;
131 lefcha 1.1
132 lefcha 1.26 if (!(*ssl = SSL_new(ctx)))
133 lefcha 1.30 goto fail;
134 lefcha 1.26
135     SSL_set_fd(*ssl, *sock);
136    
137     if ((e = SSL_connect(*ssl)) <= 0) {
138     SSL_get_error(*ssl, e);
139 lefcha 1.30 error("initiating SSL connection; %s\n",
140 lefcha 1.26 ERR_error_string(ERR_get_error(), NULL));
141 lefcha 1.30 goto fail;
142 lefcha 1.26 }
143 lefcha 1.30 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 lefcha 1.26
150 lefcha 1.28 if (imf_ssl_cert(*ssl))
151 lefcha 1.30 goto fail;
152 lefcha 1.26
153     SSL_CTX_free(ctx);
154    
155     return 0;
156 lefcha 1.30
157     fail:
158     *ssl = NULL;
159     SSL_CTX_free(ctx);
160    
161     return ERROR_SSL;
162 lefcha 1.1 }
163 lefcha 1.19
164 lefcha 1.25 #endif /* SSL_TLS */
165 lefcha 1.1
166    
167     /*
168     * Disconnect from mail server.
169     */
170 lefcha 1.26 int
171     close_connection(int *sock)
172 lefcha 1.1 {
173     #ifdef SSL_TLS
174 lefcha 1.26 SSL **ssl;
175 lefcha 1.20
176 lefcha 1.26 ssl = (sock == &sockpri ? &sslpri : &sslaux);
177    
178     if (*ssl) {
179     SSL_shutdown(*ssl);
180     SSL_free(*ssl);
181     *ssl = NULL;
182     }
183 lefcha 1.1 #endif
184    
185 lefcha 1.26 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 lefcha 1.1 }
193    
194    
195     /*
196     * Read data from socket.
197     */
198 lefcha 1.26 int
199     socket_read(int *sock, char *buf)
200 lefcha 1.1 {
201 lefcha 1.26 int f, e, s;
202     fd_set fds;
203     struct timeval tv;
204     struct timeval *tvp;
205 lefcha 1.28
206 lefcha 1.20 #ifdef SSL_TLS
207 lefcha 1.26 SSL **ssl;
208    
209 lefcha 1.20 #endif
210 lefcha 1.7
211 lefcha 1.26 e = 0;
212     s = 1;
213     tvp = NULL;
214     #ifdef SSL_TLS
215     ssl = (sock == &sockpri ? &sslpri : &sslaux);
216     #endif
217 lefcha 1.1
218 lefcha 1.29 memset(buf, 0, RESPONSE_BUF + 1);
219 lefcha 1.1
220 lefcha 1.26 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 lefcha 1.1
228 lefcha 1.26 FD_ZERO(&fds);
229     FD_SET(*sock, &fds);
230 lefcha 1.1
231     #ifdef SSL_TLS
232 lefcha 1.26 if (*ssl) {
233     while (SSL_pending(*ssl) > 0 ||
234     ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
235     FD_ISSET(*sock, &fds))) {
236 lefcha 1.29 e = SSL_read(*ssl, buf, RESPONSE_BUF);
237 lefcha 1.26
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 lefcha 1.30 fatal(ERROR_NETWORK, "reading data; %s\n",
250 lefcha 1.26 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 lefcha 1.29 e = read(*sock, buf, RESPONSE_BUF);
262 lefcha 1.26
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 lefcha 1.21
270 lefcha 1.26 fcntl(*sock, F_SETFL, f);
271 lefcha 1.21
272 lefcha 1.26 if (s == -1)
273     fatal(ERROR_NETWORK, "waiting to read from socket; %s\n",
274     strerror(errno));
275     else if (s == 0)
276 lefcha 1.21 fatal(ERROR_NETWORK,
277 lefcha 1.26 "timeout period expired while waiting to read "
278     "data\n");
279 lefcha 1.1
280 lefcha 1.26 return 0;
281 lefcha 1.1 }
282    
283    
284     /*
285     * Write data to socket.
286     */
287 lefcha 1.26 int
288     socket_write(int *sock, char *data)
289 lefcha 1.1 {
290 lefcha 1.26 int f, e, s;
291     fd_set fds;
292     struct timeval tv;
293     struct timeval *tvp = NULL;
294 lefcha 1.28
295 lefcha 1.1 #ifdef SSL_TLS
296 lefcha 1.27 SSL **ssl;
297 lefcha 1.28
298 lefcha 1.21 #endif
299 lefcha 1.28
300 lefcha 1.26 e = 0;
301     s = 1;
302 lefcha 1.27 #ifdef SSL_TLS
303     ssl = (sock == &sockpri ? &sslpri : &sslaux);
304     #endif
305 lefcha 1.21
306 lefcha 1.26 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 lefcha 1.21
314 lefcha 1.26 FD_ZERO(&fds);
315     FD_SET(*sock, &fds);
316 lefcha 1.1
317 lefcha 1.21 #ifdef SSL_TLS
318 lefcha 1.26 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 lefcha 1.30 fatal(ERROR_NETWORK, "writing data; %s\n",
335 lefcha 1.26 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 lefcha 1.21
353 lefcha 1.26 fcntl(*sock, F_SETFL, f);
354 lefcha 1.21
355 lefcha 1.26 if (s == -1)
356     fatal(ERROR_NETWORK, "waiting to write to socket; %s\n",
357     strerror(errno));
358     else if (s == 0)
359 lefcha 1.21 fatal(ERROR_NETWORK,
360 lefcha 1.26 "timeout period expired while waiting to write "
361     "data\n");
362 lefcha 1.2
363 lefcha 1.26 return 0;
364 lefcha 1.1 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26