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

Diff of /imapfilter/socket.c

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

revision 1.19.2.6 by lefcha, Fri Mar 28 16:57:52 2003 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  long timeout = -1;              /* Server non-response timeout in seconds. */  extern options_t opts;
23    extern connection_t connpri, connaux;
 int sockpri = -1;               /* Main socket used mostly. */  
 int sockaux = -1;               /* Auxiliary socked used when another  
                                    connection is needed. */  
 #ifdef SSL_TLS  
 static SSL *sslpri = NULL;  
 static SSL *sslaux = NULL;  
 #endif  
24    
25    
26  /*  /*
27   * Connect to mail server.   * Connect to mail server.
28   */   */
29  int init_connection(int *sock, char *serv, unsigned short int port,  int
30                       unsigned int protocol)  init_connection(connection_t * conn, char *serv, unsigned short int port,
31        unsigned int protocol)
32  {  {
33      struct sockaddr_in sa;          struct sockaddr_in sa;
34      struct hostent *he;          struct hostent *he;
35  #ifdef SSL_TLS  
36      SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);  #ifndef SSL_TLS
37  #else          if (protocol != SSL_DISABLED) {
38      if (protocol != SSL_DISABLED) {                  error("SSL not supported by this build\n");
39          error("imapfilter: SSL not supported by this build\n");                  return ERROR_SSL;
40          return ERROR_SSL;          }
     }  
41  #endif  #endif
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(sock);                  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(sock);                  return ERROR_NETWORK;
67          return ERROR_NETWORK;          }
68      }          if (conn == &connpri)
69                    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(sock, protocol)) {                  if (!init_secure_connection(conn, protocol))
74              if (sock == &sockpri)                          return 0;
75                  info("Connected to %s using %s.\n", serv,                  else
76                       SSL_get_cipher(*ssl));                          return ERROR_SSL;
77              return 0;          else
78          } else                  conn->ssl = NULL;
             return ERROR_SSL;  
     else  
         *ssl = NULL;  
79  #endif  #endif
80    
81      if (sock == &sockpri)          return 0;
         info("Connected to %s.\n", serv);  
   
     return 0;  
82  }  }
83    
84    
# Line 97  int init_connection(int *sock, char *ser Line 86  int init_connection(int *sock, char *ser
86  /*  /*
87   * Initialize Secure Socket Layer connection.   * Initialize Secure Socket Layer connection.
88   */   */
89  int ssl_init(int *sock, 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      const EVP_MD *evp;          SSL_library_init();
99      unsigned char digest[EVP_MAX_MD_SIZE];          SSL_load_error_strings();
100      SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);  
101            switch (protocol) {
102      SSL_library_init();          case SSL_TLS_V1:
103                    method = TLSv1_client_method();
104      switch (protocol) {                  break;
105      case SSL_SSL_V2:          case SSL_SSL_V2:
106          method = SSLv2_client_method();          case SSL_SSL_V3:
107          break;                  method = SSLv23_client_method();
108      case SSL_SSL_V3:                  break;
109          method = SSLv3_client_method();          }
         break;  
     case SSL_TLS_V1:  
         method = TLSv1_client_method();  
         break;  
     }  
