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

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.28 - (show 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 #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 extern unsigned int options;
21
22 long timeout = -1; /* Server non-response timeout in seconds. */
23
24 int sockpri = -1; /* Main socket used mostly. */
25 int sockaux = -1; /* Auxiliary socked used when another
26 * connection is needed. */
27
28 #ifdef SSL_TLS
29 static SSL *sslpri = NULL;
30 static SSL *sslaux = NULL;
31
32 #endif
33
34
35
36 /*
37 * Connect to mail server.
38 */
39 int
40 init_connection(int *sock, char *serv, unsigned short int port,
41 unsigned int protocol)
42 {
43 struct sockaddr_in sa;
44 struct hostent *he;
45
46 #ifdef SSL_TLS
47 SSL **ssl;
48
49 ssl = (sock == &sockpri ? &sslpri : &sslaux);
50 #else
51 if (protocol != SSL_DISABLED) {
52 error("SSL not supported by this build\n");
53 return ERROR_SSL;
54 }
55 #endif
56
57 memset((char *)&sa, 0, sizeof(struct sockaddr_in));
58
59 *sock = socket(PF_INET, SOCK_STREAM, 0);
60
61 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 info("Connected to %s.\n", he->h_name);
82
83 #ifdef SSL_TLS
84 if (protocol != SSL_DISABLED)
85 if (!init_ssl_connection(sock, protocol))
86 return 0;
87 else
88 return ERROR_SSL;
89 else
90 *ssl = NULL;
91 #endif
92
93 return 0;
94 }
95
96
97 #ifdef SSL_TLS
98 /*
99 * Initialize Secure Socket Layer connection.
100 */
101 int
102 init_ssl_connection(int *sock, unsigned int protocol)
103 {
104 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
126 if (!(ctx = SSL_CTX_new(method)))
127 return ERROR_SSL;
128
129 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 verbose("SSL/TLS handshake completed (%s).\n",
141 SSL_get_cipher(*ssl));
142
143 if (imf_ssl_cert(*ssl))
144 return ERROR_SSL;
145
146 SSL_CTX_free(ctx);
147
148 return 0;
149 }
150
151 #endif /* SSL_TLS */
152
153
154 /*
155 * Disconnect from mail server.
156 */
157 int
158 close_connection(int *sock)
159 {
160 #ifdef SSL_TLS
161 SSL **ssl;
162
163 ssl = (sock == &sockpri ? &sslpri : &sslaux);
164
165 if (*ssl) {
166 SSL_shutdown(*ssl);
167 SSL_free(*ssl);
168 *ssl = NULL;
169 }
170 #endif
171
172 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 }
180
181
182 /*
183 * Read data from socket.
184 */
185 int
186 socket_read(int *sock, char *buf)
187 {
188 int f, e, s;
189 fd_set fds;
190 struct timeval tv;
191 struct timeval *tvp;
192
193 #ifdef SSL_TLS
194 SSL **ssl;
195
196 #endif
197
198 e = 0;
199 s = 1;
200 tvp = NULL;
201 #ifdef SSL_TLS
202 ssl = (sock == &sockpri ? &sslpri : &sslaux);
203 #endif
204
205 memset(buf, 0, RESPONSE_BUF);
206
207 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
215 FD_ZERO(&fds);
216 FD_SET(*sock, &fds);
217
218 #ifdef SSL_TLS
219 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
257 fcntl(*sock, F_SETFL, f);
258
259 if (s == -1)
260 fatal(ERROR_NETWORK, "waiting to read from socket; %s\n",
261 strerror(errno));
262 else if (s == 0)
263 fatal(ERROR_NETWORK,
264 "timeout period expired while waiting to read "
265 "data\n");
266
267 return 0;
268 }
269
270
271 /*
272 * Write data to socket.
273 */
274 int
275 socket_write(int *sock, char *data)
276 {
277 int f, e, s;
278 fd_set fds;
279 struct timeval tv;
280 struct timeval *tvp = NULL;
281
282 #ifdef SSL_TLS
283 SSL **ssl;
284
285 #endif
286
287 e = 0;
288 s = 1;
289 #ifdef SSL_TLS
290 ssl = (sock == &sockpri ? &sslpri : &sslaux);
291 #endif
292
293 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
301 FD_ZERO(&fds);
302 FD_SET(*sock, &fds);
303
304 #ifdef SSL_TLS
305 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
340 fcntl(*sock, F_SETFL, f);
341
342 if (s == -1)
343 fatal(ERROR_NETWORK, "waiting to write to socket; %s\n",
344 strerror(errno));
345 else if (s == 0)
346 fatal(ERROR_NETWORK,
347 "timeout period expired while waiting to write "
348 "data\n");
349
350 return 0;
351 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26