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

Diff of /imapfilter/socket.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.12.2.1 by lefcha, Wed Dec 5 09:56:52 2001 UTC revision 1.42 by lefcha, Sat Feb 14 19:14:43 2004 UTC
# Line 1  Line 1 
1    #include <stdio.h>
2    #include <unistd.h>
3  #include <string.h>  #include <string.h>
4  #include <errno.h>  #include <errno.h>
 #include <unistd.h>  
 #include <sys/time.h>  
 #include <sys/types.h>  
 #include <sys/socket.h>  
5  #include <netinet/in.h>  #include <netinet/in.h>
6  #include <netdb.h>  #include <netdb.h>
7    #include <sys/socket.h>
8    #include <sys/types.h>          /* For POSIX.1-2001 non-conformant systems. */
9    #include <sys/time.h>           /* For POSIX.1-2001 non-conformant systems. */
10    #include <sys/select.h>
11  #include <fcntl.h>  #include <fcntl.h>
12    
13  #include "config.h"  #include "config.h"
# Line 14  Line 16 
16  #ifdef SSL_TLS  #ifdef SSL_TLS
17  #include <openssl/ssl.h>  #include <openssl/ssl.h>
18  #include <openssl/err.h>  #include <openssl/err.h>
 #include <openssl/x509.h>  
19  #endif  #endif
20    
21    
22  extern long timeout;  extern options_t opts;
23    extern connection_t connpri, connaux;
 static int sock;  
   
 #ifdef SSL_TLS  
 static SSL *ssl;  
 #endif  
