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

Annotation of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.28 - (hide annotations)
Sat Mar 22 15:09:33 2003 UTC (21 years, 1 month ago) by lefcha
Branch: MAIN
Changes since 1.27: +13 -40 lines
File MIME type: text/plain
Added SSL/TLS certificate checking.

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.28 if (!init_ssl_connection(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.28 init_ssl_connection(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    
109     method = NULL;
110     ssl = (sock == &sockpri ? &sslpri : &sslaux);
111    
112     SSL_library_init();
113    
114     switch (protocol) {
115     case SSL_SSL_V2:
116     method = SSLv2_client_method();
117     break;
118     case SSL_SSL_V3:
119     method = SSLv3_client_method();
120     break;
121     case SSL_TLS_V1:
122     method = TLSv1_client_method();
123     break;
124     }
125 lefcha 1.3
126 lefcha 1.26 if (!(ctx = SSL_CTX_new(method)))
127     return ERROR_SSL;
128 lefcha 1.1
129 lefcha 1.26 if (!(*ssl = SSL_new(ctx)))
130     return ERROR_SSL;
131    
132     SSL_set_fd(*ssl, *sock);
133    
134     if ((e = SSL_connect(*ssl)) <= 0) {
135     SSL_get_error(*ssl, e);
136     error("initiating SSL connection; %s",
137     ERR_error_string(ERR_get_error(), NULL));
138     return ERROR_SSL;
139     }
140 lefcha 1.28 verbose("SSL/TLS handshake completed (%s).\n",
141     SSL_get_cipher(*ssl));
142 lefcha 1.26
143 lefcha 1.28 if (imf_ssl_cert(*ssl))
144 lefcha 1.26 return ERROR_SSL;
145    
146     SSL_CTX_free(ctx);
147    
148     return 0;
149 lefcha 1.1 }
150 lefcha 1.19
151 lefcha 1.25 #endif /* SSL_TLS */
152 lefcha 1.1
153    
154     /*
155     * Disconnect from mail server.
156     */
157 lefcha 1.26 int
158     close_connection(int *sock)
159 lefcha 1.1 {
160     #ifdef SSL_TLS
161 lefcha 1.26 SSL **ssl;
162 lefcha 1.20
163 lefcha 1.26 ssl = (sock == &sockpri ? &sslpri : &sslaux);
164    
165     if (*ssl) {
166     SSL_shutdown(*ssl);
167     SSL_free(*ssl);
168     *ssl = NULL;
169     }
170 lefcha 1.1 #endif
171    
172 lefcha 1.26 if (*sock >= 0 && close(*sock) == -1) {
173     error("closing socket; %s\n", strerror(errno));
174     return ERROR_NETWORK;
175     } else {
176     *sock = -1;
177     return 0;
178     }
179 lefcha 1.1 }
180    
181    
182     /*
183     * Read data from socket.
184     */
185 lefcha 1.26 int
186     socket_read(int *sock, char *buf)
187 lefcha 1.1 {
188 lefcha 1.26 int f, e, s;
189     fd_set fds;
190     struct timeval tv;
191     struct timeval *tvp;
192 lefcha 1.28
193 lefcha 1.20 #ifdef SSL_TLS
194 lefcha 1.26 SSL **ssl;
195    
196 lefcha 1.20 #endif
197 lefcha 1.7
198 lefcha 1.26 e = 0;
199     s = 1;
200     tvp = NULL;
201     #ifdef SSL_TLS
202     ssl = (sock == &sockpri ? &sslpri : &sslaux);
203     #endif
204 lefcha 1.1
205 lefcha 1.26 memset(buf, 0, RESPONSE_BUF);
206 lefcha 1.1
207 lefcha 1.26 if (timeout >= 0) {
208     tv.tv_sec = timeout;
209     tv.tv_usec = 0;
210     tvp = &tv;
211     }
212     f = fcntl(*sock, F_GETFL, 0);
213     fcntl(*sock, F_SETFL, f | O_NONBLOCK);
214 lefcha 1.1
215 lefcha 1.26 FD_ZERO(&fds);
216     FD_SET(*sock, &fds);
217 lefcha 1.1
218     #ifdef SSL_TLS
219 lefcha 1.26 if (*ssl) {
220     while (SSL_pending(*ssl) > 0 ||
221     ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
222     FD_ISSET(*sock, &fds))) {
223     e = SSL_read(*ssl, buf, RESPONSE_BUF - 1);
224    
225     if (e > 0)
226     break;
227    
228     switch (SSL_get_error(*ssl, e)) {
229     case SSL_ERROR_WANT_READ:
230     case SSL_ERROR_WANT_WRITE:
231     continue;
232     case SSL_ERROR_ZERO_RETURN:
233     return ERROR_NETWORK;
234     case SSL_ERROR_SYSCALL:
235     case SSL_ERROR_SSL:
236     fatal(ERROR_NETWORK, "reading data; %s",
237     ERR_error_string(ERR_get_error(), NULL));
238     default:
239     fatal(ERROR_NETWORK,
240     "undefined ssl error while reading data\n");
241     }
242     }
243     } else
244     #endif
245     {
246     if ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
247     FD_ISSET(*sock, &fds))
248     e = read(*sock, buf, RESPONSE_BUF - 1);
249    
250     if (e == -1)
251     fatal(ERROR_NETWORK, "reading data; %s",
252     strerror(errno));
253     else if (e == 0)
254     return ERROR_NETWORK;
255     }
256 lefcha 1.21
257 lefcha 1.26 fcntl(*sock, F_SETFL, f);
258 lefcha 1.21
259 lefcha 1.26 if (s == -1)
260     fatal(ERROR_NETWORK, "waiting to read from socket; %s\n",
261     strerror(errno));
262     else if (s == 0)
263 lefcha 1.21 fatal(ERROR_NETWORK,
264 lefcha 1.26 "timeout period expired while waiting to read "
265     "data\n");
266 lefcha 1.1
267 lefcha 1.26 return 0;
268 lefcha 1.1 }
269    
270    
271     /*
272     * Write data to socket.
273     */
274 lefcha 1.26 int
275     socket_write(int *sock, char *data)
276 lefcha 1.1 {
277 lefcha 1.26 int f, e, s;
278     fd_set fds;
279     struct timeval tv;
280     struct timeval *tvp = NULL;
281 lefcha 1.28
282 lefcha 1.1 #ifdef SSL_TLS
283 lefcha 1.27 SSL **ssl;
284 lefcha 1.28
285 lefcha 1.21 #endif
286 lefcha 1.28
287 lefcha 1.26 e = 0;
288     s = 1;
289 lefcha 1.27 #ifdef SSL_TLS
290     ssl = (sock == &sockpri ? &sslpri : &sslaux);
291     #endif
292 lefcha 1.21
293 lefcha 1.26 if (timeout >= 0) {
294     tv.tv_sec = timeout;
295     tv.tv_usec = 0;
296     tvp = &tv;
297     }
298     f = fcntl(*sock, F_GETFL, 0);
299     fcntl(*sock, F_SETFL, f | O_NONBLOCK);
300 lefcha 1.21
301 lefcha 1.26 FD_ZERO(&fds);
302     FD_SET(*sock, &fds);
303 lefcha 1.1
304 lefcha 1.21 #ifdef SSL_TLS
305 lefcha 1.26 if (*ssl) {
306     while ((s = select(*sock + 1, NULL, &fds, NULL, tvp) > 0 &&
307     FD_ISSET(*sock, &fds))) {
308     e = SSL_write(*ssl, data, strlen(data));
309    
310     if (e > 0)
311     break;
312    
313     switch (SSL_get_error(*ssl, e)) {
314     case SSL_ERROR_WANT_READ:
315     case SSL_ERROR_WANT_WRITE:
316     continue;
317     case SSL_ERROR_ZERO_RETURN:
318     return ERROR_NETWORK;
319     case SSL_ERROR_SYSCALL:
320     case SSL_ERROR_SSL:
321     fatal(ERROR_NETWORK, "writing data; %s",
322     ERR_error_string(ERR_get_error(), NULL));
323     default:
324     fatal(ERROR_NETWORK,
325     "undefined ssl error while writing data\n");
326     }
327     }
328     } else
329     #endif
330     {
331     if ((s = select(*sock + 1, NULL, &fds, NULL, tvp)) > 0 &&
332     FD_ISSET(*sock, &fds))
333     e = write(*sock, data, strlen(data));
334    
335     if (e == -1)
336     fatal(ERROR_NETWORK, "writing data; %s",
337     strerror(errno));
338     }
339 lefcha 1.21
340 lefcha 1.26 fcntl(*sock, F_SETFL, f);
341 lefcha 1.21
342 lefcha 1.26 if (s == -1)
343     fatal(ERROR_NETWORK, "waiting to write to socket; %s\n",
344     strerror(errno));
345     else if (s == 0)
346 lefcha 1.21 fatal(ERROR_NETWORK,
347 lefcha 1.26 "timeout period expired while waiting to write "
348     "data\n");
349 lefcha 1.2
350 lefcha 1.26 return 0;
351 lefcha 1.1 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26