示例#1
0
void ssl_init_Engine(server_rec *s, apr_pool_t *p)
{
    SSLModConfigRec *mc = myModConfig(s);
    ENGINE *e;

    if (mc->szCryptoDevice) {
        if (!(e = ENGINE_by_id(mc->szCryptoDevice))) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                         "Init: Failed to load Crypto Device API `%s'",
                         mc->szCryptoDevice);
            ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
            ssl_die();
        }

        if (strEQ(mc->szCryptoDevice, "chil")) {
            ENGINE_ctrl(e, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0);
        }

        if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                         "Init: Failed to enable Crypto Device API `%s'",
                         mc->szCryptoDevice);
            ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
            ssl_die();
        }
        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 
                     "Init: loaded Crypto Device API `%s'", 
                     mc->szCryptoDevice);

        ENGINE_free(e);
    }
}
示例#2
0
static void ssl_init_server_check(server_rec *s,
                                  apr_pool_t *p,
                                  apr_pool_t *ptemp,
                                  modssl_ctx_t *mctx)
{
    /*
     * check for important parameters and the
     * possibility that the user forgot to set them.
     */
    if (!mctx->pks->cert_files[0]) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                "No SSL Certificate set [hint: SSLCertificateFile]");
        ssl_die();
    }

    /*
     *  Check for problematic re-initializations
     */
    if (mctx->pks->certs[SSL_AIDX_RSA] ||
        mctx->pks->certs[SSL_AIDX_DSA])
    {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                "Illegal attempt to re-initialise SSL for server "
                "(theoretically shouldn't happen!)");
        ssl_die();
    }
}
void ssl_scache_shmht_init(server_rec *s, pool *p)
{
    SSLModConfigRec *mc = myModConfig();
    AP_MM *mm;
    table_t *ta;
    int ta_errno;
    int avail;
    int n;

    /*
     * Create shared memory segment
     */
    if (mc->szSessionCacheDataFile == NULL) {
        ssl_log(s, SSL_LOG_ERROR, "SSLSessionCache required");
        ssl_die();
    }
    if ((mm = ap_mm_create(mc->nSessionCacheDataSize, 
                           mc->szSessionCacheDataFile)) == NULL) {
        ssl_log(s, SSL_LOG_ERROR, 
                "Cannot allocate shared memory: %s", ap_mm_error());
        ssl_die();
    }
    mc->pSessionCacheDataMM = mm;

    /* 
     * Make sure the childs have access to the underlaying files
     */
    ap_mm_permission(mm, SSL_MM_FILE_MODE, ap_user_id, -1);

    /*
     * Create hash table in shared memory segment
     */
    avail = ap_mm_available(mm);
    n = (avail/2) / 1024;
    n = n < 10 ? 10 : n;
    if ((ta = table_alloc(n, &ta_errno, 
                          ssl_scache_shmht_malloc,  
                          ssl_scache_shmht_calloc, 
                          ssl_scache_shmht_realloc, 
                          ssl_scache_shmht_free    )) == NULL) {
        ssl_log(s, SSL_LOG_ERROR,
                "Cannot allocate hash table in shared memory: %s",
                table_strerror(ta_errno));
        ssl_die();
    }
    table_attr(ta, TABLE_FLAG_AUTO_ADJUST|TABLE_FLAG_ADJUST_DOWN);
    table_set_data_alignment(ta, sizeof(char *));
    table_clear(ta);
    mc->tSessionCacheDataTable = ta;

    /*
     * Log the done work
     */
    ssl_log(s, SSL_LOG_INFO, 
            "Init: Created hash-table (%d buckets) "
            "in shared memory (%d bytes) for SSL session cache", n, avail);
    return;
}
示例#4
0
apr_status_t ssl_scache_init(server_rec *s, apr_pool_t *p)
{
    SSLModConfigRec *mc = myModConfig(s);
    apr_status_t rv;
    struct ap_socache_hints hints;

    /* The very first invocation of this function will be the
     * post_config invocation during server startup; do nothing for
     * this first (and only the first) time through, since the pool
     * will be immediately cleared anyway.  For every subsequent
     * invocation, initialize the configured cache. */
    if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG)
        return APR_SUCCESS;

#ifdef HAVE_OCSP_STAPLING
    if (mc->stapling_cache) {
        memset(&hints, 0, sizeof hints);
        hints.avg_obj_size = 1500;
        hints.avg_id_len = 20;
        hints.expiry_interval = 300;

        rv = mc->stapling_cache->init(mc->stapling_cache_context,
                                     "mod_ssl-stapling", &hints, s, p);
        if (rv) {
            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01872)
                         "Could not initialize stapling cache. Exiting.");
            return ssl_die(s);
        }
    }
