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

Annotation of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.19.2.6 - (hide annotations)
Fri Mar 28 16:57:52 2003 UTC (21 years ago) by lefcha
Branch: release-0_8-patches
Changes since 1.19.2.5: +3 -4 lines
File MIME type: text/plain
Correct bug with long headers along with action list and logger.

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.19.2.1 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.19.2.1 #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 lefcha 1.2
76 lefcha 1.1 #ifdef SSL_TLS
77 lefcha 1.11 if (protocol != SSL_DISABLED)
78 lefcha 1.18 if (!ssl_init(sock, protocol)) {
79 lefcha 1.19 if (sock == &sockpri)
80     info("Connected to %s using %s.\n", serv,
81 lefcha 1.19.2.1 SSL_get_cipher(*ssl));
82 lefcha 1.11 return 0;
83     } else
84     return ERROR_SSL;
85     else
86 lefcha 1.19.2.1 *ssl = NULL;
87 lefcha 1.1 #endif
88    
89 lefcha 1.19 if (sock == &sockpri)
90     info("Connected to %s.\n", serv);
91 lefcha 1.10
92 lefcha 1.1 return 0;
93     }
94    
95    
96     #ifdef SSL_TLS
97     /*
98     * Initialize Secure Socket Layer connection.
99     */
100 lefcha 1.18 int ssl_init(int *sock, unsigned int protocol)
101 lefcha 1.1 {
102     int e;
103 lefcha 1.7 unsigned int i, n = 0;
104 lefcha 1.1 SSL_CTX *ctx;
105     SSL_METHOD *method = NULL;
106 lefcha 1.3 X509 *cert;
107     char *c;
108 lefcha 1.19.2.4 const EVP_MD *evp;
109 lefcha 1.3 unsigned char digest[EVP_MAX_MD_SIZE];
110 lefcha 1.19.2.1 SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);
111 lefcha 1.2
112 lefcha 1.1 SSL_library_init();
113 lefcha 1.2
114 lefcha 1.1 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.2
126 lefcha 1.1 if (!(ctx = SSL_CTX_new(method)))
127     return ERROR_SSL;
128 lefcha 1.2
129 lefcha 1.19.2.1 if (!(*ssl = SSL_new(ctx)))
130 lefcha 1.1 return ERROR_SSL;
131 lefcha 1.2
132 lefcha 1.19.2.1 SSL_set_fd(*ssl, *sock);
133 lefcha 1.1
134 lefcha 1.19.2.1 e = SSL_connect(*ssl);
135 lefcha 1.2
136 lefcha 1.19.2.2 if (e <= 0) {
137     SSL_get_error(*ssl, e);
138 lefcha 1.1 error("imapfilter: initiating SSL connection; %s",
139 lefcha 1.19.2.2 ERR_error_string(ERR_get_error(), NULL));
140 lefcha 1.1 return ERROR_SSL;
141     }
142 lefcha 1.3 /* Get server's certificate. */
143 lefcha 1.19.2.1 if (!(cert = SSL_get_peer_certificate(*ssl)))
144 lefcha 1.3 return ERROR_SSL;
145    
146     if (!(c = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)))
147     return ERROR_SSL;
148     verbose("Server certificate subject: %s\n", c);
149 lefcha 1.15 xfree(c);
150 lefcha 1.3
151     if (!(c = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)))
152     return ERROR_SSL;
153     verbose("Server certificate issuer: %s\n", c);
154 lefcha 1.15 xfree(c);
155 lefcha 1.3
156     if (!(evp = EVP_md5()))
157     return ERROR_SSL;
158 lefcha 1.7 if (!(X509_digest(cert, evp, digest, &n)))
159 lefcha 1.3 return ERROR_SSL;
160    
161     verbose("Server key fingerprint: ");
162 lefcha 1.7 for (i = 0; i < n; i++)
163     verbose(i != n - 1 ? "%02X:" : "%02X\n", digest[i]);
164 lefcha 1.3
165     X509_free(cert);
166 lefcha 1.1 SSL_CTX_free(ctx);
167    
168     return 0;
169     }
170 lefcha 1.19
171 lefcha 1.1 #endif
172    
173    
174     /*
175     * Disconnect from mail server.
176     */
177 lefcha 1.18 int close_connection(int *sock)
178 lefcha 1.1 {
179     #ifdef SSL_TLS
180 lefcha 1.19.2.1 SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);
181    
182     if (*ssl) {
183     SSL_shutdown(*ssl);
184     SSL_free(*ssl);
185     *ssl = NULL;
186 lefcha 1.1 }
187     #endif
188    
189 lefcha 1.18 if (*sock >= 0 && close(*sock)) {
190 lefcha 1.1 error("imapfilter: closing socket; %s\n", strerror(errno));
191     return ERROR_NETWORK;
192 lefcha 1.16 } else {
193 lefcha 1.18 *sock = -1;
194 lefcha 1.1 return 0;
195 lefcha 1.16 }
196 lefcha 1.1 }
197    
198    
199     /*
200     * Read data from socket.
201     */
202 lefcha 1.18 int socket_read(int *sock, char *buf)
203 lefcha 1.1 {
204 lefcha 1.19.2.2 int f, e, s;
205 lefcha 1.1 fd_set fds;
206     struct timeval tv;
207 lefcha 1.13 struct timeval *tvp = NULL;
208 lefcha 1.19.2.1 #ifdef SSL_TLS
209     SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);
210     #endif
211 lefcha 1.7
212 lefcha 1.19.2.2 e = 0;
213 lefcha 1.8 s = 1;
214 lefcha 1.1
215 lefcha 1.19.2.6 memset(buf, 0, RESPONSE_BUF + 1);
216 lefcha 1.1
217 lefcha 1.14 if (timeout >= 0) {
218 lefcha 1.13 tv.tv_sec = timeout;
219     tv.tv_usec = 0;
220     tvp = &tv;
221     }
222 lefcha 1.18 f = fcntl(*sock, F_GETFL, 0);
223     fcntl(*sock, F_SETFL, f | O_NONBLOCK);
224 lefcha 1.1
225     FD_ZERO(&fds);
226 lefcha 1.18 FD_SET(*sock, &fds);
227 lefcha 1.1
228     #ifdef SSL_TLS
229 lefcha 1.19.2.1 if (*ssl) {
230 lefcha 1.19.2.2
231     for (;;) {
232 lefcha 1.19.2.4 if (SSL_pending(*ssl) ||
233     ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
234     FD_ISSET(*sock, &fds)))
235 lefcha 1.19.2.6 e = SSL_read(*ssl, buf, RESPONSE_BUF);
236 lefcha 1.19.2.2
237     if (e > 0)
238     break;
239    
240     switch (SSL_get_error(*ssl, e)) {
241     case SSL_ERROR_WANT_READ:
242     case SSL_ERROR_WANT_WRITE:
243     continue;
244 lefcha 1.19.2.5 case SSL_ERROR_ZERO_RETURN:
245     return ERROR_NETWORK;
246 lefcha 1.19.2.2 case SSL_ERROR_SYSCALL:
247     case SSL_ERROR_SSL:
248     fatal(ERROR_NETWORK, "imapfilter: reading data; %s",
249     ERR_error_string(ERR_get_error(), NULL));
250     default:
251     fatal(ERROR_NETWORK,
252     "imapfilter: undefined ssl error while reading data\n");
253     }
254     }
255 lefcha 1.6 } else
256 lefcha 1.19.2.3 #endif
257 lefcha 1.19.2.5 {
258 lefcha 1.19.2.4 if ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
259     FD_ISSET(*sock, &fds))
260 lefcha 1.19.2.6 e = read(*sock, buf, RESPONSE_BUF);
261 lefcha 1.19.2.5
262     if (e == -1)
263     fatal(ERROR_NETWORK, "imapfilter: reading data; %s",
264     strerror(errno));
265     else if (e == 0)
266     return ERROR_NETWORK;
267     }
268 lefcha 1.6
269 lefcha 1.18 fcntl(*sock, F_SETFL, f);
270 lefcha 1.2
271 lefcha 1.8 if (s == -1)
272 lefcha 1.19.2.2 fatal(ERROR_NETWORK, "imapfilter: waiting to read from socket; %s\n",
273 lefcha 1.6 strerror(errno));
274 lefcha 1.8 else if (!s)
275     fatal(ERROR_NETWORK,
276 lefcha 1.19.2.2 "imapfilter: timeout period expired while waiting to read "
277     "data\n");
278 lefcha 1.1
279 lefcha 1.6 return 0;
280 lefcha 1.1 }
281    
282    
283     /*
284     * Write data to socket.
285     */
286 lefcha 1.18 int socket_write(int *sock, char *data)
287 lefcha 1.1 {
288 lefcha 1.19.2.2 int f, e, s;
289     fd_set fds;
290     struct timeval tv;
291     struct timeval *tvp = NULL;
292 lefcha 1.1 #ifdef SSL_TLS
293 lefcha 1.19.2.1 SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);
294 lefcha 1.19.2.2 #endif
295    
296     e = 0;
297     s = 1;
298    
299     if (timeout >= 0) {
300     tv.tv_sec = timeout;
301     tv.tv_usec = 0;
302     tvp = &tv;
303     }
304     f = fcntl(*sock, F_GETFL, 0);
305     fcntl(*sock, F_SETFL, f | O_NONBLOCK);
306    
307     FD_ZERO(&fds);
308     FD_SET(*sock, &fds);
309 lefcha 1.1
310 lefcha 1.19.2.2 #ifdef SSL_TLS
311 lefcha 1.19.2.1 if (*ssl) {
312 lefcha 1.19.2.2 for (;;) {
313 lefcha 1.19.2.4 if ((s = select(*sock + 1, NULL, &fds, NULL, tvp) > 0 &&
314     FD_ISSET(*sock, &fds)))
315 lefcha 1.19.2.2 e = SSL_write(*ssl, data, strlen(data));
316    
317     if (e > 0)
318     break;
319    
320     switch (SSL_get_error(*ssl, e)) {
321     case SSL_ERROR_WANT_READ:
322     case SSL_ERROR_WANT_WRITE:
323     continue;
324 lefcha 1.19.2.5 case SSL_ERROR_ZERO_RETURN:
325     return ERROR_NETWORK;
326 lefcha 1.19.2.2 case SSL_ERROR_SYSCALL:
327     case SSL_ERROR_SSL:
328     fatal(ERROR_NETWORK, "imapfilter: writing data; %s",
329     ERR_error_string(ERR_get_error(), NULL));
330     default:
331     fatal(ERROR_NETWORK,
332     "imapfilter: undefined ssl error while writing data\n");
333     }
334     }
335 lefcha 1.1 } else
336 lefcha 1.19.2.3 #endif
337 lefcha 1.19.2.5 {
338 lefcha 1.19.2.4 if ((s = select(*sock + 1, NULL, &fds, NULL, tvp)) > 0 &&
339     FD_ISSET(*sock, &fds))
340 lefcha 1.19.2.5 e = write(*sock, data, strlen(data));
341    
342     if (e == -1)
343     fatal(ERROR_NETWORK, "imapfilter: writing data; %s",
344     strerror(errno));
345     }
346 lefcha 1.19.2.2
347     fcntl(*sock, F_SETFL, f);
348    
349     if (s == -1)
350     fatal(ERROR_NETWORK, "imapfilter: waiting to write to socket; %s\n",
351 lefcha 1.1 strerror(errno));
352 lefcha 1.19.2.2 else if (!s)
353     fatal(ERROR_NETWORK,
354     "imapfilter: timeout period expired while waiting to write "
355     "data\n");
356 lefcha 1.2
357 lefcha 1.1 return 0;
358     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26