]> granicus.if.org Git - apache/commitdiff
changing mod_ssl to do a full startup/teardown on each restart rather
authorDoug MacEachern <dougm@apache.org>
Wed, 27 Feb 2002 03:21:09 +0000 (03:21 +0000)
committerDoug MacEachern <dougm@apache.org>
Wed, 27 Feb 2002 03:21:09 +0000 (03:21 +0000)
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.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@93585 13f79535-47bb-0310-9956-ffa450edef68

modules/ssl/mod_ssl.h
modules/ssl/ssl_engine_config.c
modules/ssl/ssl_engine_init.c
modules/ssl/ssl_engine_pphrase.c

index a69e8a0bdf9f01cc2dcef17d9ec7f96880b1baae..dcade58072817e2b1ec0253e4b5dd2754de85eed 100644 (file)
@@ -463,6 +463,7 @@ typedef struct {
 typedef struct {
     long int       nData;
     unsigned char *cpData;
+    apr_time_t     source_mtime;
 } ssl_asn1_t;
 
 /*
@@ -502,7 +503,6 @@ typedef struct {
     pid_t           pid;
     apr_pool_t     *pPool;
     BOOL            bFixed;
-    int             nInitCount;
     int             nSessionCacheMode;
     char           *szSessionCacheDataFile;
     int             nSessionCacheDataSize;
index ceadc62fc0d87a414b6570ef00ed6cc9b379ba08..ff062b35bfd830e3bb66c89ea285ff0a854caeb1 100644 (file)
@@ -90,7 +90,6 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s)
         /*
          * initialize per-module configuration
          */
-        mc->nInitCount             = 0;
         mc->nSessionCacheMode      = SSL_SCMODE_UNSET;
         mc->szSessionCacheDataFile = NULL;
         mc->nSessionCacheDataSize  = 0;
index adc360512b5e0c1738fd548373dae402904edf9f..d511486f7c5b858da21b4b6dd734daa40dabd673 100644 (file)
@@ -89,8 +89,6 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
     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 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
     /*
      * 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"));
-    }
+    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, "Init: Initializing %s library",
+            SSL_LIBRARY_NAME);
 
-    /*
-     *  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...
-     */
-
-#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 5f7aa6a5309f9821211a8c4326b97273da3e3834..87dde7492a8d8c55bc0fc190925845b9600ef3e6 100644 (file)
@@ -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 @@ static apr_status_t exists_and_readable(char *fname, apr_pool_t *pool)
     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 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
     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 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
         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 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
                  * 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 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
                 /*
                  * 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) {
@@ -372,6 +410,8 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
             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
              */