diff -rc stunnel-4.11/src/client.c stunnel-4.11.mult_certs/src/client.c
*** stunnel-4.11/src/client.c	2005-07-02 02:55:58.000000000 -0400
--- stunnel-4.11.mult_certs/src/client.c	2005-08-29 16:42:37.000000000 -0400
***************
*** 147,153 ****
  
      if(init_local(c))
          return -1;
!     if(!options.option.client && !c->opt->protocol) {
          /* Server mode and no protocol negotiation needed */
          if(init_ssl(c))
              return -1;
--- 147,153 ----
  
      if(init_local(c))
          return -1;
!     if(!c->opt->ssl_ctx_data.option.client && !c->opt->protocol) {
          /* Server mode and no protocol negotiation needed */
          if(init_ssl(c))
              return -1;
***************
*** 253,266 ****
      int i, err;
      SSL_SESSION *old_session;
  
!     if(!(c->ssl=SSL_new(ctx))) {
          sslerror("SSL_new");
          return -1;
      }
  #if SSLEAY_VERSION_NUMBER >= 0x0922
      SSL_set_session_id_context(c->ssl, sid_ctx, strlen(sid_ctx));
  #endif
!     if(options.option.client) {
          if(c->opt->session) {
              enter_critical_section(CRIT_SESSION);
              SSL_set_session(c->ssl, c->opt->session);
--- 253,266 ----
      int i, err;
      SSL_SESSION *old_session;
  
!     if(!(c->ssl=SSL_new(c->opt->ssl_ctx_data.ctx))) {
          sslerror("SSL_new");
          return -1;
      }
  #if SSLEAY_VERSION_NUMBER >= 0x0922
      SSL_set_session_id_context(c->ssl, sid_ctx, strlen(sid_ctx));
  #endif
!     if(c->opt->ssl_ctx_data.option.client) {
          if(c->opt->session) {
              enter_critical_section(CRIT_SESSION);
              SSL_set_session(c->ssl, c->opt->session);
***************
*** 280,286 ****
      }
  
      /* Setup some values for transfer() function */
!     if(options.option.client) {
          c->sock_rfd=&(c->local_rfd);
          c->sock_wfd=&(c->local_wfd);
          c->ssl_rfd=c->ssl_wfd=&(c->remote_fd);
--- 280,286 ----
      }
  
      /* Setup some values for transfer() function */
!     if(c->opt->ssl_ctx_data.option.client) {
          c->sock_rfd=&(c->local_rfd);
          c->sock_wfd=&(c->local_wfd);
          c->ssl_rfd=c->ssl_wfd=&(c->remote_fd);
***************
*** 291,297 ****
      }
  
      while(1) {
!         if(options.option.client)
              i=SSL_connect(c->ssl);
          else
              i=SSL_accept(c->ssl);
--- 291,297 ----
      }
  
      while(1) {
!         if(c->opt->ssl_ctx_data.option.client)
              i=SSL_connect(c->ssl);
          else
              i=SSL_accept(c->ssl);
***************
*** 325,331 ****
                  continue;
              }
          }
!         if(options.option.client)
              sslerror("SSL_connect");
          else
              sslerror("SSL_accept");
--- 325,331 ----
                  continue;
              }
          }
!         if(c->opt->ssl_ctx_data.option.client)
              sslerror("SSL_connect");
          else
              sslerror("SSL_accept");
***************
*** 333,341 ****
      }
      if(SSL_session_reused(c->ssl)) {
          s_log(LOG_INFO, "SSL %s: previous session reused",
!             options.option.client ? "connected" : "accepted");
      } else { /* a new session was negotiated */
!         if(options.option.client) {
              s_log(LOG_INFO, "SSL connected: new session negotiated");
              enter_critical_section(CRIT_SESSION);
              old_session=c->opt->session;
--- 333,341 ----
      }
      if(SSL_session_reused(c->ssl)) {
          s_log(LOG_INFO, "SSL %s: previous session reused",
!             c->opt->ssl_ctx_data.option.client ? "connected" : "accepted");
      } else { /* a new session was negotiated */
!         if(c->opt->ssl_ctx_data.option.client) {
              s_log(LOG_INFO, "SSL connected: new session negotiated");
              enter_critical_section(CRIT_SESSION);
              old_session=c->opt->session;
diff -rc stunnel-4.11/src/gui.c stunnel-4.11.mult_certs/src/gui.c
*** stunnel-4.11/src/gui.c	2005-01-22 12:45:26.000000000 -0500
--- stunnel-4.11.mult_certs/src/gui.c	2005-08-29 16:42:50.000000000 -0400
***************
*** 403,408 ****
--- 403,409 ----
          WPARAM wParam, LPARAM lParam) {
      char titlebar[STRLEN];
      WORD cchPassword;
+ 	char *tailed_key = (char *)lParam;
  
      switch (message) {
      case WM_INITDIALOG:
***************
*** 410,416 ****
          SendMessage(hDlg, DM_SETDEFID, (WPARAM) IDCANCEL, (LPARAM) 0);
  
          safecopy(titlebar, "Private key: ");
!         safeconcat(titlebar, options.key);
          SetWindowText(hDlg, titlebar);
          return TRUE;
  
--- 411,417 ----
          SendMessage(hDlg, DM_SETDEFID, (WPARAM) IDCANCEL, (LPARAM) 0);
  
          safecopy(titlebar, "Private key: ");
!         safeconcat(titlebar, tailed_key);
          SetWindowText(hDlg, titlebar);
          return TRUE;
  
***************
*** 447,453 ****
      }
      return FALSE;
  
!     UNREFERENCED_PARAMETER(lParam);
  }
  
  int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata) {
--- 448,454 ----
      }
      return FALSE;
  
!     /* UNREFERENCED_PARAMETER(lParam); ( now defined ! ) */
  }
  
  int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata) {
***************
*** 486,492 ****
  #endif
  
      /* Display the dialog box */
!     result=DialogBox(ghInst, "PassBox", hwnd, (DLGPROC)pass_proc);
  
  #if 0
      /* Restore window station and desktop */
--- 487,493 ----
  #endif
  
      /* Display the dialog box */
!     result=DialogBoxParam(ghInst, "PassBox", hwnd, (DLGPROC)pass_proc,(LPARAM)userdata);
  
  #if 0
      /* Restore window station and desktop */
diff -rc stunnel-4.11/src/options.c stunnel-4.11.mult_certs/src/options.c
*** stunnel-4.11/src/options.c	2005-06-25 16:11:26.000000000 -0400
--- stunnel-4.11.mult_certs/src/options.c	2005-08-29 16:43:02.000000000 -0400
***************
*** 55,61 ****
  } CMD;
  
  static char *option_not_found=
!     "Specified option name is not valid here";
  
  static char *global_options(CMD cmd, char *opt, char *arg) {
  
--- 55,62 ----
  } CMD;
  
  static char *option_not_found=
! 	"Specified option name is not valid here";
! 
  
  static char *global_options(CMD cmd, char *opt, char *arg) {
  
***************
*** 63,147 ****
          log_raw("Global options");
      }
  