24    
25    
26  /*  /*
27   * Connect to mail server.   * Connect to mail server.
28   */   */
29    int
30    init_connection(connection_t * conn, char *serv, unsigned short int port,
31        unsigned int protocol)
32    {
33            struct sockaddr_in sa;
34            struct hostent *he;
35    
36  #ifndef SSL_TLS  #ifndef SSL_TLS
37  int init_connection(char *serv, unsigned short int port)          if (protocol != SSL_DISABLED) {
38  #else                  error("SSL not supported by this build\n");
39  int init_connection(char *serv, unsigned short int port,                  return ERROR_SSL;
40                       unsigned int protocol)          }
41  #endif  #endif
 {  
     struct sockaddr_in sa;  
     struct hostent *he;  
42    
43      memset((char *) &sa, 0, sizeof(struct sockaddr_in));          memset((char *)&sa, 0, sizeof(struct sockaddr_in));
44    
45      sock = socket(PF_INET, SOCK_STREAM, 0);          conn->sock = socket(AF_INET, SOCK_STREAM, 0);
46    
47      if (sock < 0) {          if (conn->sock < 0) {
48          error("imapfilter: create socket; %s\n", strerror(errno));                  error("create socket; %s\n", strerror(errno));
49          return ERROR_NETWORK;                  return ERROR_NETWORK;
50      }          }
51      if (!(he = gethostbyname(serv))) {          if (!(he = gethostbyname(serv))) {
52          error("imapfilter: get network host entry of %s; %s\n", serv,                  error("get network host entry of %s; %s\n", serv,
53                strerror(errno));                      strerror(errno));
54          close_connection();                  close_connection(conn);
55          return ERROR_NETWORK;                  return ERROR_NETWORK;
56      }          }
57      sa.sin_family = AF_INET;          sa.sin_family = AF_INET;
58      sa.sin_port = htons(port);          sa.sin_port = htons(port);
59      sa.sin_addr = *(struct in_addr *) he->h_addr;          sa.sin_addr = *(struct in_addr *)he->h_addr;
60    
61      xstrncpy(serv, he->h_name, SERVER_LEN - 1);          if (connect(conn->sock, (struct sockaddr *)&sa,
62                sizeof(struct sockaddr))) {
63      if (connect(sock, (struct sockaddr *) & sa, sizeof(struct sockaddr))) {                  error("initiating connection to %s; %s\n", serv,
64          error("imapfilter: initiating connection to %s; %s\n", serv,                      strerror(errno));
65                strerror(errno));                  close_connection(conn);
66          close_connection();                  return ERROR_NETWORK;
67          return ERROR_NETWORK;          }
68      }          if (conn == &connpri)
69      log_info(LOG_SERVER, serv);                  info("Connected to %s.\n", he->h_name);
70    
71  #ifdef SSL_TLS  #ifdef SSL_TLS
72      if (protocol != SSL_DISABLED)          if (protocol != SSL_DISABLED)
73          if (!ssl_init(protocol)) {                  if (!init_secure_connection(conn, protocol))
74              info("Connected to %s using %s.\n", serv, SSL_get_cipher(ssl));                          return 0;
75              return 0;                  else
76          } else                          return ERROR_SSL;
77              return ERROR_SSL;          else
78      else                  conn->ssl = NULL;
         ssl = NULL;  
79  #endif  #endif
80    
81      info("Connected to %s.\n", serv);          return 0;
   
     return 0;  
82  }  }
83    
84    
# Line 89  int init_connection(char *serv, unsigned Line 86  int init_connection(char *serv, unsigned
86  /*  /*
87   * Initialize Secure Socket Layer connection.   * Initialize Secure Socket Layer connection.
88   */   */
89  int ssl_init(unsigned int protocol)  int
90    init_secure_connection(connection_t * conn, unsigned int protocol)
91  {  {
92      int e;          int e;
93      unsigned int i, n = 0;          SSL_CTX *ctx;
94      SSL_CTX *ctx;          SSL_METHOD *method;
95      SSL_METHOD *method = NULL;  
96      X509 *cert;          method = NULL;
97      char *c;  
98      EVP_MD *evp;          SSL_library_init();
99      unsigned char digest[EVP_MAX_MD_SIZE];          SSL_load_error_strings();
100    
101      SSL_library_init();          switch (protocol) {
102            case SSL_TLS_V1:
103      switch (protocol) {                  method = TLSv1_client_method();
104      case SSL_SSL_V2:                  break;
105          method = SSLv2_client_method();          case SSL_SSL_V2:
106          break;          case SSL_SSL_V3:
107      case SSL_SSL_V3:                  method = SSLv23_client_method();
108          method = SSLv3_client_method();                  break;
109          break;          }
110      case SSL_TLS_V1:  
111          method = TLSv1_client_method();          if (!(ctx = SSL_CTX_new(method)))
112          break;                  goto fail;
113      }  
114            if (!(conn->ssl = SSL_new(ctx)))
115                    goto fail;
116    
117            SSL_set_fd(conn->ssl, conn->sock);
118    
119            if ((e = SSL_connect(conn->ssl)) <= 0) {
120                    SSL_get_error(conn->ssl, e);
121                    error("initiating SSL connection; %s\n",
122                        ERR_error_string(ERR_get_error(), NULL));
123                    goto fail;
124            }
125            if (opts.verbosity >= 1) {
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                    goto fail;
140    
141      if (!(ctx = SSL_CTX_new(method)))          SSL_CTX_free(ctx);
         return ERROR_SSL;  
   
     if (!(ssl = SSL_new(ctx)))  
         return ERROR_SSL;  
   
     SSL_set_fd(ssl, sock);  
   
     e = SSL_connect(ssl);  
   
     if (e < 0) {  
         error("imapfilter: initiating SSL connection; %s",  
               ERR_error_string(e, NULL));  
         return ERROR_SSL;  
     }  
     /* Get server's certificate. */  
     if (!(cert = SSL_get_peer_certificate(ssl)))  
         return ERROR_SSL;  
142    
143      if (!(c = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)))          return 0;
         return ERROR_SSL;  
     verbose("Server certificate subject: %s\n", c);  
     free(c);  
144    
145      if (!(c = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)))  fail:
146          return ERROR_SSL;          conn->ssl = NULL;
147      verbose("Server certificate issuer: %s\n", c);          SSL_CTX_free(ctx);
     free(c);  
148    
     if (!(evp = EVP_md5()))  
149          return ERROR_SSL;          return ERROR_SSL;
     if (!(X509_digest(cert, evp, digest, &n)))  
         return ERROR_SSL;  
   
     verbose("Server key fingerprint: ");  
     for (i = 0; i < n; i++)  
         verbose(i != n - 1 ? "%02X:" : "%02X\n", digest[i]);  
   
     X509_free(cert);  
     SSL_CTX_free(ctx);  
   
     return 0;  
150  }  }
151  #endif  #endif                          /* SSL_TLS */
152    
153    
154  /*  /*
155   * Disconnect from mail server.   * Disconnect from mail server.
156   */   */
157  int close_connection(void)  int
158    close_connection(connection_t * conn)
159  {  {
160    
161  #ifdef SSL_TLS  #ifdef SSL_TLS
162      if (ssl) {          if (conn->ssl) {
163          SSL_shutdown(ssl);                  SSL_shutdown(conn->ssl);
164          SSL_free(ssl);                  SSL_free(conn->ssl);
165      }                  conn->ssl = NULL;
166            }
167  #endif  #endif
168            if (conn->sock >= 0 && close(conn->sock) == -1) {
169      if (close(sock)) {                  error("closing socket; %s\n", strerror(errno));
170          error("imapfilter: closing socket; %s\n", strerror(errno));                  return ERROR_NETWORK;
171          return ERROR_NETWORK;          } else {
172      } else                  conn->sock = -1;
173          return 0;                  return 0;
174            }
175  }  }
176    
177    
178  /*  /*
179   * Read data from socket.   * Read data from socket.
180   */   */
181  int socket_read(char *buf)  int
182    socket_read(connection_t * conn, char *buf)
183  {  {
184      int flags, r, s;          int f, e, s;
185      fd_set fds;          fd_set fds;
186      struct timeval tv;          struct timeval tv;
187      struct timeval *tvp = NULL;          struct timeval *tvp;
188    
189      r = 0;          e = 0;
190      s = 1;          s = 1;
191            tvp = NULL;
192      memset(buf, 0, RESPONSE_BUF);  
193            memset(buf, 0, RESPONSE_BUF + 1);
194      if (timeout >= 0) {  
195          tv.tv_sec = timeout;          if (opts.timeout >= 0) {
196          tv.tv_usec = 0;                  tv.tv_sec = opts.timeout;
197          tvp = &tv;                  tv.tv_usec = 0;
198      }                  tvp = &tv;
199      flags = fcntl(sock, F_GETFL, 0);          }
200      fcntl(sock, F_SETFL, flags | O_NONBLOCK);          f = fcntl(conn->sock, F_GETFL, 0);
201            fcntl(conn->sock, F_SETFL, f | O_NONBLOCK);
202    
203      FD_ZERO(&fds);          FD_ZERO(&fds);
204      FD_SET(sock, &fds);          FD_SET(conn->sock, &fds);
205    
206  #ifdef SSL_TLS  #ifdef SSL_TLS
207      if (ssl) {          if (conn->ssl) {
208          if (SSL_pending(ssl)                  while (SSL_pending(conn->ssl) > 0 ||
209              || ((s = select(sock + 1, &fds, NULL, NULL, tvp)) > 0                      ((s = select(conn->sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
210                  && FD_ISSET(sock, &fds)))                      FD_ISSET(conn->sock, &fds))) {
211              r = SSL_read(ssl, buf, RESPONSE_BUF - 1);                          e = SSL_read(conn->ssl, buf, RESPONSE_BUF);
212      } else  
213  #endif                          if (e > 0)
214          if ((s = select(sock + 1, &fds, NULL, NULL, tvp)) > 0                                  break;
215              && FD_ISSET(sock, &fds))  
216          r = read(sock, buf, RESPONSE_BUF - 1);                          switch (SSL_get_error(conn->ssl, e)) {
217                            case SSL_ERROR_WANT_READ:
218      fcntl(sock, F_SETFL, flags);                          case SSL_ERROR_WANT_WRITE:
219                                    continue;
220      if (s == -1)                          case SSL_ERROR_ZERO_RETURN:
221          fatal(ERROR_NETWORK, "imapfilter: waiting input from socket; %s\n",                                  return ERROR_NETWORK;
222                strerror(errno));                          case SSL_ERROR_SYSCALL:
223      else if (!s)                          case SSL_ERROR_SSL:
224          fatal(ERROR_NETWORK,                                  fatal(ERROR_NETWORK, "reading data; %s\n",
225                "imapfilter: timeout period expired while waiting data\n");                                      ERR_error_string(ERR_get_error(), NULL));
226                            default:
227  #ifdef SSL_TLS                                  fatal(ERROR_NETWORK,
228      if (ssl) {                                      "undefined ssl error while reading data\n");
229          if (r < 0)                          }
230              fatal(ERROR_NETWORK, "imapfilter: reading data; %s",                  }
231                    ERR_error_string(r, NULL));          } else
     } else  
232  #endif  #endif
233      if (r == -1)          {
234          fatal(ERROR_NETWORK, "imapfilter: reading data; %s",                  if ((s = select(conn->sock + 1, &fds, NULL, NULL, tvp)) > 0 &&
235                strerror(errno));                      FD_ISSET(conn->sock, &fds))
236                            e = read(conn->sock, buf, RESPONSE_BUF);
237    
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    
245            fcntl(conn->sock, F_SETFL, f);
246    
247            if (s == -1)
248                    fatal(ERROR_NETWORK, "waiting to read from socket; %s\n",
249                        strerror(errno));
250            else if (s == 0)
251                    fatal(ERROR_NETWORK,
252                        "timeout period expired while waiting to read "
253                        "data\n");
254    
255      return 0;          return 0;
256  }  }
257    
258    
259  /*  /*
260   * Write data to socket.   * Write data to socket.
261   */   */
262  int socket_write(char *data)  int
263    socket_write(connection_t * conn, char *data)
264  {  {
265  #ifdef SSL_TLS          int f, e, s;
266      int e;          fd_set fds;
267            struct timeval tv;
268            struct timeval *tvp = NULL;
269    
270            e = 0;
271            s = 1;
272    
273            if (opts.timeout >= 0) {
274                    tv.tv_sec = opts.timeout;
275                    tv.tv_usec = 0;
276                    tvp = &tv;
277            }
278            f = fcntl(conn->sock, F_GETFL, 0);
279            fcntl(conn->sock, F_SETFL, f | O_NONBLOCK);
280    
281            FD_ZERO(&fds);
282            FD_SET(conn->sock, &fds);
283    
284      if (ssl) {  #ifdef SSL_TLS
285          e = SSL_write(ssl, data, strlen(data));          if (conn->ssl) {
286          if (e <= 0)                  while ((s = select(conn->sock + 1, NULL, &fds, NULL, tvp) > 0 &&
287              fatal(ERROR_NETWORK,                      FD_ISSET(conn->sock, &fds))) {
288                    "imapfilter: sending data; %s",                          e = SSL_write(conn->ssl, data, strlen(data));
289                    ERR_error_string(e, NULL));  
290      } else                          if (e > 0)
291                                    break;
292    
293                            switch (SSL_get_error(conn->ssl, e)) {
294                            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                                    fatal(ERROR_NETWORK, "writing data; %s\n",
302                                        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  #endif
310      if (write(sock, data, strlen(data)) == -1)          {
311          fatal(ERROR_NETWORK, "imapfilter: sending data; %s",                  if ((s = select(conn->sock + 1, NULL, &fds, NULL, tvp)) > 0 &&
312                strerror(errno));                      FD_ISSET(conn->sock, &fds))
313                            e = write(conn->sock, data, strlen(data));
314    
315                    if (e == -1)
316                            fatal(ERROR_NETWORK, "writing data; %s",
317                                strerror(errno));
318            }
319    
320            fcntl(conn->sock, F_SETFL, f);
321    
322            if (s == -1)
323                    fatal(ERROR_NETWORK, "waiting to write to socket; %s\n",
324                        strerror(errno));
325            else if (s == 0)
326                    fatal(ERROR_NETWORK,
327                        "timeout period expired while waiting to write "
328                        "data\n");
329    
330      return 0;          return 0;
331  }  }

Legend:
Removed from v.1.12.2.1  
changed lines
  Added in v.1.42

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26