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

Annotation of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34.2.2 - (hide 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 lefcha 1.33 #include <stdio.h>
2     #include <unistd.h>
3 lefcha 1.34.2.1 #include <string.h>
4 lefcha 1.1 #include <errno.h>
5     #include <netinet/in.h>
6     #include <netdb.h>
7 lefcha 1.34.2.1 #include <sys/socket.h>
8 lefcha 1.34.2.2 #include <sys/types.h> /* IEEE Std 1003.1-2001 non-conformance. */
9     #include <sys/time.h> /* IEEE Std 1003.1-2001 non-conformance. */
10 lefcha 1.34.2.1 #include <sys/select.h>
11 lefcha 1.1 #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 lefcha 1.13 #endif
20    
21 lefcha 1.33
22 lefcha 1.28 extern unsigned int options;
23 lefcha 1.31 extern conn_t connpri, connaux;
24 lefcha 1.1
25 lefcha 1.14 long timeout = -1; /* Server non-response timeout in seconds. */
26 lefcha 1.1
27 lefcha 1.25
28 lefcha 1.1 /*
29     * Connect to mail server.
30     */
31 lefcha 1.26 int
32 lefcha 1.31 init_connection(conn_t * conn, char *serv, unsigned short int port,
33 lefcha 1.26 unsigned int protocol)
34 lefcha 1.1 {
35 lefcha 1.26 struct sockaddr_in sa;
36     struct hostent *he;
37    
38 lefcha 1.32 #ifndef SSL_TLS
39 lefcha 1.26 if (protocol != SSL_DISABLED) {
40     error("SSL not supported by this build\n");
41     return ERROR_SSL;
42     }
43 lefcha 1.32 #endif
44    
45 lefcha 1.26 memset((char *)&sa, 0, sizeof(struct sockaddr_in));
46 lefcha 1.1
47 lefcha 1.34.2.1 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
48 lefcha 1.2
49 lefcha 1.31 if (conn->sock < 0) {
50 lefcha 1.26 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 lefcha 1.31 close_connection(conn);
57 lefcha 1.26 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 lefcha 1.31 if (connect(conn->sock, (struct sockaddr *) & sa,
64     sizeof(struct sockaddr))) {
65 lefcha 1.26 error("initiating connection to %s; %s\n", serv,
66     strerror(errno));
67 lefcha 1.31 close_connection(conn);
68 lefcha 1.26 return ERROR_NETWORK;
69     }
70 lefcha 1.34 if (conn == &connpri)
71     info("Connected to %s.\n", he->h_name);
72 lefcha 1.28
73 lefcha 1.1 #ifdef SSL_TLS
74 lefcha 1.26 if (protocol != SSL_DISABLED)
75 lefcha 1.33 if (!init_secure_connection(conn, protocol))
76 lefcha 1.26 return 0;
77 lefcha 1.28 else
78 lefcha 1.26 return ERROR_SSL;
79     else
80 lefcha 1.31 conn->ssl = NULL;
81 lefcha 1.1 #endif
82    
83 lefcha 1.26 return 0;
84 lefcha 1.1 }
85    
86    
87     #ifdef SSL_TLS
88     /*
89     * Initialize Secure Socket Layer connection.
90     */
91 lefcha 1.26 int
92 lefcha 1.33 init_secure_connection(conn_t * conn, unsigned int protocol)
93 lefcha 1.1 {
94 lefcha 1.26 int e;
95     SSL_CTX *ctx;
96     SSL_METHOD *method;
97    
98     method = NULL;
99    
100     SSL_library_init();
101 lefcha 1.30 SSL_load_error_strings();
102 lefcha 1.26
103     switch (protocol) {
104 lefcha 1.30 case SSL_TLS_V1:
105     method = TLSv1_client_method();
106     break;
107 lefcha 1.26 case SSL_SSL_V2:
108     case SSL_SSL_V3:
109 lefcha 1.30 method = SSLv23_client_method();
110 lefcha 1.26 break;
111     }
112 lefcha 1.3
113 lefcha 1.26 if (!(ctx = SSL_CTX_new(method)))
114 lefcha 1.30 goto fail;
115 lefcha 1.1
116 lefcha 1.31 if (!(conn->ssl = SSL_new(ctx)))
117 lefcha 1.30 goto fail;
118 lefcha 1.26
119 lefcha 1.31 SSL_set_fd(conn->ssl, conn->sock);
120 lefcha 1.26
121 lefcha 1.31 if ((e = SSL_connect(conn->ssl)) <= 0) {
122     SSL_get_error(conn->ssl, e);
123 lefcha 1.30 error("initiating SSL connection; %s\n",
124 lefcha 1.26 ERR_error_string(ERR_get_error(), NULL));
125 lefcha 1.30 goto fail;
126 lefcha 1.26 }
127 lefcha 1.33 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 lefcha 1.30 goto fail;
142 lefcha 1.26
143     SSL_CTX_free(ctx);
144    
145     return 0;
146 lefcha 1.30
147     fail:
148 lefcha 1.31 conn->ssl = NULL;
149 lefcha 1.30 SSL_CTX_free(ctx);
150    
151     return ERROR_SSL;
152 lefcha 1.1 }
153 lefcha 1.25 #endif /* SSL_TLS */
154 lefcha 1.1
155    
156     /*
157     * Disconnect from mail server.
158     */
159 lefcha 1.26 int
160 lefcha 1.31 close_connection(conn_t * conn)
161 lefcha 1.1 {
162 lefcha 1.34 #ifdef SSL_TLS
163 lefcha 1.31 if (conn->ssl) {
164     SSL_shutdown(conn->ssl);
165     SSL_free(conn->ssl);
166     conn->ssl = NULL;
167 lefcha 1.26 }
168 lefcha 1.34 #endif
169 lefcha 1.31 if (conn->sock >= 0 && close(conn->sock) == -1) {
170 lefcha 1.26 error("closing socket; %s\n", strerror(errno));
171     return ERROR_NETWORK;
172     } else {
173 lefcha 1.31 conn->sock = -1;
174 lefcha 1.26 return 0;
175     }
176 lefcha 1.1 }
177    
178    
179     /*
180     * Read data from socket.
181     */
182 lefcha 1.26 int
183 lefcha 1.31 socket_read(conn_t * conn, char *buf)
184 lefcha 1.1 {
185 lefcha 1.26 int f, e, s;
186     fd_set fds;
187     struct timeval tv;
188     struct timeval *tvp;
189 lefcha 1.28
190 lefcha 1.26 e = 0;
191     s = 1;
192     tvp = NULL;
193 lefcha 1.1
194 lefcha 1.29 memset(buf, 0, RESPONSE_BUF + 1);
195 lefcha 1.1
196 lefcha 1.26 if (timeout >= 0) {
197     tv.tv_sec = timeout;
198     tv.tv_usec = 0;
199     tvp = &tv;
200     }
201 lefcha 1.31 f = fcntl(conn->sock, F_GETFL, 0);
202     fcntl(conn->sock, F_SETFL, f | O_NONBLOCK);
203 lefcha 1.1
204 lefcha 1.26 FD_ZERO(&fds);
205 lefcha 1.31 FD_SET(conn->sock, &fds);
206 lefcha 1.1
207     #ifdef SSL_TLS
208 lefcha 1.31 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 lefcha 1.26
214     if (e > 0)
215     break;
216    
217 lefcha 1.31 switch (SSL_get_error(conn->ssl, e)) {
218 lefcha 1.26 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 lefcha 1.30 fatal(ERROR_NETWORK, "reading data; %s\n",
226 lefcha 1.26 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 lefcha 1.31 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 lefcha 1.26
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 lefcha 1.21
246 lefcha 1.31 fcntl(conn->sock, F_SETFL, f);
247 lefcha 1.21
248 lefcha 1.26 if (s == -1)
249     fatal(ERROR_NETWORK, "waiting to read from socket; %s\n",
250     strerror(errno));
251     else if (s == 0)
252 lefcha 1.21 fatal(ERROR_NETWORK,
253 lefcha 1.26 "timeout period expired while waiting to read "
254     "data\n");
255 lefcha 1.1
256 lefcha 1.26 return 0;
257 lefcha 1.1 }
258    
259    
260     /*
261     * Write data to socket.
262     */
263 lefcha 1.26 int
264 lefcha 1.31 socket_write(conn_t * conn, char *data)
265 lefcha 1.1 {
266 lefcha 1.26 int f, e, s;
267     fd_set fds;
268     struct timeval tv;
269     struct timeval *tvp = NULL;
270 lefcha 1.28
271 lefcha 1.26 e = 0;
272     s = 1;
273 lefcha 1.21
274 lefcha 1.26 if (timeout >= 0) {
275     tv.tv_sec = timeout;
276     tv.tv_usec = 0;
277     tvp = &tv;
278     }
279 lefcha 1.31 f = fcntl(conn->sock, F_GETFL, 0);
280     fcntl(conn->sock, F_SETFL, f | O_NONBLOCK);
281 lefcha 1.21
282 lefcha 1.26 FD_ZERO(&fds);
283 lefcha 1.31 FD_SET(conn->sock, &fds);
284 lefcha 1.1
285 lefcha 1.21 #ifdef SSL_TLS
286 lefcha 1.31 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 lefcha 1.26
291     if (e > 0)
292     break;
293    
294 lefcha 1.31 switch (SSL_get_error(conn->ssl, e)) {
295 lefcha 1.26 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 lefcha 1.30 fatal(ERROR_NETWORK, "writing data; %s\n",
303 lefcha 1.26 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 lefcha 1.31 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 lefcha 1.26
316     if (e == -1)
317     fatal(ERROR_NETWORK, "writing data; %s",
318     strerror(errno));
319     }
320 lefcha 1.21
321 lefcha 1.31 fcntl(conn->sock, F_SETFL, f);
322 lefcha 1.21
323 lefcha 1.26 if (s == -1)
324     fatal(ERROR_NETWORK, "waiting to write to socket; %s\n",
325     strerror(errno));
326     else if (s == 0)
327 lefcha 1.21 fatal(ERROR_NETWORK,
328 lefcha 1.26 "timeout period expired while waiting to write "
329     "data\n");
330 lefcha 1.2
331 lefcha 1.26 return 0;
332 lefcha 1.1 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26