#include "headers.h" /* include all important things */

#ifndef NOSSL

/* load the DH parameters */
void loadDHparams()
{
   FILE *parmfd;

   while(1)
   {
      /* FIX - no hardcode */
      parmfd = fopen(PARAMDIR "/dh.params", "r");

      if (parmfd == NULL) 
      {
         if (errno == EINTR) continue;

         error("error opening %s: %s\n\n", PARAMDIR "/dh.params",
               strerror(errno));

         quit(ERROR);
      }

      else break;
   }

   dhparms = PEM_read_DHparams(parmfd, NULL, NULL);
   if (dhparms == NULL) 
   {
      error("error in PEM_read_DHparams(): %s\n\n", strerror(errno));
 
      ERR_print_errors_fp(stderr), ERR_print_errors_fp(errlogfd1);
      if (debugging == 1) ERR_print_errors_fp(dblogfd1);

      if (parmfd != NULL)(void)fclose(parmfd);
      quit(ERROR);
   }

}


/* ------------------------------- */


/* initialize the SSL connection */
void makeSSLconn(int fd)
{
   int res;
   static int init = 0;
   int flags = SSL_VERIFY_PEER; /* | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; */

   /* FIX - no hardcode */
   char *allcert = PARAMDIR "/all.cert.pem";
   char	*serverpem = PARAMDIR "/server.pem";

   if (init == 0) 
   {
      init = 1;
      SSL_load_error_strings();
      SSLeay_add_all_algorithms(), SSLeay_add_ssl_algorithms();
   }

   /* clean up after any previous connections */
   if (clients[curClient].sslconn != NULL) 
      SSL_free(clients[curClient].sslconn);

   if (clients[curClient].sslctx != NULL) 
      SSL_CTX_free(clients[curClient].sslctx);

   clients[curClient].sslconn = NULL;
   clients[curClient].sslctx = NULL;

   /* create a context */
   clients[curClient].sslctx = SSL_CTX_new(SSLv3_server_method());

   if (clients[curClient].sslctx == NULL) 
   {
      error("error in SSL_CTX_new(): %s\n\n", strerror(errno));
 
      ERR_print_errors_fp(stderr), ERR_print_errors_fp(errlogfd1);
      if (debugging == 1) ERR_print_errors_fp(dblogfd1);

      quit(ERROR);
   }

   /* don't set any options since they always have to do with bugs */
   SSL_CTX_set_options(clients[curClient].sslctx, 0);

   /* indicate where we should load the CA's public key */
   res = SSL_CTX_load_verify_locations(clients[curClient].sslctx, 
                                       serverpem, PARAMDIR);

   if (res <= 0) 
   {
      error("error in SSL_CTX_load_verify_locations(): %s\n\n",
            strerror(errno));
 
      ERR_print_errors_fp(stderr), ERR_print_errors_fp(errlogfd1);
      if (debugging == 1) ERR_print_errors_fp(dblogfd1);

      quit(ERROR);
   }

   res = SSL_CTX_set_default_verify_paths(clients[curClient].sslctx);
   if (res <= 0) 
   {
      error("error in SSL_CTX_set_default_verify_paths(): %s\n\n",
            strerror(errno));
 
      ERR_print_errors_fp(stderr), ERR_print_errors_fp(errlogfd1);
      if (debugging == 1) ERR_print_errors_fp(dblogfd1);

      quit(ERROR);
   }

   /* setup DH parameters */
   loadDHparams();

   SSL_CTX_set_tmp_dh(clients[curClient].sslctx, dhparms);
   DH_free(dhparms);

   /* indicate where our certificate is */
   res = SSL_CTX_use_certificate_file(clients[curClient].sslctx, 
		PARAMDIR "/server.pem", SSL_FILETYPE_PEM);

   if (res <= 0) 
   {
      error("error in SSL_CTX_use_certificate_file(): %s\n\n",
            strerror(errno));
 
      ERR_print_errors_fp(stderr), ERR_print_errors_fp(errlogfd1);
      if (debugging == 1) ERR_print_errors_fp(dblogfd1);

      quit(ERROR);
   }

   res = SSL_CTX_set_cipher_list(clients[curClient].sslctx, "ADH:+DES:+EXP");

   if (res <= 0) 
   {
      error("error in SSL_CTX_set_cipher_list(): %s\n\n",
            strerror(errno));
 
      ERR_print_errors_fp(stderr), ERR_print_errors_fp(errlogfd1);
      if (debugging == 1) ERR_print_errors_fp(dblogfd1);

      quit(ERROR);
   }

   /* FIX - do I need SSL_VERIFY_CLIENT_ONCE? */
   /* FIX - mark doesn't use the verify fail.. */

   /* we want the client verified */
   SSL_CTX_set_verify(clients[curClient].sslctx, flags, NULL);

   /* indicate where the clients' certificates can be found */
   SSL_CTX_set_client_CA_list(clients[curClient].sslctx, 
                              SSL_load_client_CA_file(allcert));

   /* create a connection */
   clients[curClient].sslconn = SSL_new(clients[curClient].sslctx);
   if (clients[curClient].sslconn == NULL) 
   {
      error("error in SSL_new(): %s\n\n", strerror(errno));
 
      ERR_print_errors_fp(stderr), ERR_print_errors_fp(errlogfd1);
      if (debugging == 1) ERR_print_errors_fp(dblogfd1);

      quit(ERROR);
   }

   /* setup to perform a connection next time we send/recv data */
   SSL_set_accept_state(clients[curClient].sslconn);

   /* information the connection about the socket */
   res = SSL_set_fd(clients[curClient].sslconn, fd);
   if (res <= 0) 
   {
      error("error in SSL_set_fd(): %s\n\n", strerror(errno));
 
      ERR_print_errors_fp(stderr), ERR_print_errors_fp(errlogfd1);
      if (debugging == 1) ERR_print_errors_fp(dblogfd1);

      quit(ERROR);
   }
}

#endif /* NOSSL */
