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

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.31 - (show annotations)
Sun Jul 27 17:39:45 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.30: +52 -93 lines
File MIME type: text/plain
New structure to hold information about connection's socket, ssl socket, capabilities, namespace.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26