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

Annotation of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26