Diff for /embedaddon/lighttpd/src/network.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2013/10/14 10:32:47 version 1.1.1.2, 2014/06/15 20:20:06
Line 112  static int network_ssl_servername_callback(SSL *ssl, i Line 112  static int network_ssl_servername_callback(SSL *ssl, i
         config_patch_connection(srv, con, COMP_HTTP_SCHEME);          config_patch_connection(srv, con, COMP_HTTP_SCHEME);
         config_patch_connection(srv, con, COMP_HTTP_HOST);          config_patch_connection(srv, con, COMP_HTTP_HOST);
   
        if (NULL == con->conf.ssl_ctx) {        if (NULL == con->conf.ssl_pemfile_x509 || NULL == con->conf.ssl_pemfile_pkey) {
                /* ssl_ctx <=> pemfile was set <=> ssl_ctx got patched: so this should never happen */                /* x509/pkey available <=> pemfile was set <=> pemfile got patched: so this should never happen, unless you nest $SERVER["socket"] */
                 log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                  log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
                        "null SSL_CTX for TLS server name", con->tlsext_server_name);                        "no certificate/private key for TLS server name", con->tlsext_server_name);
                 return SSL_TLSEXT_ERR_ALERT_FATAL;                  return SSL_TLSEXT_ERR_ALERT_FATAL;
         }          }
   
        /* switch to new SSL_CTX in reaction to a client's server_name extension */        /* first set certificate! setting private key checks whether certificate matches it */
        if (con->conf.ssl_ctx != SSL_set_SSL_CTX(ssl, con->conf.ssl_ctx)) {        if (!SSL_use_certificate(ssl, con->conf.ssl_pemfile_x509)) {
                log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
                        "failed to set SSL_CTX for TLS server name", con->tlsext_server_name);                        "failed to set certificate for TLS server name", con->tlsext_server_name,
                         ERR_error_string(ERR_get_error(), NULL));
                 return SSL_TLSEXT_ERR_ALERT_FATAL;                  return SSL_TLSEXT_ERR_ALERT_FATAL;
         }          }
   
           if (!SSL_use_PrivateKey(ssl, con->conf.ssl_pemfile_pkey)) {
                   log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
                           "failed to set private key for TLS server name", con->tlsext_server_name,
                           ERR_error_string(ERR_get_error(), NULL));
                   return SSL_TLSEXT_ERR_ALERT_FATAL;
           }
   
           if (con->conf.ssl_verifyclient) {
                   if (NULL == con->conf.ssl_ca_file_cert_names) {
                           log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
                                   "can't verify client without ssl.ca-file for TLS server name", con->tlsext_server_name,
                                   ERR_error_string(ERR_get_error(), NULL));
                           return SSL_TLSEXT_ERR_ALERT_FATAL;
                   }
   
                   SSL_set_client_CA_list(ssl, SSL_dup_CA_list(con->conf.ssl_ca_file_cert_names));
                   /* forcing verification here is really not that useful - a client could just connect without SNI */
                   SSL_set_verify(
                           ssl,
                           SSL_VERIFY_PEER | (con->conf.ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0),
                           NULL
                   );
                   SSL_set_verify_depth(ssl, con->conf.ssl_verifyclient_depth);
           }
   
         return SSL_TLSEXT_ERR_OK;          return SSL_TLSEXT_ERR_OK;
 }  }
 #endif  #endif
Line 224  static int network_server_init(server *srv, buffer *ho Line 250  static int network_server_init(server *srv, buffer *ho
                         log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));                          log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
                         goto error_free_socket;                          goto error_free_socket;
                 }                  }
                 srv_socket->use_ipv6 = 1;  
         }          }
 #endif  #endif
   
Line 236  static int network_server_init(server *srv, buffer *ho Line 261  static int network_server_init(server *srv, buffer *ho
                 }                  }
         }          }
   
 #ifdef FD_CLOEXEC  
         /* set FD_CLOEXEC now, fdevent_fcntl_set is called later; needed for pipe-logger forks */          /* set FD_CLOEXEC now, fdevent_fcntl_set is called later; needed for pipe-logger forks */
        fcntl(srv_socket->fd, F_SETFD, FD_CLOEXEC);        fd_close_on_exec(srv_socket->fd);
