mod_ssl is hardwired only to initialize certain things on the first module 
init during startup. the only reason i can see is because the builtin 
SSLPassPhraseDialog can only read the passphrase from the tty before 
detach.  but if SSLPassPhraseDialog is exec: or the server key is not 
passphrase encrypted, there is no reason not to do a full startup/teardown 
of these things each time on restart.

currently it is not possible to add LoadModule mod_ssl.so to an already
running server (core dumps), nor is it possible to change the server 
cert/key on restart (continues to use the cert/key read at initial 
startup).

patch below makes both possible by removing the init counter and doing a 
full startup/teardown on restarts.  adds a special case when 
SSLPassPhraseDialog is builtin and server has detached, to reuse the 
existing private key for a vhost if the key source file/mtime have not 
changed.

Index: modules/ssl/mod_ssl.h
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/ssl/mod_ssl.h,v
retrieving revision 1.55
diff -u -r1.55 mod_ssl.h
--- modules/ssl/mod_ssl.h       18 Jan 2002 23:26:46 -0000      1.55
+++ modules/ssl/mod_ssl.h       22 Feb 2002 03:58:00 -0000
@@ -462,6 +462,8 @@
 typedef struct {
     long int       nData;
     unsigned char *cpData;
+    char          *source_file;
+    apr_time_t     source_mtime;
 } ssl_asn1_t;
 
 /*
@@ -501,7 +503,6 @@
     pid_t           pid;
     apr_pool_t     *pPool;
     BOOL            bFixed;
-    int             nInitCount;
     int             nSessionCacheMode;
     char           *szSessionCacheDataFile;
     int             nSessionCacheDataSize;
Index: modules/ssl/ssl_engine_config.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/ssl/ssl_engine_config.c,v
retrieving revision 1.20
diff -u -r1.20 ssl_engine_config.c
--- modules/ssl/ssl_engine_config.c     29 Nov 2001 06:15:01 -0000      1.20
+++ modules/ssl/ssl_engine_config.c     22 Feb 2002 03:58:00 -0000
@@ -90,7 +90,6 @@
         /*
          * initialize per-module configuration
          */
-        mc->nInitCount             = 0;
         mc->nSessionCacheMode      = SSL_SCMODE_UNSET;
         mc->szSessionCacheDataFile = NULL;
         mc->nSessionCacheDataSize  = 0;
Index: modules/ssl/ssl_engine_init.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/ssl/ssl_engine_init.c,v
retrieving revision 1.25
diff -u -r1.25 ssl_engine_init.c
--- modules/ssl/ssl_engine_init.c       16 Feb 2002 18:35:21 -0000      1.25
+++ modules/ssl/ssl_engine_init.c       22 Feb 2002 03:58:01 -0000
@@ -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
Index: modules/ssl/ssl_engine_pphrase.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/ssl/ssl_engine_pphrase.c,v
retrieving revision 1.12
diff -u -r1.12 ssl_engine_pphrase.c
--- modules/ssl/ssl_engine_pphrase.c    9 Jan 2002 19:24:32 -0000       1.12
+++ modules/ssl/ssl_engine_pphrase.c    22 Feb 2002 03:58:01 -0000
@@ -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,42 @@
                  * 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) &&
+                        !strcmp(asn1->source_file, szPath))
+                    {
+                        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 +330,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 +411,9 @@
             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_file = apr_pstrdup(mc->pPool, szPath);
+            asn1->source_mtime = pkey_mtime;
 
             /*
              * Free the private key structure

Reply via email to