-     /* CApath */
-     switch(cmd) {
-     case CMD_INIT:
- #if 0
-         options.ca_dir=(char *)X509_get_default_cert_dir();
- #endif
-         options.ca_dir=NULL;
-         break;
-     case CMD_EXEC:
-         if(strcasecmp(opt, "CApath"))
-             break;
-         if(arg[0]) /* not empty */
-             options.ca_dir=stralloc(arg);
-         else
-             options.ca_dir=NULL;
-         return NULL; /* OK */
-     case CMD_DEFAULT:
- #if 0
-         log_raw("%-15s = %s", "CApath",
-             options.ca_dir ? options.ca_dir : "(none)");
- #endif
-         break;
-     case CMD_HELP:
-         log_raw("%-15s = CA certificate directory for 'verify' option",
-             "CApath");
-         break;
-     }
- 
-     /* CAfile */
-     switch(cmd) {
-     case CMD_INIT:
- #if 0
-         options.ca_file=(char *)X509_get_default_certfile();
- #endif
-         options.ca_file=NULL;
-         break;
-     case CMD_EXEC:
-         if(strcasecmp(opt, "CAfile"))
-             break;
-         if(arg[0]) /* not empty */
-             options.ca_file=stralloc(arg);
-         else
-             options.ca_file=NULL;
-         return NULL; /* OK */
-     case CMD_DEFAULT:
- #if 0
-         log_raw("%-15s = %s", "CAfile",
-             options.ca_file ? options.ca_file : "(none)");
- #endif
-         break;
-     case CMD_HELP:
-         log_raw("%-15s = CA certificate file for 'verify' option",
-             "CAfile");
-         break;
-     }
- 
-     /* cert */
-     switch(cmd) {
-     case CMD_INIT:
- #ifdef CONFDIR
-         options.cert=CONFDIR "/stunnel.pem";
- #else
-         options.cert="stunnel.pem";
- #endif
-         break;
-     case CMD_EXEC:
-         if(strcasecmp(opt, "cert"))
-             break;
-         options.cert=stralloc(arg);
-         options.option.cert=1;
-         return NULL; /* OK */
-     case CMD_DEFAULT:
-         log_raw("%-15s = %s", "cert", options.cert);
-         break;
-     case CMD_HELP:
-         log_raw("%-15s = certificate chain", "cert");
-         break;
-     }
- 
      /* chroot */
  #ifdef HAVE_CHROOT
      switch(cmd) {
--- 64,69 ----
***************
*** 161,207 ****
      }
  #endif /* HAVE_CHROOT */
  
-     /* ciphers */
-     switch(cmd) {
-     case CMD_INIT:
-         options.cipher_list=SSL_DEFAULT_CIPHER_LIST;
-         break;
-     case CMD_EXEC:
-         if(strcasecmp(opt, "ciphers"))
-             break;
-         options.cipher_list=stralloc(arg);
-         return NULL; /* OK */
-     case CMD_DEFAULT:
-         log_raw("%-15s = %s", "ciphers", SSL_DEFAULT_CIPHER_LIST);
-         break;
-     case CMD_HELP:
-         log_raw("%-15s = list of permitted SSL ciphers", "ciphers");
-         break;
-     }
- 
-     /* client */
-     switch(cmd) {
-     case CMD_INIT:
-         options.option.client=0;
-         break;
-     case CMD_EXEC:
-         if(strcasecmp(opt, "client"))
-             break;
-         if(!strcasecmp(arg, "yes"))
-             options.option.client=1;
-         else if(!strcasecmp(arg, "no"))
-             options.option.client=0;
-         else
-             return "argument should be either 'yes' or 'no'";
-         return NULL; /* OK */
-     case CMD_DEFAULT:
-         break;
-     case CMD_HELP:
-         log_raw("%-15s = yes|no client mode (remote service uses SSL)",
-             "client");
-         break;
-     }
- 
      /* compression */
      switch(cmd) {
      case CMD_INIT:
--- 83,88 ----
***************
*** 225,270 ****
          break;
      }
  
-     /* CRLpath */
-     switch(cmd) {
-     case CMD_INIT:
-         options.crl_dir=NULL;
-         break;
-     case CMD_EXEC:
-         if(strcasecmp(opt, "CRLpath"))
-             break;
-         if(arg[0]) /* not empty */
-             options.crl_dir=stralloc(arg);
-         else
-             options.crl_dir=NULL;
-         return NULL; /* OK */
-     case CMD_DEFAULT:
-         break;
-     case CMD_HELP:
-         log_raw("%-15s = CRL directory", "CRLpath");
-         break;
-     }
- 
-     /* CRLfile */
-     switch(cmd) {
-     case CMD_INIT:
-         options.crl_file=NULL;
-         break;
-     case CMD_EXEC:
-         if(strcasecmp(opt, "CRLfile"))
-             break;
-         if(arg[0]) /* not empty */
-             options.crl_file=stralloc(arg);
-         else
-             options.crl_file=NULL;
-         return NULL; /* OK */
-     case CMD_DEFAULT:
-         break;
-     case CMD_HELP:
-         log_raw("%-15s = CRL file", "CRLfile");
-         break;
-     }
- 
      /* debug */
      switch(cmd) {
      case CMD_INIT:
--- 106,111 ----
***************
*** 355,397 ****
      }
  #endif
  
