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

Contents of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.13 - (show annotations)
Sun Nov 18 13:07:47 2001 UTC (22 years, 5 months ago) by lefcha
Branch: MAIN
Changes since 1.12: +15 -9 lines
File MIME type: text/plain
Added option to control server non-response timeout.

1 #include <string.h>
2 #include <errno.h>
3 #include <unistd.h>
4 #include <sys/time.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 long timeout;
22
23 static int sock;
24
25 #ifdef SSL_TLS
26 static SSL *ssl;
27 #endif
28
29
30 /*
31 * Connect to mail server.
32 */
33 #ifndef SSL_TLS
34 int init_connection(char *serv, unsigned short int port)
35 #else
36 int init_connection(char *serv, unsigned short int port, unsigned int protocol)
37 #endif
38 {
39 struct sockaddr_in sa;
40 struct hostent *he;
41
42 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
43
44 sock = socket(PF_INET, SOCK_STREAM, 0);
45
46 if (sock < 0) {
47 error("imapfilter: create socket; %s\n", strerror(errno));
48 return ERROR_NETWORK;
49 }
50 if (!(he = gethostbyname(serv))) {
51 error("imapfilter: get network host entry of %s; %s\n", serv,
52 strerror(errno));
53 close_connection();
54 return ERROR_NETWORK;
55 }
56 sa.sin_family = AF_INET;
57 sa.sin_port = htons(port);
58 sa.sin_addr = *(struct in_addr *) he->h_addr;
59
60 xstrncpy(serv, he->h_name, SERVER_LEN - 1);
61
62 if (connect(sock, (struct sockaddr *) & sa, sizeof(struct sockaddr))) {
63 error("imapfilter: initiating connection to %s; %s\n", serv, strerror(errno));
64 close_connection();
65 return ERROR_NETWORK;
66 }
67 log_info(LOG_SERVER, serv);
68
69 #ifdef SSL_TLS
70 if (protocol != SSL_DISABLED)
71 if (!ssl_init(protocol)) {
72 info("Connected to %s using %s.\n", serv, SSL_get_cipher(ssl));
73 return 0;
74 } else
75 return ERROR_SSL;
76 else
77 ssl = NULL;
78 #endif
79
80 info("Connected to %s.\n", serv);
81
82 return 0;
83 }
84
85
86 #ifdef SSL_TLS
87 /*
88 * Initialize Secure Socket Layer connection.
89 */
90 int ssl_init(unsigned int protocol)
91 {
92 int e;
93 unsigned int i, n = 0;
94 SSL_CTX *ctx;
95 SSL_METHOD *method = NULL;
96 X509 *cert;
97 char *c;
98 EVP_MD *evp;
99 unsigned char digest[EVP_MAX_MD_SIZE];
100
101 SSL_library_init();
102
103 switch (protocol) {
104 case SSL_SSL_V2:
105 method = SSLv2_client_method();
106 break;
107 case SSL_SSL_V3:
108 method = SSLv3_client_method();
109 break;
110 case SSL_TLS_V1:
111 method = TLSv1_client_method();
112 break;
113 }
114
115 if (!(ctx = SSL_CTX_new(method)))
116 return ERROR_SSL;
117
118 if (!(ssl = SSL_new(ctx)))
119 return ERROR_SSL;
120
121 SSL_set_fd(ssl, sock);
122
123 e = SSL_connect(ssl);
124
125 if (e < 0) {
126 error("imapfilter: initiating SSL connection; %s",
127 ERR_error_string(e, NULL));
128 return ERROR_SSL;
129 }
130 /* Get server's certificate. */
131 if (!(cert = SSL_get_peer_certificate(ssl)))
132 return ERROR_SSL;
133
134 if (!(c = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)))
135 return ERROR_SSL;
136 verbose("Server certificate subject: %s\n", c);
137 free(c);
138
139 if (!(c = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)))
140 return ERROR_SSL;
141 verbose("Server certificate issuer: %s\n", c);
142 free(c);
143
144 if (!(evp = EVP_md5()))
145 return ERROR_SSL;
146 if (!(X509_digest(cert, evp, digest, &n)))
147 return ERROR_SSL;
148
149 verbose("Server key fingerprint: ");
150 for (i = 0; i < n; i++)
151 verbose(i != n - 1 ? "%02X:" : "%02X\n", digest[i]);
152
153 X509_free(cert);
154 SSL_CTX_free(ctx);
155
156 return 0;
157 }
158 #endif
159
160
161 /*
162 * Disconnect from mail server.
163 */
164 int close_connection(void)
165 {
166 #ifdef SSL_TLS
167 if (ssl) {
168 SSL_shutdown(ssl);
169 SSL_free(ssl);
170 }
171 #endif
172
173 if (close(sock)) {
174 error("imapfilter: closing socket; %s\n", strerror(errno));
175 return ERROR_NETWORK;
176 } else
177 return 0;
178 }
179
180
181 /*
182 * Read data from socket.
183 */
184 int socket_read(char *buf)
185 {
186 int flags, r, s;
187 fd_set fds;
188 struct timeval tv;
189 struct timeval *tvp = NULL;
190
191 r = 0;
192 s = 1;
193
194 memset(buf, 0, RESPONSE_BUF);
195
196 if (timeout) {
197 tv.tv_sec = timeout;
198 tv.tv_usec = 0;
199 tvp = &tv;
200 }
201 flags = fcntl(sock, F_GETFL, 0);
202 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
203
204 FD_ZERO(&fds);
205 FD_SET(sock, &fds);
206
207 #ifdef SSL_TLS
208 if (ssl) {
209 if (SSL_pending(ssl)
210 || ((s = select(sock + 1, &fds, NULL, NULL, tvp)) > 0
211 && FD_ISSET(sock, &fds)))
212 r = SSL_read(ssl, buf, RESPONSE_BUF - 1);
213 } else
214 #endif
215 if ((s = select(sock + 1, &fds, NULL, NULL, tvp)) > 0
216 && FD_ISSET(sock, &fds))
217 r = read(sock, buf, RESPONSE_BUF - 1);
218
219 fcntl(sock, F_SETFL, flags);
220
221 if (s == -1)
222 fatal(ERROR_NETWORK, "imapfilter: waiting input from socket; %s\n",
223 strerror(errno));
224 else if (!s)
225 fatal(ERROR_NETWORK,
226 "imapfilter: timeout period expired while waiting data\n");
227
228 #ifdef SSL_TLS
229 if (ssl) {
230 if (r < 0)
231 fatal(ERROR_NETWORK, "imapfilter: reading data; %s",
232 ERR_error_string(r, NULL));
233 } else
234 #endif
235 if (r == -1)
236 fatal(ERROR_NETWORK, "imapfilter: reading data; %s",
237 strerror(errno));
238
239 return 0;
240 }
241
242
243 /*
244 * Write data to socket.
245 */
246 int socket_write(char *data)
247 {
248 #ifdef SSL_TLS
249 int e;
250
251 if (ssl) {
252 e = SSL_write(ssl, data, strlen(data));
253 if (e <= 0)
254 fatal(ERROR_NETWORK,
255 "imapfilter: sending data; %s",
256 ERR_error_string(e, NULL));
257 } else
258 #endif
259 if (write(sock, data, strlen(data)) == -1)
260 fatal(ERROR_NETWORK, "imapfilter: sending data; %s",
261 strerror(errno));
262
263 return 0;
264 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26