110    
111      if (!(ctx = SSL_CTX_new(method)))          if (!(ctx = SSL_CTX_new(method)))
112          return ERROR_SSL;                  goto fail;
113    
114      if (!(*ssl = SSL_new(ctx)))          if (!(conn->ssl = SSL_new(ctx)))
115          return ERROR_SSL;                  goto fail;
116    
117      SSL_set_fd(*ssl, *sock);          SSL_set_fd(conn->ssl, conn->sock);
118    
119      e = SSL_connect(*ssl);          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 (e <= 0) {          SSL_CTX_free(ctx);
         SSL_get_error(*ssl, e);  
         error("imapfilter: initiating SSL connection; %s",  
               ERR_error_string(ERR_get_error(), 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);  
     xfree(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);
     xfree(c);  
148    
     if (!(evp = EVP_md5()))  
         return ERROR_SSL;  
     if (!(X509_digest(cert, evp, digest, &n)))  
149          return ERROR_SSL;          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                          /* SSL_TLS */
 #endif  
152    
153    
154  /*  /*
155   * Disconnect from mail server.   * Disconnect from mail server.
156   */   */
157  int close_connection(int *sock)  int
158    close_connection(connection_t * conn)
159  {  {
 #ifdef SSL_TLS  
     SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);  
160    
161      if (*ssl) {  #ifdef SSL_TLS
162          SSL_shutdown(*ssl);          if (conn->ssl) {
163          SSL_free(*ssl);                  SSL_shutdown(conn->ssl);
164          *ssl = NULL;                  SSL_free(conn->ssl);
165      }                  conn->ssl = NULL;
166            }
167  #endif  #endif
168            if (conn->sock >= 0 && close(conn->sock) == -1) {
169      if (*sock >= 0 && 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          *sock = -1;                  return 0;
174          return 0;          }
     }  
175  }  }
176    
177    
178  /*  /*
179   * Read data from socket.   * Read data from socket.
180   */   */
181  int socket_read(int *sock, char *buf)  int
182    socket_read(connection_t * conn, char *buf)
183  {  {
184      int f, e, 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  #ifdef SSL_TLS  
189      SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);          e = 0;
190  #endif          s = 1;
191            tvp = NULL;
192      e = 0;  
193      s = 1;          memset(buf, 0, RESPONSE_BUF + 1);
194    
195      memset(buf, 0, RESPONSE_BUF + 1);          if (opts.timeout >= 0) {
196                    tv.tv_sec = opts.timeout;
197      if (timeout >= 0) {                  tv.tv_usec = 0;
198          tv.tv_sec = timeout;                  tvp = &tv;
199          tv.tv_usec = 0;          }
200          tvp = &tv;          f = fcntl(conn->sock, F_GETFL, 0);
201      }          fcntl(conn->sock, F_SETFL, f | O_NONBLOCK);
     f = fcntl(*sock, F_GETFL, 0);  
     fcntl(*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                    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    
213                            if (e > 0)
214                                    break;
215    
216                            switch (SSL_get_error(conn->ssl, e)) {
217                            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                                    fatal(ERROR_NETWORK, "reading data; %s\n",
225                                        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                    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    
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          for (;;) {          fcntl(conn->sock, F_SETFL, f);
             if (SSL_pending(*ssl) ||  
                 ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&  
                  FD_ISSET(*sock, &fds)))  
                 e = SSL_read(*ssl, buf, RESPONSE_BUF);  
246    
247              if (e > 0)          if (s == -1)
248                  break;                  fatal(ERROR_NETWORK, "waiting to read from socket; %s\n",
249                        strerror(errno));
250              switch (SSL_get_error(*ssl, e)) {          else if (s == 0)
             case SSL_ERROR_WANT_READ:  
             case SSL_ERROR_WANT_WRITE:  
                 continue;  
             case SSL_ERROR_ZERO_RETURN:  
                  return ERROR_NETWORK;  
             case SSL_ERROR_SYSCALL:  
             case SSL_ERROR_SSL:  
                 fatal(ERROR_NETWORK, "imapfilter: reading data; %s",  
                       ERR_error_string(ERR_get_error(), NULL));  
             default:  
251                  fatal(ERROR_NETWORK,                  fatal(ERROR_NETWORK,
252                      "imapfilter: undefined ssl error while reading data\n");                      "timeout period expired while waiting to read "
253              }                      "data\n");
         }  
     } else  
 #endif  
     {  
         if ((s = select(*sock + 1, &fds, NULL, NULL, tvp)) > 0 &&  
             FD_ISSET(*sock, &fds))  
             e = read(*sock, buf, RESPONSE_BUF);  
           
         if (e == -1)  
             fatal(ERROR_NETWORK, "imapfilter: reading data; %s",  
                   strerror(errno));  
         else if (e == 0)  
             return ERROR_NETWORK;  
     }  
   
     fcntl(*sock, F_SETFL, f);  
   
     if (s == -1)  
         fatal(ERROR_NETWORK, "imapfilter: waiting to read from socket; %s\n",  
               strerror(errno));  
     else if (!s)  
         fatal(ERROR_NETWORK,  
               "imapfilter: timeout period expired while waiting to read "  
               "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(int *sock, char *data)  int
263    socket_write(connection_t * conn, char *data)
264  {  {
265      int f, e, s;          int f, e, s;
266      fd_set fds;          fd_set fds;
267      struct timeval tv;          struct timeval tv;
268      struct timeval *tvp = NULL;          struct timeval *tvp = NULL;
269  #ifdef SSL_TLS  
270      SSL **ssl = (sock == &sockpri ? &sslpri : &sslaux);          e = 0;
271  #endif          s = 1;
272    
273      e = 0;          if (opts.timeout >= 0) {
274      s = 1;                  tv.tv_sec = opts.timeout;
275                    tv.tv_usec = 0;
276      if (timeout >= 0) {                  tvp = &tv;
277          tv.tv_sec = timeout;          }
278          tv.tv_usec = 0;          f = fcntl(conn->sock, F_GETFL, 0);
279          tvp = &tv;          fcntl(conn->sock, F_SETFL, f | O_NONBLOCK);
     }  
     f = fcntl(*sock, F_GETFL, 0);  
     fcntl(*sock, F_SETFL, f | O_NONBLOCK);  
280    
281      FD_ZERO(&fds);          FD_ZERO(&fds);
282      FD_SET(*sock, &fds);          FD_SET(conn->sock, &fds);
283    
284  #ifdef SSL_TLS  #ifdef SSL_TLS
285      if (*ssl) {          if (conn->ssl) {
286          for (;;) {                  while ((s = select(conn->sock + 1, NULL, &fds, NULL, tvp) > 0 &&
287              if ((s = select(*sock + 1, NULL, &fds, NULL, tvp) > 0 &&                      FD_ISSET(conn->sock, &fds))) {
288                   FD_ISSET(*sock, &fds)))                          e = SSL_write(conn->ssl, data, strlen(data));
289                  e = SSL_write(*ssl, data, strlen(data));  
290                            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
310            {
311                    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    
315                    if (e == -1)
316                            fatal(ERROR_NETWORK, "writing data; %s",
317                                strerror(errno));
318            }
319    
320              if (e > 0)          fcntl(conn->sock, F_SETFL, f);
                 break;  
321    
322              switch (SSL_get_error(*ssl, e)) {          if (s == -1)
323              case SSL_ERROR_WANT_READ:                  fatal(ERROR_NETWORK, "waiting to write to socket; %s\n",
324              case SSL_ERROR_WANT_WRITE:                      strerror(errno));
325                  continue;          else if (s == 0)
             case SSL_ERROR_ZERO_RETURN:  
                  return ERROR_NETWORK;  
             case SSL_ERROR_SYSCALL:  
             case SSL_ERROR_SSL:  
                 fatal(ERROR_NETWORK, "imapfilter: writing data; %s",  
                       ERR_error_string(ERR_get_error(), NULL));  
             default:  
326                  fatal(ERROR_NETWORK,                  fatal(ERROR_NETWORK,
327                      "imapfilter: undefined ssl error while writing data\n");                      "timeout period expired while waiting to write "
328              }                      "data\n");
         }  
     } else  
 #endif  
     {  
         if ((s = select(*sock + 1, NULL, &fds, NULL, tvp)) > 0 &&  
             FD_ISSET(*sock, &fds))  
             e = write(*sock, data, strlen(data));  
           
         if (e == -1)  
             fatal(ERROR_NETWORK, "imapfilter: writing data; %s",  
                   strerror(errno));  
     }  
   
     fcntl(*sock, F_SETFL, f);  
   
     if (s == -1)  
         fatal(ERROR_NETWORK, "imapfilter: waiting to write to socket; %s\n",  
               strerror(errno));  
     else if (!s)  
         fatal(ERROR_NETWORK,  
               "imapfilter: timeout period expired while waiting to write "  
               "data\n");  
329    
330      return 0;          return 0;
331  }  }

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26