-     /* key */
-     switch(cmd) {
-     case CMD_INIT:
-         options.key=NULL;
-         break;
-     case CMD_EXEC:
-         if(strcasecmp(opt, "key"))
-             break;
-         options.key=stralloc(arg);
-         return NULL; /* OK */
-     case CMD_DEFAULT:
-         log_raw("%-15s = %s", "key", options.cert); /* set in stunnel.c */
-         break;
-     case CMD_HELP:
-         log_raw("%-15s = certificate private key", "key");
-         break;
-     }
- 
-     /* options */
-     switch(cmd) {
-     case CMD_INIT:
-         options.ssl_options=0;
-         break;
-     case CMD_EXEC:
-         if(strcasecmp(opt, "options"))
-             break;
-         if(!parse_ssl_option(arg))
-             return "Illegal SSL option";
-         return NULL; /* OK */
-     case CMD_DEFAULT:
-         break;
-     case CMD_HELP:
-         log_raw("%-15s = SSL option", "options");
-         log_raw("%18sset an SSL option", "");
-         break;
-     }
- 
      /* output */
      switch(cmd) {
      case CMD_INIT:
--- 196,201 ----
***************
*** 631,653 ****
      }
  #endif
  
      /* verify */
      switch(cmd) {
      case CMD_INIT:
!         options.verify_level=-1;
!         options.verify_use_only_my=0;
          break;
      case CMD_EXEC:
          if(strcasecmp(opt, "verify"))
              break;
!         options.verify_level=SSL_VERIFY_NONE;
          switch(atoi(arg)) {
          case 3:
!             options.verify_use_only_my=1;
          case 2:
!             options.verify_level|=SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
          case 1:
!             options.verify_level|=SSL_VERIFY_PEER;
          case 0:
              return NULL; /* OK */
          default:
--- 435,644 ----
      }
  #endif
  
+     if(cmd==CMD_EXEC)
+         return option_not_found;
+     return NULL; /* OK */
+ }
+ 
+ static char *service_options(CMD cmd, LOCAL_OPTIONS *section,
+         char *opt, char *arg) {
+ 
+     if(cmd==CMD_DEFAULT || cmd==CMD_HELP) {
+         log_raw(" ");
+         log_raw("Service-level options");
+     }
+ 
+     /* CApath */
+     switch(cmd) {
+     case CMD_INIT:
+ #if 0
+         options.ssl_ctx_data.ca_dir=(char *)X509_get_default_cert_dir();
+ #endif
+         section->ssl_ctx_data.ca_dir=NULL;
+         break;
+     case CMD_EXEC:
+         if(strcasecmp(opt, "CApath"))
+             break;
+         if(arg[0]) /* not empty */
+             section->ssl_ctx_data.ca_dir=stralloc(arg);
+         else
+             section->ssl_ctx_data.ca_dir=NULL;
+         return NULL; /* OK */
+     case CMD_DEFAULT:
+ #if 0
+         log_raw("%-15s = %s", "CApath",
+             section->ssl_ctx_data.ca_dir ? section->ssl_ctx_data.ca_dir : "(none)");
+ #endif
+         break;
+     case CMD_HELP:
+         log_raw("%-15s = CA certificate directory for 'verify' option",
+             "CApath");
+         break;
+     }
+ 
+     /* CAfile */
+     switch(cmd) {
+     case CMD_INIT:
+ #if 0
+         section->ssl_ctx_data.ca_file=(char *)X509_get_default_certfile();
+ #endif
+         section->ssl_ctx_data.ca_file=NULL;
+         break;
+     case CMD_EXEC:
+         if(strcasecmp(opt, "CAfile"))
+             break;
+         if(arg[0]) /* not empty */
+             section->ssl_ctx_data.ca_file=stralloc(arg);
+         else
+             section->ssl_ctx_data.ca_file=NULL;
+         return NULL; /* OK */
+     case CMD_DEFAULT:
+ #if 0
+         log_raw("%-15s = %s", "CAfile",
+             section->ssl_ctx_data.ca_file ? section->ssl_ctx_data.ca_file : "(none)");
+ #endif
+         break;
+     case CMD_HELP:
+         log_raw("%-15s = CA certificate file for 'verify' option",
+             "CAfile");
+         break;
+     }
+ 
+     /* cert */
+     switch(cmd) {
+     case CMD_INIT:
+ #ifdef CONFDIR
+         section->ssl_ctx_data.cert=CONFDIR "/stunnel.pem";
+ #else
+         section->ssl_ctx_data.cert="stunnel.pem";
+ #endif
+         break;
+     case CMD_EXEC:
+         if(strcasecmp(opt, "cert"))
+             break;
+         section->ssl_ctx_data.cert=stralloc(arg);
+         section->ssl_ctx_data.option.have_cert=1;
+         return NULL; /* OK */
+     case CMD_DEFAULT:
+         log_raw("%-15s = %s", "cert", section->ssl_ctx_data.cert);
+         break;
+     case CMD_HELP:
+         log_raw("%-15s = certificate chain", "cert");
+         break;
+     }
+ 
+     /* ciphers */
+     switch(cmd) {
+     case CMD_INIT:
+         section->ssl_ctx_data.cipher_list=SSL_DEFAULT_CIPHER_LIST;
+         break;
+     case CMD_EXEC:
+         if(strcasecmp(opt, "ciphers"))
+             break;
+         section->ssl_ctx_data.cipher_list=stralloc(arg);
+         return NULL; /* OK */
+     case CMD_DEFAULT:
+         log_raw("%-15s = %s", "ciphers", SSL_DEFAULT_CIPHER_LIST);
+         break;
+     case CMD_HELP:
+         log_raw("%-15s = list of permitted SSL ciphers", "ciphers");
+         break;
+     }
+ 
+     /* CRLpath */
+     switch(cmd) {
+     case CMD_INIT:
+         section->ssl_ctx_data.crl_dir=NULL;
+         break;
+     case CMD_EXEC:
+         if(strcasecmp(opt, "CRLpath"))
+             break;
+         if(arg[0]) /* not empty */
+             section->ssl_ctx_data.crl_dir=stralloc(arg);
+         else
+             section->ssl_ctx_data.crl_dir=NULL;
+         return NULL; /* OK */
+     case CMD_DEFAULT:
+         break;
+     case CMD_HELP:
+         log_raw("%-15s = CRL directory", "CRLpath");
+         break;
+     }
+ 
+     /* CRLfile */
+     switch(cmd) {
+     case CMD_INIT:
+         section->ssl_ctx_data.crl_file=NULL;
+         break;
+     case CMD_EXEC:
+         if(strcasecmp(opt, "CRLfile"))
+             break;
+         if(arg[0]) /* not empty */
+             section->ssl_ctx_data.crl_file=stralloc(arg);
+         else
+             section->ssl_ctx_data.crl_file=NULL;
+         return NULL; /* OK */
+     case CMD_DEFAULT:
+         break;
+     case CMD_HELP:
+         log_raw("%-15s = CRL file", "CRLfile");
+         break;
+     }
+ 
+     /* key */
+     switch(cmd) {
+     case CMD_INIT:
+         section->ssl_ctx_data.key=NULL;
+         break;
+     case CMD_EXEC:
+         if(strcasecmp(opt, "key"))
+             break;
+         section->ssl_ctx_data.key=stralloc(arg);
+         return NULL; /* OK */
+     case CMD_DEFAULT:
+         log_raw("%-15s = %s", "key", section->ssl_ctx_data.cert); /* set in stunnel.c */
+         break;
+     case CMD_HELP:
+         log_raw("%-15s = certificate private key", "key");
+         break;
+     }
+ 
+     /* options */
+     switch(cmd) {
+     case CMD_INIT:
+         section->ssl_ctx_data.ssl_options=0;
+         break;
+     case CMD_EXEC:
+         if(strcasecmp(opt, "options"))
+             break;
+         if(!parse_ssl_option(arg))
+             return "Illegal SSL option";
+         return NULL; /* OK */
+     case CMD_DEFAULT:
+         break;
+     case CMD_HELP:
+         log_raw("%-15s = SSL option", "options");
+         log_raw("%18sset an SSL option", "");
+         break;
+     }
+ 
      /* verify */
      switch(cmd) {
      case CMD_INIT:
!         section->ssl_ctx_data.verify_level=-1;
!         section->ssl_ctx_data.verify_use_only_my=0;
          break;
      case CMD_EXEC:
          if(strcasecmp(opt, "verify"))
              break;
!         section->ssl_ctx_data.verify_level=SSL_VERIFY_NONE;
          switch(atoi(arg)) {
          case 3:
!             section->ssl_ctx_data.verify_use_only_my=1;
          case 2:
!             section->ssl_ctx_data.verify_level|=SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
          case 1:
!             section->ssl_ctx_data.verify_level|=SSL_VERIFY_PEER;
          case 0:
              return NULL; /* OK */
          default:
***************
*** 665,681 ****
          break;
      }
  
!     if(cmd==CMD_EXEC)
!         return option_not_found;
!     return NULL; /* OK */
! }
! 
! static char *service_options(CMD cmd, LOCAL_OPTIONS *section,
!         char *opt, char *arg) {
! 
!     if(cmd==CMD_DEFAULT || cmd==CMD_HELP) {
!         log_raw(" ");
!         log_raw("Service-level options");
      }
  
      /* accept */
--- 656,682 ----
          break;
      }
  
!     /* client */
!     switch(cmd) {
!     case CMD_INIT:
!         section->ssl_ctx_data.option.client=0;
!         break;
!     case CMD_EXEC:
!         if(strcasecmp(opt, "client"))
!             break;
!         if(!strcasecmp(arg, "yes"))
!             section->ssl_ctx_data.option.client=1;
!         else if(!strcasecmp(arg, "no"))
!             section->ssl_ctx_data.option.client=0;
!         else
!             return "argument should be either 'yes' or 'no'";
!         return NULL; /* OK */
!     case CMD_DEFAULT:
!         break;
!     case CMD_HELP:
!         log_raw("%-15s = yes|no client mode (remote service uses SSL)",
!             "client");
!         break;
      }
  
      /* accept */
***************
*** 1099,1104 ****
--- 1100,1108 ----
                  log_raw("file %s line %d: %s", filename, line_number, errstr);
                  exit(1);
              }
+     		if(section->ssl_ctx_data.option.client)
+         		section->ssl_ctx_data.option.have_cert=1; 	 /*	Server always needs
+ 																	a certificate */
              opt++;
              opt[strlen(opt)-1]='\0';
              new_section=calloc(1, sizeof(LOCAL_OPTIONS));
