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

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34.2.2 - (show annotations)
Fri Aug 8 12:25:51 2003 UTC (20 years, 7 months ago) by lefcha
Branch: release-0_9-patches
Changes since 1.34.2.1: +2 -0 lines
File MIME type: text/plain
Added header includes to compile on systems that don't conform to IEEE Std 1003.1-2001 (POSIX.1).

1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <netinet/in.h>
6 #include <netdb.h>
7 #include <sys/socket.h>
8 #include <sys/types.h> /* IEEE Std 1003.1-2001 non-conformance. */
9 #include <sys/time.h> /* IEEE Std 1003.1-2001 non-conformance. */
10 #include <sys/select.h>
11 #include <fcntl.h>
12
13 #include "config.h"
14 #include "imapfilter.h"
15
16 #ifdef SSL_TLS
17 #include <openssl/ssl.h>
18 #include <openssl/err.h>
19 #endif
20
21
22 extern unsigned int options;
23 extern conn_t connpri, connaux;
24
25 long timeout = -1; /* Server non-response timeout in seconds. */
26
27
28 /*
29 * Connect to mail server.
30 */
31 int
32 init_connection(conn_t * conn, char *serv, unsigned short int port,
33 unsigned int protocol)
34 {
35 struct sockaddr_in sa;
36 struct hostent *he;
37
38 #ifndef SSL_TLS
39 if (protocol != SSL_DISABLED) {
40 error("SSL not supported by this build\n");
41 return ERROR_SSL;
42 }
43 #endif
44
45 memset((char *)&sa, 0, sizeof(struct sockaddr_in));
46
47 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
48
49 if (conn->sock < 0) {
50 error("create socket; %s\n", strerror(errno));
51 return ERROR_NETWORK;
52 }
53 if (!(he = gethostbyname(serv))) {
54 error("get network host entry of %s; %s\n", serv,
55 strerror(errno));
56 close_connection(conn);
57 return ERROR_NETWORK;
58 }
59 sa.sin_family = AF_INET;
60 sa.sin_port = htons(port);
61 sa.sin_addr = *(struct in_addr *) he->h_addr;
62
63 if (connect(conn->sock, (struct sockaddr *) & sa,
64 sizeof(struct sockaddr))) {
65 error("initiating connection to %s; %s\n", serv,
66 strerror(errno));
67 close_connection(conn);
68 return ERROR_NETWORK;
69 }
70 if (conn == &connpri)
71 info("Connected to %s.\n", he->h_name);
72
73 #ifdef SSL_TLS
74 if (protocol != SSL_DISABLED)
75 if (!init_secure_connection(conn, protocol))
76 return 0;
77 else
78 return ERROR_SSL;
79 else
80 conn->ssl = NULL;
81 #endif
82
83 return 0;
84 }
85
86
87 #ifdef SSL_TLS
88 /*
89 * Initialize Secure Socket Layer connection.
90 */
91 int
92 init_secure_connection(conn_t * conn, unsigned int protocol)
93 {
94 int e;
95 SSL_CTX *ctx;
96 SSL_METHOD *method;
97
98 method = NULL;
99
100 SSL_library_init();
101 SSL_load_error_strings();
102
103 switch (protocol) {
104 case SSL_TLS_V1:
105 method = TLSv1_client_method();
106 break;
107 case SSL_SSL_V2:
108 case SSL_SSL_V3:
109 method = SSLv23_client_method();
110 break;
111 }
112
113 if (!(ctx = SSL_CTX_new(method)))
114 goto fail;
115
116 if (!(conn->ssl = SSL_new(ctx)))
117 goto fail;
118
119 SSL_set_fd(conn->ssl, conn->sock);
120
121 if ((e = SSL_connect(conn->ssl)) <= 0) {
122 SSL_get_error(conn->ssl, e);
123 error("initiating SSL connection; %s\n",
124 ERR_error_string(ERR_get_error(), NULL));
125 goto fail;
126 }
127 if (options & OPTION_DETAILS_VERBOSE) {
128 SSL_CIPHER *cipher;
129 char *ver;
130 const char *name;
131 int usebits, algbits;
132
133 cipher = SSL_get_current_cipher(conn->ssl);
134 ver = SSL_CIPHER_get_version(cipher);
135 name = SSL_CIPHER_get_name(cipher);
136 usebits = SSL_CIPHER_get_bits(cipher, &algbits);
137 printf("SSL/TLS handshake completed: %s with cipher %s "
138 "(%d/%d bits).\n", ver, name, usebits, algbits);
139 }
140 if (get_cert(conn))
141 goto fail;
142
143 SSL_CTX_free(ctx);
144
145 return 0;
146
147 fail:
148 conn->ssl = NULL;
149 SSL_CTX_free(ctx);
150
151 return ERROR_SSL;
152 }
153 #endif /* SSL_TLS */
154
155
156 /*
157 * Disconnect from mail server.
158 */
159 int
160 close_connection(conn_t * conn)
161 {
162 #ifdef SSL_TLS
163 if (conn->ssl) {
164 SSL_shutdown(conn->ssl);
165 SSL_free(conn->ssl);
166 conn->ssl = NULL;
167 }
168 #endif
169 if (conn->sock >= 0 && close(conn->sock) == -1) {
170 error("closing socket; %s\n", strerror(errno));
171 return ERROR_NETWORK;
172 } else {
173 conn->sock = -1;
174 return 0;
175 }
176 }
177
178
179 /*
180 * Read data from socket.
181 */
182 int
183 socket_read(conn_t * conn, char *buf)
184 {
185 int f, e, s;
186 fd_set fds;
187 struct timeval tv;
188 struct timeval *tvp;
189
190 e = 0;
191 s = 1;
192 tvp = NULL;
193
194 memset(buf, 0, RESPONSE_BUF + 1);
195
196 if (timeout >= 0) {
197 tv.tv_sec = timeout;
198 tv.tv_usec = 0;
199 tvp = &tv;
200 }
201 f = fcntl(conn->sock, F_GETFL, 0);
202 fcntl(conn->sock, F_SETFL, f | O_NONBLOCK);
203
204 FD_ZERO(&fds);
205 FD_SET(conn->sock, &fds);
206
207 #ifdef SSL_TLS
208 if (conn->ssl) {
209 while (SSL_pending(conn->ssl) > 0 ||
210 ((s = select(conn->sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
211 FD_ISSET(conn->sock, &fds))) {
212 e = SSL_read(conn->ssl, buf, RESPONSE_BUF);
213
214 if (e > 0)
215 break;
216
217 switch (SSL_get_error(conn->ssl, e)) {
218 case SSL_ERROR_WANT_READ:
219 case SSL_ERROR_WANT_WRITE:
220 continue;
221 case SSL_ERROR_ZERO_RETURN:
222 return ERROR_NETWORK;
223 case SSL_ERROR_SYSCALL:
224 case SSL_ERROR_SSL:
225 fatal(ERROR_NETWORK, "reading data; %s\n",
226 ERR_error_string(ERR_get_error(), NULL));
227 default:
228 fatal(ERROR_NETWORK,
229 "undefined ssl error while reading data\n");
230 }
231 }
232 } else
233 #endif
234 {
235 if ((s = select(conn->sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
236 FD_ISSET(conn->sock, &fds))
237 e = read(conn->sock, buf, RESPONSE_BUF);
238
239 if (e == -1)
240 fatal(ERROR_NETWORK, "reading data; %s",
241 strerror(errno));
242 else if (e == 0)
243 return ERROR_NETWORK;
244 }
245
246 fcntl(conn->sock, F_SETFL, f);
247
248 if (s == -1)
249 fatal(ERROR_NETWORK, "waiting to read from socket; %s\n",
250 strerror(errno));
251 else if (s == 0)
252 fatal(ERROR_NETWORK,
253 "timeout period expired while waiting to read "
254 "data\n");
255
256 return 0;
257 }
258
259
260 /*
261 * Write data to socket.
262 */
263 int
264 socket_write(conn_t * conn, char *data)
265 {
266 int f, e, s;
267 fd_set fds;
268 struct timeval tv;
269 struct timeval *tvp = NULL;
270
271 e = 0;
272 s = 1;
273
274 if (timeout >= 0) {
275 tv.tv_sec = timeout;
276 tv.tv_usec = 0;
277 tvp = &tv;
278 }
279 f = fcntl(conn->sock, F_GETFL, 0);
280 fcntl(conn->sock, F_SETFL, f | O_NONBLOCK);
281
282 FD_ZERO(&fds);
283 FD_SET(conn->sock, &fds);
284
285 #ifdef SSL_TLS
286 if (conn->ssl) {
287 while ((s = select(conn->sock + 1, NULL, &fds, NULL, tvp) > 0 &&
288 FD_ISSET(conn->sock, &fds))) {
289 e = SSL_write(conn->ssl, data, strlen(data));
290
291 if (e > 0)
292 break;
293
294 switch (SSL_get_error(conn->ssl, e)) {
295 case SSL_ERROR_WANT_READ:
296 case SSL_ERROR_WANT_WRITE:
297 continue;
298 case SSL_ERROR_ZERO_RETURN:
299 return ERROR_NETWORK;
300 case SSL_ERROR_SYSCALL:
301 case SSL_ERROR_SSL:
302 fatal(ERROR_NETWORK, "writing data; %s\n",
303 ERR_error_string(ERR_get_error(), NULL));
304 default:
305 fatal(ERROR_NETWORK,
306 "undefined ssl error while writing data\n");
307 }
308 }
309 } else
310 #endif
311 {
312 if ((s = select(conn->sock + 1, NULL, &fds, NULL, tvp)) > 0 &&
313 FD_ISSET(conn->sock, &fds))
314 e = write(conn->sock, data, strlen(data));
315
316 if (e == -1)
317 fatal(ERROR_NETWORK, "writing data; %s",
318 strerror(errno));
319 }
320
321 fcntl(conn->sock, F_SETFL, f);
322
323 if (s == -1)
324 fatal(ERROR_NETWORK, "waiting to write to socket; %s\n",
325 strerror(errno));
326 else if (s == 0)
327 fatal(ERROR_NETWORK,
328 "timeout period expired while waiting to write "
329 "data\n");
330
331 return 0;
332 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26