#endif 
   
         /* */          /* */
         srv->cur_fds = srv_socket->fd;          srv->cur_fds = srv_socket->fd;
Line 326  static int network_server_init(server *srv, buffer *ho Line 349  static int network_server_init(server *srv, buffer *ho
   
                 break;                  break;
         case AF_UNIX:          case AF_UNIX:
                   {
                           size_t hostlen = strlen(host) + 1;
                           if (hostlen > sizeof(srv_socket->addr.un.sun_path)) {
                                   log_error_write(srv, __FILE__, __LINE__, "sS", "unix socket filename too long:", host);
                                   goto error_free_socket;
                           }
                           memcpy(srv_socket->addr.un.sun_path, host, hostlen);
                   }
                 srv_socket->addr.un.sun_family = AF_UNIX;                  srv_socket->addr.un.sun_family = AF_UNIX;
                 strcpy(srv_socket->addr.un.sun_path, host);  
   
 #ifdef SUN_LEN  #ifdef SUN_LEN
                 addr_len = SUN_LEN(&srv_socket->addr.un);                  addr_len = SUN_LEN(&srv_socket->addr.un);
 #else  #else
                 /* stevens says: */                  /* stevens says: */
                addr_len = strlen(host) + 1 + sizeof(srv_socket->addr.un.sun_family);                addr_len = hostlen + sizeof(srv_socket->addr.un.sun_family);
 #endif  #endif
   
                 /* check if the socket exists and try to connect to it. */                  /* check if the socket exists and try to connect to it. */
Line 428  static int network_server_init(server *srv, buffer *ho Line 458  static int network_server_init(server *srv, buffer *ho
         if (srv->srv_sockets.size == 0) {          if (srv->srv_sockets.size == 0) {
                 srv->srv_sockets.size = 4;                  srv->srv_sockets.size = 4;
                 srv->srv_sockets.used = 0;                  srv->srv_sockets.used = 0;
                srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket));                srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket*));
         } else if (srv->srv_sockets.used == srv->srv_sockets.size) {          } else if (srv->srv_sockets.used == srv->srv_sockets.size) {
                 srv->srv_sockets.size += 4;                  srv->srv_sockets.size += 4;
                srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));                srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket*));
         }          }
   
         srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;          srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
