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

Annotation of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.32 - (hide annotations)
Sun Jul 27 17:45:13 2003 UTC (20 years, 8 months ago) by lefcha
Branch: MAIN
Changes since 1.31: +3 -0 lines
File MIME type: text/plain
Added missing preprocessor conditional.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26