***************
*** 1112,1117 ****
--- 1116,1122 ----
              new_section->next=NULL;
              section->next=new_section;
              section=new_section;
+ 
              continue;
          }
          arg=strchr(confline, '=');
***************
*** 1149,1163 ****
              exit(1);
          }
      }
-     if(!options.option.client)
-         options.option.cert=1; /* Server always needs a certificate */
      if(!options.option.foreground)
          options.option.syslog=1;
  }
  
  static char *section_validate(LOCAL_OPTIONS *section) {
      if(section==&local_options)
!         return NULL; /* No need to validate defaults */
  #ifdef USE_WIN32
      if(!section->option.accept || !section->option.remote)
  #else
--- 1154,1168 ----
              exit(1);
          }
      }
      if(!options.option.foreground)
          options.option.syslog=1;
  }
  
  static char *section_validate(LOCAL_OPTIONS *section) {
      if(section==&local_options)
! 	{
!         return NULL; /* No need to validate other defaults */
! 	}
  #ifdef USE_WIN32
      if(!section->option.accept || !section->option.remote)
  #else
***************
*** 1166,1171 ****
--- 1171,1177 ----
              (unsigned int)section->option.remote != 2)
  #endif
          return "Each service section must define exactly two endpoints";
+ 
      return NULL; /* All tests passed -- continue program execution */
  }
  
***************
*** 1328,1334 ****
  
      for(option=ssl_opts; option->name; option++)
          if(!strcasecmp(option->name, arg)) {
!             options.ssl_options|=option->value;
              return 1; /* OK */
          }
      return 0; /* FAILED */
--- 1334,1340 ----
  
      for(option=ssl_opts; option->name; option++)
          if(!strcasecmp(option->name, arg)) {
!             local_options.ssl_ctx_data.ssl_options|=option->value;
              return 1; /* OK */
          }
      return 0; /* FAILED */
diff -rc stunnel-4.11/src/protocol.c stunnel-4.11.mult_certs/src/protocol.c
*** stunnel-4.11/src/protocol.c	2005-04-11 09:45:56.000000000 -0400
--- stunnel-4.11.mult_certs/src/protocol.c	2005-08-29 16:43:10.000000000 -0400
***************
*** 48,66 ****
      if(!c->opt->protocol)
          return 0; /* No protocol negotiations */
      s_log(LOG_NOTICE, "Negotiations for %s (%s side) started", c->opt->protocol,
!         options.option.client ? "client" : "server");
  
      if(!strcmp(c->opt->protocol, "cifs"))
!         retval = options.option.client ? cifs_client(c) : cifs_server(c);
      else if(!strcmp(c->opt->protocol, "smtp"))
!         retval = options.option.client ? smtp_client(c) : smtp_server(c);
      else if(!strcmp(c->opt->protocol, "pop3"))
!         retval = options.option.client ? pop3_client(c) : pop3_server(c);
      else if(!strcmp(c->opt->protocol, "nntp"))
!         retval = options.option.client ? nntp_client(c) : nntp_server(c);
      else {
          s_log(LOG_ERR, "Protocol %s not supported in %s mode",
!             c->opt->protocol, options.option.client ? "client" : "server");
          return -1;
      }
  
--- 48,66 ----
      if(!c->opt->protocol)
          return 0; /* No protocol negotiations */
      s_log(LOG_NOTICE, "Negotiations for %s (%s side) started", c->opt->protocol,
!         c->opt->ssl_ctx_data.option.client ? "client" : "server");
  
      if(!strcmp(c->opt->protocol, "cifs"))
!         retval = c->opt->ssl_ctx_data.option.client ? cifs_client(c) : cifs_server(c);
      else if(!strcmp(c->opt->protocol, "smtp"))
!         retval = c->opt->ssl_ctx_data.option.client ? smtp_client(c) : smtp_server(c);
      else if(!strcmp(c->opt->protocol, "pop3"))
!         retval = c->opt->ssl_ctx_data.option.client ? pop3_client(c) : pop3_server(c);
      else if(!strcmp(c->opt->protocol, "nntp"))
!         retval = c->opt->ssl_ctx_data.option.client ? nntp_client(c) : nntp_server(c);
      else {
          s_log(LOG_ERR, "Protocol %s not supported in %s mode",
!             c->opt->protocol, c->opt->ssl_ctx_data.option.client ? "client" : "server");
          return -1;
      }
  
diff -rc stunnel-4.11/src/prototypes.h stunnel-4.11.mult_certs/src/prototypes.h
*** stunnel-4.11/src/prototypes.h	2005-07-02 03:03:23.000000000 -0400
--- stunnel-4.11.mult_certs/src/prototypes.h	2005-08-29 16:43:34.000000000 -0400
***************
*** 56,63 ****
  } COMP_TYPE;
  
  void ssl_init(void);
- void context_init(void);
- void context_free(void);
  void sslerror(char *);
  
  /**************************************** Prototypes for log.c */