#endif

    /*
     * Warn the user that he should use the session cache.
     * But we can operate without it, of course.
     */
    if (mc->sesscache == NULL) {
        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01873)
                     "Init: Session Cache is not configured "
                     "[hint: SSLSessionCache]");
        return APR_SUCCESS;
    }

    memset(&hints, 0, sizeof hints);
    hints.avg_obj_size = 150;
    hints.avg_id_len = 30;
    hints.expiry_interval = 30;

    rv = mc->sesscache->init(mc->sesscache_context, "mod_ssl-session", &hints, s, p);
    if (rv) {
        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01874)
                     "Could not initialize session cache. Exiting.");
        return ssl_die(s);
    }

    return APR_SUCCESS;
}
/*
 * Open the SSL logfile
 */
void ssl_log_open(server_rec *s_main, server_rec *s, pool *p)
{
    char *szLogFile;
    SSLSrvConfigRec *sc_main = mySrvConfig(s_main);
    SSLSrvConfigRec *sc = mySrvConfig(s);
    piped_log *pl;
    char *cp;

    /* 
     * Short-circuit for inherited logfiles in order to save
     * filedescriptors in mass-vhost situation. Be careful, this works
     * fine because the close happens implicitly by the pool facility.
     */
    if (   s != s_main 
        && sc_main->fileLogFile != NULL
        && (   (sc->szLogFile == NULL)
            || (   sc->szLogFile != NULL 
                && sc_main->szLogFile != NULL 
                && strEQ(sc->szLogFile, sc_main->szLogFile)))) {
        sc->fileLogFile = sc_main->fileLogFile;
    }
    else if (sc->szLogFile != NULL) {
        if (strEQ(sc->szLogFile, "/dev/null"))
            return;
        else if (sc->szLogFile[0] == '|') {
            cp = sc->szLogFile+1;
            while (*cp == ' ' || *cp == '\t')
                cp++;
            szLogFile = ssl_util_server_root_relative(p, "log", cp);
            if ((pl = ap_open_piped_log(p, szLogFile)) == NULL) {
                ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
                        "Cannot open reliable pipe to SSL logfile filter %s", szLogFile);
                ssl_die();
            }
            sc->fileLogFile = ap_pfdopen(p, ap_piped_log_write_fd(pl), "a");
            setbuf(sc->fileLogFile, NULL);
        }
        else {
            szLogFile = ssl_util_server_root_relative(p, "log", sc->szLogFile);
            if ((sc->fileLogFile = ap_pfopen(p, szLogFile, "a")) == NULL) {
                ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
                        "Cannot open SSL logfile %s", szLogFile);
                ssl_die();
            }
            setbuf(sc->fileLogFile, NULL);
        }
    }
    return;
}
示例#6
0
STACK_OF(X509) *ssl_read_pkcs7(server_rec *s, const char *pkcs7)
{
    PKCS7 *p7;
    STACK_OF(X509) *certs = NULL;
    FILE *f;

    f = fopen(pkcs7, "r");
    if (!f) {
        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02212) "Can't open %s", pkcs7);
        ssl_die(s);
    }

    p7 = PEM_read_PKCS7(f, NULL, NULL, NULL);
    if (!p7) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02274)
                     "Can't read PKCS7 object %s", pkcs7);
        ssl_log_ssl_error(SSLLOG_MARK, APLOG_CRIT, s);
        exit(1);
    }

    switch (OBJ_obj2nid(p7->type)) {
    case NID_pkcs7_signed:
        certs = p7->d.sign->cert;
        p7->d.sign->cert = NULL;
        PKCS7_free(p7);
        break;

    case NID_pkcs7_signedAndEnveloped:
        certs = p7->d.signed_and_enveloped->cert;
        p7->d.signed_and_enveloped->cert = NULL;
        PKCS7_free(p7);
        break;

    default:
        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02213)
                     "Don't understand PKCS7 file %s", pkcs7);
        ssl_die(s);
    }

    if (!certs) {
        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02214)
                     "No certificates in %s", pkcs7);
        ssl_die(s);
    }

    fclose(f);

    return certs;
}
示例#7
0
void ssl_scache_dc_init(server_rec *s, apr_pool_t *p)
{
    DC_CTX *ctx;
    SSLModConfigRec *mc = myModConfig(s);
    /*
     * Create a session context
     */
    if (mc->szSessionCacheDataFile == NULL) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "SSLSessionCache required");
        ssl_die();
    }
