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

Annotation of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.23 - (hide annotations)
Sat Jan 18 02:06:23 2003 UTC (21 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.22: +9 -9 lines
File MIME type: text/plain
Stylistic changes.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26