1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-01 07:26:57 +03:00

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.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@93585 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Doug MacEachern
2002-02-27 03:21:09 +00:00
parent 50e50ff4f9
commit 0ba62becc5
4 changed files with 58 additions and 77 deletions

View 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;

View 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;

View 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

View 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,11 +254,36 @@ 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);
@ -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
*/