--- 56,61 ----
***************
*** 93,118 ****
  /**************************************** Prototypes for options.c */
  
  typedef struct {
!         /* some data for SSL initialization in ssl.c */
!     COMP_TYPE compression;                               /* compression type */
! 
! #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && defined(HAVE_OSSL_ENGINE_H)
!     char *engine;                                     /* hardware SSL engine */
! #endif
      char *ca_dir;                              /* directory for hashed certs */
      char *ca_file;                       /* file containing bunches of certs */
      char *crl_dir;                              /* directory for hashed CRLs */
      char *crl_file;                       /* file containing bunches of CRLs */
      char *cipher_list;
      char *cert;                                             /* cert filename */
-     char *egd_sock;                       /* entropy gathering daemon socket */
      char *key;                               /* pem (priv key/cert) filename */
-     char *rand_file;                                /* file with random data */
-     int random_bytes;                       /* how many random bytes to read */
-     long session_timeout;
      int verify_level;
      int verify_use_only_my;
      long ssl_options;
  
          /* some global data for stunnel.c */
  #ifndef USE_WIN32
--- 91,128 ----
  /**************************************** Prototypes for options.c */
  
  typedef struct {
! 	SSL_CTX *ctx;
      char *ca_dir;                              /* directory for hashed certs */
      char *ca_file;                       /* file containing bunches of certs */
      char *crl_dir;                              /* directory for hashed CRLs */
      char *crl_file;                       /* file containing bunches of CRLs */
      char *cipher_list;
+     struct
+ 	{
+         unsigned int client:1;
+ 		unsigned int have_cert:1;
+     } option;
      char *cert;                                             /* cert filename */
      char *key;                               /* pem (priv key/cert) filename */
      int verify_level;
      int verify_use_only_my;
      long ssl_options;
+ } SSL_CTX_DATA;
+ 
+ void context_init(SSL_CTX_DATA *);
+ void context_free(SSL_CTX_DATA *);
+ 
+ typedef struct {
+         /* some data for SSL initialization in ssl.c */
+     COMP_TYPE compression;                               /* compression type */
+ 
+ #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && defined(HAVE_OSSL_ENGINE_H)
+     char *engine;                                     /* hardware SSL engine */
+ #endif
+     char *egd_sock;                       /* entropy gathering daemon socket */
+     char *rand_file;                                /* file with random data */
+     int random_bytes;                       /* how many random bytes to read */
+     long session_timeout;
  
          /* some global data for stunnel.c */
  #ifndef USE_WIN32
***************
*** 140,147 ****
  
          /* on/off switches */
      struct {
-         unsigned int cert:1;
-         unsigned int client:1;
          unsigned int foreground:1;
          unsigned int syslog:1;                              /* log to syslog */
          unsigned int rand_write:1;                    /* overwrite rand_file */
--- 150,155 ----
***************
*** 174,179 ****
--- 182,190 ----
          /* protocol name for protocol.c */
      char *protocol;
  
+ 		/* SSL context data */
+ 	SSL_CTX_DATA ssl_ctx_data;
+ 
          /* on/off switches */
      struct {
          unsigned int delayed_lookup:1;
diff -rc stunnel-4.11/src/ssl.c stunnel-4.11.mult_certs/src/ssl.c
*** stunnel-4.11/src/ssl.c	2005-06-25 11:47:39.000000000 -0400
--- stunnel-4.11.mult_certs/src/ssl.c	2005-08-29 16:43:18.000000000 -0400
***************
*** 55,77 ****
  static int add_rand_file(char *);
  
      /* SSL context initalization */
! static int init_dh(void);
  #ifndef NO_RSA
  static RSA *tmp_rsa_cb(SSL *, int, int);
  static RSA *make_temp_key(int);
  #endif /* NO_RSA */
! static void verify_init(void);
! static int verify_callback(int, X509_STORE_CTX *);
  static int crl_callback(X509_STORE_CTX *);
  #if SSLEAY_VERSION_NUMBER >= 0x00907000L
  static void info_callback(const SSL *, int, int);
  #else
  static void info_callback(SSL *, int, int);
  #endif
! static void print_stats(void);
  static void sslerror_stack(void);
  
! SSL_CTX *ctx; /* global SSL context */
  static X509_STORE *revocation_store=NULL;
  
  void ssl_init(void) { /* init SSL */
--- 55,88 ----
  static int add_rand_file(char *);
  
      /* SSL context initalization */
! static int init_dh(SSL_CTX_DATA *);
  #ifndef NO_RSA
  static RSA *tmp_rsa_cb(SSL *, int, int);
  static RSA *make_temp_key(int);
  #endif /* NO_RSA */
! static void verify_init(SSL_CTX_DATA *);
! static int verify_callback(int, X509_STORE_CTX *,int,int);
  static int crl_callback(X509_STORE_CTX *);
  #if SSLEAY_VERSION_NUMBER >= 0x00907000L
  static void info_callback(const SSL *, int, int);
  #else
  static void info_callback(SSL *, int, int);
  #endif
! static void print_stats(SSL_CTX *);
  static void sslerror_stack(void);
  
! 	/* Covenience routines */
! static int(*get_verify_callback(int,int))(int, X509_STORE_CTX *);
! 
! static int verify_callback_l0_my(int, X509_STORE_CTX *);
! static int verify_callback_l1_my(int, X509_STORE_CTX *);
! static int verify_callback_l2_my(int, X509_STORE_CTX *);
! static int verify_callback_l3_my(int, X509_STORE_CTX *);
! static int verify_callback_l0_not_my(int, X509_STORE_CTX *);
! static int verify_callback_l1_not_my(int, X509_STORE_CTX *);
! static int verify_callback_l2_not_my(int, X509_STORE_CTX *);
! static int verify_callback_l3_not_my(int, X509_STORE_CTX *);
! 
  static X509_STORE *revocation_store=NULL;
  
  void ssl_init(void) { /* init SSL */
***************
*** 266,315 ****
      return readbytes;
  }
  
! void context_init(void) { /* init global SSL context */
      int i;
  
      /* create SSL context */
!     if(options.option.client) {
!         ctx=SSL_CTX_new(SSLv3_client_method());
      } else { /* Server mode */
!         ctx=SSL_CTX_new(SSLv23_server_method());
  #ifndef NO_RSA
!         SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb);
  #endif /* NO_RSA */
!         if(init_dh())
              s_log(LOG_WARNING, "Diffie-Hellman initialization failed");
      }
!     if(options.ssl_options) {
          s_log(LOG_DEBUG, "Configuration SSL options: 0x%08lX",
!             options.ssl_options);
          s_log(LOG_DEBUG, "SSL options set: 0x%08lX", 
!             SSL_CTX_set_options(ctx, options.ssl_options));
      }
  #if SSLEAY_VERSION_NUMBER >= 0x00906000L
!     SSL_CTX_set_mode(ctx,
          SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
  #endif /* OpenSSL-0.9.6 */
  
!     SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
!     SSL_CTX_set_timeout(ctx, options.session_timeout);
!     if(options.option.cert) {
!         if(!SSL_CTX_use_certificate_chain_file(ctx, options.cert)) {
!             s_log(LOG_ERR, "Error reading certificate file: %s", options.cert);
              sslerror("SSL_CTX_use_certificate_chain_file");
              exit(1);
          }
!         s_log(LOG_DEBUG, "Certificate: %s", options.cert);
!         s_log(LOG_DEBUG, "Key file: %s", options.key);
  #ifdef USE_WIN32
!         SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
  #endif
          for(i=0; i<3; i++) {
  #ifdef NO_RSA
!             if(SSL_CTX_use_PrivateKey_file(ctx, options.key,
                      SSL_FILETYPE_PEM))
  #else /* NO_RSA */
!             if(SSL_CTX_use_RSAPrivateKey_file(ctx, options.key,
                      SSL_FILETYPE_PEM))
  #endif /* NO_RSA */
                  break;
--- 277,389 ----
      return readbytes;
  }
  
! void context_init(SSL_CTX_DATA *ctx_data) { /* init SSL context */
!     struct stat st; /* buffer for stat */
      int i;
+ #ifndef USE_WIN32
+ 	size_t prompt_len;
+ 	static char *pw_prompt_format = "\nKey -> %.*s\nEnter pass phrase: ";
+ 
+ 	/*
+ 		openssl only allows 79 characters for the password prompt
+ 	*/
+ 	size_t tailed_key_max_width = 79-(strlen(pw_prompt_format)-4);
+ 
+ 	char *pw_prompt;
+ 
+ #endif /* defined USE_WIN32 */
+ 
+ 	char *last_slash, *tailed_key;
+ 
+ 	if ( ! (ctx_data->key) ) /* key file not specified */
+ 	{
+ 		ctx_data->key = ctx_data->cert;
+ 	}
+ 
+ 	if(ctx_data->option.have_cert)
+ 	{
+ 		if(stat(ctx_data->key, &st))
+ 		{
+        		ioerror(ctx_data->key);
+ 			exit(1);
+ 		}
+ 			
+ #ifndef USE_WIN32
+         if(st.st_mode & 7)
+ 		{
+ 			s_log(LOG_WARNING, "Wrong permissions on %s",
+ 				ctx_data->key);
+ 		}
+ #endif /* defined USE_WIN32 */
+ 	}
+ 
+ 	/*
+ 		tailed_key: derived condensed key name for password prompt
+ 	*/
+ 	last_slash = strrchr(ctx_data->key,'/');
+ #ifdef WIN32
+ 	last_slash = strrchr(ctx_data->key,'\\');
+ #endif
+ 	tailed_key = (last_slash==NULL)?ctx_data->key:last_slash+1;
  
      /* create SSL context */
! 
! 
!     if(ctx_data->option.client) {
!         ctx_data->ctx=SSL_CTX_new(SSLv3_client_method());
      } else { /* Server mode */
!         ctx_data->ctx=SSL_CTX_new(SSLv23_server_method());
  #ifndef NO_RSA
!         SSL_CTX_set_tmp_rsa_callback(ctx_data->ctx, tmp_rsa_cb);
  #endif /* NO_RSA */
!         if(init_dh(ctx_data))
              s_log(LOG_WARNING, "Diffie-Hellman initialization failed");
      }
!     if(ctx_data->ssl_options) {
          s_log(LOG_DEBUG, "Configuration SSL options: 0x%08lX",
!             ctx_data->ssl_options);
          s_log(LOG_DEBUG, "SSL options set: 0x%08lX", 
!             SSL_CTX_set_options(ctx_data->ctx, ctx_data->ssl_options));
      }
  #if SSLEAY_VERSION_NUMBER >= 0x00906000L
!     SSL_CTX_set_mode(ctx_data->ctx,
          SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
  #endif /* OpenSSL-0.9.6 */
  
!     SSL_CTX_set_session_cache_mode(ctx_data->ctx, SSL_SESS_CACHE_BOTH);
!     SSL_CTX_set_timeout(ctx_data->ctx, options.session_timeout);
!     if(ctx_data->option.have_cert) {
!         if(!SSL_CTX_use_certificate_chain_file(ctx_data->ctx, ctx_data->cert)) {
!             s_log(LOG_ERR, "Error reading certificate file: %s", ctx_data->cert);
              sslerror("SSL_CTX_use_certificate_chain_file");
              exit(1);
          }
!         s_log(LOG_DEBUG, "Certificate: %s", ctx_data->cert);
!         s_log(LOG_DEBUG, "Key file: %s", ctx_data->key);
  #ifdef USE_WIN32
!         SSL_CTX_set_default_passwd_cb(ctx_data->ctx, pem_passwd_cb);
!         SSL_CTX_set_default_passwd_cb_userdata(ctx_data->ctx, tailed_key);
! #else
! 		prompt_len = snprintf(NULL,0,pw_prompt_format,
! 						tailed_key_max_width,tailed_key);
! 
! 		if ( ( pw_prompt = (char *)malloc(prompt_len+1) ) == NULL )
! 		{
! 			log_raw("Fatal memory allocation error");
! 			exit(2);
! 		}
! 
! 		snprintf(pw_prompt,prompt_len+1,pw_prompt_format,
! 			tailed_key_max_width,tailed_key);
! 
! 		EVP_set_pw_prompt(pw_prompt);
  #endif
          for(i=0; i<3; i++) {
  #ifdef NO_RSA
!             if(SSL_CTX_use_PrivateKey_file(ctx_data->ctx, ctx_data->key,
                      SSL_FILETYPE_PEM))
  #else /* NO_RSA */
!             if(SSL_CTX_use_RSAPrivateKey_file(ctx_data->ctx, ctx_data->key,
                      SSL_FILETYPE_PEM))
  #endif /* NO_RSA */
                  break;
***************
*** 325,365 ****
  #endif /* NO_RSA */
              exit(1);
          }
!         if(!SSL_CTX_check_private_key(ctx)) {
              sslerror("Private key does not match the certificate");
              exit(1);
          }
      }
  
!     verify_init(); /* Initialize certificate verification */
  
!     SSL_CTX_set_info_callback(ctx, info_callback);
  
!     if(options.cipher_list) {
!         if (!SSL_CTX_set_cipher_list(ctx, options.cipher_list)) {
              sslerror("SSL_CTX_set_cipher_list");
              exit(1);
          }
      }
  }
  
! void context_free(void) { /* free SSL */
!     SSL_CTX_free(ctx);
  }
  
! static int init_dh(void) {
  #ifdef USE_DH
      FILE *fp;
      DH *dh;
      BIO *bio;
  
!     fp=fopen(options.cert, "r");
      if(!fp) {
  #ifdef USE_WIN32
          /* fopen() does not return the error via GetLastError() on Win32 */
!         s_log(LOG_ERR, "Failed to open %s", options.cert);
  #else
!         ioerror(options.cert);
  #endif
          return -1; /* FAILED */
      }
--- 399,444 ----
  #endif /* NO_RSA */
              exit(1);
          }
! 
! #ifndef USE_WIN32
! 		free(pw_prompt);
! #endif
! 
!         if(!SSL_CTX_check_private_key(ctx_data->ctx)) {
              sslerror("Private key does not match the certificate");
              exit(1);
          }
      }
  
!     verify_init(ctx_data); /* Initialize certificate verification */
  
!     SSL_CTX_set_info_callback(ctx_data->ctx, info_callback);
  
!     if(ctx_data->cipher_list) {
!         if (!SSL_CTX_set_cipher_list(ctx_data->ctx, ctx_data->cipher_list)) {
              sslerror("SSL_CTX_set_cipher_list");
              exit(1);
          }
      }
  }
  
! void context_free(SSL_CTX_DATA *ctx_data) { /* free SSL */
!     SSL_CTX_free(ctx_data->ctx);
  }
  
! static int init_dh(SSL_CTX_DATA *ctx_data) {
  #ifdef USE_DH
      FILE *fp;
      DH *dh;
      BIO *bio;
  
!     fp=fopen(ctx_data->cert, "r");
      if(!fp) {
  #ifdef USE_WIN32
          /* fopen() does not return the error via GetLastError() on Win32 */
!         s_log(LOG_ERR, "Failed to open %s", ctx_data->cert);
  #else
!         ioerror(ctx_data->cert);
  #endif
          return -1; /* FAILED */
      }
***************
*** 375,384 ****
              ))) {
          BIO_free(bio);
          s_log(LOG_DEBUG, "Using Diffie-Hellman parameters from %s",
!             options.cert);
      } else { /* Failed to load DH parameters from file */
          BIO_free(bio);
!         s_log(LOG_NOTICE, "Could not load DH parameters from %s", options.cert);
          return -1; /* FAILED */
      }
      SSL_CTX_set_tmp_dh(ctx, dh);
--- 454,463 ----
              ))) {
          BIO_free(bio);
          s_log(LOG_DEBUG, "Using Diffie-Hellman parameters from %s",
!             ctx_data->cert);
      } else { /* Failed to load DH parameters from file */
          BIO_free(bio);
!         s_log(LOG_NOTICE, "Could not load DH parameters from %s", ctx_data->cert);
          return -1; /* FAILED */
      }
      SSL_CTX_set_tmp_dh(ctx, dh);
***************
*** 452,542 ****
  
  #endif /* NO_RSA */
  
! static void verify_init(void) {
      X509_LOOKUP *lookup;
  
!     if(options.verify_level<0)
          return; /* No certificate verification */
  
!     if(options.verify_level>1 && !options.ca_file && !options.ca_dir) {
          s_log(LOG_ERR, "Either CApath or CAfile "
              "has to be used for authentication");
          exit(1);
      }
  
!     if(options.ca_file) {
!         if(!SSL_CTX_load_verify_locations(ctx, options.ca_file, NULL)) {
              s_log(LOG_ERR, "Error loading verify certificates from %s",
!                 options.ca_file);
              sslerror("SSL_CTX_load_verify_locations");
              exit(1);
          }
  #if 0
!         SSL_CTX_set_client_CA_list(ctx,
!             SSL_load_client_CA_file(options.ca_file));
  #endif
          s_log(LOG_DEBUG, "Loaded verify certificates from %s",
!             options.ca_file);
      }
  
!     if(options.ca_dir) {
!         if(!SSL_CTX_load_verify_locations(ctx, NULL, options.ca_dir)) {
              s_log(LOG_ERR, "Error setting verify directory to %s",
!                 options.ca_dir);
              sslerror("SSL_CTX_load_verify_locations");
              exit(1);
          }
!         s_log(LOG_DEBUG, "Verify directory set to %s", options.ca_dir);
      }
  
!     if(options.crl_file || options.crl_dir) { /* setup CRL store */
          revocation_store=X509_STORE_new();
          if(!revocation_store) {
              sslerror("X509_STORE_new");
              exit(1);
          }
!         if(options.crl_file) {
              lookup=X509_STORE_add_lookup(revocation_store,
                  X509_LOOKUP_file());
              if(!lookup) {
                  sslerror("X509_STORE_add_lookup");
                  exit(1);
              }
!             if(!X509_LOOKUP_load_file(lookup, options.crl_file,
                      X509_FILETYPE_PEM)) {
                  s_log(LOG_ERR, "Error loading CRLs from %s",
!                     options.crl_file);
                  sslerror("X509_LOOKUP_load_file");
                  exit(1);
              }
!             s_log(LOG_DEBUG, "Loaded CRLs from %s", options.crl_file);
          }
!         if(options.crl_dir) {
              lookup=X509_STORE_add_lookup(revocation_store,
                  X509_LOOKUP_hash_dir());
              if(!lookup) {
                  sslerror("X509_STORE_add_lookup");
                  exit(1);
              }
!             if(!X509_LOOKUP_add_dir(lookup, options.crl_dir,
                      X509_FILETYPE_PEM)) {
                  s_log(LOG_ERR, "Error setting CRL directory to %s",
!                     options.crl_dir);
                  sslerror("X509_LOOKUP_add_dir");
                  exit(1);
              }
!             s_log(LOG_DEBUG, "CRL directory set to %s", options.crl_dir);
          }
      }
  
!     SSL_CTX_set_verify(ctx, options.verify_level==SSL_VERIFY_NONE ?
!         SSL_VERIFY_PEER : options.verify_level, verify_callback);
! 
!     if(options.ca_dir && options.verify_use_only_my)
!         s_log(LOG_NOTICE, "Peer certificate location %s", options.ca_dir);
! }
! 
! static int verify_callback(int preverify_ok, X509_STORE_CTX *callback_ctx) {
          /* our verify callback function */
      char txt[STRLEN];
      X509_OBJECT ret;
--- 531,715 ----
  
  #endif /* NO_RSA */
  
! static void verify_init(SSL_CTX_DATA *ctx_data) {
      X509_LOOKUP *lookup;
  
!     if(ctx_data->verify_level<0)
          return; /* No certificate verification */
  
!     if(ctx_data->verify_level>1 && !ctx_data->ca_file && !ctx_data->ca_dir) {
          s_log(LOG_ERR, "Either CApath or CAfile "
              "has to be used for authentication");
          exit(1);
      }
  
!     if(ctx_data->ca_file) {
!         if(!SSL_CTX_load_verify_locations(ctx_data->ctx, ctx_data->ca_file, NULL)) {
              s_log(LOG_ERR, "Error loading verify certificates from %s",
!                 ctx_data->ca_file);
              sslerror("SSL_CTX_load_verify_locations");
              exit(1);
          }
  #if 0
!         SSL_CTX_set_client_CA_list(ctx_data->ctx,
!             SSL_load_client_CA_file(ctx_data->ca_file));
  #endif
          s_log(LOG_DEBUG, "Loaded verify certificates from %s",
!             ctx_data->ca_file);
      }
  
!     if(ctx_data->ca_dir) {
!         if(!SSL_CTX_load_verify_locations(ctx_data->ctx, NULL, ctx_data->ca_dir)) {
              s_log(LOG_ERR, "Error setting verify directory to %s",
!                 ctx_data->ca_dir);
              sslerror("SSL_CTX_load_verify_locations");
              exit(1);
          }
!         s_log(LOG_DEBUG, "Verify directory set to %s", ctx_data->ca_dir);
      }
  
!     if(ctx_data->crl_file || ctx_data->crl_dir) { /* setup CRL store */
          revocation_store=X509_STORE_new();
          if(!revocation_store) {
              sslerror("X509_STORE_new");
              exit(1);
          }
!         if(ctx_data->crl_file) {
              lookup=X509_STORE_add_lookup(revocation_store,
                  X509_LOOKUP_file());
              if(!lookup) {
                  sslerror("X509_STORE_add_lookup");
                  exit(1);
              }
!             if(!X509_LOOKUP_load_file(lookup, ctx_data->crl_file,
                      X509_FILETYPE_PEM)) {
                  s_log(LOG_ERR, "Error loading CRLs from %s",
!                     ctx_data->crl_file);
                  sslerror("X509_LOOKUP_load_file");
                  exit(1);
              }
!             s_log(LOG_DEBUG, "Loaded CRLs from %s", ctx_data->crl_file);
          }
!         if(ctx_data->crl_dir) {
              lookup=X509_STORE_add_lookup(revocation_store,
                  X509_LOOKUP_hash_dir());
              if(!lookup) {
                  sslerror("X509_STORE_add_lookup");
                  exit(1);
              }
!             if(!X509_LOOKUP_add_dir(lookup, ctx_data->crl_dir,
                      X509_FILETYPE_PEM)) {
                  s_log(LOG_ERR, "Error setting CRL directory to %s",
!                     ctx_data->crl_dir);
                  sslerror("X509_LOOKUP_add_dir");
                  exit(1);
              }
!             s_log(LOG_DEBUG, "CRL directory set to %s", ctx_data->crl_dir);
          }
      }
  
!     SSL_CTX_set_verify(ctx_data->ctx, ctx_data->verify_level==SSL_VERIFY_NONE ?
!         SSL_VERIFY_PEER : ctx_data->verify_level,
! 			get_verify_callback(ctx_data->verify_level,ctx_data->verify_use_only_my));
! 
!     if(ctx_data->ca_dir && ctx_data->verify_use_only_my)
!         s_log(LOG_NOTICE, "Peer certificate location %s", ctx_data->ca_dir);
! }
! 
! static int verify_callback_l0_my(int preverify_ok, X509_STORE_CTX *callback_ctx)
! {
! 	return verify_callback(preverify_ok,callback_ctx,SSL_VERIFY_NONE,1);
! }
! 
! static int verify_callback_l1_my(int preverify_ok, X509_STORE_CTX *callback_ctx)
! {
! 	return verify_callback(preverify_ok,callback_ctx,1,1);
! }
! 
! static int verify_callback_l2_my(int preverify_ok, X509_STORE_CTX *callback_ctx)
! {
! 	return verify_callback(preverify_ok,callback_ctx,2,1);
! }
! 
! static int verify_callback_l3_my(int preverify_ok, X509_STORE_CTX *callback_ctx)
! {
! 	return verify_callback(preverify_ok,callback_ctx,3,1);
! }
! 
! static int verify_callback_l0_not_my(int preverify_ok, X509_STORE_CTX *callback_ctx)
! {
! 	return verify_callback(preverify_ok,callback_ctx,SSL_VERIFY_NONE,0);
! }
! 
! static int verify_callback_l1_not_my(int preverify_ok, X509_STORE_CTX *callback_ctx)
! {
! 	return verify_callback(preverify_ok,callback_ctx,1,0);
! }
! 
! static int verify_callback_l2_not_my(int preverify_ok, X509_STORE_CTX *callback_ctx)
! {
! 	return verify_callback(preverify_ok,callback_ctx,2,0);
! }
! 
! static int verify_callback_l3_not_my(int preverify_ok, X509_STORE_CTX *callback_ctx)
! {
! 	return verify_callback(preverify_ok,callback_ctx,3,0);
! }
! 
! static int(*get_verify_callback(int verify_level,int verify_use_only_my))
! 														(int, X509_STORE_CTX *)
! {
! 	if ( verify_use_only_my ) 
! 	{
! 		if ( verify_level == SSL_VERIFY_NONE )
! 		{
! 			return verify_callback_l0_my;
! 		}
! 		else if ( verify_level == 1 )
! 		{
! 			return verify_callback_l1_my;
! 		}
! 		else if ( verify_level == 2 )
! 		{
! 			return verify_callback_l2_my;
! 		}
! 		else if ( verify_level == 3 )
! 		{
! 			return verify_callback_l3_my;
! 		}
! 		else
! 		{
! 			return verify_callback_l3_my; /* Highest verify level */
! 		}
! 	}
! 	else
! 	{
! 		if ( verify_level == SSL_VERIFY_NONE )
! 		{
! 			return verify_callback_l0_not_my;
! 		}
! 		else if ( verify_level == 1 )
! 		{
! 			return verify_callback_l1_not_my;
! 		}
! 		else if ( verify_level == 2 )
! 		{
! 			return verify_callback_l2_not_my;
! 		}
! 		else if ( verify_level == 3 )
! 		{
! 			return verify_callback_l3_not_my;
! 		}
! 		else
! 		{
! 			return verify_callback_l3_not_my; /* Highest verify level */
! 		}
! 	}
! }
! 
! static int verify_callback(int preverify_ok, X509_STORE_CTX *callback_ctx,
! 															int verify_level,
! 															int verify_use_only_my) {
          /* our verify callback function */
      char txt[STRLEN];
      X509_OBJECT ret;
***************
*** 544,550 ****
      X509_NAME_oneline(X509_get_subject_name(callback_ctx->current_cert),
          txt, STRLEN);
      safestring(txt);
!     if(options.verify_level==SSL_VERIFY_NONE) {
          s_log(LOG_NOTICE, "VERIFY IGNORE: depth=%d, %s",
              callback_ctx->error_depth, txt);
          return 1; /* Accept connection */
--- 717,723 ----
      X509_NAME_oneline(X509_get_subject_name(callback_ctx->current_cert),
          txt, STRLEN);
      safestring(txt);
!     if(verify_level==SSL_VERIFY_NONE) {
          s_log(LOG_NOTICE, "VERIFY IGNORE: depth=%d, %s",
              callback_ctx->error_depth, txt);
          return 1; /* Accept connection */
***************
*** 556,562 ****
              X509_verify_cert_error_string (callback_ctx->error), txt);
          return 0; /* Reject connection */
      }
!     if(options.verify_use_only_my && callback_ctx->error_depth==0 &&
              X509_STORE_get_by_subject(callback_ctx, X509_LU_X509,
                  X509_get_subject_name(callback_ctx->current_cert), &ret)!=1) {
          s_log(LOG_WARNING, "VERIFY ERROR ONLY MY: no cert for %s", txt);
--- 729,735 ----
              X509_verify_cert_error_string (callback_ctx->error), txt);
          return 0; /* Reject connection */
      }
!     if(verify_use_only_my && callback_ctx->error_depth==0 &&
              X509_STORE_get_by_subject(callback_ctx, X509_LU_X509,
                  X509_get_subject_name(callback_ctx->current_cert), &ret)!=1) {
          s_log(LOG_WARNING, "VERIFY ERROR ONLY MY: no cert for %s", txt);
***************
*** 703,712 ****
              SSL_alert_type_string_long(ret),
              SSL_alert_desc_string_long(ret));
      else if(where==SSL_CB_HANDSHAKE_DONE)
!         print_stats();
  }
  
! static void print_stats(void) { /* print statistics */
      s_log(LOG_DEBUG, "%4ld items in the session cache",
          SSL_CTX_sess_number(ctx));
      s_log(LOG_DEBUG, "%4ld client connects (SSL_connect())",
--- 876,885 ----
              SSL_alert_type_string_long(ret),
              SSL_alert_desc_string_long(ret));
      else if(where==SSL_CB_HANDSHAKE_DONE)
!         print_stats(s->ctx);
  }
  
! static void print_stats(SSL_CTX *ctx) { /* print statistics */
      s_log(LOG_DEBUG, "%4ld items in the session cache",
          SSL_CTX_sess_number(ctx));
      s_log(LOG_DEBUG, "%4ld client connects (SSL_connect())",
diff -rc stunnel-4.11/src/stunnel.c stunnel-4.11.mult_certs/src/stunnel.c
*** stunnel-4.11/src/stunnel.c	2005-07-09 17:35:38.000000000 -0400
--- stunnel-4.11.mult_certs/src/stunnel.c	2005-08-29 16:43:25.000000000 -0400
***************
*** 79,109 ****
  #endif
  
  void main_initialize(char *arg1, char *arg2) {
!     struct stat st; /* buffer for stat */
  
      sthreads_init(); /* initialize critical sections & SSL callbacks */
      parse_config(arg1, arg2);
!     log_open();
      s_log(LOG_NOTICE, "%s", stunnel_info());
  
!     /* check if certificate exists */
!     if(!options.key) /* key file not specified */
!         options.key=options.cert;
!     if(options.option.cert) {
!         if(stat(options.key, &st)) {
!             ioerror(options.key);
!             exit(1);
!         }
! #ifndef USE_WIN32
!         if(st.st_mode & 7)
!             s_log(LOG_WARNING, "Wrong permissions on %s", options.key);
! #endif /* defined USE_WIN32 */
!     }
  }
  
  void main_execute(void) {
!     ssl_init(); /* initialize SSL library */
!     context_init(); /* initialize global SSL context */
      /* check if started from inetd */
      if(local_options.next) { /* there are service sections -> daemon mode */
          daemon_loop();
--- 79,119 ----
  #endif
  
  void main_initialize(char *arg1, char *arg2) {
! 	LOCAL_OPTIONS *section; /* section iterator */
  
      sthreads_init(); /* initialize critical sections & SSL callbacks */
+     ssl_init(); /* initialize SSL library */
      parse_config(arg1, arg2);
! 	log_open();
      s_log(LOG_NOTICE, "%s", stunnel_info());
  
!     /* check if certificate(s) exists */
! 
! 	section = &local_options;
! 
! 	while ( ( section = section->next ) != NULL )
! 	{
! 		section->ssl_ctx_data.ctx = local_options.ssl_ctx_data.ctx;
! 
! 		if ( memcmp(&(local_options.ssl_ctx_data),&(section->ssl_ctx_data),
! 													sizeof(SSL_CTX_DATA)) )
! 		{
! 			context_init(&(section->ssl_ctx_data));
! 		}
! 		else
! 		{
! 			if ( local_options.ssl_ctx_data.ctx == NULL )
! 			{
! 				context_init(&(local_options.ssl_ctx_data));
! 			}
! 
! 			section->ssl_ctx_data.ctx = local_options.ssl_ctx_data.ctx;
! 		}
! 	}
  }
  
  void main_execute(void) {
! 	LOCAL_OPTIONS *section; /* Used for iterating through service to free all contexts */
      /* check if started from inetd */
      if(local_options.next) { /* there are service sections -> daemon mode */
          daemon_loop();
***************
*** 115,122 ****
          num_clients=1;
          client(alloc_client_session(&local_options, 0, 1));
      }
!     /* close SSL */
!     context_free(); /* free global SSL context */
      log_close();
  }
  
--- 125,148 ----
          num_clients=1;
          client(alloc_client_session(&local_options, 0, 1));
      }
! 
! 	/* Here we will iterate through all ssl contexts and free them */
! 
! 	section = &local_options;
! 
! 	while ( ( section = section->next ) != NULL )
! 	{
! 		if ( section->ssl_ctx_data.ctx != local_options.ssl_ctx_data.ctx )
! 		{
! 			context_free(&(section->ssl_ctx_data));
! 		}
! 	}
! 
! 	if ( local_options.ssl_ctx_data.ctx != NULL )
! 	{
! 		context_free(&(local_options.ssl_ctx_data));
! 	}
! 
      log_close();
  }
  
