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

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.26 - (show annotations)
Sat Feb 22 16:06:41 2003 UTC (21 years, 1 month ago) by lefcha
Branch: MAIN
Changes since 1.25: +272 -254 lines
File MIME type: text/plain
Coding style to KNF and some code cleanup.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26