#if 0
    /* If a "persistent connection" mode of operation is preferred, you *must*
     * also use the PIDCHECK flag to ensure fork()'d processes don't interlace
     * comms on the same connection as each other. */
#define SESSION_CTX_FLAGS        SESSION_CTX_FLAG_PERSISTENT | \
                                 SESSION_CTX_FLAG_PERSISTENT_PIDCHECK | \
                                 SESSION_CTX_FLAG_PERSISTENT_RETRY | \
                                 SESSION_CTX_FLAG_PERSISTENT_LATE
#else
    /* This mode of operation will open a temporary connection to the 'target'
     * for each cache operation - this makes it safe against fork()
     * automatically. This mode is preferred when running a local proxy (over
     * unix domain sockets) because overhead is negligable and it reduces the
     * performance/stability danger of file-descriptor bloatage. */
#define SESSION_CTX_FLAGS        0
#endif
    ctx = DC_CTX_new(mc->szSessionCacheDataFile, SESSION_CTX_FLAGS);
    if (!ctx) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "distributed scache failed to obtain context");
        ssl_die();
    }
    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, "distributed scache context initialised");
    /*
     * Success ...
     */
    mc->tSessionCacheDataTable = ctx;
    return;
}
示例#8
0
static void ssl_init_ctx_verify(server_rec *s,
                                apr_pool_t *p,
                                apr_pool_t *ptemp,
                                modssl_ctx_t *mctx)
{
    SSL_CTX *ctx = mctx->ssl_ctx;

    int verify = SSL_VERIFY_NONE;
    STACK_OF(X509_NAME) *ca_list;

    if (mctx->auth.verify_mode == SSL_CVERIFY_UNSET) {
        mctx->auth.verify_mode = SSL_CVERIFY_NONE;
    }

    if (mctx->auth.verify_depth == UNSET) {
        mctx->auth.verify_depth = 1;
    }

    /*
     *  Configure callbacks for SSL context
     */
    if (mctx->auth.verify_mode == SSL_CVERIFY_REQUIRE) {
        verify |= SSL_VERIFY_PEER_STRICT;
    }

    if ((mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL) ||
        (mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))
    {
        verify |= SSL_VERIFY_PEER;
    }

    SSL_CTX_set_verify(ctx, verify, ssl_callback_SSLVerify);

    /*
     * Configure Client Authentication details
     */
    if (mctx->auth.ca_cert_file || mctx->auth.ca_cert_path) {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                     "Configuring client authentication");

        if (!SSL_CTX_load_verify_locations(ctx,
                         MODSSL_PCHAR_CAST mctx->auth.ca_cert_file,
                         MODSSL_PCHAR_CAST mctx->auth.ca_cert_path))
        {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                    "Unable to configure verify locations "
                    "for client authentication");
            ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
            ssl_die();
        }

        if (mctx->pks && (mctx->pks->ca_name_file || mctx->pks->ca_name_path)) {
            ca_list = ssl_init_FindCAList(s, ptemp,
                                          mctx->pks->ca_name_file,
                                          mctx->pks->ca_name_path);
        } else
            ca_list = ssl_init_FindCAList(s, ptemp,
                                          mctx->auth.ca_cert_file,
                                          mctx->auth.ca_cert_path);
        if (!ca_list) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                    "Unable to determine list of acceptable "
                    "CA certificates for client authentication");
            ssl_die();
        }

        SSL_CTX_set_client_CA_list(ctx, (STACK *)ca_list);
    }

    /*
     * Give a warning when no CAs were configured but client authentication
     * should take place. This cannot work.
     */
    if (mctx->auth.verify_mode == SSL_CVERIFY_REQUIRE) {
        ca_list = (STACK_OF(X509_NAME) *)SSL_CTX_get_client_CA_list(ctx);

        if (sk_X509_NAME_num(ca_list) == 0) {
            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
                         "Init: Oops, you want to request client "
                         "authentication, but no CAs are known for "
                         "verification!?  [Hint: SSLCACertificate*]");
        }
    }