Line 492  typedef enum { Line 522  typedef enum {
         NETWORK_BACKEND_SOLARIS_SENDFILEV          NETWORK_BACKEND_SOLARIS_SENDFILEV
 } network_backend_t;  } network_backend_t;
   
   #ifdef USE_OPENSSL
   static X509* x509_load_pem_file(server *srv, const char *file) {
           BIO *in;
           X509 *x = NULL;
   
           in = BIO_new(BIO_s_file());
           if (NULL == in) {
                   log_error_write(srv, __FILE__, __LINE__, "S", "SSL: BIO_new(BIO_s_file()) failed");
                   goto error;
           }
   
           if (BIO_read_filename(in,file) <= 0) {
                   log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: BIO_read_filename('", file,"') failed");
                   goto error;
           }
           x = PEM_read_bio_X509(in, NULL, NULL, NULL);
   
           if (NULL == x) {
                   log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: couldn't read X509 certificate from '", file,"'");
                   goto error;
           }
   
           BIO_free(in);
           return x;
   
   error:
           if (NULL != in) BIO_free(in);
           return NULL;
   }
   
   static EVP_PKEY* evp_pkey_load_pem_file(server *srv, const char *file) {
           BIO *in;
           EVP_PKEY *x = NULL;
   
           in=BIO_new(BIO_s_file());
           if (NULL == in) {
                   log_error_write(srv, __FILE__, __LINE__, "s", "SSL: BIO_new(BIO_s_file()) failed");
                   goto error;
           }
   
           if (BIO_read_filename(in,file) <= 0) {
                   log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: BIO_read_filename('", file,"') failed");
                   goto error;
           }
           x = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
   
           if (NULL == x) {
                   log_error_write(srv, __FILE__, __LINE__, "SSS", "SSL: couldn't read private key from '", file,"'");
                   goto error;
           }
   
           BIO_free(in);
           return x;
   
   error:
           if (NULL != in) BIO_free(in);
           return NULL;
   }
   
   static int network_openssl_load_pemfile(server *srv, size_t ndx) {
           specific_config *s = srv->config_storage[ndx];
   
   #ifdef OPENSSL_NO_TLSEXT
           {
                   data_config *dc = (data_config *)srv->config_context->data[ndx];
                   if ((ndx > 0 && (COMP_SERVER_SOCKET != dc->comp || dc->cond != CONFIG_COND_EQ))
                           || !s->ssl_enabled) {
                           log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
                                           "ssl.pemfile only works in SSL socket binding context as openssl version does not support TLS extensions");
                           return -1;
                   }
           }
   #endif
   
           if (NULL == (s->ssl_pemfile_x509 = x509_load_pem_file(srv, s->ssl_pemfile->ptr))) return -1;
           if (NULL == (s->ssl_pemfile_pkey = evp_pkey_load_pem_file(srv, s->ssl_pemfile->ptr))) return -1;
   
           if (!X509_check_private_key(s->ssl_pemfile_x509, s->ssl_pemfile_pkey)) {
                   log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
                                   "Private key does not match the certificate public key, reason:",
                                   ERR_error_string(ERR_get_error(), NULL),
                                   s->ssl_pemfile);
                   return -1;
           }
   
           return 0;
   }
   #endif
   
 int network_init(server *srv) {  int network_init(server *srv) {
         buffer *b;          buffer *b;
        size_t i;        size_t i, j;
         network_backend_t backend;          network_backend_t backend;
   
 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL  #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
Line 581  int network_init(server *srv) { Line 700  int network_init(server *srv) {
                 long ssloptions =                  long ssloptions =
                         SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION;                          SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION;
   
                if (buffer_is_empty(s->ssl_pemfile)) continue;                if (buffer_is_empty(s->ssl_pemfile) && buffer_is_empty(s->ssl_ca_file)) continue;
   
 #ifdef OPENSSL_NO_TLSEXT  
                 {  
                         data_config *dc = (data_config *)srv->config_context->data[i];  
                         if (COMP_HTTP_HOST == dc->comp) {  
                             log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",  
                                             "can't use ssl.pemfile with $HTTP[\"host\"], openssl version does not support TLS extensions");  
                             return -1;  
                         }  
                 }  
 #endif  
   
                 if (srv->ssl_is_init == 0) {                  if (srv->ssl_is_init == 0) {
                         SSL_load_error_strings();                          SSL_load_error_strings();
                         SSL_library_init();                          SSL_library_init();
Line 607  int network_init(server *srv) { Line 715  int network_init(server *srv) {
                         }                          }
                 }                  }
   
                   if (!buffer_is_empty(s->ssl_pemfile)) {
   #ifdef OPENSSL_NO_TLSEXT
                           data_config *dc = (data_config *)srv->config_context->data[i];
                           if (COMP_HTTP_HOST == dc->comp) {
                                   log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
                                                   "can't use ssl.pemfile with $HTTP[\"host\"], openssl version does not support TLS extensions");
                                   return -1;
                           }
   #endif
                           if (network_openssl_load_pemfile(srv, i)) return -1;
                   }
   
   
                   if (!buffer_is_empty(s->ssl_ca_file)) {
                           s->ssl_ca_file_cert_names = SSL_load_client_CA_file(s->ssl_ca_file->ptr);
                           if (NULL == s->ssl_ca_file_cert_names) {
                                   log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
                                                   ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
                           }
                   }
   
                   if (buffer_is_empty(s->ssl_pemfile) || !s->ssl_enabled) continue;
   
                 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {                  if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
                         log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",                          log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
                                         ERR_error_string(ERR_get_error(), NULL));                                          ERR_error_string(ERR_get_error(), NULL));
                         return -1;                          return -1;
                 }                  }
   
                   /* completely useless identifier; required for client cert verification to work with sessions */
                   if (0 == SSL_CTX_set_session_id_context(s->ssl_ctx, (const unsigned char*) CONST_STR_LEN("lighttpd"))) {
                           log_error_write(srv, __FILE__, __LINE__, "ss:s", "SSL:",
                                   "failed to set session context",
                                   ERR_error_string(ERR_get_error(), NULL));
                           return -1;
                   }
   
                 if (s->ssl_empty_fragments) {                  if (s->ssl_empty_fragments) {
 #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS  #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
                         ssloptions &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;                          ssloptions &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
Line 722  int network_init(server *srv) { Line 861  int network_init(server *srv) {
 #endif  #endif
 #endif  #endif
   
                if (!buffer_is_empty(s->ssl_ca_file)) {                /* load all ssl.ca-files specified in the config into each SSL_CTX to be prepared for SNI */
                        if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {                for (j = 0; j < srv->config_context->used; j++) {
                                log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                        specific_config *s1 = srv->config_storage[j];
                                                ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
                                return -1;                        if (!buffer_is_empty(s1->ssl_ca_file)) {
                        }                                if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s1->ssl_ca_file->ptr, NULL)) {
                        if (s->ssl_verifyclient) { 
                                STACK_OF(X509_NAME) *certs = SSL_load_client_CA_file(s->ssl_ca_file->ptr); 
                                if (!certs) { 
                                         log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                                          log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
                                                        ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);                                                        ERR_error_string(ERR_get_error(), NULL), s1->ssl_ca_file);
                                } 
                                if (SSL_CTX_set_session_id_context(s->ssl_ctx, (void*) &srv, sizeof(srv)) != 1) { 
                                        log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", 
                                                ERR_error_string(ERR_get_error(), NULL)); 
                                         return -1;                                          return -1;
                                 }                                  }
                                SSL_CTX_set_client_CA_list(s->ssl_ctx, certs);                        }
                                SSL_CTX_set_verify(                }
                                        s->ssl_ctx,
                                        SSL_VERIFY_PEER | (s->ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0),                if (s->ssl_verifyclient) {
                                        NULL                        if (NULL == s->ssl_ca_file_cert_names) {
                                 log_error_write(srv, __FILE__, __LINE__, "s",
                                         "SSL: You specified ssl.verifyclient.activate but no ca_file"
                                 );                                  );
                                SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth);                                return -1;
                         }                          }
                } else if (s->ssl_verifyclient) {                        SSL_CTX_set_client_CA_list(s->ssl_ctx, SSL_dup_CA_list(s->ssl_ca_file_cert_names));
                        log_error_write(                        SSL_CTX_set_verify(
                                srv, __FILE__, __LINE__, "s",                                s->ssl_ctx,
                                "SSL: You specified ssl.verifyclient.activate but no ca_file"                                SSL_VERIFY_PEER | (s->ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0),
                                 NULL
                         );                          );
                           SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth);
                 }                  }
   
                if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {                if (SSL_CTX_use_certificate(s->ssl_ctx, s->ssl_pemfile_x509) < 0) {
                         log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                          log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);                                          ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
                         return -1;                          return -1;
                 }                  }
   
                if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {                if (SSL_CTX_use_PrivateKey(s->ssl_ctx, s->ssl_pemfile_pkey) < 0) {
                         log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",                          log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
                                         ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);                                          ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
                         return -1;                          return -1;
Line 794  int network_init(server *srv) { Line 930  int network_init(server *srv) {
         buffer_append_long(b, srv->srvconf.port);          buffer_append_long(b, srv->srvconf.port);
   
         if (0 != network_server_init(srv, b, srv->config_storage[0])) {          if (0 != network_server_init(srv, b, srv->config_storage[0])) {
                   buffer_free(b);
                 return -1;                  return -1;
         }          }
         buffer_free(b);          buffer_free(b);
Line 857  int network_init(server *srv) { Line 994  int network_init(server *srv) {
         for (i = 1; i < srv->config_context->used; i++) {          for (i = 1; i < srv->config_context->used; i++) {
                 data_config *dc = (data_config *)srv->config_context->data[i];                  data_config *dc = (data_config *)srv->config_context->data[i];
                 specific_config *s = srv->config_storage[i];                  specific_config *s = srv->config_storage[i];
                 size_t j;  
   
                 /* not our stage */                  /* not our stage */
                 if (COMP_SERVER_SOCKET != dc->comp) continue;                  if (COMP_SERVER_SOCKET != dc->comp) continue;

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>