You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by do...@apache.org on 2002/02/27 04:21:10 UTC

cvs commit: httpd-2.0/modules/ssl mod_ssl.h ssl_engine_config.c ssl_engine_init.c ssl_engine_pphrase.c

dougm       02/02/26 19:21:10

  Modified:    modules/ssl mod_ssl.h ssl_engine_config.c ssl_engine_init.c
                        ssl_engine_pphrase.c
  Log:
  changing mod_ssl to do a full startup/teardown on each restart rather
  than hack to only read passphrase on 1st round startup.  this change:
  - fixes current segv on restarts (SHARED_MODULE is not defined)
  - allows LoadModule ssl_module to be added to httpd.conf on restart
    (was core dumping previously)
  - allows certs/keys to be changed on restart provided key is not
    encrypted or SSLPassPhraseDialog is exec.  if key is encrypted and
    SSLPassPhraseDialog is builtin, existing private keys will be reused
    on restart (which happens currently for any type of key/dialog).
  
  note: mod_ssl currently leaks on restart; leaks more with this change.
        fixes to come.
  
  Revision  Changes    Path
  1.58      +1 -1      httpd-2.0/modules/ssl/mod_ssl.h
  
  Index: mod_ssl.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/ssl/mod_ssl.h,v
  retrieving revision 1.57
  retrieving revision 1.58
  diff -u -r1.57 -r1.58
  --- mod_ssl.h	27 Feb 2002 00:39:01 -0000	1.57
  +++ mod_ssl.h	27 Feb 2002 03:21:09 -0000	1.58
  @@ -463,6 +463,7 @@
   typedef struct {
       long int       nData;
       unsigned char *cpData;
  +    apr_time_t     source_mtime;
   } ssl_asn1_t;
   
   /*
  @@ -502,7 +503,6 @@
       pid_t           pid;
       apr_pool_t     *pPool;
       BOOL            bFixed;
  -    int             nInitCount;
       int             nSessionCacheMode;
       char           *szSessionCacheDataFile;
       int             nSessionCacheDataSize;
  
  
  
  1.21      +0 -1      httpd-2.0/modules/ssl/ssl_engine_config.c
  
  Index: ssl_engine_config.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/ssl/ssl_engine_config.c,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- ssl_engine_config.c	29 Nov 2001 06:15:01 -0000	1.20
  +++ ssl_engine_config.c	27 Feb 2002 03:21:09 -0000	1.21
  @@ -90,7 +90,6 @@
           /*
            * initialize per-module configuration
            */
  -        mc->nInitCount             = 0;
           mc->nSessionCacheMode      = SSL_SCMODE_UNSET;
           mc->szSessionCacheDataFile = NULL;
           mc->nSessionCacheDataSize  = 0;
  
  
  
  1.27      +10 -68    httpd-2.0/modules/ssl/ssl_engine_init.c
  
  Index: ssl_engine_init.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/ssl/ssl_engine_init.c,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- ssl_engine_init.c	25 Feb 2002 04:23:03 -0000	1.26
  +++ ssl_engine_init.c	27 Feb 2002 03:21:09 -0000	1.27
  @@ -89,8 +89,6 @@
       ssl_config_global_create(s); /* just to avoid problems */
       ssl_config_global_fix(mc);
   
  -    mc->nInitCount++;
  -
       /*
        *  try to fix the configuration and open the dedicated SSL
        *  logfile as early as possible
  @@ -121,78 +119,22 @@
       /*
        * Identification
        */
  -    if (mc->nInitCount == 1) {
  -        ssl_log(s, SSL_LOG_INFO, "Server: %s, Interface: %s, Library: %s",
  -                AP_SERVER_BASEVERSION,
  -                ssl_var_lookup(p, s, NULL, NULL, "SSL_VERSION_INTERFACE"),
  -                ssl_var_lookup(p, s, NULL, NULL, "SSL_VERSION_LIBRARY"));
  -    }
  -
  -    /*
  -     * Initialization round information
  -     */
  -    if (mc->nInitCount == 1)
  -        ssl_log(s, SSL_LOG_INFO, "Init: 1st startup round (still not detached)");
  -    else if (mc->nInitCount == 2)
  -        ssl_log(s, SSL_LOG_INFO, "Init: 2nd startup round (already detached)");
  -    else
  -        ssl_log(s, SSL_LOG_INFO, "Init: %d%s restart round (already detached)",
  -                mc->nInitCount-2, (mc->nInitCount-2) == 1 ? "st" : "nd");
  +    ssl_log(s, SSL_LOG_INFO, "Server: %s, Interface: %s, Library: %s",
  +            AP_SERVER_BASEVERSION,
  +            ssl_var_lookup(p, s, NULL, NULL, "SSL_VERSION_INTERFACE"),
  +            ssl_var_lookup(p, s, NULL, NULL, "SSL_VERSION_LIBRARY"));
   
  -    /*
  -     *  The initialization phase inside the Apache API is totally bogus.
  -     *  We actually have three non-trivial problems:
  -     *
  -     *  1. Under Unix the API does a 2-round initialization of modules while
  -     *     under Win32 it doesn't. This means we have to make sure that at
  -     *     least the pass phrase dialog doesn't occur twice.  We overcome this
  -     *     problem by using a counter (mc->nInitCount) which has to
  -     *     survive the init rounds.
  -     *
  -     *  2. Between the first and the second round Apache detaches from
  -     *     the terminal under Unix. This means that our pass phrase dialog
  -     *     _has_ to be done in the first round and _cannot_ be done in the
  -     *     second round.
  -     *
  -     *  3. When Dynamic Shared Object (DSO) mechanism is used under Unix the
  -     *     module segment (code & data) gets unloaded and re-loaded between
  -     *     the first and the second round. This means no global data survives
  -     *     between first and the second init round. We overcome this by using
  -     *     an entry ("ssl_module") inside the process_rec->pool->user_data.
  -     *
  -     *  The situation as a table:
  -     *
  -     *  Unix/static Unix/DSO          Win32     Action Required
  -     *              (-DSHARED_MODULE) (-DWIN32)
  -     *  ----------- ----------------- --------- -----------------------------------
  -     *  -           load module       -         -
  -     *  init        init              init      SSL library init, Pass Phrase Dialog
  -     *  detach      detach            -         -
  -     *  -           reload module     -         -
  -     *  init        init              -         SSL library init, mod_ssl init
  -     *
  -     *  Ok, now try to solve this totally ugly situation...
  -     */
  +    ssl_log(s, SSL_LOG_INFO, "Init: Initializing %s library",
  +            SSL_LIBRARY_NAME);
   
  -#ifdef SHARED_MODULE
  -    ssl_log(s, SSL_LOG_INFO, "Init: %snitializing %s library",
  -            mc->nInitCount == 1 ? "I" : "Rei", SSL_LIBRARY_NAME);
       ssl_init_SSLLibrary();
  -#else
  -    if (mc->nInitCount <= 2) {
  -        ssl_log(s, SSL_LOG_INFO, "Init: %snitializing %s library",
  -                mc->nInitCount == 1 ? "I" : "Rei", SSL_LIBRARY_NAME);
  -        ssl_init_SSLLibrary();
  -    }
  -#endif
  +
   #if APR_HAS_THREADS
       ssl_util_thread_setup(s, p);
   #endif
  -    if (mc->nInitCount == 1) {
  -        ssl_pphrase_Handle(s, p);
  -        ssl_init_TmpKeysHandle(SSL_TKP_GEN, s, p);
  -        return OK;
  -    }
  +
  +    ssl_pphrase_Handle(s, p);
  +    ssl_init_TmpKeysHandle(SSL_TKP_GEN, s, p);
   
       /*
        * SSL external crypto device ("engine") support
  
  
  
  1.13      +47 -7     httpd-2.0/modules/ssl/ssl_engine_pphrase.c
  
  Index: ssl_engine_pphrase.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/ssl/ssl_engine_pphrase.c,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- ssl_engine_pphrase.c	9 Jan 2002 19:24:32 -0000	1.12
  +++ ssl_engine_pphrase.c	27 Feb 2002 03:21:09 -0000	1.13
  @@ -67,7 +67,7 @@
    * Return true if the named file exists and is readable
    */
   
  -static apr_status_t exists_and_readable(char *fname, apr_pool_t *pool)
  +static apr_status_t exists_and_readable(char *fname, apr_pool_t *pool, apr_time_t *mtime)
   {
       apr_status_t stat;
       apr_finfo_t sbuf;
  @@ -82,6 +82,10 @@
       if ((stat = apr_file_open(&fd, fname, APR_READ, 0, pool)) != APR_SUCCESS)
           return stat;
   
  +    if (mtime) {
  +        *mtime = sbuf.mtime;
  +    }
  +
       apr_file_close(fd);
       return APR_SUCCESS;
   }
  @@ -121,7 +125,8 @@
       ssl_algo_t algoCert, algoKey, at;
       char *an;
       char *cp;
  -
  +    apr_time_t pkey_mtime = 0;
  +    int isterm = 1;
       /*
        * Start with a fresh pass phrase array
        */
  @@ -158,7 +163,7 @@
           for (i = 0, j = 0; i < SSL_AIDX_MAX && sc->szPublicCertFile[i] != NULL; i++) {
   
               apr_cpystrn(szPath, sc->szPublicCertFile[i], sizeof(szPath));
  -            if ( exists_and_readable(szPath, p) != APR_SUCCESS ) {
  +            if ( exists_and_readable(szPath, p, NULL) != APR_SUCCESS ) {
                   ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
                           "Init: Can't open server certificate file %s", szPath);
                   ssl_die();
  @@ -249,15 +254,40 @@
                    * the callback function which serves the pass
                    * phrases to OpenSSL
                    */
  -                if ( exists_and_readable(szPath, p) != APR_SUCCESS ) {
  +                if ( exists_and_readable(szPath, p, &pkey_mtime) != APR_SUCCESS ) {
                        ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
                            "Init: Can't open server private key file %s",szPath);
                        ssl_die();
                   }
  +
  +                /*
  +                 * isatty() returns false once httpd has detached from the terminal.
  +                 * if the private key is encrypted and SSLPassPhraseDialog is configured to "builtin"
  +                 * it isn't possible to prompt for a password.  in this case if we already have a
  +                 * private key and the file name/mtime hasn't changed, then reuse the existing key.
  +                 * of course this will not work if the server was started without LoadModule ssl_module
  +                 * configured, then restarted with it configured.  but we fall through with a chance of
  +                 * success if the key is not encrypted.  and in the case of fallthrough, pkey_mtime and
  +                 * isterm values are used to give a better idea as to what failed.
  +                 */
  +                if ((sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) &&
  +                    !(isterm = isatty(fileno(stdout)))) /* XXX: apr_isatty() */
  +                {
  +                    char *key_id = apr_psprintf(p, "%s:%s", cpVHostID, "RSA"); /* XXX: check for DSA key too? */
  +                    ssl_asn1_t *asn1 = (ssl_asn1_t *)ssl_ds_table_get(mc->tPrivateKey, key_id);
  +                    
  +                    if (asn1 && (asn1->source_mtime == pkey_mtime)) {
  +                        ssl_log(pServ, SSL_LOG_INFO,
  +                                "%s reusing existing private key on restart",
  +                                cpVHostID);
  +                        return;
  +                    }
  +                }
  +
                   cpPassPhraseCur = NULL;
                   bReadable = ((pPrivateKey = SSL_read_PrivateKey(szPath, NULL,
                               ssl_pphrase_Handle_CB, s)) != NULL ? TRUE : FALSE);
  -  
  +                
                   /*
                    * when the private key file now was readable,
                    * it's fine and we go out of the loop
  @@ -298,12 +328,20 @@
                   /*
                    * Ok, anything else now means a fatal error.
                    */
  -                if (cpPassPhraseCur == NULL)
  -                    ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Private key not found");
  +                if (cpPassPhraseCur == NULL) {
  +                    if (nPassPhraseDialogCur && pkey_mtime && !isterm) {
  +                        ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR,
  +                                "Init: Unable read passphrase "
  +                                "[Hint: key introduced or changed before restart?]");
  +                    }
  +                    else {
  +                        ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Private key not found");
  +                    }
                       if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) {
                           fprintf(stdout, "Apache:mod_ssl:Error: Private key not found.\n");
                           fprintf(stdout, "**Stopped\n");
                       }
  +                }
                   else {
                       ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Pass phrase incorrect");
                       if (sc->nPassPhraseDialogType == SSL_PPTYPE_BUILTIN) {
  @@ -371,6 +409,8 @@
               asn1->nData  = i2d_PrivateKey(pPrivateKey, NULL);
               asn1->cpData = apr_palloc(mc->pPool, asn1->nData);
               ucp = asn1->cpData; i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */
  +
  +            asn1->source_mtime = pkey_mtime;
   
               /*
                * Free the private key structure