示例#9
0
static void ssl_init_ctx_protocol(server_rec *s,
                                  apr_pool_t *p,
                                  apr_pool_t *ptemp,
                                  modssl_ctx_t *mctx)
{
    SSL_CTX *ctx = NULL;
    MODSSL_SSL_METHOD_CONST SSL_METHOD *method = NULL;
    char *cp;
    int protocol = mctx->protocol;

    /*
     *  Create the new per-server SSL context
     */
    if (protocol == SSL_PROTOCOL_NONE) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                "No SSL protocols available [hint: SSLProtocol]");
        ssl_die();
    }

    cp = apr_pstrcat(p,
                     (protocol & SSL_PROTOCOL_SSLV2 ? "SSLv2, " : ""),
                     (protocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""),
                     (protocol & SSL_PROTOCOL_TLSV1 ? "TLSv1, " : ""),
                     NULL);
    cp[strlen(cp)-2] = NUL;

    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                 "Creating new SSL context (protocols: %s)", cp);

    if (protocol == SSL_PROTOCOL_SSLV2) {
        method = mctx->pkp ?
            SSLv2_client_method() : /* proxy */
            SSLv2_server_method();  /* server */
        ctx = SSL_CTX_new(method);  /* only SSLv2 is left */
    }
    else {
        method = mctx->pkp ?
            SSLv23_client_method() : /* proxy */
            SSLv23_server_method();  /* server */
        ctx = SSL_CTX_new(method); /* be more flexible */
    }

    mctx->ssl_ctx = ctx;

    SSL_CTX_set_options(ctx, SSL_OP_ALL);

    if (!(protocol & SSL_PROTOCOL_SSLV2)) {
        SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
    }

    if (!(protocol & SSL_PROTOCOL_SSLV3)) {
        SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
    }

    if (!(protocol & SSL_PROTOCOL_TLSV1)) {
        SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
    }

#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
    {
        SSLSrvConfigRec *sc = mySrvConfig(s);
        if (sc->cipher_server_pref == TRUE) {
            SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
        }
    }
#endif

    SSL_CTX_set_app_data(ctx, s);

    /*
     * Configure additional context ingredients
     */
    SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);

#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
    /*
     * Disallow a session from being resumed during a renegotiation,
     * so that an acceptable cipher suite can be negotiated.
     */
    SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
