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

Annotation of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.35 - (hide annotations)
Fri Aug 8 00:22:13 2003 UTC (20 years, 7 months ago) by lefcha
Branch: MAIN
Changes since 1.34: +4 -5 lines
File MIME type: text/plain
Changed PF_INET to AF_INET and corrected header includes.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26