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

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.33 - (show annotations)
Thu Jul 31 15:53:20 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.32: +19 -17 lines
File MIME type: text/plain
Broke up program files and created some new header files.

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 info("Connected to %s.\n", he->h_name);
70
71 #ifdef SSL_TLS
72 if (protocol != SSL_DISABLED)
73 if (!init_secure_connection(conn, protocol))
74 return 0;
75 else
76 return ERROR_SSL;
77 else
78 conn->ssl = NULL;
79 #endif
80
81 return 0;
82 }
83
84
85 #ifdef SSL_TLS
86 /*
87 * Initialize Secure Socket Layer connection.
88 */
89 int
90 init_secure_connection(conn_t * conn, unsigned int protocol)
91 {
92 int e;
93 SSL_CTX *ctx;
94 SSL_METHOD *method;
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 if (options & OPTION_DETAILS_VERBOSE) {
126 SSL_CIPHER *cipher;
127 char *ver;
128 const char *name;
129 int usebits, algbits;
130
131 cipher = SSL_get_current_cipher(conn->ssl);
132 ver = SSL_CIPHER_get_version(cipher);
133 name = SSL_CIPHER_get_name(cipher);
134 usebits = SSL_CIPHER_get_bits(cipher, &algbits);
135 printf("SSL/TLS handshake completed: %s with cipher %s "
136 "(%d/%d bits).\n", ver, name, usebits, algbits);
137 }
138 if (get_cert(conn))
139 goto fail;
140
141 SSL_CTX_free(ctx);
142
143 return 0;
144
145 fail:
146 conn->ssl = NULL;
147 SSL_CTX_free(ctx);
148
149 return ERROR_SSL;
150 }
151 #endif /* SSL_TLS */
152
153
154 /*
155 * Disconnect from mail server.
156 */
157 int
158 close_connection(conn_t * conn)
159 {
160 if (conn->ssl) {
161 SSL_shutdown(conn->ssl);
162 SSL_free(conn->ssl);
163 conn->ssl = NULL;
164 }
165 if (conn->sock >= 0 && close(conn->sock) == -1) {
166 error("closing socket; %s\n", strerror(errno));
167 return ERROR_NETWORK;
168 } else {
169 conn->sock = -1;
170 return 0;
171 }
172 }
173
174
175 /*
176 * Read data from socket.
177 */
178 int
179 socket_read(conn_t * conn, char *buf)
180 {
181 int f, e, s;
182 fd_set fds;
183 struct timeval tv;
184 struct timeval *tvp;
185
186 e = 0;
187 s = 1;
188 tvp = NULL;
189
190 memset(buf, 0, RESPONSE_BUF + 1);
191
192 if (timeout >= 0) {
193 tv.tv_sec = timeout;
194 tv.tv_usec = 0;
195 tvp = &tv;
196 }
197 f = fcntl(conn->sock, F_GETFL, 0);
198 fcntl(conn->sock, F_SETFL, f | O_NONBLOCK);
199
200 FD_ZERO(&fds);
201 FD_SET(conn->sock, &fds);
202
203 #ifdef SSL_TLS
204 if (conn->ssl) {
205 while (SSL_pending(conn->ssl) > 0 ||
206 ((s = select(conn->sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
207 FD_ISSET(conn->sock, &fds))) {
208 e = SSL_read(conn->ssl, buf, RESPONSE_BUF);
209
210 if (e > 0)
211 break;
212
213 switch (SSL_get_error(conn->ssl, e)) {
214 case SSL_ERROR_WANT_READ:
215 case SSL_ERROR_WANT_WRITE:
216 continue;
217 case SSL_ERROR_ZERO_RETURN:
218 return ERROR_NETWORK;
219 case SSL_ERROR_SYSCALL:
220 case SSL_ERROR_SSL:
221 fatal(ERROR_NETWORK, "reading data; %s\n",
222 ERR_error_string(ERR_get_error(), NULL));
223 default:
224 fatal(ERROR_NETWORK,
225 "undefined ssl error while reading data\n");
226 }
227 }
228 } else
229 #endif
230 {
231 if ((s = select(conn->sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
232 FD_ISSET(conn->sock, &fds))
233 e = read(conn->sock, buf, RESPONSE_BUF);
234
235 if (e == -1)
236 fatal(ERROR_NETWORK, "reading data; %s",
237 strerror(errno));
238 else if (e == 0)
239 return ERROR_NETWORK;
240 }
241
242 fcntl(conn->sock, F_SETFL, f);
243
244 if (s == -1)
245 fatal(ERROR_NETWORK, "waiting to read from socket; %s\n",
246 strerror(errno));
247 else if (s == 0)
248 fatal(ERROR_NETWORK,
249 "timeout period expired while waiting to read "
250 "data\n");
251
252 return 0;
253 }
254
255
256 /*
257 * Write data to socket.
258 */
259 int
260 socket_write(conn_t * conn, char *data)
261 {
262 int f, e, s;
263 fd_set fds;
264 struct timeval tv;
265 struct timeval *tvp = NULL;
266
267 e = 0;
268 s = 1;
269
270 if (timeout >= 0) {
271 tv.tv_sec = timeout;
272 tv.tv_usec = 0;
273 tvp = &tv;
274 }
275 f = fcntl(conn->sock, F_GETFL, 0);
276 fcntl(conn->sock, F_SETFL, f | O_NONBLOCK);
277
278 FD_ZERO(&fds);
279 FD_SET(conn->sock, &fds);
280
281 #ifdef SSL_TLS
282 if (conn->ssl) {
283 while ((s = select(conn->sock + 1, NULL, &fds, NULL, tvp) > 0 &&
284 FD_ISSET(conn->sock, &fds))) {
285 e = SSL_write(conn->ssl, data, strlen(data));
286
287 if (e > 0)
288 break;
289
290 switch (SSL_get_error(conn->ssl, e)) {
291 case SSL_ERROR_WANT_READ:
292 case SSL_ERROR_WANT_WRITE:
293 continue;
294 case SSL_ERROR_ZERO_RETURN:
295 return ERROR_NETWORK;
296 case SSL_ERROR_SYSCALL:
297 case SSL_ERROR_SSL:
298 fatal(ERROR_NETWORK, "writing data; %s\n",
299 ERR_error_string(ERR_get_error(), NULL));
300 default:
301 fatal(ERROR_NETWORK,
302 "undefined ssl error while writing data\n");
303 }
304 }
305 } else
306 #endif
307 {
308 if ((s = select(conn->sock + 1, NULL, &fds, NULL, tvp)) > 0 &&
309 FD_ISSET(conn->sock, &fds))
310 e = write(conn->sock, data, strlen(data));
311
312 if (e == -1)
313 fatal(ERROR_NETWORK, "writing data; %s",
314 strerror(errno));
315 }
316
317 fcntl(conn->sock, F_SETFL, f);
318
319 if (s == -1)
320 fatal(ERROR_NETWORK, "waiting to write to socket; %s\n",
321 strerror(errno));
322 else if (s == 0)
323 fatal(ERROR_NETWORK,
324 "timeout period expired while waiting to write "
325 "data\n");
326
327 return 0;
328 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26