#endif
}
示例#10
0
void ssl_scache_shmht_init(server_rec *s, apr_pool_t *p)
{
    SSLModConfigRec *mc = myModConfig(s);
    table_t *ta;
    int ta_errno;
    apr_size_t avail;
    int n;
    apr_status_t rv;

    /*
     * Create shared memory segment
     */
    if (mc->szSessionCacheDataFile == NULL) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                     "SSLSessionCache required");
        ssl_die();
    }

    if ((rv = apr_shm_create(&(mc->pSessionCacheDataMM), 
                   mc->nSessionCacheDataSize, 
                   mc->szSessionCacheDataFile, mc->pPool)) != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
                     "Cannot allocate shared memory");
        ssl_die();
    }

    if ((rv = apr_rmm_init(&(mc->pSessionCacheDataRMM), NULL,
                   apr_shm_baseaddr_get(mc->pSessionCacheDataMM),
                   mc->nSessionCacheDataSize, mc->pPool)) != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
                     "Cannot initialize rmm");
        ssl_die();
    }
    ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                 "initialize MM %pp RMM %pp",
                 mc->pSessionCacheDataMM, mc->pSessionCacheDataRMM);

    /*
     * Create hash table in shared memory segment
     */
    avail = mc->nSessionCacheDataSize;
    n = (avail/2) / 1024;
    n = n < 10 ? 10 : n;

    /*
     * Passing server_rec as opt_param to table_alloc so that we can do
     * logging if required ssl_util_table. Otherwise, mc is sufficient.
     */ 
    if ((ta = table_alloc(n, &ta_errno, 
                          ssl_scache_shmht_malloc,  
                          ssl_scache_shmht_calloc, 
                          ssl_scache_shmht_realloc, 
                          ssl_scache_shmht_free, s )) == NULL) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                     "Cannot allocate hash table in shared memory: %s",
                     table_strerror(ta_errno));
        ssl_die();
    }

    table_attr(ta, TABLE_FLAG_AUTO_ADJUST|TABLE_FLAG_ADJUST_DOWN);
    table_set_data_alignment(ta, sizeof(char *));
    table_clear(ta);
    mc->tSessionCacheDataTable = ta;

    /*
     * Log the done work
     */
    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 
                 "Init: Created hash-table (%d buckets) "
                 "in shared memory (%" APR_SIZE_T_FMT 
                 " bytes) for SSL session cache",
                 n, avail);
    return;
}
void ssl_scache_shmcb_init(server_rec *s, apr_pool_t *p)
{
    SSLModConfigRec *mc = myModConfig(s);
    void *shm_segment;
    apr_size_t shm_segsize;
    apr_status_t rv;
    SHMCBHeader *header;
    unsigned int num_subcache, num_idx, loop;

    /* Create shared memory segment */
    if (mc->szSessionCacheDataFile == NULL) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                     "SSLSessionCache required");
        ssl_die();
    }

    /* Use anonymous shm by default, fall back on name-based. */
    rv = apr_shm_create(&(mc->pSessionCacheDataMM), 
                        mc->nSessionCacheDataSize, 
                        NULL, mc->pPool);
    if (APR_STATUS_IS_ENOTIMPL(rv)) {
        /* For a name-based segment, remove it first in case of a
         * previous unclean shutdown. */
        apr_shm_remove(mc->szSessionCacheDataFile, mc->pPool);

        rv = apr_shm_create(&(mc->pSessionCacheDataMM),
                            mc->nSessionCacheDataSize,
                            mc->szSessionCacheDataFile,
                            mc->pPool);
    }

    if (rv != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
                     "could not allocate shared memory for shmcb "
                     "session cache");
        ssl_die();
    }

    shm_segment = apr_shm_baseaddr_get(mc->pSessionCacheDataMM);
    shm_segsize = apr_shm_size_get(mc->pSessionCacheDataMM);
    if (shm_segsize < (5 * sizeof(SHMCBHeader))) {
        /* the segment is ridiculously small, bail out */
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                     "shared memory segment too small");
        ssl_die();
    }
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                 "shmcb_init allocated %" APR_SIZE_T_FMT
                 " bytes of shared memory",
                 shm_segsize);
    /* Discount the header */
    shm_segsize -= sizeof(SHMCBHeader);
    /* Select the number of subcaches to create and how many indexes each
     * should contain based on the size of the memory (the header has already
     * been subtracted). Typical non-client-auth sslv3/tlsv1 sessions are
     * around 150 bytes, so erring to division by 120 helps ensure we would
     * exhaust data storage before index storage (except sslv2, where it's
     * *slightly* the other way). From there, we select the number of subcaches
     * to be a power of two, such that the number of indexes per subcache at
     * least twice the number of subcaches. */
    num_idx = (shm_segsize) / 120;
    num_subcache = 256;
    while ((num_idx / num_subcache) < (2 * num_subcache))
        num_subcache /= 2;
    num_idx /= num_subcache;
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                 "for %" APR_SIZE_T_FMT " bytes (%" APR_SIZE_T_FMT 
                 " including header), recommending %u subcaches, "
                 "%u indexes each", shm_segsize,
                 shm_segsize + sizeof(SHMCBHeader), num_subcache, num_idx);
    if (num_idx < 5) {
        /* we're still too small, bail out */
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                     "shared memory segment too small");
        ssl_die();
    }
    /* OK, we're sorted */
    header = shm_segment;
    header->stat_stores = 0;
    header->stat_expiries = 0;
    header->stat_scrolled = 0;
    header->stat_retrieves_hit = 0;
    header->stat_retrieves_miss = 0;
    header->stat_removes_hit = 0;
    header->stat_removes_miss = 0;
    header->subcache_num = num_subcache;
    /* Convert the subcache size (in bytes) to a value that is suitable for
     * structure alignment on the host platform, by rounding down if necessary.
     * This assumes that sizeof(unsigned long) provides an appropriate
     * alignment unit.  */
    header->subcache_size = ((size_t)(shm_segsize / num_subcache) &
                             ~(size_t)(sizeof(unsigned long) - 1));
    header->subcache_data_offset = sizeof(SHMCBSubcache) +
                                   num_idx * sizeof(SHMCBIndex);
    header->subcache_data_size = header->subcache_size -
                                 header->subcache_data_offset;
    header->index_num = num_idx;

    /* Output trace info */
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                 "shmcb_init_memory choices follow");
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                 "subcache_num = %u", header->subcache_num);
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                 "subcache_size = %u", header->subcache_size);
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                 "subcache_data_offset = %u", header->subcache_data_offset);
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                 "subcache_data_size = %u", header->subcache_data_size);
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                 "index_num = %u", header->index_num);
    /* The header is done, make the caches empty */
    for (loop = 0; loop < header->subcache_num; loop++) {
        SHMCBSubcache *subcache = SHMCB_SUBCACHE(header, loop);
        subcache->idx_pos = subcache->idx_used = 0;
        subcache->data_pos = subcache->data_used = 0;
    }
    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
                 "Shared memory session cache initialised");
    /* Success ... */
    mc->tSessionCacheDataTable = shm_segment;
}