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

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34 - (show annotations)
Sun Aug 3 16:07:06 2003 UTC (20 years, 7 months ago) by lefcha
Branch: MAIN
CVS Tags: release-0_9
Branch point for: release-0_9-patches
Changes since 1.33: +4 -1 lines
File MIME type: text/plain
Added missing conditional and 'Connected to' message only during primary connections.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26