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

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.24 - (show annotations)
Sat Feb 1 19:44:40 2003 UTC (21 years, 2 months ago) by lefcha
Branch: MAIN
Changes since 1.23: +1 -1 lines
File MIME type: text/plain
Correction of variable's data type.

1 #include <string.h>
2 #include <errno.h>
3 #include <unistd.h>
4 #include <sys/time.h>
5 #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 #include <openssl/x509.h>
18 #endif
19
20
21 long timeout = -1; /* Server non-response timeout in seconds. */
22
23 int sockpri = -1; /* Main socket used mostly. */
24 int sockaux = -1; /* Auxiliary socked used when another
25 connection is needed. */
26 #ifdef SSL_TLS
27 static SSL *sslpri = NULL;
28 static SSL *sslaux = NULL;
29 #endif
30
31
32 /*
33 * Connect to mail server.
34 */
35 int init_connection(int *sock, char *serv, unsigned short int port,
36 unsigned int protocol)
37 {
38 struct sockaddr_in sa;
39 struct hostent *he;
40 #ifdef SSL_TLS
41 SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);
42 #else
43 if (protocol != SSL_DISABLED) {
44 error("imapfilter: SSL not supported by this build\n");
45 return ERROR_SSL;
46 }
47 #endif
48
49 memset((char *)&sa, 0, sizeof(struct sockaddr_in));
50
51 *sock = socket(PF_INET, SOCK_STREAM, 0);
52
53 if (*sock < 0) {
54 error("imapfilter: create socket; %s\n", strerror(errno));
55 return ERROR_NETWORK;
56 }
57 if (!(he = gethostbyname(serv))) {
58 error("imapfilter: get network host entry of %s; %s\n", serv,
59 strerror(errno));
60 close_connection(sock);
61 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 xstrncpy(serv, he->h_name, SERVER_LEN - 1);
68
69 if (connect(*sock, (struct sockaddr *) & sa, sizeof(struct sockaddr))) {
70 error("imapfilter: initiating connection to %s; %s\n", serv,
71 strerror(errno));
72 close_connection(sock);
73 return ERROR_NETWORK;
74 }
75 log_info(LOG_SERVER, serv);
76
77 #ifdef SSL_TLS
78 if (protocol != SSL_DISABLED)
79 if (!ssl_init(sock, protocol)) {
80 if (sock == &sockpri)
81 info("Connected to %s using %s.\n", serv,
82 SSL_get_cipher(*ssl));
83 return 0;
84 } else
85 return ERROR_SSL;
86 else
87 *ssl = NULL;
88 #endif
89
90 if (sock == &sockpri)
91 info("Connected to %s.\n", serv);
92
93 return 0;
94 }
95
96
97 #ifdef SSL_TLS
98 /*
99 * Initialize Secure Socket Layer connection.
100 */
101 int ssl_init(int *sock, unsigned int protocol)
102 {
103 int e;
104 unsigned int i, n = 0;
105 SSL_CTX *ctx;
106 SSL_METHOD *method = NULL;
107 X509 *cert;
108 char *c;
109 const EVP_MD *evp;
110 unsigned char digest[EVP_MAX_MD_SIZE];
111 SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);
112
113 SSL_library_init();
114
115 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
127 if (!(ctx = SSL_CTX_new(method)))
128 return ERROR_SSL;
129
130 if (!(*ssl = SSL_new(ctx)))
131 return ERROR_SSL;
132
133 SSL_set_fd(*ssl, *sock);
134
135 e = SSL_connect(*ssl);
136
137 if (e <= 0) {
138 SSL_get_error(*ssl, e);
139 error("imapfilter: initiating SSL connection; %s",
140 ERR_error_string(ERR_get_error(), NULL));
141 return ERROR_SSL;
142 }
143 /* Get server's certificate. */
144 if (!(cert = SSL_get_peer_certificate(*ssl)))
145 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 xfree(c);
151
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 xfree(c);
156
157 if (!(evp = EVP_md5()))
158 return ERROR_SSL;
159 if (!(X509_digest(cert, evp, digest, &n)))
160 return ERROR_SSL;
161
162 verbose("Server key fingerprint: ");
163 for (i = 0; i < n; i++)
164 verbose(i != n - 1 ? "%02X:" : "%02X\n", digest[i]);
165
166 X509_free(cert);
167 SSL_CTX_free(ctx);
168
169 return 0;
170 }
171
172 #endif
173
174
175 /*
176 * Disconnect from mail server.
177 */
178 int close_connection(int *sock)
179 {
180 #ifdef SSL_TLS
181 SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);
182
183 if (*ssl) {
184 SSL_shutdown(*ssl);
185 SSL_free(*ssl);
186 *ssl = NULL;
187 }
188 #endif
189
190 if (*sock >= 0 && close(*sock)) {
191 error("imapfilter: closing socket; %s\n", strerror(errno));
192 return ERROR_NETWORK;
193 } else {
194 *sock = -1;
195 return 0;
196 }
197 }
198
199
200 /*
201 * Read data from socket.
202 */
203 int socket_read(int *sock, char *buf)
204 {
205 int f, e, s;
206 fd_set fds;
207 struct timeval tv;
208 struct timeval *tvp = NULL;
209 #ifdef SSL_TLS
210 SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);
211 #endif
212
213 e = 0;
214 s = 1;
215
216 memset(buf, 0, RESPONSE_BUF);
217
218 if (timeout >= 0) {
219 tv.tv_sec = timeout;
220 tv.tv_usec = 0;
221 tvp = &tv;
222 }
223 f = fcntl(*sock, F_GETFL, 0);
224 fcntl(*sock, F_SETFL, f | O_NONBLOCK);
225
226 FD_ZERO(&fds);
227 FD_SET(*sock, &fds);
228
229 #ifdef SSL_TLS
230 if (*ssl) {
231
232 for (;;) {
233 if (SSL_pending(*ssl) ||
234 ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
235 FD_ISSET(*sock, &fds)))
236 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 } else
255 #endif
256 if ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
257 FD_ISSET(*sock, &fds))
258 e = read(*sock, buf, RESPONSE_BUF - 1);
259
260 if (e == -1)
261 fatal(ERROR_NETWORK, "imapfilter: reading data; %s",
262 strerror(errno));
263
264 fcntl(*sock, F_SETFL, f);
265
266 if (s == -1)
267 fatal(ERROR_NETWORK, "imapfilter: waiting to read from socket; %s\n",
268 strerror(errno));
269 else if (!s)
270 fatal(ERROR_NETWORK,
271 "imapfilter: timeout period expired while waiting to read "
272 "data\n");
273
274 return 0;
275 }
276
277
278 /*
279 * Write data to socket.
280 */
281 int socket_write(int *sock, char *data)
282 {
283 int f, e, s;
284 fd_set fds;
285 struct timeval tv;
286 struct timeval *tvp = NULL;
287 #ifdef SSL_TLS
288 SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);
289 #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
305 #ifdef SSL_TLS
306 if (*ssl) {
307 for (;;) {
308 if ((s = select(*sock + 1, NULL, &fds, NULL, tvp) > 0 &&
309 FD_ISSET(*sock, &fds)))
310 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 } else
329 #endif
330 if ((s = select(*sock + 1, NULL, &fds, NULL, tvp)) > 0 &&
331 FD_ISSET(*sock, &fds))
332 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 strerror(errno));
343 else if (!s)
344 fatal(ERROR_NETWORK,
345 "imapfilter: timeout period expired while waiting to write "
346 "data\n");
347
348 return 0;
349 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26