Changeset e183628 in mod_gnutls


Ignore:
Timestamp:
Sep 19, 2011, 11:58:43 PM (8 years ago)
Author:
Dash Shendy <neuromancer@…>
Branches:
debian/master, debian/stretch-backports, jessie-backports, master, msva, upstream
Children:
c7c2ad2
Parents:
6223319
Message:

Updated Copyright Headers & Formatting

Location:
src
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_cache.c

    r6223319 re183628  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Portions Copyright 2008 Nikos Mavrogiannopoulos
     3 *  Copyright 2008 Nikos Mavrogiannopoulos
     4 *  Copyright 2011 Dash Shendy
    45 *
    56 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    4546
    4647char *mgs_session_id2sz(unsigned char *id, int idlen,
    47                         char *str, int strsize)
    48 {
    49         char *cp;
    50         int n;
    51 
    52         cp = str;
    53         for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
    54                 apr_snprintf(cp, strsize - (cp - str), "%02X", id[n]);
    55                 cp += 2;
    56         }
    57         *cp = '\0';
    58         return str;
    59 }
    60 
     48        char *str, int strsize) {
     49    char *cp;
     50    int n;
     51
     52    cp = str;
     53    for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
     54        apr_snprintf(cp, strsize - (cp - str), "%02X", id[n]);
     55        cp += 2;
     56    }
     57    *cp = '\0';
     58    return str;
     59}
    6160
    6261/* Name the Session ID as:
     
    6564 */
    6665static int mgs_session_id2dbm(conn_rec * c, unsigned char *id, int idlen,
    67                               apr_datum_t * dbmkey)
    68 {
    69         char buf[STR_SESSION_LEN];
    70         char *sz;
    71 
    72         sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf));
    73         if (sz == NULL)
    74                 return -1;
    75 
    76         dbmkey->dptr =
    77             apr_psprintf(c->pool, "%s:%d.%s",
    78                          c->base_server->server_hostname,
    79                          c->base_server->port, sz);
    80         dbmkey->dsize = strlen(dbmkey->dptr);
    81 
    82         return 0;
     66        apr_datum_t * dbmkey) {
     67    char buf[STR_SESSION_LEN];
     68    char *sz;
     69
     70    sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf));
     71    if (sz == NULL)
     72        return -1;
     73
     74    dbmkey->dptr =
     75            apr_psprintf(c->pool, "%s:%d.%s",
     76            c->base_server->server_hostname,
     77            c->base_server->port, sz);
     78    dbmkey->dsize = strlen(dbmkey->dptr);
     79
     80    return 0;
    8381}
    8482
    8583#define CTIME "%b %d %k:%M:%S %Y %Z"
    86 char *mgs_time2sz(time_t in_time, char *str, int strsize)
    87 {
    88         apr_time_exp_t vtm;
    89         apr_size_t ret_size;
    90         apr_time_t t;
    91 
    92 
    93         apr_time_ansi_put(&t, in_time);
    94         apr_time_exp_gmt(&vtm, t);
    95         apr_strftime(str, &ret_size, strsize - 1, CTIME, &vtm);
    96 
    97         return str;
     84
     85char *mgs_time2sz(time_t in_time, char *str, int strsize) {
     86    apr_time_exp_t vtm;
     87    apr_size_t ret_size;
     88    apr_time_t t;
     89
     90
     91    apr_time_ansi_put(&t, in_time);
     92    apr_time_exp_gmt(&vtm, t);
     93    apr_strftime(str, &ret_size, strsize - 1, CTIME, &vtm);
     94
     95    return str;
    9896}
    9997
    10098#if HAVE_APR_MEMCACHE
     99
    101100/* Name the Session ID as:
    102101 * server:port.SessionID
    103102 * to disallow resuming sessions on different servers
    104103 */
    105 static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen)
    106 {
    107         char buf[STR_SESSION_LEN];
    108         char *sz;
    109 
    110         sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf));
    111         if (sz == NULL)
    112                 return NULL;
    113 
    114         return apr_psprintf(c->pool, MC_TAG "%s:%d.%s",
    115                             c->base_server->server_hostname,
    116                             c->base_server->port, sz);
     104static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen) {
     105    char buf[STR_SESSION_LEN];
     106    char *sz;
     107
     108    sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf));
     109    if (sz == NULL)
     110        return NULL;
     111
     112    return apr_psprintf(c->pool, MC_TAG "%s:%d.%s",
     113            c->base_server->server_hostname,
     114            c->base_server->port, sz);
    117115}
    118116
     
    126124
    127125static int mc_cache_child_init(apr_pool_t * p, server_rec * s,
    128                                mgs_srvconf_rec * sc)
    129 {
    130         apr_status_t rv = APR_SUCCESS;
    131         int thread_limit = 0;
    132         int nservers = 0;
    133         char *cache_config;
    134         char *split;
    135         char *tok;
    136 
    137         ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
    138 
    139         /* Find all the servers in the first run to get a total count */
    140         cache_config = apr_pstrdup(p, sc->cache_config);
    141         split = apr_strtok(cache_config, " ", &tok);
    142         while (split) {
    143                 nservers++;
    144                 split = apr_strtok(NULL, " ", &tok);
    145         }
    146 
    147         rv = apr_memcache_create(p, nservers, 0, &mc);
    148         if (rv != APR_SUCCESS) {
    149                 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    150                              "[gnutls_cache] Failed to create Memcache Object of '%d' size.",
    151                              nservers);
    152                 return rv;
    153         }
    154 
    155         /* Now add each server to the memcache */
    156         cache_config = apr_pstrdup(p, sc->cache_config);
    157         split = apr_strtok(cache_config, " ", &tok);
    158         while (split) {
    159                 apr_memcache_server_t *st;
    160                 char *host_str;
    161                 char *scope_id;
    162                 apr_port_t port;
    163 
    164                 rv = apr_parse_addr_port(&host_str, &scope_id, &port,
    165                                          split, p);
    166                 if (rv != APR_SUCCESS) {
    167                         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    168                                      "[gnutls_cache] Failed to Parse Server: '%s'",
    169                                      split);
    170                         return rv;
    171                 }
    172 
    173                 if (host_str == NULL) {
    174                         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    175                                      "[gnutls_cache] Failed to Parse Server, "
    176                                      "no hostname specified: '%s'", split);
    177                         return rv;
    178                 }
    179 
    180                 if (port == 0) {
    181                         port = 11211;   /* default port */
    182                 }
    183 
    184                 /* Should Max Conns be (thread_limit / nservers) ? */
    185                 rv = apr_memcache_server_create(p,
    186                                                 host_str, port,
    187                                                 0,
    188                                                 1, thread_limit, 600, &st);
    189                 if (rv != APR_SUCCESS) {
    190                         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    191                                      "[gnutls_cache] Failed to Create Server: %s:%d",
    192                                      host_str, port);
    193                         return rv;
    194                 }
    195 
    196                 rv = apr_memcache_add_server(mc, st);
    197                 if (rv != APR_SUCCESS) {
    198                         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    199                                      "[gnutls_cache] Failed to Add Server: %s:%d",
    200                                      host_str, port);
    201                         return rv;
    202                 }
    203 
    204                 split = apr_strtok(NULL, " ", &tok);
    205         }
    206         return rv;
     126        mgs_srvconf_rec * sc) {
     127    apr_status_t rv = APR_SUCCESS;
     128    int thread_limit = 0;
     129    int nservers = 0;
     130    char *cache_config;
     131    char *split;
     132    char *tok;
     133
     134    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
     135
     136    /* Find all the servers in the first run to get a total count */
     137    cache_config = apr_pstrdup(p, sc->cache_config);
     138    split = apr_strtok(cache_config, " ", &tok);
     139    while (split) {
     140        nservers++;
     141        split = apr_strtok(NULL, " ", &tok);
     142    }
     143
     144    rv = apr_memcache_create(p, nservers, 0, &mc);
     145    if (rv != APR_SUCCESS) {
     146        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
     147                "[gnutls_cache] Failed to create Memcache Object of '%d' size.",
     148                nservers);
     149        return rv;
     150    }
     151
     152    /* Now add each server to the memcache */
     153    cache_config = apr_pstrdup(p, sc->cache_config);
     154    split = apr_strtok(cache_config, " ", &tok);
     155    while (split) {
     156        apr_memcache_server_t *st;
     157        char *host_str;
     158        char *scope_id;
     159        apr_port_t port;
     160
     161        rv = apr_parse_addr_port(&host_str, &scope_id, &port,
     162                split, p);
     163        if (rv != APR_SUCCESS) {
     164            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
     165                    "[gnutls_cache] Failed to Parse Server: '%s'",
     166                    split);
     167            return rv;
     168        }
     169
     170        if (host_str == NULL) {
     171            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
     172                    "[gnutls_cache] Failed to Parse Server, "
     173                    "no hostname specified: '%s'", split);
     174            return rv;
     175        }
     176
     177        if (port == 0) {
     178            port = 11211; /* default port */
     179        }
     180
     181        /* Should Max Conns be (thread_limit / nservers) ? */
     182        rv = apr_memcache_server_create(p,
     183                host_str, port,
     184                0,
     185                1, thread_limit, 600, &st);
     186        if (rv != APR_SUCCESS) {
     187            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
     188                    "[gnutls_cache] Failed to Create Server: %s:%d",
     189                    host_str, port);
     190            return rv;
     191        }
     192
     193        rv = apr_memcache_add_server(mc, st);
     194        if (rv != APR_SUCCESS) {
     195            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
     196                    "[gnutls_cache] Failed to Add Server: %s:%d",
     197                    host_str, port);
     198            return rv;
     199        }
     200
     201        split = apr_strtok(NULL, " ", &tok);
     202    }
     203    return rv;
    207204}
    208205
    209206static int mc_cache_store(void *baton, gnutls_datum_t key,
    210                           gnutls_datum_t data)
    211 {
    212         apr_status_t rv = APR_SUCCESS;
    213         mgs_handle_t *ctxt = baton;
    214         char *strkey = NULL;
    215         apr_uint32_t timeout;
    216 
    217         strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    218         if (!strkey)
    219                 return -1;
    220 
    221         timeout = apr_time_sec(ctxt->sc->cache_timeout);
    222 
    223         rv = apr_memcache_set(mc, strkey,(char *)data.data, data.size, timeout,
    224                               0);
    225 
    226         if (rv != APR_SUCCESS) {
    227                 ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
    228                              ctxt->c->base_server,
    229                              "[gnutls_cache] error setting key '%s' "
    230                              "with %d bytes of data", strkey, data.size);
    231                 return -1;
    232         }
    233 
    234         return 0;
    235 }
    236 
    237 static gnutls_datum_t mc_cache_fetch(void *baton, gnutls_datum_t key)
    238 {
    239         apr_status_t rv = APR_SUCCESS;
    240         mgs_handle_t *ctxt = baton;
    241         char *strkey = NULL;
    242         char *value;
    243         apr_size_t value_len;
    244         gnutls_datum_t data = { NULL, 0 };
    245 
    246         strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    247         if (!strkey) {
    248                 return data;
    249         }
    250 
    251         rv = apr_memcache_getp(mc, ctxt->c->pool, strkey,
    252                                &value, &value_len, NULL);
    253 
    254         if (rv != APR_SUCCESS) {
     207        gnutls_datum_t data) {
     208    apr_status_t rv = APR_SUCCESS;
     209    mgs_handle_t *ctxt = baton;
     210    char *strkey = NULL;
     211    apr_uint32_t timeout;
     212
     213    strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
     214    if (!strkey)
     215        return -1;
     216
     217    timeout = apr_time_sec(ctxt->sc->cache_timeout);
     218
     219    rv = apr_memcache_set(mc, strkey, (char *) data.data, data.size, timeout,
     220            0);
     221
     222    if (rv != APR_SUCCESS) {
     223        ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
     224                ctxt->c->base_server,
     225                "[gnutls_cache] error setting key '%s' "
     226                "with %d bytes of data", strkey, data.size);
     227        return -1;
     228    }
     229
     230    return 0;
     231}
     232
     233static gnutls_datum_t mc_cache_fetch(void *baton, gnutls_datum_t key) {
     234    apr_status_t rv = APR_SUCCESS;
     235    mgs_handle_t *ctxt = baton;
     236    char *strkey = NULL;
     237    char *value;
     238    apr_size_t value_len;
     239    gnutls_datum_t data = {NULL, 0};
     240
     241    strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
     242    if (!strkey) {
     243        return data;
     244    }
     245
     246    rv = apr_memcache_getp(mc, ctxt->c->pool, strkey,
     247            &value, &value_len, NULL);
     248
     249    if (rv != APR_SUCCESS) {
    255250#if MOD_GNUTLS_DEBUG
    256                 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    257                              ctxt->c->base_server,
    258                              "[gnutls_cache] error fetching key '%s' ",
    259                              strkey);
     251        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
     252                ctxt->c->base_server,
     253                "[gnutls_cache] error fetching key '%s' ",
     254                strkey);
    260255#endif
    261                 data.size = 0;
    262                 data.data = NULL;
    263                 return data;
    264         }
    265 
    266         /* TODO: Eliminate this memcpy. gnutls-- */
    267         data.data = gnutls_malloc(value_len);
    268         if (data.data == NULL)
    269                 return data;
    270 
    271         data.size = value_len;
    272         memcpy(data.data, value, value_len);
    273 
    274         return data;
    275 }
    276 
    277 static int mc_cache_delete(void *baton, gnutls_datum_t key)
    278 {
    279         apr_status_t rv = APR_SUCCESS;
    280         mgs_handle_t *ctxt = baton;
    281         char *strkey = NULL;
    282 
    283         strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    284         if (!strkey)
    285                 return -1;
    286 
    287         rv = apr_memcache_delete(mc, strkey, 0);
    288 
    289         if (rv != APR_SUCCESS) {
    290                 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    291                              ctxt->c->base_server,
    292                              "[gnutls_cache] error deleting key '%s' ",
    293                              strkey);
    294                 return -1;
    295         }
    296 
    297         return 0;
     256        data.size = 0;
     257        data.data = NULL;
     258        return data;
     259    }
     260
     261    /* TODO: Eliminate this memcpy. gnutls-- */
     262    data.data = gnutls_malloc(value_len);
     263    if (data.data == NULL)
     264        return data;
     265
     266    data.size = value_len;
     267    memcpy(data.data, value, value_len);
     268
     269    return data;
     270}
     271
     272static int mc_cache_delete(void *baton, gnutls_datum_t key) {
     273    apr_status_t rv = APR_SUCCESS;
     274    mgs_handle_t *ctxt = baton;
     275    char *strkey = NULL;
     276
     277    strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
     278    if (!strkey)
     279        return -1;
     280
     281    rv = apr_memcache_delete(mc, strkey, 0);
     282
     283    if (rv != APR_SUCCESS) {
     284        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
     285                ctxt->c->base_server,
     286                "[gnutls_cache] error deleting key '%s' ",
     287                strkey);
     288        return -1;
     289    }
     290
     291    return 0;
    298292}
    299293
    300294#endif                          /* have_apr_memcache */
    301295
    302 const char *db_type(mgs_srvconf_rec * sc)
    303 {
    304         if (sc->cache_type == mgs_cache_gdbm)
    305                 return "gdbm";
    306         else
    307                 return "db";
     296const char *db_type(mgs_srvconf_rec * sc) {
     297    if (sc->cache_type == mgs_cache_gdbm)
     298        return "gdbm";
     299    else
     300        return "db";
    308301}
    309302
    310303#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
    311304
    312 static void dbm_cache_expire(mgs_handle_t * ctxt)
    313 {
    314         apr_status_t rv;
    315         apr_dbm_t *dbm;
    316         apr_datum_t dbmkey;
    317         apr_datum_t dbmval;
    318         apr_time_t now;
    319         apr_time_t dtime;
    320         apr_pool_t *spool;
    321         int total, deleted;
    322 
    323         now = apr_time_now();
    324 
    325         if (now - ctxt->sc->last_cache_check <
    326             (ctxt->sc->cache_timeout) / 2)
    327                 return;
    328 
    329         ctxt->sc->last_cache_check = now;
    330 
    331         apr_pool_create(&spool, ctxt->c->pool);
    332 
    333         total = 0;
    334         deleted = 0;
    335 
    336         rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    337                              ctxt->sc->cache_config, APR_DBM_RWCREATE,
    338                              SSL_DBM_FILE_MODE, spool);
    339         if (rv != APR_SUCCESS) {
    340                 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    341                              ctxt->c->base_server,
    342                              "[gnutls_cache] error opening cache searcher '%s'",
    343                              ctxt->sc->cache_config);
    344                 apr_pool_destroy(spool);
    345                 return;
    346         }
    347 
    348         apr_dbm_firstkey(dbm, &dbmkey);
    349         while (dbmkey.dptr != NULL) {
    350                 apr_dbm_fetch(dbm, dbmkey, &dbmval);
    351                 if (dbmval.dptr != NULL
    352                     && dbmval.dsize >= sizeof(apr_time_t)) {
    353                         memcpy(&dtime, dbmval.dptr, sizeof(apr_time_t));
    354 
    355                         if (now >= dtime) {
    356                                 apr_dbm_delete(dbm, dbmkey);
    357                                 deleted++;
    358                         }
    359                         apr_dbm_freedatum(dbm, dbmval);
    360                 } else {
    361                         apr_dbm_delete(dbm, dbmkey);
    362                         deleted++;
    363                 }
    364                 total++;
    365                 apr_dbm_nextkey(dbm, &dbmkey);
    366         }
    367         apr_dbm_close(dbm);
    368 
    369         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    370                      ctxt->c->base_server,
    371                      "[gnutls_cache] Cleaned up cache '%s'. Deleted %d and left %d",
    372                      ctxt->sc->cache_config, deleted, total - deleted);
    373 
    374         apr_pool_destroy(spool);
    375 
    376         return;
    377 }
    378 
    379 static gnutls_datum_t dbm_cache_fetch(void *baton, gnutls_datum_t key)
    380 {
    381         gnutls_datum_t data = { NULL, 0 };
    382         apr_dbm_t *dbm;
    383         apr_datum_t dbmkey;
    384         apr_datum_t dbmval;
    385         mgs_handle_t *ctxt = baton;
    386         apr_status_t rv;
    387 
    388         if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    389                 return data;
    390 
    391         rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    392                              ctxt->sc->cache_config, APR_DBM_READONLY,
    393                              SSL_DBM_FILE_MODE, ctxt->c->pool);
    394         if (rv != APR_SUCCESS) {
    395                 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    396                              ctxt->c->base_server,
    397                              "[gnutls_cache] error opening cache '%s'",
    398                              ctxt->sc->cache_config);
    399                 return data;
    400         }
    401 
    402         rv = apr_dbm_fetch(dbm, dbmkey, &dbmval);
    403 
    404         if (rv != APR_SUCCESS) {
    405                 apr_dbm_close(dbm);
    406                 return data;
    407         }
    408 
    409         if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(apr_time_t)) {
    410                 apr_dbm_freedatum(dbm, dbmval);
    411                 apr_dbm_close(dbm);
    412                 return data;
    413         }
    414 
    415         data.size = dbmval.dsize - sizeof(apr_time_t);
    416 
    417         data.data = gnutls_malloc(data.size);
    418         if (data.data == NULL) {
    419                 apr_dbm_freedatum(dbm, dbmval);
    420                 apr_dbm_close(dbm);
    421                 return data;
    422         }
    423 
    424         memcpy(data.data, dbmval.dptr + sizeof(apr_time_t), data.size);
    425 
    426         apr_dbm_freedatum(dbm, dbmval);
    427         apr_dbm_close(dbm);
    428 
    429         return data;
     305static void dbm_cache_expire(mgs_handle_t * ctxt) {
     306    apr_status_t rv;
     307    apr_dbm_t *dbm;
     308    apr_datum_t dbmkey;
     309    apr_datum_t dbmval;
     310    apr_time_t now;
     311    apr_time_t dtime;
     312    apr_pool_t *spool;
     313    int total, deleted;
     314
     315    now = apr_time_now();
     316
     317    if (now - ctxt->sc->last_cache_check <
     318            (ctxt->sc->cache_timeout) / 2)
     319        return;
     320
     321    ctxt->sc->last_cache_check = now;
     322
     323    apr_pool_create(&spool, ctxt->c->pool);
     324
     325    total = 0;
     326    deleted = 0;
     327
     328    rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
     329            ctxt->sc->cache_config, APR_DBM_RWCREATE,
     330            SSL_DBM_FILE_MODE, spool);
     331    if (rv != APR_SUCCESS) {
     332        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
     333                ctxt->c->base_server,
     334                "[gnutls_cache] error opening cache searcher '%s'",
     335                ctxt->sc->cache_config);
     336        apr_pool_destroy(spool);
     337        return;
     338    }
     339
     340    apr_dbm_firstkey(dbm, &dbmkey);
     341    while (dbmkey.dptr != NULL) {
     342        apr_dbm_fetch(dbm, dbmkey, &dbmval);
     343        if (dbmval.dptr != NULL
     344                && dbmval.dsize >= sizeof (apr_time_t)) {
     345            memcpy(&dtime, dbmval.dptr, sizeof (apr_time_t));
     346
     347            if (now >= dtime) {
     348                apr_dbm_delete(dbm, dbmkey);
     349                deleted++;
     350            }
     351            apr_dbm_freedatum(dbm, dbmval);
     352        } else {
     353            apr_dbm_delete(dbm, dbmkey);
     354            deleted++;
     355        }
     356        total++;
     357        apr_dbm_nextkey(dbm, &dbmkey);
     358    }
     359    apr_dbm_close(dbm);
     360
     361    ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
     362            ctxt->c->base_server,
     363            "[gnutls_cache] Cleaned up cache '%s'. Deleted %d and left %d",
     364            ctxt->sc->cache_config, deleted, total - deleted);
     365
     366    apr_pool_destroy(spool);
     367
     368    return;
     369}
     370
     371static gnutls_datum_t dbm_cache_fetch(void *baton, gnutls_datum_t key) {
     372    gnutls_datum_t data = {NULL, 0};
     373    apr_dbm_t *dbm;
     374    apr_datum_t dbmkey;
     375    apr_datum_t dbmval;
     376    mgs_handle_t *ctxt = baton;
     377    apr_status_t rv;
     378
     379    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
     380        return data;
     381
     382    rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
     383            ctxt->sc->cache_config, APR_DBM_READONLY,
     384            SSL_DBM_FILE_MODE, ctxt->c->pool);
     385    if (rv != APR_SUCCESS) {
     386        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
     387                ctxt->c->base_server,
     388                "[gnutls_cache] error opening cache '%s'",
     389                ctxt->sc->cache_config);
     390        return data;
     391    }
     392
     393    rv = apr_dbm_fetch(dbm, dbmkey, &dbmval);
     394
     395    if (rv != APR_SUCCESS) {
     396        apr_dbm_close(dbm);
     397        return data;
     398    }
     399
     400    if (dbmval.dptr == NULL || dbmval.dsize <= sizeof (apr_time_t)) {
     401        apr_dbm_freedatum(dbm, dbmval);
     402        apr_dbm_close(dbm);
     403        return data;
     404    }
     405
     406    data.size = dbmval.dsize - sizeof (apr_time_t);
     407
     408    data.data = gnutls_malloc(data.size);
     409    if (data.data == NULL) {
     410        apr_dbm_freedatum(dbm, dbmval);
     411        apr_dbm_close(dbm);
     412        return data;
     413    }
     414
     415    memcpy(data.data, dbmval.dptr + sizeof (apr_time_t), data.size);
     416
     417    apr_dbm_freedatum(dbm, dbmval);
     418    apr_dbm_close(dbm);
     419
     420    return data;
    430421}
    431422
    432423static int dbm_cache_store(void *baton, gnutls_datum_t key,
    433                            gnutls_datum_t data)
    434 {
    435         apr_dbm_t *dbm;
    436         apr_datum_t dbmkey;
    437         apr_datum_t dbmval;
    438         mgs_handle_t *ctxt = baton;
    439         apr_status_t rv;
    440         apr_time_t expiry;
    441         apr_pool_t *spool;
    442 
    443         if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    444                 return -1;
    445 
    446         /* we expire dbm only on every store
    447          */
    448         dbm_cache_expire(ctxt);
    449 
    450         apr_pool_create(&spool, ctxt->c->pool);
    451 
    452         /* create DBM value */
    453         dbmval.dsize = data.size + sizeof(apr_time_t);
    454         dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize);
    455 
    456         expiry = apr_time_now() + ctxt->sc->cache_timeout;
    457 
    458         memcpy((char *) dbmval.dptr, &expiry, sizeof(apr_time_t));
    459         memcpy((char *) dbmval.dptr + sizeof(apr_time_t),
    460                data.data, data.size);
    461 
    462         rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    463                              ctxt->sc->cache_config, APR_DBM_RWCREATE,
    464                              SSL_DBM_FILE_MODE, ctxt->c->pool);
    465         if (rv != APR_SUCCESS) {
    466                 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    467                              ctxt->c->base_server,
    468                              "[gnutls_cache] error opening cache '%s'",
    469                              ctxt->sc->cache_config);
    470                 apr_pool_destroy(spool);
    471                 return -1;
    472         }
    473 
    474         rv = apr_dbm_store(dbm, dbmkey, dbmval);
    475 
    476         if (rv != APR_SUCCESS) {
    477                 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    478                              ctxt->c->base_server,
    479                              "[gnutls_cache] error storing in cache '%s'",
    480                              ctxt->sc->cache_config);
    481                 apr_dbm_close(dbm);
    482                 apr_pool_destroy(spool);
    483                 return -1;
    484         }
    485 
    486         apr_dbm_close(dbm);
    487 
    488         apr_pool_destroy(spool);
    489 
    490         return 0;
    491 }
    492 
    493 static int dbm_cache_delete(void *baton, gnutls_datum_t key)
    494 {
    495         apr_dbm_t *dbm;
    496         apr_datum_t dbmkey;
    497         mgs_handle_t *ctxt = baton;
    498         apr_status_t rv;
    499 
    500         if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    501                 return -1;
    502 
    503         rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    504                              ctxt->sc->cache_config, APR_DBM_RWCREATE,
    505                              SSL_DBM_FILE_MODE, ctxt->c->pool);
    506         if (rv != APR_SUCCESS) {
    507                 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    508                              ctxt->c->base_server,
    509                              "[gnutls_cache] error opening cache '%s'",
    510                              ctxt->sc->cache_config);
    511                 return -1;
    512         }
    513 
    514         rv = apr_dbm_delete(dbm, dbmkey);
    515 
    516         if (rv != APR_SUCCESS) {
    517                 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    518                              ctxt->c->base_server,
    519                              "[gnutls_cache] error deleting from cache '%s'",
    520                              ctxt->sc->cache_config);
    521                 apr_dbm_close(dbm);
    522                 return -1;
    523         }
    524 
    525         apr_dbm_close(dbm);
    526 
    527         return 0;
     424        gnutls_datum_t data) {
     425    apr_dbm_t *dbm;
     426    apr_datum_t dbmkey;
     427    apr_datum_t dbmval;
     428    mgs_handle_t *ctxt = baton;
     429    apr_status_t rv;
     430    apr_time_t expiry;
     431    apr_pool_t *spool;
     432
     433    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
     434        return -1;
     435
     436    /* we expire dbm only on every store
     437     */
     438    dbm_cache_expire(ctxt);
     439
     440    apr_pool_create(&spool, ctxt->c->pool);
     441
     442    /* create DBM value */
     443    dbmval.dsize = data.size + sizeof (apr_time_t);
     444    dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize);
     445
     446    expiry = apr_time_now() + ctxt->sc->cache_timeout;
     447
     448    memcpy((char *) dbmval.dptr, &expiry, sizeof (apr_time_t));
     449    memcpy((char *) dbmval.dptr + sizeof (apr_time_t),
     450            data.data, data.size);
     451
     452    rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
     453            ctxt->sc->cache_config, APR_DBM_RWCREATE,
     454            SSL_DBM_FILE_MODE, ctxt->c->pool);
     455    if (rv != APR_SUCCESS) {
     456        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
     457                ctxt->c->base_server,
     458                "[gnutls_cache] error opening cache '%s'",
     459                ctxt->sc->cache_config);
     460        apr_pool_destroy(spool);
     461        return -1;
     462    }
     463
     464    rv = apr_dbm_store(dbm, dbmkey, dbmval);
     465
     466    if (rv != APR_SUCCESS) {
     467        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
     468                ctxt->c->base_server,
     469                "[gnutls_cache] error storing in cache '%s'",
     470                ctxt->sc->cache_config);
     471        apr_dbm_close(dbm);
     472        apr_pool_destroy(spool);
     473        return -1;
     474    }
     475
     476    apr_dbm_close(dbm);
     477
     478    apr_pool_destroy(spool);
     479
     480    return 0;
     481}
     482
     483static int dbm_cache_delete(void *baton, gnutls_datum_t key) {
     484    apr_dbm_t *dbm;
     485    apr_datum_t dbmkey;
     486    mgs_handle_t *ctxt = baton;
     487    apr_status_t rv;
     488
     489    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
     490        return -1;
     491
     492    rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
     493            ctxt->sc->cache_config, APR_DBM_RWCREATE,
     494            SSL_DBM_FILE_MODE, ctxt->c->pool);
     495    if (rv != APR_SUCCESS) {
     496        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
     497                ctxt->c->base_server,
     498                "[gnutls_cache] error opening cache '%s'",
     499                ctxt->sc->cache_config);
     500        return -1;
     501    }
     502
     503    rv = apr_dbm_delete(dbm, dbmkey);
     504
     505    if (rv != APR_SUCCESS) {
     506        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
     507                ctxt->c->base_server,
     508                "[gnutls_cache] error deleting from cache '%s'",
     509                ctxt->sc->cache_config);
     510        apr_dbm_close(dbm);
     511        return -1;
     512    }
     513
     514    apr_dbm_close(dbm);
     515
     516    return 0;
    528517}
    529518
    530519static int dbm_cache_post_config(apr_pool_t * p, server_rec * s,
    531                                  mgs_srvconf_rec * sc)
    532 {
    533         apr_status_t rv;
    534         apr_dbm_t *dbm;
    535         const char *path1;
    536         const char *path2;
    537 
    538         rv = apr_dbm_open_ex(&dbm, db_type(sc), sc->cache_config,
    539                              APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, p);
    540 
    541         if (rv != APR_SUCCESS) {
    542                 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
    543                              "GnuTLS: Cannot create DBM Cache at `%s'",
    544                              sc->cache_config);
    545                 return rv;
    546         }
    547 
    548         apr_dbm_close(dbm);
    549 
    550         apr_dbm_get_usednames_ex(p, db_type(sc), sc->cache_config, &path1,
    551                                  &path2);
    552 
    553         /* The Following Code takes logic directly from mod_ssl's DBM Cache */
     520        mgs_srvconf_rec * sc) {
     521    apr_status_t rv;
     522    apr_dbm_t *dbm;
     523    const char *path1;
     524    const char *path2;
     525
     526    rv = apr_dbm_open_ex(&dbm, db_type(sc), sc->cache_config,
     527            APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, p);
     528
     529    if (rv != APR_SUCCESS) {
     530        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
     531                "GnuTLS: Cannot create DBM Cache at `%s'",
     532                sc->cache_config);
     533        return rv;
     534    }
     535
     536    apr_dbm_close(dbm);
     537
     538    apr_dbm_get_usednames_ex(p, db_type(sc), sc->cache_config, &path1,
     539            &path2);
     540
     541    /* The Following Code takes logic directly from mod_ssl's DBM Cache */
    554542#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
    555         /* Running as Root */
    556         if (path1 && geteuid() == 0) {
    557                 chown(path1, ap_unixd_config.user_id, -1);
    558                 if (path2 != NULL) {
    559                         chown(path2, ap_unixd_config.user_id, -1);
    560                 }
    561         }
     543    /* Running as Root */
     544    if (path1 && geteuid() == 0) {
     545        chown(path1, ap_unixd_config.user_id, -1);
     546        if (path2 != NULL) {
     547            chown(path2, ap_unixd_config.user_id, -1);
     548        }
     549    }
    562550#endif
    563551
    564         return rv;
     552    return rv;
    565553}
    566554
    567555int mgs_cache_post_config(apr_pool_t * p, server_rec * s,
    568                           mgs_srvconf_rec * sc)
    569 {
    570         if (sc->cache_type == mgs_cache_dbm
    571             || sc->cache_type == mgs_cache_gdbm) {
    572                 return dbm_cache_post_config(p, s, sc);
    573         }
    574         return 0;
     556        mgs_srvconf_rec * sc) {
     557    if (sc->cache_type == mgs_cache_dbm
     558            || sc->cache_type == mgs_cache_gdbm) {
     559        return dbm_cache_post_config(p, s, sc);
     560    }
     561    return 0;
    575562}
    576563
    577564int mgs_cache_child_init(apr_pool_t * p, server_rec * s,
    578                          mgs_srvconf_rec * sc)
    579 {
    580         if (sc->cache_type == mgs_cache_dbm
    581             || sc->cache_type == mgs_cache_gdbm) {
    582                 return 0;
    583         }
     565        mgs_srvconf_rec * sc) {
     566    if (sc->cache_type == mgs_cache_dbm
     567            || sc->cache_type == mgs_cache_gdbm) {
     568        return 0;
     569    }
    584570#if HAVE_APR_MEMCACHE
    585         else if (sc->cache_type == mgs_cache_memcache) {
    586                 return mc_cache_child_init(p, s, sc);
    587         }
     571    else if (sc->cache_type == mgs_cache_memcache) {
     572        return mc_cache_child_init(p, s, sc);
     573    }
    588574#endif
    589         return 0;
     575    return 0;
    590576}
    591577
    592578#include <assert.h>
    593579
    594 int mgs_cache_session_init(mgs_handle_t * ctxt)
    595 {
    596         if (ctxt->sc->cache_type == mgs_cache_dbm
    597             || ctxt->sc->cache_type == mgs_cache_gdbm) {
    598                 gnutls_db_set_retrieve_function(ctxt->session,
    599                                                 dbm_cache_fetch);
    600                 gnutls_db_set_remove_function(ctxt->session,
    601                                               dbm_cache_delete);
    602                 gnutls_db_set_store_function(ctxt->session,
    603                                              dbm_cache_store);
    604                 gnutls_db_set_ptr(ctxt->session, ctxt);
    605         }
     580int mgs_cache_session_init(mgs_handle_t * ctxt) {
     581    if (ctxt->sc->cache_type == mgs_cache_dbm
     582            || ctxt->sc->cache_type == mgs_cache_gdbm) {
     583        gnutls_db_set_retrieve_function(ctxt->session,
     584                dbm_cache_fetch);
     585        gnutls_db_set_remove_function(ctxt->session,
     586                dbm_cache_delete);
     587        gnutls_db_set_store_function(ctxt->session,
     588                dbm_cache_store);
     589        gnutls_db_set_ptr(ctxt->session, ctxt);
     590    }
    606591#if HAVE_APR_MEMCACHE
    607         else if (ctxt->sc->cache_type == mgs_cache_memcache) {
    608                 gnutls_db_set_retrieve_function(ctxt->session,
    609                                                 mc_cache_fetch);
    610                 gnutls_db_set_remove_function(ctxt->session,
    611                                               mc_cache_delete);
    612                 gnutls_db_set_store_function(ctxt->session,
    613                                              mc_cache_store);
    614                 gnutls_db_set_ptr(ctxt->session, ctxt);
    615         }
     592    else if (ctxt->sc->cache_type == mgs_cache_memcache) {
     593        gnutls_db_set_retrieve_function(ctxt->session,
     594                mc_cache_fetch);
     595        gnutls_db_set_remove_function(ctxt->session,
     596                mc_cache_delete);
     597        gnutls_db_set_store_function(ctxt->session,
     598                mc_cache_store);
     599        gnutls_db_set_ptr(ctxt->session, ctxt);
     600    }
    616601#endif
    617602
    618         return 0;
    619 }
     603    return 0;
     604}
  • src/gnutls_config.c

    r6223319 re183628  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Copyright 2007 Nikos Mavrogiannopoulos
     3 *  Copyright 2008 Nikos Mavrogiannopoulos
     4 *  Copyright 2011 Dash Shendy
    45 *
    56 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2021
    2122static int load_datum_from_file(apr_pool_t * pool,
    22                                 const char *file, gnutls_datum_t * data)
    23 {
    24         apr_file_t *fp;
    25         apr_finfo_t finfo;
    26         apr_status_t rv;
    27         apr_size_t br = 0;
    28 
    29         rv = apr_file_open(&fp, file, APR_READ | APR_BINARY,
    30                            APR_OS_DEFAULT, pool);
    31         if (rv != APR_SUCCESS) {
    32                 return rv;
    33         }
    34 
    35         rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
    36 
    37         if (rv != APR_SUCCESS) {
    38                 return rv;
    39         }
    40 
    41         data->data = apr_palloc(pool, finfo.size + 1);
    42         rv = apr_file_read_full(fp, data->data, finfo.size, &br);
    43 
    44         if (rv != APR_SUCCESS) {
    45                 return rv;
    46         }
    47         apr_file_close(fp);
    48 
    49         data->data[br] = '\0';
    50         data->size = br;
    51 
    52         return 0;
     23        const char *file, gnutls_datum_t * data) {
     24    apr_file_t *fp;
     25    apr_finfo_t finfo;
     26    apr_status_t rv;
     27    apr_size_t br = 0;
     28
     29    rv = apr_file_open(&fp, file, APR_READ | APR_BINARY,
     30            APR_OS_DEFAULT, pool);
     31    if (rv != APR_SUCCESS) {
     32        return rv;
     33    }
     34
     35    rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
     36
     37    if (rv != APR_SUCCESS) {
     38        return rv;
     39    }
     40
     41    data->data = apr_palloc(pool, finfo.size + 1);
     42    rv = apr_file_read_full(fp, data->data, finfo.size, &br);
     43
     44    if (rv != APR_SUCCESS) {
     45        return rv;
     46    }
     47    apr_file_close(fp);
     48
     49    data->data[br] = '\0';
     50    data->size = br;
     51
     52    return 0;
    5353}
    5454
    5555const char *mgs_set_dh_file(cmd_parms * parms, void *dummy,
    56                             const char *arg)
    57 {
    58         int ret;
    59         gnutls_datum_t data;
    60         const char *file;
    61         apr_pool_t *spool;
    62         mgs_srvconf_rec *sc =
    63             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    64                                                      module_config,
    65                                                      &gnutls_module);
    66 
    67         apr_pool_create(&spool, parms->pool);
    68 
    69         file = ap_server_root_relative(spool, arg);
    70 
    71         if (load_datum_from_file(spool, file, &data) != 0) {
    72                 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    73                                     "DH params '%s'", file);
    74         }
    75 
    76         ret = gnutls_dh_params_init(&sc->dh_params);
    77         if (ret < 0) {
    78                 return apr_psprintf(parms->pool,
    79                                     "GnuTLS: Failed to initialize"
    80                                     ": (%d) %s", ret,
    81                                     gnutls_strerror(ret));
    82         }
    83 
    84         ret =
    85             gnutls_dh_params_import_pkcs3(sc->dh_params, &data,
    86                                           GNUTLS_X509_FMT_PEM);
    87         if (ret < 0) {
    88                 return apr_psprintf(parms->pool,
    89                                     "GnuTLS: Failed to Import "
    90                                     "DH params '%s': (%d) %s", file, ret,
    91                                     gnutls_strerror(ret));
    92         }
    93 
    94         apr_pool_destroy(spool);
    95 
    96         return NULL;
     56        const char *arg) {
     57    int ret;
     58    gnutls_datum_t data;
     59    const char *file;
     60    apr_pool_t *spool;
     61    mgs_srvconf_rec *sc =
     62            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     63            module_config,
     64            &gnutls_module);
     65
     66    apr_pool_create(&spool, parms->pool);
     67
     68    file = ap_server_root_relative(spool, arg);
     69
     70    if (load_datum_from_file(spool, file, &data) != 0) {
     71        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     72                "DH params '%s'", file);
     73    }
     74
     75    ret = gnutls_dh_params_init(&sc->dh_params);
     76    if (ret < 0) {
     77        return apr_psprintf(parms->pool,
     78                "GnuTLS: Failed to initialize"
     79                ": (%d) %s", ret,
     80                gnutls_strerror(ret));
     81    }
     82
     83    ret =
     84            gnutls_dh_params_import_pkcs3(sc->dh_params, &data,
     85            GNUTLS_X509_FMT_PEM);
     86    if (ret < 0) {
     87        return apr_psprintf(parms->pool,
     88                "GnuTLS: Failed to Import "
     89                "DH params '%s': (%d) %s", file, ret,
     90                gnutls_strerror(ret));
     91    }
     92
     93    apr_pool_destroy(spool);
     94
     95    return NULL;
    9796}
    9897
    9998const char *mgs_set_rsa_export_file(cmd_parms * parms, void *dummy,
    100                                     const char *arg)
    101 {
    102         int ret;
    103         gnutls_datum_t data;
    104         const char *file;
    105         apr_pool_t *spool;
    106         mgs_srvconf_rec *sc =
    107             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    108                                                      module_config,
    109                                                      &gnutls_module);
    110 
    111         apr_pool_create(&spool, parms->pool);
    112 
    113         file = ap_server_root_relative(spool, arg);
    114 
    115         if (load_datum_from_file(spool, file, &data) != 0) {
    116                 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    117                                     "RSA params '%s'", file);
    118         }
    119 
    120         ret = gnutls_rsa_params_init(&sc->rsa_params);
    121         if (ret < 0) {
    122                 return apr_psprintf(parms->pool,
    123                                     "GnuTLS: Failed to initialize"
    124                                     ": (%d) %s", ret,
    125                                     gnutls_strerror(ret));
    126         }
    127 
    128         ret =
    129             gnutls_rsa_params_import_pkcs1(sc->rsa_params, &data,
    130                                            GNUTLS_X509_FMT_PEM);
    131         if (ret != 0) {
    132                 return apr_psprintf(parms->pool,
    133                                     "GnuTLS: Failed to Import "
    134                                     "RSA params '%s': (%d) %s", file, ret,
    135                                     gnutls_strerror(ret));
    136         }
    137 
    138         apr_pool_destroy(spool);
    139         return NULL;
    140 }
    141 
     99        const char *arg) {
     100    int ret;
     101    gnutls_datum_t data;
     102    const char *file;
     103    apr_pool_t *spool;
     104    mgs_srvconf_rec *sc =
     105            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     106            module_config,
     107            &gnutls_module);
     108
     109    apr_pool_create(&spool, parms->pool);
     110
     111    file = ap_server_root_relative(spool, arg);
     112
     113    if (load_datum_from_file(spool, file, &data) != 0) {
     114        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     115                "RSA params '%s'", file);
     116    }
     117
     118    ret = gnutls_rsa_params_init(&sc->rsa_params);
     119    if (ret < 0) {
     120        return apr_psprintf(parms->pool,
     121                "GnuTLS: Failed to initialize"
     122                ": (%d) %s", ret,
     123                gnutls_strerror(ret));
     124    }
     125
     126    ret =
     127            gnutls_rsa_params_import_pkcs1(sc->rsa_params, &data,
     128            GNUTLS_X509_FMT_PEM);
     129    if (ret != 0) {
     130        return apr_psprintf(parms->pool,
     131                "GnuTLS: Failed to Import "
     132                "RSA params '%s': (%d) %s", file, ret,
     133                gnutls_strerror(ret));
     134    }
     135
     136    apr_pool_destroy(spool);
     137    return NULL;
     138}
    142139
    143140const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
    144                               const char *arg)
    145 {
    146         int ret;
    147         gnutls_datum_t data;
    148         const char *file;
    149         apr_pool_t *spool;
    150         mgs_srvconf_rec *sc =
    151             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    152                                                      module_config,
    153                                                      &gnutls_module);
    154         apr_pool_create(&spool, parms->pool);
    155 
    156         file = ap_server_root_relative(spool, arg);
    157 
    158         if (load_datum_from_file(spool, file, &data) != 0) {
    159                 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    160                                     "Certificate '%s'", file);
    161         }
    162 
    163         sc->certs_x509_num = MAX_CHAIN_SIZE;
    164         ret =
    165             gnutls_x509_crt_list_import(sc->certs_x509,
    166                                         &sc->certs_x509_num, &data,
    167                                         GNUTLS_X509_FMT_PEM, 0);
    168         if (ret < 0) {
    169                 return apr_psprintf(parms->pool,
    170                                     "GnuTLS: Failed to Import "
    171                                     "Certificate '%s': (%d) %s", file, ret,
    172                                     gnutls_strerror(ret));
    173         }
    174 
    175         apr_pool_destroy(spool);
    176         return NULL;
     141        const char *arg) {
     142    int ret;
     143    gnutls_datum_t data;
     144    const char *file;
     145    apr_pool_t *spool;
     146    mgs_srvconf_rec *sc =
     147            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     148            module_config,
     149            &gnutls_module);
     150    apr_pool_create(&spool, parms->pool);
     151
     152    file = ap_server_root_relative(spool, arg);
     153
     154    if (load_datum_from_file(spool, file, &data) != 0) {
     155        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     156                "Certificate '%s'", file);
     157    }
     158
     159    sc->certs_x509_num = MAX_CHAIN_SIZE;
     160    ret =
     161            gnutls_x509_crt_list_import(sc->certs_x509,
     162            &sc->certs_x509_num, &data,
     163            GNUTLS_X509_FMT_PEM, 0);
     164    if (ret < 0) {
     165        return apr_psprintf(parms->pool,
     166                "GnuTLS: Failed to Import "
     167                "Certificate '%s': (%d) %s", file, ret,
     168                gnutls_strerror(ret));
     169    }
     170
     171    apr_pool_destroy(spool);
     172    return NULL;
    177173}
    178174
    179175const char *mgs_set_key_file(cmd_parms * parms, void *dummy,
    180                              const char *arg)
    181 {
    182         int ret;
    183         gnutls_datum_t data;
    184         const char *file;
    185         apr_pool_t *spool;
    186         mgs_srvconf_rec *sc =
    187             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    188                                                      module_config,
    189                                                      &gnutls_module);
    190         apr_pool_create(&spool, parms->pool);
    191 
    192         file = ap_server_root_relative(spool, arg);
    193 
    194         if (load_datum_from_file(spool, file, &data) != 0) {
    195                 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    196                                     "Private Key '%s'", file);
    197         }
    198 
    199         ret = gnutls_x509_privkey_init(&sc->privkey_x509);
    200         if (ret < 0) {
    201                 return apr_psprintf(parms->pool,
    202                                     "GnuTLS: Failed to initialize"
    203                                     ": (%d) %s", ret,
    204                                     gnutls_strerror(ret));
    205         }
    206 
    207         ret =
    208             gnutls_x509_privkey_import(sc->privkey_x509, &data,
    209                                        GNUTLS_X509_FMT_PEM);
    210 
    211         if (ret < 0)
    212                 ret =
    213                     gnutls_x509_privkey_import_pkcs8(sc->privkey_x509,
    214                                                      &data,
    215                                                      GNUTLS_X509_FMT_PEM,
    216                                                      NULL,
    217                                                      GNUTLS_PKCS_PLAIN);
    218 
    219         if (ret < 0) {
    220                 return apr_psprintf(parms->pool,
    221                                     "GnuTLS: Failed to Import "
    222                                     "Private Key '%s': (%d) %s", file, ret,
    223                                     gnutls_strerror(ret));
    224         }
    225         apr_pool_destroy(spool);
    226         return NULL;
     176        const char *arg) {
     177    int ret;
     178    gnutls_datum_t data;
     179    const char *file;
     180    apr_pool_t *spool;
     181    mgs_srvconf_rec *sc =
     182            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     183            module_config,
     184            &gnutls_module);
     185    apr_pool_create(&spool, parms->pool);
     186
     187    file = ap_server_root_relative(spool, arg);
     188
     189    if (load_datum_from_file(spool, file, &data) != 0) {
     190        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     191                "Private Key '%s'", file);
     192    }
     193
     194    ret = gnutls_x509_privkey_init(&sc->privkey_x509);
     195    if (ret < 0) {
     196        return apr_psprintf(parms->pool,
     197                "GnuTLS: Failed to initialize"
     198                ": (%d) %s", ret,
     199                gnutls_strerror(ret));
     200    }
     201
     202    ret =
     203            gnutls_x509_privkey_import(sc->privkey_x509, &data,
     204            GNUTLS_X509_FMT_PEM);
     205
     206    if (ret < 0)
     207        ret =
     208            gnutls_x509_privkey_import_pkcs8(sc->privkey_x509,
     209            &data,
     210            GNUTLS_X509_FMT_PEM,
     211            NULL,
     212            GNUTLS_PKCS_PLAIN);
     213
     214    if (ret < 0) {
     215        return apr_psprintf(parms->pool,
     216                "GnuTLS: Failed to Import "
     217                "Private Key '%s': (%d) %s", file, ret,
     218                gnutls_strerror(ret));
     219    }
     220    apr_pool_destroy(spool);
     221    return NULL;
    227222}
    228223
    229224const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy,
    230                                  const char *arg)
    231 {
    232         int ret;
    233         gnutls_datum_t data;
    234         const char *file;
    235         apr_pool_t *spool;
    236         mgs_srvconf_rec *sc =
    237             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    238                                                      module_config,
    239                                                      &gnutls_module);
    240         apr_pool_create(&spool, parms->pool);
    241 
    242         file = ap_server_root_relative(spool, arg);
    243 
    244         if (load_datum_from_file(spool, file, &data) != 0) {
    245                 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    246                                     "Certificate '%s'", file);
    247         }
    248 
    249         ret = gnutls_openpgp_crt_init(&sc->cert_pgp);
    250         if (ret < 0) {
    251                 return apr_psprintf(parms->pool, "GnuTLS: Failed to Init "
    252                                     "PGP Certificate: (%d) %s", ret,
    253                                     gnutls_strerror(ret));
    254         }
    255 
    256         ret =
    257             gnutls_openpgp_crt_import(sc->cert_pgp, &data,
    258                                       GNUTLS_OPENPGP_FMT_BASE64);
    259         if (ret < 0) {
    260                 return apr_psprintf(parms->pool,
    261                                     "GnuTLS: Failed to Import "
    262                                     "PGP Certificate '%s': (%d) %s", file,
    263                                     ret, gnutls_strerror(ret));
    264         }
    265 
    266         apr_pool_destroy(spool);
    267         return NULL;
     225        const char *arg) {
     226    int ret;
     227    gnutls_datum_t data;
     228    const char *file;
     229    apr_pool_t *spool;
     230    mgs_srvconf_rec *sc =
     231            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     232            module_config,
     233            &gnutls_module);
     234    apr_pool_create(&spool, parms->pool);
     235
     236    file = ap_server_root_relative(spool, arg);
     237
     238    if (load_datum_from_file(spool, file, &data) != 0) {
     239        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     240                "Certificate '%s'", file);
     241    }
     242
     243    ret = gnutls_openpgp_crt_init(&sc->cert_pgp);
     244    if (ret < 0) {
     245        return apr_psprintf(parms->pool, "GnuTLS: Failed to Init "
     246                "PGP Certificate: (%d) %s", ret,
     247                gnutls_strerror(ret));
     248    }
     249
     250    ret =
     251            gnutls_openpgp_crt_import(sc->cert_pgp, &data,
     252            GNUTLS_OPENPGP_FMT_BASE64);
     253    if (ret < 0) {
     254        return apr_psprintf(parms->pool,
     255                "GnuTLS: Failed to Import "
     256                "PGP Certificate '%s': (%d) %s", file,
     257                ret, gnutls_strerror(ret));
     258    }
     259
     260    apr_pool_destroy(spool);
     261    return NULL;
    268262}
    269263
    270264const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy,
    271                                 const char *arg)
    272 {
    273         int ret;
    274         gnutls_datum_t data;
    275         const char *file;
    276         apr_pool_t *spool;
    277         mgs_srvconf_rec *sc =
    278             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    279                                                      module_config,
    280                                                      &gnutls_module);
    281         apr_pool_create(&spool, parms->pool);
    282 
    283         file = ap_server_root_relative(spool, arg);
    284 
    285         if (load_datum_from_file(spool, file, &data) != 0) {
    286                 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    287                                     "Private Key '%s'", file);
    288         }
    289 
    290         ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp);
    291         if (ret < 0) {
    292                 return apr_psprintf(parms->pool,
    293                                     "GnuTLS: Failed to initialize"
    294                                     ": (%d) %s", ret,
    295                                     gnutls_strerror(ret));
    296         }
    297 
    298         ret =
    299             gnutls_openpgp_privkey_import(sc->privkey_pgp, &data,
    300                                           GNUTLS_OPENPGP_FMT_BASE64, NULL,
    301                                           0);
    302         if (ret != 0) {
    303                 return apr_psprintf(parms->pool,
    304                                     "GnuTLS: Failed to Import "
    305                                     "PGP Private Key '%s': (%d) %s", file,
    306                                     ret, gnutls_strerror(ret));
    307         }
    308         apr_pool_destroy(spool);
    309         return NULL;
     265        const char *arg) {
     266    int ret;
     267    gnutls_datum_t data;
     268    const char *file;
     269    apr_pool_t *spool;
     270    mgs_srvconf_rec *sc =
     271            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     272            module_config,
     273            &gnutls_module);
     274    apr_pool_create(&spool, parms->pool);
     275
     276    file = ap_server_root_relative(spool, arg);
     277
     278    if (load_datum_from_file(spool, file, &data) != 0) {
     279        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     280                "Private Key '%s'", file);
     281    }
     282
     283    ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp);
     284    if (ret < 0) {
     285        return apr_psprintf(parms->pool,
     286                "GnuTLS: Failed to initialize"
     287                ": (%d) %s", ret,
     288                gnutls_strerror(ret));
     289    }
     290
     291    ret =
     292            gnutls_openpgp_privkey_import(sc->privkey_pgp, &data,
     293            GNUTLS_OPENPGP_FMT_BASE64, NULL,
     294            0);
     295    if (ret != 0) {
     296        return apr_psprintf(parms->pool,
     297                "GnuTLS: Failed to Import "
     298                "PGP Private Key '%s': (%d) %s", file,
     299                ret, gnutls_strerror(ret));
     300    }
     301    apr_pool_destroy(spool);
     302    return NULL;
    310303}
    311304
    312305const char *mgs_set_tickets(cmd_parms * parms, void *dummy,
    313                             const char *arg)
    314 {
    315         mgs_srvconf_rec *sc =
    316             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    317                                                      module_config,
    318                                                      &gnutls_module);
    319 
    320         sc->tickets = 0;
    321         if (strcasecmp("on", arg) == 0) {
    322                 sc->tickets = 1;
    323         }
    324 
    325         return NULL;
     306        const char *arg) {
     307    mgs_srvconf_rec *sc =
     308            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     309            module_config,
     310            &gnutls_module);
     311
     312    sc->tickets = 0;
     313    if (strcasecmp("on", arg) == 0) {
     314        sc->tickets = 1;
     315    }
     316
     317    return NULL;
    326318}
    327319
     
    330322
    331323const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy,
    332                                      const char *arg)
    333 {
    334         mgs_srvconf_rec *sc =
    335             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    336                                                      module_config,
    337                                                      &gnutls_module);
    338 
    339         sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg);
    340 
    341         return NULL;
     324        const char *arg) {
     325    mgs_srvconf_rec *sc =
     326            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     327            module_config,
     328            &gnutls_module);
     329
     330    sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg);
     331
     332    return NULL;
    342333}
    343334
    344335const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy,
    345                                           const char *arg)
    346 {
    347         mgs_srvconf_rec *sc =
    348             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    349                                                      module_config,
    350                                                      &gnutls_module);
    351 
    352         sc->srp_tpasswd_conf_file =
    353             ap_server_root_relative(parms->pool, arg);
    354 
    355         return NULL;
     336        const char *arg) {
     337    mgs_srvconf_rec *sc =
     338            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     339            module_config,
     340            &gnutls_module);
     341
     342    sc->srp_tpasswd_conf_file =
     343            ap_server_root_relative(parms->pool, arg);
     344
     345    return NULL;
    356346}
    357347
     
    359349
    360350const char *mgs_set_cache(cmd_parms * parms, void *dummy,
    361                           const char *type, const char *arg)
    362 {
    363         const char *err;
    364         mgs_srvconf_rec *sc =
    365             ap_get_module_config(parms->server->module_config,
    366                                  &gnutls_module);
    367         if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
    368                 return err;
    369         }
    370 
    371         if (strcasecmp("none", type) == 0) {
    372                 sc->cache_type = mgs_cache_none;
    373                 sc->cache_config = NULL;
    374                 return NULL;
    375         } else if (strcasecmp("dbm", type) == 0) {
    376                 sc->cache_type = mgs_cache_dbm;
    377         } else if (strcasecmp("gdbm", type) == 0) {
    378                 sc->cache_type = mgs_cache_gdbm;
    379         }
     351        const char *type, const char *arg) {
     352    const char *err;
     353    mgs_srvconf_rec *sc =
     354            ap_get_module_config(parms->server->module_config,
     355            &gnutls_module);
     356    if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
     357        return err;
     358    }
     359
     360    if (strcasecmp("none", type) == 0) {
     361        sc->cache_type = mgs_cache_none;
     362        sc->cache_config = NULL;
     363        return NULL;
     364    } else if (strcasecmp("dbm", type) == 0) {
     365        sc->cache_type = mgs_cache_dbm;
     366    } else if (strcasecmp("gdbm", type) == 0) {
     367        sc->cache_type = mgs_cache_gdbm;
     368    }
    380369#if HAVE_APR_MEMCACHE
    381         else if (strcasecmp("memcache", type) == 0) {
    382                 sc->cache_type = mgs_cache_memcache;
    383         }
     370    else if (strcasecmp("memcache", type) == 0) {
     371        sc->cache_type = mgs_cache_memcache;
     372    }
    384373#endif
    385         else {
    386                 return "Invalid Type for GnuTLSCache!";
    387         }
    388        
    389         if (arg == NULL)
    390                 return "Invalid argument 2 for GnuTLSCache!";
    391 
    392         if (sc->cache_type == mgs_cache_dbm
    393             || sc->cache_type == mgs_cache_gdbm) {
    394                 sc->cache_config =
    395                     ap_server_root_relative(parms->pool, arg);
    396         } else {
    397                 sc->cache_config = apr_pstrdup(parms->pool, arg);
    398         }
    399 
    400         return NULL;
     374    else {
     375        return "Invalid Type for GnuTLSCache!";
     376    }
     377
     378    if (arg == NULL)
     379        return "Invalid argument 2 for GnuTLSCache!";
     380
     381    if (sc->cache_type == mgs_cache_dbm
     382            || sc->cache_type == mgs_cache_gdbm) {
     383        sc->cache_config =
     384                ap_server_root_relative(parms->pool, arg);
     385    } else {
     386        sc->cache_config = apr_pstrdup(parms->pool, arg);
     387    }
     388
     389    return NULL;
    401390}
    402391
    403392const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy,
    404                                   const char *arg)
    405 {
    406         int argint;
    407         mgs_srvconf_rec *sc =
    408             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    409                                                      module_config,
    410                                                      &gnutls_module);
    411 
    412         argint = atoi(arg);
    413 
    414         if (argint < 0) {
    415                 return "GnuTLSCacheTimeout: Invalid argument";
    416         } else if (argint == 0) {
    417                 sc->cache_timeout = 0;
    418         } else {
    419                 sc->cache_timeout = apr_time_from_sec(argint);
    420         }
    421 
    422         return NULL;
     393        const char *arg) {
     394    int argint;
     395    mgs_srvconf_rec *sc =
     396            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     397            module_config,
     398            &gnutls_module);
     399
     400    argint = atoi(arg);
     401
     402    if (argint < 0) {
     403        return "GnuTLSCacheTimeout: Invalid argument";
     404    } else if (argint == 0) {
     405        sc->cache_timeout = 0;
     406    } else {
     407        sc->cache_timeout = apr_time_from_sec(argint);
     408    }
     409
     410    return NULL;
    423411}
    424412
    425413const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
    426                                   const char *arg)
    427 {
    428         int mode;
    429 
    430         if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) {
    431                 mode = GNUTLS_CERT_IGNORE;
    432         } else if (strcasecmp("optional", arg) == 0
    433                    || strcasecmp("request", arg) == 0) {
    434                 mode = GNUTLS_CERT_REQUEST;
    435         } else if (strcasecmp("require", arg) == 0) {
    436                 mode = GNUTLS_CERT_REQUIRE;
    437         } else {
    438                 return "GnuTLSClientVerify: Invalid argument";
    439         }
    440 
    441         /* This was set from a directory context */
    442         if (parms->path) {
    443                 mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy;
    444                 dc->client_verify_mode = mode;
    445         } else {
    446                 mgs_srvconf_rec *sc =
    447                     (mgs_srvconf_rec *)
    448                     ap_get_module_config(parms->server->module_config,
    449                                          &gnutls_module);
    450                 sc->client_verify_mode = mode;
    451         }
    452 
    453         return NULL;
     414        const char *arg) {
     415    int mode;
     416
     417    if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) {
     418        mode = GNUTLS_CERT_IGNORE;
     419    } else if (strcasecmp("optional", arg) == 0
     420            || strcasecmp("request", arg) == 0) {
     421        mode = GNUTLS_CERT_REQUEST;
     422    } else if (strcasecmp("require", arg) == 0) {
     423        mode = GNUTLS_CERT_REQUIRE;
     424    } else {
     425        return "GnuTLSClientVerify: Invalid argument";
     426    }
     427
     428    /* This was set from a directory context */
     429    if (parms->path) {
     430        mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy;
     431        dc->client_verify_mode = mode;
     432    } else {
     433        mgs_srvconf_rec *sc =
     434                (mgs_srvconf_rec *)
     435                ap_get_module_config(parms->server->module_config,
     436                &gnutls_module);
     437        sc->client_verify_mode = mode;
     438    }
     439
     440    return NULL;
    454441}
    455442
    456443#define INIT_CA_SIZE 128
     444
    457445const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
    458                                    const char *arg)
    459 {
    460         int rv;
    461         const char *file;
    462         apr_pool_t *spool;
    463         gnutls_datum_t data;
    464 
    465         mgs_srvconf_rec *sc =
    466             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    467                                                      module_config,
    468                                                      &gnutls_module);
    469         apr_pool_create(&spool, parms->pool);
    470 
    471         file = ap_server_root_relative(spool, arg);
    472 
    473         if (load_datum_from_file(spool, file, &data) != 0) {
    474                 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    475                                     "Client CA File '%s'", file);
    476         }
    477 
    478         sc->ca_list_size = INIT_CA_SIZE;
    479         sc->ca_list = malloc(sc->ca_list_size * sizeof(*sc->ca_list));
    480         if (sc->ca_list == NULL) {
    481                 return apr_psprintf(parms->pool,
    482                                     "mod_gnutls: Memory allocation error");
    483         }
    484 
    485         rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size,
    486                                          &data, GNUTLS_X509_FMT_PEM,
    487                                          GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
    488         if (rv < 0 && rv != GNUTLS_E_SHORT_MEMORY_BUFFER) {
    489                 return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
    490                                     "Client CA File '%s': (%d) %s", file,
    491                                     rv, gnutls_strerror(rv));
    492         }
    493 
    494         if (INIT_CA_SIZE < sc->ca_list_size) {
    495                 sc->ca_list =
    496                     realloc(sc->ca_list,
    497                             sc->ca_list_size * sizeof(*sc->ca_list));
    498                 if (sc->ca_list == NULL) {
    499                         return apr_psprintf(parms->pool,
    500                                             "mod_gnutls: Memory allocation error");
    501                 }
    502 
    503                 /* re-read */
    504                 rv = gnutls_x509_crt_list_import(sc->ca_list,
    505                                                  &sc->ca_list_size, &data,
    506                                                  GNUTLS_X509_FMT_PEM, 0);
    507 
    508                 if (rv < 0) {
    509                         return apr_psprintf(parms->pool,
    510                                             "GnuTLS: Failed to load "
    511                                             "Client CA File '%s': (%d) %s",
    512                                             file, rv, gnutls_strerror(rv));
    513                 }
    514         }
    515 
    516         apr_pool_destroy(spool);
    517         return NULL;
     446        const char *arg) {
     447    int rv;
     448    const char *file;
     449    apr_pool_t *spool;
     450    gnutls_datum_t data;
     451
     452    mgs_srvconf_rec *sc =
     453            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     454            module_config,
     455            &gnutls_module);
     456    apr_pool_create(&spool, parms->pool);
     457
     458    file = ap_server_root_relative(spool, arg);
     459
     460    if (load_datum_from_file(spool, file, &data) != 0) {
     461        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     462                "Client CA File '%s'", file);
     463    }
     464
     465    sc->ca_list_size = INIT_CA_SIZE;
     466    sc->ca_list = malloc(sc->ca_list_size * sizeof (*sc->ca_list));
     467    if (sc->ca_list == NULL) {
     468        return apr_psprintf(parms->pool,
     469                "mod_gnutls: Memory allocation error");
     470    }
     471
     472    rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size,
     473            &data, GNUTLS_X509_FMT_PEM,
     474            GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
     475    if (rv < 0 && rv != GNUTLS_E_SHORT_MEMORY_BUFFER) {
     476        return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
     477                "Client CA File '%s': (%d) %s", file,
     478                rv, gnutls_strerror(rv));
     479    }
     480
     481    if (INIT_CA_SIZE < sc->ca_list_size) {
     482        sc->ca_list =
     483                realloc(sc->ca_list,
     484                sc->ca_list_size * sizeof (*sc->ca_list));
     485        if (sc->ca_list == NULL) {
     486            return apr_psprintf(parms->pool,
     487                    "mod_gnutls: Memory allocation error");
     488        }
     489
     490        /* re-read */
     491        rv = gnutls_x509_crt_list_import(sc->ca_list,
     492                &sc->ca_list_size, &data,
     493                GNUTLS_X509_FMT_PEM, 0);
     494
     495        if (rv < 0) {
     496            return apr_psprintf(parms->pool,
     497                    "GnuTLS: Failed to load "
     498                    "Client CA File '%s': (%d) %s",
     499                    file, rv, gnutls_strerror(rv));
     500        }
     501    }
     502
     503    apr_pool_destroy(spool);
     504    return NULL;
    518505}
    519506
    520507const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
    521                                  const char *arg)
    522 {
    523         int rv;
    524         const char *file;
    525         apr_pool_t *spool;
    526         gnutls_datum_t data;
    527 
    528         mgs_srvconf_rec *sc =
    529             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    530                                                      module_config,
    531                                                      &gnutls_module);
    532         apr_pool_create(&spool, parms->pool);
    533 
    534         file = ap_server_root_relative(spool, arg);
    535 
    536         if (load_datum_from_file(spool, file, &data) != 0) {
    537                 return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    538                                     "Keyring File '%s'", file);
    539         }
    540 
    541         rv = gnutls_openpgp_keyring_init(&sc->pgp_list);
    542         if (rv < 0) {
    543                 return apr_psprintf(parms->pool,
    544                                     "GnuTLS: Failed to initialize"
    545                                     "keyring: (%d) %s", rv,
    546                                     gnutls_strerror(rv));
    547         }
    548 
    549         rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data,
    550                                            GNUTLS_OPENPGP_FMT_BASE64);
    551         if (rv < 0) {
    552                 return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
    553                                     "Keyring File '%s': (%d) %s", file, rv,
    554                                     gnutls_strerror(rv));
    555         }
    556 
    557         apr_pool_destroy(spool);
    558         return NULL;
     508        const char *arg) {
     509    int rv;
     510    const char *file;
     511    apr_pool_t *spool;
     512    gnutls_datum_t data;
     513
     514    mgs_srvconf_rec *sc =
     515            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     516            module_config,
     517            &gnutls_module);
     518    apr_pool_create(&spool, parms->pool);
     519
     520    file = ap_server_root_relative(spool, arg);
     521
     522    if (load_datum_from_file(spool, file, &data) != 0) {
     523        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     524                "Keyring File '%s'", file);
     525    }
     526
     527    rv = gnutls_openpgp_keyring_init(&sc->pgp_list);
     528    if (rv < 0) {
     529        return apr_psprintf(parms->pool,
     530                "GnuTLS: Failed to initialize"
     531                "keyring: (%d) %s", rv,
     532                gnutls_strerror(rv));
     533    }
     534
     535    rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data,
     536            GNUTLS_OPENPGP_FMT_BASE64);
     537    if (rv < 0) {
     538        return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
     539                "Keyring File '%s': (%d) %s", file, rv,
     540                gnutls_strerror(rv));
     541    }
     542
     543    apr_pool_destroy(spool);
     544    return NULL;
    559545}
    560546
    561547const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
    562                             const char *arg)
    563 {
    564         mgs_srvconf_rec *sc =
    565             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    566                                                      module_config,
    567                                                      &gnutls_module);
    568         if (!strcasecmp(arg, "On")) {
    569                 sc->enabled = GNUTLS_ENABLED_TRUE;
    570         } else if (!strcasecmp(arg, "Off")) {
    571                 sc->enabled = GNUTLS_ENABLED_FALSE;
    572         } else {
    573                 return "GnuTLSEnable must be set to 'On' or 'Off'";
    574         }
    575 
    576         return NULL;
     548        const char *arg) {
     549    mgs_srvconf_rec *sc =
     550            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     551            module_config,
     552            &gnutls_module);
     553    if (!strcasecmp(arg, "On")) {
     554        sc->enabled = GNUTLS_ENABLED_TRUE;
     555    } else if (!strcasecmp(arg, "Off")) {
     556        sc->enabled = GNUTLS_ENABLED_FALSE;
     557    } else {
     558        return "GnuTLSEnable must be set to 'On' or 'Off'";
     559    }
     560
     561    return NULL;
    577562}
    578563
    579564const char *mgs_set_export_certificates_enabled(cmd_parms * parms,
    580                                                 void *dummy,
    581                                                 const char *arg)
    582 {
    583         mgs_srvconf_rec *sc =
    584             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    585                                                      module_config,
    586                                                      &gnutls_module);
    587         if (!strcasecmp(arg, "On")) {
    588                 sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE;
    589         } else if (!strcasecmp(arg, "Off")) {
    590                 sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE;
    591         } else {
    592                 return
    593                     "GnuTLSExportCertificates must be set to 'On' or 'Off'";
    594         }
    595 
    596         return NULL;
    597 }
    598 
     565        void *dummy,
     566        const char *arg) {
     567    mgs_srvconf_rec *sc =
     568            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     569            module_config,
     570            &gnutls_module);
     571    if (!strcasecmp(arg, "On")) {
     572        sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE;
     573    } else if (!strcasecmp(arg, "Off")) {
     574        sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE;
     575    } else {
     576        return
     577        "GnuTLSExportCertificates must be set to 'On' or 'Off'";
     578    }
     579
     580    return NULL;
     581}
    599582
    600583const char *mgs_set_priorities(cmd_parms * parms, void *dummy,
    601                                const char *arg)
    602 {
    603         int ret;
    604         const char *err;
    605         mgs_srvconf_rec *sc =
    606             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    607                                                      module_config,
    608                                                      &gnutls_module);
    609 
    610 
    611         ret = gnutls_priority_init(&sc->priorities, arg, &err);
    612         if (ret < 0) {
    613                 if (ret == GNUTLS_E_INVALID_REQUEST)
    614                         return apr_psprintf(parms->pool,
    615                                             "GnuTLS: Syntax error parsing priorities string at: %s",
    616                                             err);
    617                 return "Error setting priorities";
    618         }
    619 
    620         return NULL;
    621 }
    622 
    623 void *mgs_config_server_create(apr_pool_t * p, server_rec * s)
    624 {
    625         mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
    626         int ret;
    627 
    628         sc->enabled = GNUTLS_ENABLED_FALSE;
    629 
    630         ret = gnutls_certificate_allocate_credentials(&sc->certs);
    631         if (ret < 0) {
    632                 return apr_psprintf(p, "GnuTLS: Failed to initialize"
    633                                     ": (%d) %s", ret,
    634                                     gnutls_strerror(ret));
    635         }
    636 
    637         ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds);
    638         if (ret < 0) {
    639                 return apr_psprintf(p, "GnuTLS: Failed to initialize"
    640                                     ": (%d) %s", ret,
    641                                     gnutls_strerror(ret));
    642         }
     584        const char *arg) {
     585    int ret;
     586    const char *err;
     587    mgs_srvconf_rec *sc =
     588            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     589            module_config,
     590            &gnutls_module);
     591
     592
     593    ret = gnutls_priority_init(&sc->priorities, arg, &err);
     594    if (ret < 0) {
     595        if (ret == GNUTLS_E_INVALID_REQUEST)
     596            return apr_psprintf(parms->pool,
     597                "GnuTLS: Syntax error parsing priorities string at: %s",
     598                err);
     599        return "Error setting priorities";
     600    }
     601
     602    return NULL;
     603}
     604
     605void *mgs_config_server_create(apr_pool_t * p, server_rec * s) {
     606    mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof (*sc));
     607    int ret;
     608
     609    sc->enabled = GNUTLS_ENABLED_FALSE;
     610
     611    ret = gnutls_certificate_allocate_credentials(&sc->certs);
     612    if (ret < 0) {
     613        return apr_psprintf(p, "GnuTLS: Failed to initialize"
     614                ": (%d) %s", ret,
     615                gnutls_strerror(ret));
     616    }
     617
     618    ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds);
     619    if (ret < 0) {
     620        return apr_psprintf(p, "GnuTLS: Failed to initialize"
     621                ": (%d) %s", ret,
     622                gnutls_strerror(ret));
     623    }
    643624#ifdef ENABLE_SRP
    644         ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds);
    645         if (ret < 0) {
    646                 return apr_psprintf(p, "GnuTLS: Failed to initialize"
    647                                     ": (%d) %s", ret,
    648                                     gnutls_strerror(ret));
    649         }
    650 
    651         sc->srp_tpasswd_conf_file = NULL;
    652         sc->srp_tpasswd_file = NULL;
     625    ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds);
     626    if (ret < 0) {
     627        return apr_psprintf(p, "GnuTLS: Failed to initialize"
     628                ": (%d) %s", ret,
     629                gnutls_strerror(ret));
     630    }
     631
     632    sc->srp_tpasswd_conf_file = NULL;
     633    sc->srp_tpasswd_file = NULL;
    653634#endif
    654635
    655         sc->privkey_x509 = NULL;
    656         memset(sc->certs_x509, 0, sizeof(sc->certs_x509));
    657         sc->certs_x509_num = 0;
    658         sc->cache_timeout = apr_time_from_sec(300);
    659         sc->cache_type = mgs_cache_none;
    660         sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache");
    661         sc->tickets = 1;        /* by default enable session tickets */
    662 
    663         sc->client_verify_mode = GNUTLS_CERT_IGNORE;
    664 
    665         return sc;
    666 }
    667 
    668 void *mgs_config_dir_merge(apr_pool_t * p, void *basev, void *addv)
    669 {
    670         mgs_dirconf_rec *new;
    671 /*    mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */
    672         mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv;
    673 
    674         new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec));
    675         new->client_verify_mode = add->client_verify_mode;
    676         return new;
    677 }
    678 
    679 void *mgs_config_dir_create(apr_pool_t * p, char *dir)
    680 {
    681         mgs_dirconf_rec *dc = apr_palloc(p, sizeof(*dc));
    682         dc->client_verify_mode = -1;
    683         return dc;
    684 }
     636    sc->privkey_x509 = NULL;
     637    memset(sc->certs_x509, 0, sizeof (sc->certs_x509));
     638    sc->certs_x509_num = 0;
     639    sc->cache_timeout = apr_time_from_sec(300);
     640    sc->cache_type = mgs_cache_none;
     641    sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache");
     642    sc->tickets = 1; /* by default enable session tickets */
     643
     644    sc->client_verify_mode = GNUTLS_CERT_IGNORE;
     645
     646    return sc;
     647}
     648
     649void *mgs_config_dir_merge(apr_pool_t * p, void *basev, void *addv) {
     650    mgs_dirconf_rec *new;
     651    /*    mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */
     652    mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv;
     653
     654    new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof (mgs_dirconf_rec));
     655    new->client_verify_mode = add->client_verify_mode;
     656    return new;
     657}
     658
     659void *mgs_config_dir_create(apr_pool_t * p, char *dir) {
     660    mgs_dirconf_rec *dc = apr_palloc(p, sizeof (*dc));
     661    dc->client_verify_mode = -1;
     662    return dc;
     663}
  • src/gnutls_hooks.c

    r6223319 re183628  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
    3  *  Copyright 2007 Nikos Mavrogiannopoulos
     3 *  Copyright 2008 Nikos Mavrogiannopoulos
     4 *  Copyright 2011 Dash Shendy
    45 *
    56 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2223
    2324#if APR_HAS_THREADS
    24 # if GNUTLS_VERSION_MAJOR <= 2 && GNUTLS_VERSION_MINOR < 11
     25#if GNUTLS_VERSION_MAJOR <= 2 && GNUTLS_VERSION_MINOR < 11
    2526#include <gcrypt.h>
    2627GCRY_THREAD_OPTION_PTHREAD_IMPL;
    27 # endif
     28#endif
    2829#endif
    2930
     
    3738
    3839static int mpm_is_threaded;
    39 static gnutls_datum session_ticket_key = { NULL, 0 };
     40static gnutls_datum session_ticket_key = {NULL, 0};
    4041
    4142static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    4243/* use side==0 for server and side==1 for client */
    4344static void mgs_add_common_cert_vars(request_rec * r,
    44                                      gnutls_x509_crt_t cert, int side,
    45                                      int export_certificates_enabled);
     45        gnutls_x509_crt_t cert, int side,
     46        int export_certificates_enabled);
    4647static void mgs_add_common_pgpcert_vars(request_rec * r,
    47                                         gnutls_openpgp_crt_t cert,
    48                                         int side,
    49                                         int export_certificates_enabled);
    50 
    51 static apr_status_t mgs_cleanup_pre_config(void *data)
    52 {
    53         gnutls_free(session_ticket_key.data);
    54         session_ticket_key.data = NULL;
    55         session_ticket_key.size = 0;
    56         gnutls_global_deinit();
    57         return APR_SUCCESS;
     48        gnutls_openpgp_crt_t cert,
     49        int side,
     50        int export_certificates_enabled);
     51
     52static apr_status_t mgs_cleanup_pre_config(void *data) {
     53    gnutls_free(session_ticket_key.data);
     54    session_ticket_key.data = NULL;
     55    session_ticket_key.size = 0;
     56    gnutls_global_deinit();
     57    return APR_SUCCESS;
    5858}
    5959
    6060#if MOD_GNUTLS_DEBUG
    61 static void gnutls_debug_log_all(int level, const char *str)
    62 {
    63         apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
     61
     62static void gnutls_debug_log_all(int level, const char *str) {
     63    apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
    6464}
    6565
    6666#define _gnutls_log apr_file_printf
    6767#else
    68 # define _gnutls_log(...)
     68#define _gnutls_log(...)
    6969#endif
    7070
    7171int
    7272mgs_hook_pre_config(apr_pool_t * pconf,
    73                     apr_pool_t * plog, apr_pool_t * ptemp)
    74 {
    75         int ret;
     73        apr_pool_t * plog, apr_pool_t * ptemp) {
     74    int ret;
    7675
    7776#if MOD_GNUTLS_DEBUG
    78         apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
    79                       APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
    80                       pconf);
    81 
    82         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    83 
    84         gnutls_global_set_log_level(9);
    85         gnutls_global_set_log_function(gnutls_debug_log_all);
    86         _gnutls_log(debug_log_fp, "gnutls: %s\n",
    87                     gnutls_check_version(NULL));
     77    apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
     78            APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT,
     79            pconf);
     80
     81    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     82
     83    gnutls_global_set_log_level(9);
     84    gnutls_global_set_log_function(gnutls_debug_log_all);
     85    _gnutls_log(debug_log_fp, "gnutls: %s\n",
     86            gnutls_check_version(NULL));
    8887#endif
    8988
    9089#if APR_HAS_THREADS
    91         ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded);
     90    ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded);
    9291#if (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 11) || GNUTLS_VERSION_MAJOR < 2
    93         if (mpm_is_threaded) {
    94                 gcry_control(GCRYCTL_SET_THREAD_CBS,
    95                              &gcry_threads_pthread);
    96         }
     92    if (mpm_is_threaded) {
     93        gcry_control(GCRYCTL_SET_THREAD_CBS,
     94                &gcry_threads_pthread);
     95    }
    9796#endif
    9897#else
    99         mpm_is_threaded = 0;
    100 #endif
    101 
    102 
    103         if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) {
    104                 _gnutls_log(debug_log_fp,
    105                             "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n",
    106                             LIBGNUTLS_VERSION, gnutls_check_version(NULL));
    107                 return -3;
    108         }
    109 
    110         ret = gnutls_global_init();
    111         if (ret < 0) {
    112                 _gnutls_log(debug_log_fp, "gnutls_global_init: %s\n",
    113                             gnutls_strerror(ret));
    114                 return -3;
    115         }
    116 
    117         ret = gnutls_session_ticket_key_generate(&session_ticket_key);
    118         if (ret < 0) {
    119                 _gnutls_log(debug_log_fp,
    120                             "gnutls_session_ticket_key_generate: %s\n",
    121                             gnutls_strerror(ret));
    122         }
    123 
    124         apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
    125                                   apr_pool_cleanup_null);
    126 
    127 
    128         return OK;
    129 }
    130 
    131 static int mgs_select_virtual_server_cb(gnutls_session_t session)
    132 {
    133         mgs_handle_t *ctxt;
    134         mgs_srvconf_rec *tsc;
    135         int ret;
    136         int cprio[2];
    137 
    138         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    139 
    140         ctxt = gnutls_transport_get_ptr(session);
    141 
    142         /* find the virtual server */
    143         tsc = mgs_find_sni_server(session);
    144 
    145         if (tsc != NULL)
    146                 ctxt->sc = tsc;
    147 
    148         gnutls_certificate_server_set_request(session,
    149                                               ctxt->
    150                                               sc->client_verify_mode);
    151 
    152         /* set the new server credentials
    153          */
    154 
    155         gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
    156                                ctxt->sc->certs);
    157 
    158         gnutls_credentials_set(session, GNUTLS_CRD_ANON,
    159                                ctxt->sc->anon_creds);
     98    mpm_is_threaded = 0;
     99#endif
     100
     101
     102    if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) {
     103        _gnutls_log(debug_log_fp,
     104                "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n",
     105                LIBGNUTLS_VERSION, gnutls_check_version(NULL));
     106        return -3;
     107    }
     108
     109    ret = gnutls_global_init();
     110    if (ret < 0) {
     111        _gnutls_log(debug_log_fp, "gnutls_global_init: %s\n",
     112                gnutls_strerror(ret));
     113        return -3;
     114    }
     115
     116    ret = gnutls_session_ticket_key_generate(&session_ticket_key);
     117    if (ret < 0) {
     118        _gnutls_log(debug_log_fp,
     119                "gnutls_session_ticket_key_generate: %s\n",
     120                gnutls_strerror(ret));
     121    }
     122
     123    apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
     124            apr_pool_cleanup_null);
     125
     126
     127    return OK;
     128}
     129
     130static int mgs_select_virtual_server_cb(gnutls_session_t session) {
     131    mgs_handle_t *ctxt;
     132    mgs_srvconf_rec *tsc;
     133    int ret;
     134    int cprio[2];
     135
     136    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     137
     138    ctxt = gnutls_transport_get_ptr(session);
     139
     140    /* find the virtual server */
     141    tsc = mgs_find_sni_server(session);
     142
     143    if (tsc != NULL)
     144        ctxt->sc = tsc;
     145
     146    gnutls_certificate_server_set_request(session,
     147            ctxt->
     148            sc->client_verify_mode);
     149
     150    /* set the new server credentials
     151     */
     152
     153    gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
     154            ctxt->sc->certs);
     155
     156    gnutls_credentials_set(session, GNUTLS_CRD_ANON,
     157            ctxt->sc->anon_creds);
    160158
    161159#ifdef ENABLE_SRP
    162         if (ctxt->sc->srp_tpasswd_conf_file != NULL
    163             && ctxt->sc->srp_tpasswd_file != NULL) {
    164                 gnutls_credentials_set(session, GNUTLS_CRD_SRP,
    165                                        ctxt->sc->srp_creds);
    166         }
    167 #endif
    168 
    169         /* update the priorities - to avoid negotiating a ciphersuite that is not
    170          * enabled on this virtual server. Note that here we ignore the version
    171          * negotiation.
    172          */
    173         ret = gnutls_priority_set(session, ctxt->sc->priorities);
    174         /* actually it shouldn't fail since we have checked at startup */
    175         if (ret < 0)
    176                 return ret;
    177 
    178         /* If both certificate types are not present disallow them from
    179          * being negotiated.
    180          */
    181         if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) {
    182                 cprio[0] = GNUTLS_CRT_X509;
    183                 cprio[1] = 0;
    184                 gnutls_certificate_type_set_priority(session, cprio);
    185         } else if (ctxt->sc->cert_pgp != NULL
    186                    && ctxt->sc->certs_x509[0] == NULL) {
    187                 cprio[0] = GNUTLS_CRT_OPENPGP;
    188                 cprio[1] = 0;
    189                 gnutls_certificate_type_set_priority(session, cprio);
    190         }
    191 
    192         return 0;
    193 }
    194 
    195 static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret)
    196 {
    197         mgs_handle_t *ctxt;
    198 
    199         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    200         ctxt = gnutls_transport_get_ptr(session);
    201 
    202         if (ctxt == NULL)
    203                 return GNUTLS_E_INTERNAL_ERROR;
    204 
    205         if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
    206                 ret->type = GNUTLS_CRT_X509;
    207                 ret->ncerts = ctxt->sc->certs_x509_num;
    208                 ret->deinit_all = 0;
    209 
    210                 ret->cert.x509 = ctxt->sc->certs_x509;
    211                 ret->key.x509 = ctxt->sc->privkey_x509;
    212 
    213                 return 0;
    214         } else if (gnutls_certificate_type_get(session) ==
    215                    GNUTLS_CRT_OPENPGP) {
    216                 ret->type = GNUTLS_CRT_OPENPGP;
    217                 ret->ncerts = 1;
    218                 ret->deinit_all = 0;
    219 
    220                 ret->cert.pgp = ctxt->sc->cert_pgp;
    221                 ret->key.pgp = ctxt->sc->privkey_pgp;
    222 
    223                 return 0;
    224 
    225         }
    226 
    227         return GNUTLS_E_INTERNAL_ERROR;
     160    if (ctxt->sc->srp_tpasswd_conf_file != NULL
     161            && ctxt->sc->srp_tpasswd_file != NULL) {
     162        gnutls_credentials_set(session, GNUTLS_CRD_SRP,
     163                ctxt->sc->srp_creds);
     164    }
     165#endif
     166
     167    /* update the priorities - to avoid negotiating a ciphersuite that is not
     168     * enabled on this virtual server. Note that here we ignore the version
     169     * negotiation.
     170     */
     171    ret = gnutls_priority_set(session, ctxt->sc->priorities);
     172    /* actually it shouldn't fail since we have checked at startup */
     173    if (ret < 0)
     174        return ret;
     175
     176    /* If both certificate types are not present disallow them from
     177     * being negotiated.
     178     */
     179    if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) {
     180        cprio[0] = GNUTLS_CRT_X509;
     181        cprio[1] = 0;
     182        gnutls_certificate_type_set_priority(session, cprio);
     183    } else if (ctxt->sc->cert_pgp != NULL
     184            && ctxt->sc->certs_x509[0] == NULL) {
     185        cprio[0] = GNUTLS_CRT_OPENPGP;
     186        cprio[1] = 0;
     187        gnutls_certificate_type_set_priority(session, cprio);
     188    }
     189
     190    return 0;
     191}
     192
     193static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret) {
     194    mgs_handle_t *ctxt;
     195
     196    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     197    ctxt = gnutls_transport_get_ptr(session);
     198
     199    if (ctxt == NULL)
     200        return GNUTLS_E_INTERNAL_ERROR;
     201
     202    if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
     203        ret->type = GNUTLS_CRT_X509;
     204        ret->ncerts = ctxt->sc->certs_x509_num;
     205        ret->deinit_all = 0;
     206
     207        ret->cert.x509 = ctxt->sc->certs_x509;
     208        ret->key.x509 = ctxt->sc->privkey_x509;
     209
     210        return 0;
     211    } else if (gnutls_certificate_type_get(session) ==
     212            GNUTLS_CRT_OPENPGP) {
     213        ret->type = GNUTLS_CRT_OPENPGP;
     214        ret->ncerts = 1;
     215        ret->deinit_all = 0;
     216
     217        ret->cert.pgp = ctxt->sc->cert_pgp;
     218        ret->key.pgp = ctxt->sc->privkey_pgp;
     219
     220        return 0;
     221
     222    }
     223
     224    return GNUTLS_E_INTERNAL_ERROR;
    228225}
    229226
    230227/* 2048-bit group parameters from SRP specification */
    231228const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
    232     "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
    233     "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
    234     "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
    235     "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
    236     "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
    237     "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
    238     "-----END DH PARAMETERS-----\n";
     229        "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
     230        "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
     231        "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
     232        "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
     233        "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
     234        "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
     235        "-----END DH PARAMETERS-----\n";
    239236
    240237/* Read the common name or the alternative name of the certificate.
     
    244241 */
    245242static int read_crt_cn(server_rec * s, apr_pool_t * p,
    246                        gnutls_x509_crt_t cert, char **cert_cn)
    247 {
    248         int rv = 0, i;
    249         size_t data_len;
    250 
    251 
    252         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    253         *cert_cn = NULL;
    254 
    255         data_len = 0;
    256         rv = gnutls_x509_crt_get_dn_by_oid(cert,
    257                                            GNUTLS_OID_X520_COMMON_NAME,
    258                                            0, 0, NULL, &data_len);
    259 
    260         if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    261                 *cert_cn = apr_palloc(p, data_len);
    262                 rv = gnutls_x509_crt_get_dn_by_oid(cert,
    263                                                    GNUTLS_OID_X520_COMMON_NAME,
    264                                                    0, 0, *cert_cn,
    265                                                    &data_len);
    266         } else {                /* No CN return subject alternative name */
    267                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
    268                              "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
    269                              s->server_hostname, s->port);
    270                 rv = 0;
    271                 /* read subject alternative name */
    272                 for (i = 0; !(rv < 0); i++) {
    273                         data_len = 0;
    274                         rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
    275                                                                   NULL,
    276                                                                   &data_len,
    277                                                                   NULL);
    278 
    279                         if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER
    280                             && data_len > 1) {
    281                                 /* FIXME: not very efficient. What if we have several alt names
    282                                  * before DNSName?
    283                                  */
    284                                 *cert_cn = apr_palloc(p, data_len + 1);
    285 
    286                                 rv = gnutls_x509_crt_get_subject_alt_name
    287                                     (cert, i, *cert_cn, &data_len, NULL);
    288                                 (*cert_cn)[data_len] = 0;
    289 
    290                                 if (rv == GNUTLS_SAN_DNSNAME)
    291                                         break;
    292                         }
    293                 }
    294         }
    295 
    296         return rv;
     243        gnutls_x509_crt_t cert, char **cert_cn) {
     244    int rv = 0, i;
     245    size_t data_len;
     246
     247
     248    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     249    *cert_cn = NULL;
     250
     251    data_len = 0;
     252    rv = gnutls_x509_crt_get_dn_by_oid(cert,
     253            GNUTLS_OID_X520_COMMON_NAME,
     254            0, 0, NULL, &data_len);
     255
     256    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
     257        *cert_cn = apr_palloc(p, data_len);
     258        rv = gnutls_x509_crt_get_dn_by_oid(cert,
     259                GNUTLS_OID_X520_COMMON_NAME,
     260                0, 0, *cert_cn,
     261                &data_len);
     262    } else { /* No CN return subject alternative name */
     263        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
     264                "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
     265                s->server_hostname, s->port);
     266        rv = 0;
     267        /* read subject alternative name */
     268        for (i = 0; !(rv < 0); i++) {
     269            data_len = 0;
     270            rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
     271                    NULL,
     272                    &data_len,
     273                    NULL);
     274
     275            if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER
     276                    && data_len > 1) {
     277                /* FIXME: not very efficient. What if we have several alt names
     278                 * before DNSName?
     279                 */
     280                *cert_cn = apr_palloc(p, data_len + 1);
     281
     282                rv = gnutls_x509_crt_get_subject_alt_name
     283                        (cert, i, *cert_cn, &data_len, NULL);
     284                (*cert_cn)[data_len] = 0;
     285
     286                if (rv == GNUTLS_SAN_DNSNAME)
     287                    break;
     288            }
     289        }
     290    }
     291
     292    return rv;
    297293}
    298294
    299295static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
    300                           gnutls_openpgp_crt_t cert, char **cert_cn)
    301 {
    302         int rv = 0;
    303         size_t data_len;
    304 
    305 
    306         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    307         *cert_cn = NULL;
    308 
    309         data_len = 0;
    310         rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
    311 
    312         if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    313                 *cert_cn = apr_palloc(p, data_len);
    314                 rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn,
    315                                                  &data_len);
    316         } else {                /* No CN return subject alternative name */
    317                 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    318                              "No name found in PGP certificate for '%s:%d'.",
    319                              s->server_hostname, s->port);
    320         }
    321 
    322         return rv;
    323 }
    324 
     296        gnutls_openpgp_crt_t cert, char **cert_cn) {
     297    int rv = 0;
     298    size_t data_len;
     299
     300
     301    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     302    *cert_cn = NULL;
     303
     304    data_len = 0;
     305    rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
     306
     307    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
     308        *cert_cn = apr_palloc(p, data_len);
     309        rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn,
     310                &data_len);
     311    } else { /* No CN return subject alternative name */
     312        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     313                "No name found in PGP certificate for '%s:%d'.",
     314                s->server_hostname, s->port);
     315    }
     316
     317    return rv;
     318}
    325319
    326320int
    327321mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
    328                      apr_pool_t * ptemp, server_rec * base_server)
    329 {
    330         int rv;
    331         server_rec *s;
    332         gnutls_dh_params_t dh_params = NULL;
    333         gnutls_rsa_params_t rsa_params = NULL;
    334         mgs_srvconf_rec *sc;
    335         mgs_srvconf_rec *sc_base;
    336         void *data = NULL;
    337         int first_run = 0;
    338         const char *userdata_key = "mgs_init";
    339 
    340         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    341         apr_pool_userdata_get(&data, userdata_key,
    342                               base_server->process->pool);
    343         if (data == NULL) {
    344                 first_run = 1;
    345                 apr_pool_userdata_set((const void *) 1, userdata_key,
    346                                       apr_pool_cleanup_null,
    347                                       base_server->process->pool);
    348         }
    349 
    350 
    351         s = base_server;
    352         sc_base =
    353             (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    354                                                      &gnutls_module);
    355 
    356         gnutls_dh_params_init(&dh_params);
    357 
    358         if (sc_base->dh_params == NULL) {
    359                 gnutls_datum pdata = {
    360                         (void *) static_dh_params,
    361                         sizeof(static_dh_params)
    362                 };
    363                 /* loading defaults */
    364                 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
    365                                                    GNUTLS_X509_FMT_PEM);
    366 
    367                 if (rv < 0) {
    368                         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    369                                      "GnuTLS: Unable to load DH Params: (%d) %s",
    370                                      rv, gnutls_strerror(rv));
    371                         exit(rv);
    372                 }
    373         } else
    374                 dh_params = sc_base->dh_params;
    375 
    376         if (sc_base->rsa_params != NULL)
    377                 rsa_params = sc_base->rsa_params;
    378 
    379         /* else not an error but RSA-EXPORT ciphersuites are not available
    380          */
    381 
    382         rv = mgs_cache_post_config(p, s, sc_base);
    383         if (rv != 0) {
    384                 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
    385                              "GnuTLS: Post Config for GnuTLSCache Failed."
    386                              " Shutting Down.");
    387                 exit(-1);
    388         }
    389 
    390         for (s = base_server; s; s = s->next) {
    391                 void *load = NULL;
    392                 sc = (mgs_srvconf_rec *)
    393                     ap_get_module_config(s->module_config, &gnutls_module);
    394                 sc->cache_type = sc_base->cache_type;
    395                 sc->cache_config = sc_base->cache_config;
    396 
    397                 /* Check if the priorities have been set */
    398                 if (sc->priorities == NULL
    399                     && sc->enabled == GNUTLS_ENABLED_TRUE) {
    400                         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    401                                      "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
    402                                      s->server_hostname, s->port);
    403                         exit(-1);
    404                 }
    405 
    406                 /* Check if DH or RSA params have been set per host */
    407                 if (sc->rsa_params != NULL)
    408                         load = sc->rsa_params;
    409                 else if (rsa_params)
    410                         load = rsa_params;
    411 
    412                 if (load != NULL)
    413                         gnutls_certificate_set_rsa_export_params(sc->certs,
    414                                                                  load);
    415 
    416 
    417                 load = NULL;
    418                 if (sc->dh_params != NULL)
    419                         load = sc->dh_params;
    420                 else if (dh_params)
    421                         load = dh_params;
    422 
    423                 if (load != NULL) {     /* not needed but anyway */
    424                         gnutls_certificate_set_dh_params(sc->certs, load);
    425                         gnutls_anon_set_server_dh_params(sc->anon_creds,
    426                                                          load);
    427                 }
    428 
    429                 gnutls_certificate_server_set_retrieve_function(sc->certs,
    430                                                                 cert_retrieve_fn);
     322        apr_pool_t * ptemp, server_rec * base_server) {
     323    int rv;
     324    server_rec *s;
     325    gnutls_dh_params_t dh_params = NULL;
     326    gnutls_rsa_params_t rsa_params = NULL;
     327    mgs_srvconf_rec *sc;
     328    mgs_srvconf_rec *sc_base;
     329    void *data = NULL;
     330    int first_run = 0;
     331    const char *userdata_key = "mgs_init";
     332
     333    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     334    apr_pool_userdata_get(&data, userdata_key,
     335            base_server->process->pool);
     336    if (data == NULL) {
     337        first_run = 1;
     338        apr_pool_userdata_set((const void *) 1, userdata_key,
     339                apr_pool_cleanup_null,
     340                base_server->process->pool);
     341    }
     342
     343
     344    s = base_server;
     345    sc_base =
     346            (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
     347            &gnutls_module);
     348
     349    gnutls_dh_params_init(&dh_params);
     350
     351    if (sc_base->dh_params == NULL) {
     352        gnutls_datum pdata = {
     353            (void *) static_dh_params,
     354            sizeof (static_dh_params)
     355        };
     356        /* loading defaults */
     357        rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
     358                GNUTLS_X509_FMT_PEM);
     359
     360        if (rv < 0) {
     361            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     362                    "GnuTLS: Unable to load DH Params: (%d) %s",
     363                    rv, gnutls_strerror(rv));
     364            exit(rv);
     365        }
     366    } else
     367        dh_params = sc_base->dh_params;
     368
     369    if (sc_base->rsa_params != NULL)
     370        rsa_params = sc_base->rsa_params;
     371
     372    /* else not an error but RSA-EXPORT ciphersuites are not available
     373     */
     374
     375    rv = mgs_cache_post_config(p, s, sc_base);
     376    if (rv != 0) {
     377        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
     378                "GnuTLS: Post Config for GnuTLSCache Failed."
     379                " Shutting Down.");
     380        exit(-1);
     381    }
     382
     383    for (s = base_server; s; s = s->next) {
     384        void *load = NULL;
     385        sc = (mgs_srvconf_rec *)
     386                ap_get_module_config(s->module_config, &gnutls_module);
     387        sc->cache_type = sc_base->cache_type;
     388        sc->cache_config = sc_base->cache_config;
     389
     390        /* Check if the priorities have been set */
     391        if (sc->priorities == NULL
     392                && sc->enabled == GNUTLS_ENABLED_TRUE) {
     393            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     394                    "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
     395                    s->server_hostname, s->port);
     396            exit(-1);
     397        }
     398
     399        /* Check if DH or RSA params have been set per host */
     400        if (sc->rsa_params != NULL)
     401            load = sc->rsa_params;
     402        else if (rsa_params)
     403            load = rsa_params;
     404
     405        if (load != NULL)
     406            gnutls_certificate_set_rsa_export_params(sc->certs,
     407                load);
     408
     409
     410        load = NULL;
     411        if (sc->dh_params != NULL)
     412            load = sc->dh_params;
     413        else if (dh_params)
     414            load = dh_params;
     415
     416        if (load != NULL) { /* not needed but anyway */
     417            gnutls_certificate_set_dh_params(sc->certs, load);
     418            gnutls_anon_set_server_dh_params(sc->anon_creds,
     419                    load);
     420        }
     421
     422        gnutls_certificate_server_set_retrieve_function(sc->certs,
     423                cert_retrieve_fn);
    431424
    432425#ifdef ENABLE_SRP
    433                 if (sc->srp_tpasswd_conf_file != NULL
    434                     && sc->srp_tpasswd_file != NULL) {
    435                         rv = gnutls_srp_set_server_credentials_file
    436                             (sc->srp_creds, sc->srp_tpasswd_file,
    437                              sc->srp_tpasswd_conf_file);
    438 
    439                         if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
    440                                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
    441                                              s,
    442                                              "[GnuTLS] - Host '%s:%d' is missing a "
    443                                              "SRP password or conf File!",
    444                                              s->server_hostname, s->port);
    445                                 exit(-1);
    446                         }
    447                 }
    448 #endif
    449 
    450                 if (sc->certs_x509[0] == NULL &&
    451                     sc->cert_pgp == NULL &&
    452                     sc->enabled == GNUTLS_ENABLED_TRUE) {
    453                         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    454                                      "[GnuTLS] - Host '%s:%d' is missing a "
    455                                      "Certificate File!",
    456                                      s->server_hostname, s->port);
    457                         exit(-1);
    458                 }
    459 
    460                 if (sc->enabled == GNUTLS_ENABLED_TRUE &&
    461                     ((sc->certs_x509[0] != NULL
    462                       && sc->privkey_x509 == NULL) || (sc->cert_pgp != NULL
    463                                                        && sc->privkey_pgp
    464                                                        == NULL))) {
    465                         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    466                                      "[GnuTLS] - Host '%s:%d' is missing a "
    467                                      "Private Key File!",
    468                                      s->server_hostname, s->port);
    469                         exit(-1);
    470                 }
    471 
    472                 if (sc->enabled == GNUTLS_ENABLED_TRUE) {
    473                         rv = read_crt_cn(s, p, sc->certs_x509[0],
    474                                          &sc->cert_cn);
    475                         if (rv < 0 && sc->cert_pgp != NULL)     /* try openpgp certificate */
    476                                 rv = read_pgpcrt_cn(s, p, sc->cert_pgp,
    477                                                     &sc->cert_cn);
    478 
    479                         if (rv < 0) {
    480                                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
    481                                              s,
    482                                              "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
    483                                              s->server_hostname, s->port);
    484                                 sc->cert_cn = NULL;
    485                                 continue;
    486                         }
    487                 }
    488         }
    489 
    490 
    491         ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
    492 
    493         return OK;
    494 }
    495 
    496 void mgs_hook_child_init(apr_pool_t * p, server_rec * s)
    497 {
    498         apr_status_t rv = APR_SUCCESS;
    499         mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
    500                                                    &gnutls_module);
    501 
    502         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    503         if (sc->cache_type != mgs_cache_none) {
    504                 rv = mgs_cache_child_init(p, s, sc);
    505                 if (rv != APR_SUCCESS) {
    506                         ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    507                                      "[GnuTLS] - Failed to run Cache Init");
    508                 }
    509         }
    510 }
    511 
    512 const char *mgs_hook_http_scheme(const request_rec * r)
    513 {
    514         mgs_srvconf_rec *sc;
    515 
    516         if (r == NULL)
    517                 return NULL;
    518 
    519         sc = (mgs_srvconf_rec *) ap_get_module_config(r->
    520                                                       server->module_config,
    521                                                       &gnutls_module);
    522 
    523         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    524         if (sc->enabled == GNUTLS_ENABLED_FALSE) {
    525                 return NULL;
    526         }
    527 
    528         return "https";
    529 }
    530 
    531 apr_port_t mgs_hook_default_port(const request_rec * r)
    532 {
    533         mgs_srvconf_rec *sc;
    534 
    535         if (r == NULL)
    536                 return 0;
    537 
    538         sc = (mgs_srvconf_rec *) ap_get_module_config(r->
    539                                                       server->module_config,
    540                                                       &gnutls_module);
    541 
    542         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    543         if (sc->enabled == GNUTLS_ENABLED_FALSE) {
    544                 return 0;
    545         }
    546 
    547         return 443;
     426        if (sc->srp_tpasswd_conf_file != NULL
     427                && sc->srp_tpasswd_file != NULL) {
     428            rv = gnutls_srp_set_server_credentials_file
     429                    (sc->srp_creds, sc->srp_tpasswd_file,
     430                    sc->srp_tpasswd_conf_file);
     431
     432            if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
     433                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
     434                        s,
     435                        "[GnuTLS] - Host '%s:%d' is missing a "
     436                        "SRP password or conf File!",
     437                        s->server_hostname, s->port);
     438                exit(-1);
     439            }
     440        }
     441#endif
     442
     443        if (sc->certs_x509[0] == NULL &&
     444                sc->cert_pgp == NULL &&
     445                sc->enabled == GNUTLS_ENABLED_TRUE) {
     446            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     447                    "[GnuTLS] - Host '%s:%d' is missing a "
     448                    "Certificate File!",
     449                    s->server_hostname, s->port);
     450            exit(-1);
     451        }
     452
     453        if (sc->enabled == GNUTLS_ENABLED_TRUE &&
     454                ((sc->certs_x509[0] != NULL
     455                && sc->privkey_x509 == NULL) || (sc->cert_pgp != NULL
     456                && sc->privkey_pgp
     457                == NULL))) {
     458            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     459                    "[GnuTLS] - Host '%s:%d' is missing a "
     460                    "Private Key File!",
     461                    s->server_hostname, s->port);
     462            exit(-1);
     463        }
     464
     465        if (sc->enabled == GNUTLS_ENABLED_TRUE) {
     466            rv = read_crt_cn(s, p, sc->certs_x509[0],
     467                    &sc->cert_cn);
     468            if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */
     469                rv = read_pgpcrt_cn(s, p, sc->cert_pgp,
     470                    &sc->cert_cn);
     471
     472            if (rv < 0) {
     473                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
     474                        s,
     475                        "[GnuTLS] - Cannot find a certificate for host '%s:%d'!",
     476                        s->server_hostname, s->port);
     477                sc->cert_cn = NULL;
     478                continue;
     479            }
     480        }
     481    }
     482
     483
     484    ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
     485
     486    return OK;
     487}
     488
     489void mgs_hook_child_init(apr_pool_t * p, server_rec * s) {
     490    apr_status_t rv = APR_SUCCESS;
     491    mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
     492            &gnutls_module);
     493
     494    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     495    if (sc->cache_type != mgs_cache_none) {
     496        rv = mgs_cache_child_init(p, s, sc);
     497        if (rv != APR_SUCCESS) {
     498            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
     499                    "[GnuTLS] - Failed to run Cache Init");
     500        }
     501    }
     502}
     503
     504const char *mgs_hook_http_scheme(const request_rec * r) {
     505    mgs_srvconf_rec *sc;
     506
     507    if (r == NULL)
     508        return NULL;
     509
     510    sc = (mgs_srvconf_rec *) ap_get_module_config(r->
     511            server->module_config,
     512            &gnutls_module);
     513
     514    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     515    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
     516        return NULL;
     517    }
     518
     519    return "https";
     520}
     521
     522apr_port_t mgs_hook_default_port(const request_rec * r) {
     523    mgs_srvconf_rec *sc;
     524
     525    if (r == NULL)
     526        return 0;
     527
     528    sc = (mgs_srvconf_rec *) ap_get_module_config(r->
     529            server->module_config,
     530            &gnutls_module);
     531
     532    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     533    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
     534        return 0;
     535    }
     536
     537    return 443;
    548538}
    549539
     
    551541
    552542#if USING_2_1_RECENT
     543
    553544typedef struct {
    554         mgs_handle_t *ctxt;
    555         mgs_srvconf_rec *sc;
    556         const char *sni_name;
     545    mgs_handle_t *ctxt;
     546    mgs_srvconf_rec *sc;
     547    const char *sni_name;
    557548} vhost_cb_rec;
    558549
    559 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s)
    560 {
    561         mgs_srvconf_rec *tsc;
    562         vhost_cb_rec *x = baton;
    563 
    564         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    565         tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    566                                                        &gnutls_module);
    567 
    568         if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
    569                 return 0;
    570         }
    571 
    572         /* The CN can contain a * -- this will match those too. */
    573         if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
    574                 /* found a match */
     550static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) {
     551    mgs_srvconf_rec *tsc;
     552    vhost_cb_rec *x = baton;
     553
     554    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     555    tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
     556            &gnutls_module);
     557
     558    if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
     559        return 0;
     560    }
     561
     562    /* The CN can contain a * -- this will match those too. */
     563    if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
     564        /* found a match */
    575565#if MOD_GNUTLS_DEBUG
    576                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    577                              x->ctxt->c->base_server,
    578                              "GnuTLS: Virtual Host CB: "
    579                              "'%s' == '%s'", tsc->cert_cn, x->sni_name);
    580 #endif
    581                 /* Because we actually change the server used here, we need to reset
    582                 * things like ClientVerify.
    583                 */
    584                 x->sc = tsc;
    585                 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
    586                 * certificate structure *should* change when the server changes.
    587                 * acccckkkkkk.
    588                 */
    589                 return 1;
    590         } else {
     566        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     567                x->ctxt->c->base_server,
     568                "GnuTLS: Virtual Host CB: "
     569                "'%s' == '%s'", tsc->cert_cn, x->sni_name);
     570#endif
     571        /* Because we actually change the server used here, we need to reset
     572        * things like ClientVerify.
     573        */
     574        x->sc = tsc;
     575        /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
     576        * certificate structure *should* change when the server changes.
     577        * acccckkkkkk.
     578        */
     579        return 1;
     580    } else {
    591581#if MOD_GNUTLS_DEBUG
    592                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    593                              x->ctxt->c->base_server,
    594                              "GnuTLS: Virtual Host CB: "
    595                              "'%s' != '%s'", tsc->cert_cn, x->sni_name);
    596 #endif
    597 
    598         }
    599         return 0;
    600 }
    601 #endif
    602 
    603 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
    604 {
    605         int rv;
    606         unsigned int sni_type;
    607         size_t data_len = MAX_HOST_LEN;
    608         char sni_name[MAX_HOST_LEN];
    609         mgs_handle_t *ctxt;
     582        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     583                x->ctxt->c->base_server,
     584                "GnuTLS: Virtual Host CB: "
     585                "'%s' != '%s'", tsc->cert_cn, x->sni_name);
     586#endif
     587
     588    }
     589    return 0;
     590}
     591#endif
     592
     593mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) {
     594    int rv;
     595    unsigned int sni_type;
     596    size_t data_len = MAX_HOST_LEN;
     597    char sni_name[MAX_HOST_LEN];
     598    mgs_handle_t *ctxt;
    610599#if USING_2_1_RECENT
    611         vhost_cb_rec cbx;
     600    vhost_cb_rec cbx;
    612601#else
    613         server_rec *s;
    614         mgs_srvconf_rec *tsc;
    615 #endif
    616 
    617         if (session == NULL)
    618                 return NULL;
    619 
    620         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    621         ctxt = gnutls_transport_get_ptr(session);
    622 
    623         rv = gnutls_server_name_get(ctxt->session, sni_name,
    624                                     &data_len, &sni_type, 0);
    625 
    626         if (rv != 0) {
    627                 return NULL;
    628         }
    629 
    630         if (sni_type != GNUTLS_NAME_DNS) {
    631                 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
    632                              ctxt->c->base_server,
    633                              "GnuTLS: Unknown type '%d' for SNI: "
    634                              "'%s'", sni_type, sni_name);
    635                 return NULL;
    636         }
     602    server_rec *s;
     603    mgs_srvconf_rec *tsc;
     604#endif
     605
     606    if (session == NULL)
     607        return NULL;
     608
     609    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     610    ctxt = gnutls_transport_get_ptr(session);
     611
     612    rv = gnutls_server_name_get(ctxt->session, sni_name,
     613            &data_len, &sni_type, 0);
     614
     615    if (rv != 0) {
     616        return NULL;
     617    }
     618
     619    if (sni_type != GNUTLS_NAME_DNS) {
     620        ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
     621                ctxt->c->base_server,
     622                "GnuTLS: Unknown type '%d' for SNI: "
     623                "'%s'", sni_type, sni_name);
     624        return NULL;
     625    }
    637626
    638627    /**
     
    641630     */
    642631#if USING_2_1_RECENT
    643         cbx.ctxt = ctxt;
    644         cbx.sc = NULL;
    645         cbx.sni_name = sni_name;
    646 
    647         rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
    648         if (rv == 1) {
    649                 return cbx.sc;
    650         }
     632    cbx.ctxt = ctxt;
     633    cbx.sc = NULL;
     634    cbx.sni_name = sni_name;
     635
     636    rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
     637    if (rv == 1) {
     638        return cbx.sc;
     639    }
    651640#else
    652         for (s = ap_server_conf; s; s = s->next) {
    653 
    654                 tsc =
    655                     (mgs_srvconf_rec *)
    656                     ap_get_module_config(s->module_config, &gnutls_module);
    657                 if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
    658                         continue;
    659                 }
     641    for (s = ap_server_conf; s; s = s->next) {
     642
     643        tsc =
     644                (mgs_srvconf_rec *)
     645                ap_get_module_config(s->module_config, &gnutls_module);
     646        if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
     647            continue;
     648        }
    660649#if MOD_GNUTLS_DEBUG
    661                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    662                              ctxt->c->base_server,
    663                              "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X  sc: 0x%08X",
    664                              tsc->cert_cn, rv,
    665                              gnutls_pk_algorithm_get_name
    666                              (gnutls_x509_privkey_get_pk_algorithm
    667                               (ctxt->sc->privkey_x509)), (unsigned int) s,
    668                              (unsigned int) s->next, (unsigned int) tsc);
    669 #endif
    670                 /* The CN can contain a * -- this will match those too. */
    671                 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
     650        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     651                ctxt->c->base_server,
     652                "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X  sc: 0x%08X",
     653                tsc->cert_cn, rv,
     654                gnutls_pk_algorithm_get_name
     655                (gnutls_x509_privkey_get_pk_algorithm
     656                (ctxt->sc->privkey_x509)), (unsigned int) s,
     657                (unsigned int) s->next, (unsigned int) tsc);
     658#endif
     659        /* The CN can contain a * -- this will match those too. */
     660        if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
    672661#if MOD_GNUTLS_DEBUG
    673                         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
    674                                      ctxt->c->base_server,
    675                                      "GnuTLS: Virtual Host: "
    676                                      "'%s' == '%s'", tsc->cert_cn,
    677                                      sni_name);
    678 #endif
    679                         return tsc;
    680                 }
    681         }
    682 #endif
    683         return NULL;
     662            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
     663                    ctxt->c->base_server,
     664                    "GnuTLS: Virtual Host: "
     665                    "'%s' == '%s'", tsc->cert_cn,
     666                    sni_name);
     667#endif
     668            return tsc;
     669        }
     670    }
     671#endif
     672    return NULL;
    684673}
    685674
    686675
    687676static const int protocol_priority[] = {
    688         GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
     677    GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
    689678};
    690679
    691 
    692 static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c)
    693 {
    694         mgs_handle_t *ctxt;
    695         mgs_srvconf_rec *sc =
    696             (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
    697                                                      module_config,
    698                                                      &gnutls_module);
    699 
    700         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    701         ctxt = apr_pcalloc(pool, sizeof(*ctxt));
    702         ctxt->c = c;
    703         ctxt->sc = sc;
    704         ctxt->status = 0;
    705 
    706         ctxt->input_rc = APR_SUCCESS;
    707         ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
    708         ctxt->input_cbuf.length = 0;
    709 
    710         ctxt->output_rc = APR_SUCCESS;
    711         ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
    712         ctxt->output_blen = 0;
    713         ctxt->output_length = 0;
    714 
    715         gnutls_init(&ctxt->session, GNUTLS_SERVER);
    716         if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0)
    717                 gnutls_session_ticket_enable_server(ctxt->session,
    718                                                     &session_ticket_key);
    719 
    720         /* because we don't set any default priorities here (we set later at
    721          * the user hello callback) we need to at least set this in order for
    722          * gnutls to be able to read packets.
    723          */
    724         gnutls_protocol_set_priority(ctxt->session, protocol_priority);
    725 
    726         gnutls_handshake_set_post_client_hello_function(ctxt->session,
    727                                                         mgs_select_virtual_server_cb);
    728 
    729         mgs_cache_session_init(ctxt);
    730 
    731         return ctxt;
    732 }
    733 
    734 int mgs_hook_pre_connection(conn_rec * c, void *csd)
    735 {
    736         mgs_handle_t *ctxt;
    737         mgs_srvconf_rec *sc;
    738 
    739         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    740 
    741         if (c == NULL) {
    742                 return DECLINED;
    743         }
    744 
    745         sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
    746                                                       module_config,
    747                                                       &gnutls_module);
    748 
    749         if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
    750                 return DECLINED;
    751         }
    752 
    753         if (c->remote_addr->hostname || apr_strnatcmp(c->remote_ip,c->local_ip) == 0) {
     680static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c) {
     681    mgs_handle_t *ctxt;
     682    mgs_srvconf_rec *sc =
     683            (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
     684            module_config,
     685            &gnutls_module);
     686
     687    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     688    ctxt = apr_pcalloc(pool, sizeof (*ctxt));
     689    ctxt->c = c;
     690    ctxt->sc = sc;
     691    ctxt->status = 0;
     692
     693    ctxt->input_rc = APR_SUCCESS;
     694    ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
     695    ctxt->input_cbuf.length = 0;
     696
     697    ctxt->output_rc = APR_SUCCESS;
     698    ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
     699    ctxt->output_blen = 0;
     700    ctxt->output_length = 0;
     701
     702    gnutls_init(&ctxt->session, GNUTLS_SERVER);
     703    if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0)
     704        gnutls_session_ticket_enable_server(ctxt->session,
     705            &session_ticket_key);
     706
     707    /* because we don't set any default priorities here (we set later at
     708     * the user hello callback) we need to at least set this in order for
     709     * gnutls to be able to read packets.
     710     */
     711    gnutls_protocol_set_priority(ctxt->session, protocol_priority);
     712
     713    gnutls_handshake_set_post_client_hello_function(ctxt->session,
     714            mgs_select_virtual_server_cb);
     715
     716    mgs_cache_session_init(ctxt);
     717
     718    return ctxt;
     719}
     720
     721int mgs_hook_pre_connection(conn_rec * c, void *csd) {
     722    mgs_handle_t *ctxt;
     723    mgs_srvconf_rec *sc;
     724
     725    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     726
     727    if (c == NULL) {
     728        return DECLINED;
     729    }
     730
     731    sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
     732            module_config,
     733            &gnutls_module);
     734
     735    if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
     736        return DECLINED;
     737    }
     738
     739    if (c->remote_addr->hostname || apr_strnatcmp(c->remote_ip, c->local_ip) == 0) {
    754740        /* Connection initiated by Apache (mod_proxy) => ignore */
    755                 return OK;
    756         }
    757                
    758         ctxt = create_gnutls_handle(c->pool, c);
    759 
    760         ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
    761 
    762         gnutls_transport_set_pull_function(ctxt->session,
    763                                            mgs_transport_read);
    764         gnutls_transport_set_push_function(ctxt->session,
    765                                            mgs_transport_write);
    766         gnutls_transport_set_ptr(ctxt->session, ctxt);
    767 
    768         ctxt->input_filter =
    769             ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
    770         ctxt->output_filter =
    771             ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
    772 
    773         return OK;
    774 }
    775 
    776 int mgs_hook_fixups(request_rec * r)
    777 {
    778         unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
    779         char buf[AP_IOBUFSIZE];
    780         const char *tmp;
    781         size_t len;
    782         mgs_handle_t *ctxt;
    783         int rv = OK;
    784 
    785         if (r == NULL)
    786                 return DECLINED;
    787 
    788         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    789         apr_table_t *env = r->subprocess_env;
    790 
    791         ctxt =
    792             ap_get_module_config(r->connection->conn_config,
    793                                  &gnutls_module);
    794 
    795         if (!ctxt || ctxt->session == NULL) {
    796                 return DECLINED;
    797         }
    798 
    799         apr_table_setn(env, "HTTPS", "on");
    800 
    801         apr_table_setn(env, "SSL_VERSION_LIBRARY",
    802                        "GnuTLS/" LIBGNUTLS_VERSION);
    803         apr_table_setn(env, "SSL_VERSION_INTERFACE",
    804                        "mod_gnutls/" MOD_GNUTLS_VERSION);
    805 
    806         apr_table_setn(env, "SSL_PROTOCOL",
    807                        gnutls_protocol_get_name(gnutls_protocol_get_version
    808                                                 (ctxt->session)));
    809 
    810         /* should have been called SSL_CIPHERSUITE instead */
    811         apr_table_setn(env, "SSL_CIPHER",
    812                        gnutls_cipher_suite_get_name(gnutls_kx_get
    813                                                     (ctxt->session),
    814                                                     gnutls_cipher_get
    815                                                     (ctxt->session),
    816                                                     gnutls_mac_get
    817                                                     (ctxt->session)));
    818 
    819         apr_table_setn(env, "SSL_COMPRESS_METHOD",
    820                        gnutls_compression_get_name(gnutls_compression_get
    821                                                    (ctxt->session)));
     741        return OK;
     742    }
     743
     744    ctxt = create_gnutls_handle(c->pool, c);
     745
     746    ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
     747
     748    gnutls_transport_set_pull_function(ctxt->session,
     749            mgs_transport_read);
     750    gnutls_transport_set_push_function(ctxt->session,
     751            mgs_transport_write);
     752    gnutls_transport_set_ptr(ctxt->session, ctxt);
     753
     754    ctxt->input_filter =
     755            ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
     756    ctxt->output_filter =
     757            ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
     758
     759    return OK;
     760}
     761
     762int mgs_hook_fixups(request_rec * r) {
     763    unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
     764    char buf[AP_IOBUFSIZE];
     765    const char *tmp;
     766    size_t len;
     767    mgs_handle_t *ctxt;
     768    int rv = OK;
     769
     770    if (r == NULL)
     771        return DECLINED;
     772
     773    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     774    apr_table_t *env = r->subprocess_env;
     775
     776    ctxt =
     777            ap_get_module_config(r->connection->conn_config,
     778            &gnutls_module);
     779
     780    if (!ctxt || ctxt->session == NULL) {
     781        return DECLINED;
     782    }
     783
     784    apr_table_setn(env, "HTTPS", "on");
     785
     786    apr_table_setn(env, "SSL_VERSION_LIBRARY",
     787            "GnuTLS/" LIBGNUTLS_VERSION);
     788    apr_table_setn(env, "SSL_VERSION_INTERFACE",
     789            "mod_gnutls/" MOD_GNUTLS_VERSION);
     790
     791    apr_table_setn(env, "SSL_PROTOCOL",
     792            gnutls_protocol_get_name(gnutls_protocol_get_version
     793            (ctxt->session)));
     794
     795    /* should have been called SSL_CIPHERSUITE instead */
     796    apr_table_setn(env, "SSL_CIPHER",
     797            gnutls_cipher_suite_get_name(gnutls_kx_get
     798            (ctxt->session),
     799            gnutls_cipher_get
     800            (ctxt->session),
     801            gnutls_mac_get
     802            (ctxt->session)));
     803
     804    apr_table_setn(env, "SSL_COMPRESS_METHOD",
     805            gnutls_compression_get_name(gnutls_compression_get
     806            (ctxt->session)));
    822807
    823808#ifdef ENABLE_SRP
    824         tmp = gnutls_srp_server_get_username(ctxt->session);
    825         apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : "");
    826 #endif
    827 
    828         if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
    829                 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
    830 
    831         unsigned int key_size =
    832             8 *
    833             gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
    834         tmp = apr_psprintf(r->pool, "%u", key_size);
    835 
    836         apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
    837 
    838         apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
    839 
    840         apr_table_setn(env, "SSL_CIPHER_EXPORT",
    841                        (key_size <= 40) ? "true" : "false");
    842 
    843         len = sizeof(sbuf);
    844         gnutls_session_get_id(ctxt->session, sbuf, &len);
    845         tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
    846         apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
    847 
    848         if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
    849                 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
    850                                          ctxt->
    851                                          sc->export_certificates_enabled);
    852         else if (gnutls_certificate_type_get(ctxt->session) ==
    853                  GNUTLS_CRT_OPENPGP)
    854                 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
    855                                             ctxt->
    856                                             sc->export_certificates_enabled);
    857 
    858         return rv;
    859 }
    860 
    861 int mgs_hook_authz(request_rec * r)
    862 {
    863         int rv;
    864         mgs_handle_t *ctxt;
    865         mgs_dirconf_rec *dc;
    866 
    867         if (r == NULL)
    868                 return DECLINED;
    869 
    870         dc = ap_get_module_config(r->per_dir_config, &gnutls_module);
    871 
    872         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    873         ctxt =
    874             ap_get_module_config(r->connection->conn_config,
    875                                  &gnutls_module);
    876 
    877         if (!ctxt || ctxt->session == NULL) {
    878                 return DECLINED;
    879         }
    880 
    881         if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
    882                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    883                               "GnuTLS: Directory set to Ignore Client Certificate!");
    884         } else {
    885                 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
    886                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    887                                       "GnuTLS: Attempting to rehandshake with peer. %d %d",
    888                                       ctxt->sc->client_verify_mode,
    889                                       dc->client_verify_mode);
    890 
    891                         /* If we already have a client certificate, there's no point in
    892                          * re-handshaking... */
    893                         rv = mgs_cert_verify(r, ctxt);
    894                         if (rv != DECLINED && rv != HTTP_FORBIDDEN)
    895                                 return rv;
    896 
    897                         gnutls_certificate_server_set_request
    898                             (ctxt->session, dc->client_verify_mode);
    899 
    900                         if (mgs_rehandshake(ctxt) != 0) {
    901                                 return HTTP_FORBIDDEN;
    902                         }
    903                 } else if (ctxt->sc->client_verify_mode ==
    904                            GNUTLS_CERT_IGNORE) {
     809    tmp = gnutls_srp_server_get_username(ctxt->session);
     810    apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : "");
     811#endif
     812
     813    if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
     814        apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
     815
     816    unsigned int key_size =
     817            8 *
     818            gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
     819    tmp = apr_psprintf(r->pool, "%u", key_size);
     820
     821    apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
     822
     823    apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
     824
     825    apr_table_setn(env, "SSL_CIPHER_EXPORT",
     826            (key_size <= 40) ? "true" : "false");
     827
     828    len = sizeof (sbuf);
     829    gnutls_session_get_id(ctxt->session, sbuf, &len);
     830    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
     831    apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
     832
     833    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
     834        mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
     835            ctxt->
     836            sc->export_certificates_enabled);
     837    else if (gnutls_certificate_type_get(ctxt->session) ==
     838            GNUTLS_CRT_OPENPGP)
     839        mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
     840            ctxt->
     841            sc->export_certificates_enabled);
     842
     843    return rv;
     844}
     845
     846int mgs_hook_authz(request_rec * r) {
     847    int rv;
     848    mgs_handle_t *ctxt;
     849    mgs_dirconf_rec *dc;
     850
     851    if (r == NULL)
     852        return DECLINED;
     853
     854    dc = ap_get_module_config(r->per_dir_config, &gnutls_module);
     855
     856    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     857    ctxt =
     858            ap_get_module_config(r->connection->conn_config,
     859            &gnutls_module);
     860
     861    if (!ctxt || ctxt->session == NULL) {
     862        return DECLINED;
     863    }
     864
     865    if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
     866        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     867                "GnuTLS: Directory set to Ignore Client Certificate!");
     868    } else {
     869        if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
     870            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     871                    "GnuTLS: Attempting to rehandshake with peer. %d %d",
     872                    ctxt->sc->client_verify_mode,
     873                    dc->client_verify_mode);
     874
     875            /* If we already have a client certificate, there's no point in
     876             * re-handshaking... */
     877            rv = mgs_cert_verify(r, ctxt);
     878            if (rv != DECLINED && rv != HTTP_FORBIDDEN)
     879                return rv;
     880
     881            gnutls_certificate_server_set_request
     882                    (ctxt->session, dc->client_verify_mode);
     883
     884            if (mgs_rehandshake(ctxt) != 0) {
     885                return HTTP_FORBIDDEN;
     886            }
     887        } else if (ctxt->sc->client_verify_mode ==
     888                GNUTLS_CERT_IGNORE) {
    905889#if MOD_GNUTLS_DEBUG
    906                         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    907                                       "GnuTLS: Peer is set to IGNORE");
    908 #endif
    909                         return DECLINED;
    910                 }
    911                 rv = mgs_cert_verify(r, ctxt);
    912                 if (rv != DECLINED &&
    913                     (rv != HTTP_FORBIDDEN ||
    914                      dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) {
    915                         return rv;
    916                 }
    917         }
    918 
    919         return DECLINED;
     890            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     891                    "GnuTLS: Peer is set to IGNORE");
     892#endif
     893            return DECLINED;
     894        }
     895        rv = mgs_cert_verify(r, ctxt);
     896        if (rv != DECLINED &&
     897                (rv != HTTP_FORBIDDEN ||
     898                dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) {
     899            return rv;
     900        }
     901    }
     902
     903    return DECLINED;
    920904}
    921905
     
    929913 */
    930914#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
     915
    931916static void
    932917mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
    933                          int export_certificates_enabled)
    934 {
    935         unsigned char sbuf[64]; /* buffer to hold serials */
    936         char buf[AP_IOBUFSIZE];
    937         const char *tmp;
    938         char *tmp2;
    939         size_t len;
    940         int ret, i;
    941 
    942         if (r == NULL)
    943                 return;
    944 
    945         apr_table_t *env = r->subprocess_env;
    946 
    947         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    948         if (export_certificates_enabled != 0) {
    949                 char cert_buf[10 * 1024];
    950                 len = sizeof(cert_buf);
    951 
    952                 if (gnutls_x509_crt_export
    953                     (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
    954                         apr_table_setn(env,
    955                                        apr_pstrcat(r->pool, MGS_SIDE,
    956                                                    "_CERT", NULL),
    957                                        apr_pstrmemdup(r->pool, cert_buf,
    958                                                       len));
    959 
    960         }
    961 
    962         len = sizeof(buf);
    963         gnutls_x509_crt_get_dn(cert, buf, &len);
    964         apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
    965                        apr_pstrmemdup(r->pool, buf, len));
    966 
    967         len = sizeof(buf);
    968         gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
    969         apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
    970                        apr_pstrmemdup(r->pool, buf, len));
    971 
    972         len = sizeof(sbuf);
    973         gnutls_x509_crt_get_serial(cert, sbuf, &len);
    974         tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
    975         apr_table_setn(env,
    976                        apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
    977                        apr_pstrdup(r->pool, tmp));
    978 
    979         ret = gnutls_x509_crt_get_version(cert);
    980         if (ret > 0)
    981                 apr_table_setn(env,
    982                                apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
    983                                            NULL), apr_psprintf(r->pool,
    984                                                                "%u", ret));
    985 
    986         apr_table_setn(env,
    987                        apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
    988                        "X.509");
    989 
    990         tmp =
    991             mgs_time2sz(gnutls_x509_crt_get_expiration_time
    992                         (cert), buf, sizeof(buf));
    993         apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
    994                        apr_pstrdup(r->pool, tmp));
    995 
    996         tmp =
    997             mgs_time2sz(gnutls_x509_crt_get_activation_time
    998                         (cert), buf, sizeof(buf));
    999         apr_table_setn(env,
    1000                        apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
    1001                        apr_pstrdup(r->pool, tmp));
    1002 
    1003         ret = gnutls_x509_crt_get_signature_algorithm(cert);
    1004         if (ret >= 0) {
    1005                 apr_table_setn(env,
    1006                                apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG",
    1007                                            NULL),
    1008                                gnutls_sign_algorithm_get_name(ret));
    1009         }
    1010 
    1011         ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
    1012         if (ret >= 0) {
    1013                 apr_table_setn(env,
    1014                                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
    1015                                            NULL),
    1016                                gnutls_pk_algorithm_get_name(ret));
    1017         }
    1018 
    1019         /* export all the alternative names (DNS, RFC822 and URI) */
    1020         for (i = 0; !(ret < 0); i++) {
    1021                 len = 0;
    1022                 ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
    1023                                                            NULL, &len,
    1024                                                            NULL);
    1025 
    1026                 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) {
    1027                         tmp2 = apr_palloc(r->pool, len + 1);
    1028 
    1029                         ret =
    1030                             gnutls_x509_crt_get_subject_alt_name(cert, i,
    1031                                                                  tmp2,
    1032                                                                  &len,
    1033                                                                  NULL);
    1034                         tmp2[len] = 0;
    1035 
    1036                         if (ret == GNUTLS_SAN_DNSNAME) {
    1037                                 apr_table_setn(env,
    1038                                                apr_psprintf(r->pool,
    1039                                                             "%s_S_AN%u",
    1040                                                             MGS_SIDE, i),
    1041                                                apr_psprintf(r->pool,
    1042                                                             "DNSNAME:%s",
    1043                                                             tmp2));
    1044                         } else if (ret == GNUTLS_SAN_RFC822NAME) {
    1045                                 apr_table_setn(env,
    1046                                                apr_psprintf(r->pool,
    1047                                                             "%s_S_AN%u",
    1048                                                             MGS_SIDE, i),
    1049                                                apr_psprintf(r->pool,
    1050                                                             "RFC822NAME:%s",
    1051                                                             tmp2));
    1052                         } else if (ret == GNUTLS_SAN_URI) {
    1053                                 apr_table_setn(env,
    1054                                                apr_psprintf(r->pool,
    1055                                                             "%s_S_AN%u",
    1056                                                             MGS_SIDE, i),
    1057                                                apr_psprintf(r->pool,
    1058                                                             "URI:%s",
    1059                                                             tmp2));
    1060                         } else {
    1061                                 apr_table_setn(env,
    1062                                                apr_psprintf(r->pool,
    1063                                                             "%s_S_AN%u",
    1064                                                             MGS_SIDE, i),
    1065                                                "UNSUPPORTED");
    1066                         }
    1067                 }
    1068         }
     918        int export_certificates_enabled) {
     919    unsigned char sbuf[64]; /* buffer to hold serials */
     920    char buf[AP_IOBUFSIZE];
     921    const char *tmp;
     922    char *tmp2;
     923    size_t len;
     924    int ret, i;
     925
     926    if (r == NULL)
     927        return;
     928
     929    apr_table_t *env = r->subprocess_env;
     930
     931    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     932    if (export_certificates_enabled != 0) {
     933        char cert_buf[10 * 1024];
     934        len = sizeof (cert_buf);
     935
     936        if (gnutls_x509_crt_export
     937                (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0)
     938            apr_table_setn(env,
     939                apr_pstrcat(r->pool, MGS_SIDE,
     940                "_CERT", NULL),
     941                apr_pstrmemdup(r->pool, cert_buf,
     942                len));
     943
     944    }
     945
     946    len = sizeof (buf);
     947    gnutls_x509_crt_get_dn(cert, buf, &len);
     948    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL),
     949            apr_pstrmemdup(r->pool, buf, len));
     950
     951    len = sizeof (buf);
     952    gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
     953    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL),
     954            apr_pstrmemdup(r->pool, buf, len));
     955
     956    len = sizeof (sbuf);
     957    gnutls_x509_crt_get_serial(cert, sbuf, &len);
     958    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
     959    apr_table_setn(env,
     960            apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL),
     961            apr_pstrdup(r->pool, tmp));
     962
     963    ret = gnutls_x509_crt_get_version(cert);
     964    if (ret > 0)
     965        apr_table_setn(env,
     966            apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
     967            NULL), apr_psprintf(r->pool,
     968            "%u", ret));
     969
     970    apr_table_setn(env,
     971            apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
     972            "X.509");
     973
     974    tmp =
     975            mgs_time2sz(gnutls_x509_crt_get_expiration_time
     976            (cert), buf, sizeof (buf));
     977    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
     978            apr_pstrdup(r->pool, tmp));
     979
     980    tmp =
     981            mgs_time2sz(gnutls_x509_crt_get_activation_time
     982            (cert), buf, sizeof (buf));
     983    apr_table_setn(env,
     984            apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
     985            apr_pstrdup(r->pool, tmp));
     986
     987    ret = gnutls_x509_crt_get_signature_algorithm(cert);
     988    if (ret >= 0) {
     989        apr_table_setn(env,
     990                apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG",
     991                NULL),
     992                gnutls_sign_algorithm_get_name(ret));
     993    }
     994
     995    ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
     996    if (ret >= 0) {
     997        apr_table_setn(env,
     998                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
     999                NULL),
     1000                gnutls_pk_algorithm_get_name(ret));
     1001    }
     1002
     1003    /* export all the alternative names (DNS, RFC822 and URI) */
     1004    for (i = 0; !(ret < 0); i++) {
     1005        len = 0;
     1006        ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
     1007                NULL, &len,
     1008                NULL);
     1009
     1010        if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) {
     1011            tmp2 = apr_palloc(r->pool, len + 1);
     1012
     1013            ret =
     1014                    gnutls_x509_crt_get_subject_alt_name(cert, i,
     1015                    tmp2,
     1016                    &len,
     1017                    NULL);
     1018            tmp2[len] = 0;
     1019
     1020            if (ret == GNUTLS_SAN_DNSNAME) {
     1021                apr_table_setn(env,
     1022                        apr_psprintf(r->pool,
     1023                        "%s_S_AN%u",
     1024                        MGS_SIDE, i),
     1025                        apr_psprintf(r->pool,
     1026                        "DNSNAME:%s",
     1027                        tmp2));
     1028            } else if (ret == GNUTLS_SAN_RFC822NAME) {
     1029                apr_table_setn(env,
     1030                        apr_psprintf(r->pool,
     1031                        "%s_S_AN%u",
     1032                        MGS_SIDE, i),
     1033                        apr_psprintf(r->pool,
     1034                        "RFC822NAME:%s",
     1035                        tmp2));
     1036            } else if (ret == GNUTLS_SAN_URI) {
     1037                apr_table_setn(env,
     1038                        apr_psprintf(r->pool,
     1039                        "%s_S_AN%u",
     1040                        MGS_SIDE, i),
     1041                        apr_psprintf(r->pool,
     1042                        "URI:%s",
     1043                        tmp2));
     1044            } else {
     1045                apr_table_setn(env,
     1046                        apr_psprintf(r->pool,
     1047                        "%s_S_AN%u",
     1048                        MGS_SIDE, i),
     1049                        "UNSUPPORTED");
     1050            }
     1051        }
     1052    }
    10691053}
    10701054
    10711055static void
    10721056mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert,
    1073                             int side, int export_certificates_enabled)
    1074 {
    1075         unsigned char sbuf[64]; /* buffer to hold serials */
    1076         char buf[AP_IOBUFSIZE];
    1077         const char *tmp;
    1078         size_t len;
    1079         int ret;
    1080 
    1081         if (r == NULL)
    1082                 return;
    1083 
    1084         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    1085         apr_table_t *env = r->subprocess_env;
    1086 
    1087         if (export_certificates_enabled != 0) {
    1088                 char cert_buf[10 * 1024];
    1089                 len = sizeof(cert_buf);
    1090 
    1091                 if (gnutls_openpgp_crt_export
    1092                     (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
    1093                         apr_table_setn(env,
    1094                                        apr_pstrcat(r->pool, MGS_SIDE,
    1095                                                    "_CERT", NULL),
    1096                                        apr_pstrmemdup(r->pool, cert_buf,
    1097                                                       len));
    1098 
    1099         }
    1100 
    1101         len = sizeof(buf);
    1102         gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
    1103         apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
    1104                        apr_pstrmemdup(r->pool, buf, len));
    1105 
    1106         len = sizeof(sbuf);
    1107         gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
    1108         tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
    1109         apr_table_setn(env,
    1110                        apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT",
    1111                                    NULL), apr_pstrdup(r->pool, tmp));
    1112 
    1113         ret = gnutls_openpgp_crt_get_version(cert);
    1114         if (ret > 0)
    1115                 apr_table_setn(env,
    1116                                apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
    1117                                            NULL), apr_psprintf(r->pool,
    1118                                                                "%u", ret));
    1119 
    1120         apr_table_setn(env,
    1121                        apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
    1122                        "OPENPGP");
    1123 
    1124         tmp =
    1125             mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
    1126                         (cert), buf, sizeof(buf));
    1127         apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
    1128                        apr_pstrdup(r->pool, tmp));
    1129 
    1130         tmp =
    1131             mgs_time2sz(gnutls_openpgp_crt_get_creation_time
    1132                         (cert), buf, sizeof(buf));
    1133         apr_table_setn(env,
    1134                        apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
    1135                        apr_pstrdup(r->pool, tmp));
    1136 
    1137         ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
    1138         if (ret >= 0) {
    1139                 apr_table_setn(env,
    1140                                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
    1141                                            NULL),
    1142                                gnutls_pk_algorithm_get_name(ret));
    1143         }
     1057        int side, int export_certificates_enabled) {
     1058    unsigned char sbuf[64]; /* buffer to hold serials */
     1059    char buf[AP_IOBUFSIZE];
     1060    const char *tmp;
     1061    size_t len;
     1062    int ret;
     1063
     1064    if (r == NULL)
     1065        return;
     1066
     1067    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     1068    apr_table_t *env = r->subprocess_env;
     1069
     1070    if (export_certificates_enabled != 0) {
     1071        char cert_buf[10 * 1024];
     1072        len = sizeof (cert_buf);
     1073
     1074        if (gnutls_openpgp_crt_export
     1075                (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
     1076            apr_table_setn(env,
     1077                apr_pstrcat(r->pool, MGS_SIDE,
     1078                "_CERT", NULL),
     1079                apr_pstrmemdup(r->pool, cert_buf,
     1080                len));
     1081
     1082    }
     1083
     1084    len = sizeof (buf);
     1085    gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
     1086    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
     1087            apr_pstrmemdup(r->pool, buf, len));
     1088
     1089    len = sizeof (sbuf);
     1090    gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
     1091    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf));
     1092    apr_table_setn(env,
     1093            apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT",
     1094            NULL), apr_pstrdup(r->pool, tmp));
     1095
     1096    ret = gnutls_openpgp_crt_get_version(cert);
     1097    if (ret > 0)
     1098        apr_table_setn(env,
     1099            apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION",
     1100            NULL), apr_psprintf(r->pool,
     1101            "%u", ret));
     1102
     1103    apr_table_setn(env,
     1104            apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL),
     1105            "OPENPGP");
     1106
     1107    tmp =
     1108            mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
     1109            (cert), buf, sizeof (buf));
     1110    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
     1111            apr_pstrdup(r->pool, tmp));
     1112
     1113    tmp =
     1114            mgs_time2sz(gnutls_openpgp_crt_get_creation_time
     1115            (cert), buf, sizeof (buf));
     1116    apr_table_setn(env,
     1117            apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
     1118            apr_pstrdup(r->pool, tmp));
     1119
     1120    ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
     1121    if (ret >= 0) {
     1122        apr_table_setn(env,
     1123                apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY",
     1124                NULL),
     1125                gnutls_pk_algorithm_get_name(ret));
     1126    }
    11441127
    11451128}
    11461129
    11471130/* TODO: Allow client sending a X.509 certificate chain */
    1148 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
    1149 {
    1150         const gnutls_datum_t *cert_list;
    1151         unsigned int cert_list_size, status;
    1152         int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;
    1153         unsigned int ch_size = 0;
    1154         union {
    1155                 gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
    1156                 gnutls_openpgp_crt_t pgp;
    1157         } cert;
    1158         apr_time_t expiration_time, cur_time;
    1159 
    1160         if (r == NULL || ctxt == NULL || ctxt->session == NULL)
    1161                 return HTTP_FORBIDDEN;
    1162 
    1163         _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    1164         cert_list =
    1165             gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
    1166 
    1167         if (cert_list == NULL || cert_list_size == 0) {
    1168                 /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
    1169                 */
    1170                 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
    1171                         return OK;
    1172 
    1173                 /* no certificate provided by the client, but one was required. */
    1174                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1175                               "GnuTLS: Failed to Verify Peer: "
    1176                               "Client did not submit a certificate");
    1177                 return HTTP_FORBIDDEN;
    1178         }
    1179 
    1180         if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1181                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    1182                               "GnuTLS: A Chain of %d certificate(s) was provided for validation",
    1183                               cert_list_size);
    1184 
    1185                 for (ch_size = 0; ch_size < cert_list_size; ch_size++) {
    1186                         gnutls_x509_crt_init(&cert.x509[ch_size]);
    1187                         rv = gnutls_x509_crt_import(cert.x509[ch_size],
    1188                                                     &cert_list[ch_size],
    1189                                                     GNUTLS_X509_FMT_DER);
    1190                         // When failure to import, leave the loop
    1191                         if (rv != GNUTLS_E_SUCCESS) {
    1192                                 if (ch_size < 1) {
    1193                                         ap_log_rerror(APLOG_MARK,
    1194                                                       APLOG_INFO, 0, r,
    1195                                                       "GnuTLS: Failed to Verify Peer: "
    1196                                                       "Failed to import peer certificates.");
    1197                                         ret = HTTP_FORBIDDEN;
    1198                                         goto exit;
    1199                                 }
    1200                                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1201                                               "GnuTLS: Failed to import some peer certificates. Using %d certificates",
    1202                                               ch_size);
    1203                                 rv = GNUTLS_E_SUCCESS;
    1204                                 break;
    1205                         }
    1206                 }
    1207         } else if (gnutls_certificate_type_get(ctxt->session) ==
    1208                    GNUTLS_CRT_OPENPGP) {
    1209                 if (cert_list_size > 1) {
    1210                         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1211                                       "GnuTLS: Failed to Verify Peer: "
    1212                                       "Chained Client Certificates are not supported.");
    1213                         return HTTP_FORBIDDEN;
    1214                 }
    1215 
    1216                 gnutls_openpgp_crt_init(&cert.pgp);
    1217                 rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0],
    1218                                                GNUTLS_OPENPGP_FMT_RAW);
    1219 
    1220         } else
    1221                 return HTTP_FORBIDDEN;
    1222 
    1223         if (rv < 0) {
    1224                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1225                               "GnuTLS: Failed to Verify Peer: "
    1226                               "Failed to import peer certificates.");
    1227                 ret = HTTP_FORBIDDEN;
    1228                 goto exit;
    1229         }
    1230 
    1231         if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1232                 apr_time_ansi_put(&expiration_time,
    1233                                   gnutls_x509_crt_get_expiration_time
    1234                                   (cert.x509[0]));
    1235 
    1236                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
    1237                               "GnuTLS: Verifying list of  %d certificate(s)",
    1238                               ch_size);
    1239                 rv = gnutls_x509_crt_list_verify(cert.x509, ch_size,
    1240                                                 ctxt->sc->ca_list,
    1241                                                 ctxt->sc->ca_list_size,
    1242                                                 NULL, 0, 0, &status);
    1243         } else {
    1244                 apr_time_ansi_put(&expiration_time,
    1245                                   gnutls_openpgp_crt_get_expiration_time
    1246                                   (cert.pgp));
    1247 
    1248                 rv = gnutls_openpgp_crt_verify_ring(cert.pgp,
    1249                                                     ctxt->sc->pgp_list, 0,
    1250                                                     &status);
    1251         }
    1252 
    1253         if (rv < 0) {
    1254                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1255                               "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
    1256                               rv, gnutls_strerror(rv));
    1257                 if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
    1258                         ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
    1259                                       "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
    1260                 ret = HTTP_FORBIDDEN;
    1261                 goto exit;
    1262         }
    1263 
    1264         /* TODO: X509 CRL Verification. */
    1265         /* May add later if anyone needs it.
    1266         */
    1267         /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
    1268 
    1269         cur_time = apr_time_now();
    1270 
    1271         if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
    1272                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1273                               "GnuTLS: Could not find Signer for Peer Certificate");
    1274         }
    1275 
    1276         if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
    1277                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1278                               "GnuTLS: Peer's Certificate signer is not a CA");
    1279         }
    1280 
    1281         if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
    1282                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1283                               "GnuTLS: Peer's Certificate is using insecure algorithms");
    1284         }
    1285 
    1286         if (status & GNUTLS_CERT_EXPIRED
    1287             || status & GNUTLS_CERT_NOT_ACTIVATED) {
    1288                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1289                               "GnuTLS: Peer's Certificate signer is expired or not yet activated");
    1290         }
    1291 
    1292         if (status & GNUTLS_CERT_INVALID) {
    1293                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1294                               "GnuTLS: Peer Certificate is invalid.");
    1295         } else if (status & GNUTLS_CERT_REVOKED) {
    1296                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1297                               "GnuTLS: Peer Certificate is revoked.");
    1298         }
    1299 
    1300         if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
    1301                 mgs_add_common_cert_vars(r, cert.x509[0], 1,
    1302                                         ctxt->
    1303                                         sc->export_certificates_enabled);
    1304         else if (gnutls_certificate_type_get(ctxt->session) ==
    1305                 GNUTLS_CRT_OPENPGP)
    1306                 mgs_add_common_pgpcert_vars(r, cert.pgp, 1,
    1307                                             ctxt->
    1308                                             sc->export_certificates_enabled);
    1309 
    1310         {
    1311                 /* days remaining */
    1312                 unsigned long remain =
    1313                     (apr_time_sec(expiration_time) -
    1314                      apr_time_sec(cur_time)) / 86400;
    1315                 apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
    1316                                apr_psprintf(r->pool, "%lu", remain));
    1317         }
    1318 
    1319         if (status == 0) {
    1320                 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
    1321                                "SUCCESS");
    1322                 ret = OK;
    1323         } else {
    1324                 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
    1325                                "FAILED");
    1326                 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
    1327                         ret = OK;
    1328                 else
    1329                         ret = HTTP_FORBIDDEN;
    1330         }
    1331 
    1332       exit:
    1333         if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1334                 int i;
    1335                 for (i = 0; i < ch_size; i++) {
    1336                         gnutls_x509_crt_deinit(cert.x509[i]);
    1337                 }
    1338         } else if (gnutls_certificate_type_get(ctxt->session) ==
    1339                    GNUTLS_CRT_OPENPGP)
    1340                 gnutls_openpgp_crt_deinit(cert.pgp);
    1341         return ret;
    1342 
    1343 
    1344 }
     1131static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) {
     1132    const gnutls_datum_t *cert_list;
     1133    unsigned int cert_list_size, status;
     1134    int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;
     1135    unsigned int ch_size = 0;
     1136
     1137    union {
     1138        gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
     1139        gnutls_openpgp_crt_t pgp;
     1140    } cert;
     1141    apr_time_t expiration_time, cur_time;
     1142
     1143    if (r == NULL || ctxt == NULL || ctxt->session == NULL)
     1144        return HTTP_FORBIDDEN;
     1145
     1146    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     1147    cert_list =
     1148            gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
     1149
     1150    if (cert_list == NULL || cert_list_size == 0) {
     1151        /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
     1152        */
     1153        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
     1154            return OK;
     1155
     1156        /* no certificate provided by the client, but one was required. */
     1157        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1158                "GnuTLS: Failed to Verify Peer: "
     1159                "Client did not submit a certificate");
     1160        return HTTP_FORBIDDEN;
     1161    }
     1162
     1163    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
     1164        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     1165                "GnuTLS: A Chain of %d certificate(s) was provided for validation",
     1166                cert_list_size);
     1167
     1168        for (ch_size = 0; ch_size < cert_list_size; ch_size++) {
     1169            gnutls_x509_crt_init(&cert.x509[ch_size]);
     1170            rv = gnutls_x509_crt_import(cert.x509[ch_size],
     1171                    &cert_list[ch_size],
     1172                    GNUTLS_X509_FMT_DER);
     1173            // When failure to import, leave the loop
     1174            if (rv != GNUTLS_E_SUCCESS) {
     1175                if (ch_size < 1) {
     1176                    ap_log_rerror(APLOG_MARK,
     1177                            APLOG_INFO, 0, r,
     1178                            "GnuTLS: Failed to Verify Peer: "
     1179                            "Failed to import peer certificates.");
     1180                    ret = HTTP_FORBIDDEN;
     1181                    goto exit;
     1182                }
     1183                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1184                        "GnuTLS: Failed to import some peer certificates. Using %d certificates",
     1185                        ch_size);
     1186                rv = GNUTLS_E_SUCCESS;
     1187                break;
     1188            }
     1189        }
     1190    } else if (gnutls_certificate_type_get(ctxt->session) ==
     1191            GNUTLS_CRT_OPENPGP) {
     1192        if (cert_list_size > 1) {
     1193            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1194                    "GnuTLS: Failed to Verify Peer: "
     1195                    "Chained Client Certificates are not supported.");
     1196            return HTTP_FORBIDDEN;
     1197        }
     1198
     1199        gnutls_openpgp_crt_init(&cert.pgp);
     1200        rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0],
     1201                GNUTLS_OPENPGP_FMT_RAW);
     1202
     1203    } else
     1204        return HTTP_FORBIDDEN;
     1205
     1206    if (rv < 0) {
     1207        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1208                "GnuTLS: Failed to Verify Peer: "
     1209                "Failed to import peer certificates.");
     1210        ret = HTTP_FORBIDDEN;
     1211        goto exit;
     1212    }
     1213
     1214    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
     1215        apr_time_ansi_put(&expiration_time,
     1216                gnutls_x509_crt_get_expiration_time
     1217                (cert.x509[0]));
     1218
     1219        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
     1220                "GnuTLS: Verifying list of  %d certificate(s)",
     1221                ch_size);
     1222        rv = gnutls_x509_crt_list_verify(cert.x509, ch_size,
     1223                ctxt->sc->ca_list,
     1224                ctxt->sc->ca_list_size,
     1225                NULL, 0, 0, &status);
     1226    } else {
     1227        apr_time_ansi_put(&expiration_time,
     1228                gnutls_openpgp_crt_get_expiration_time
     1229                (cert.pgp));
     1230
     1231        rv = gnutls_openpgp_crt_verify_ring(cert.pgp,
     1232                ctxt->sc->pgp_list, 0,
     1233                &status);
     1234    }
     1235
     1236    if (rv < 0) {
     1237        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1238                "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
     1239                rv, gnutls_strerror(rv));
     1240        if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
     1241            ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
     1242                "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
     1243        ret = HTTP_FORBIDDEN;
     1244        goto exit;
     1245    }
     1246
     1247    /* TODO: X509 CRL Verification. */
     1248    /* May add later if anyone needs it.
     1249    */
     1250    /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
     1251
     1252    cur_time = apr_time_now();
     1253
     1254    if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
     1255        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1256                "GnuTLS: Could not find Signer for Peer Certificate");
     1257    }
     1258
     1259    if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
     1260        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1261                "GnuTLS: Peer's Certificate signer is not a CA");
     1262    }
     1263
     1264    if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
     1265        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1266                "GnuTLS: Peer's Certificate is using insecure algorithms");
     1267    }
     1268
     1269    if (status & GNUTLS_CERT_EXPIRED
     1270            || status & GNUTLS_CERT_NOT_ACTIVATED) {
     1271        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1272                "GnuTLS: Peer's Certificate signer is expired or not yet activated");
     1273    }
     1274
     1275    if (status & GNUTLS_CERT_INVALID) {
     1276        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1277                "GnuTLS: Peer Certificate is invalid.");
     1278    } else if (status & GNUTLS_CERT_REVOKED) {
     1279        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1280                "GnuTLS: Peer Certificate is revoked.");
     1281    }
     1282
     1283    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
     1284        mgs_add_common_cert_vars(r, cert.x509[0], 1,
     1285            ctxt->
     1286            sc->export_certificates_enabled);
     1287    else if (gnutls_certificate_type_get(ctxt->session) ==
     1288            GNUTLS_CRT_OPENPGP)
     1289        mgs_add_common_pgpcert_vars(r, cert.pgp, 1,
     1290            ctxt->
     1291            sc->export_certificates_enabled);
     1292
     1293    {
     1294        /* days remaining */
     1295        unsigned long remain =
     1296                (apr_time_sec(expiration_time) -
     1297                apr_time_sec(cur_time)) / 86400;
     1298        apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
     1299                apr_psprintf(r->pool, "%lu", remain));
     1300    }
     1301
     1302    if (status == 0) {
     1303        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
     1304                "SUCCESS");
     1305        ret = OK;
     1306    } else {
     1307        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
     1308                "FAILED");
     1309        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
     1310            ret = OK;
     1311        else
     1312            ret = HTTP_FORBIDDEN;
     1313    }
     1314
     1315exit:
     1316    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
     1317        int i;
     1318        for (i = 0; i < ch_size; i++) {
     1319            gnutls_x509_crt_deinit(cert.x509[i]);
     1320        }
     1321    } else if (gnutls_certificate_type_get(ctxt->session) ==
     1322            GNUTLS_CRT_OPENPGP)
     1323        gnutls_openpgp_crt_deinit(cert.pgp);
     1324    return ret;
     1325
     1326
     1327}
  • src/gnutls_io.c

    r6223319 re183628  
    11/**
    22 *  Copyright 2004-2005 Paul Querna
     3 *  Copyright 2008 Nikos Mavrogiannopoulos
     4 *  Copyright 2011 Dash Shendy
    35 *
    46 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    3335
    3436static apr_status_t gnutls_io_filter_error(ap_filter_t * f,
    35                                            apr_bucket_brigade * bb,
    36                                            apr_status_t status)
    37 {
    38         mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
    39         apr_bucket *bucket;
    40 
    41         switch (status) {
    42         case HTTP_BAD_REQUEST:
    43                 /* log the situation */
    44                 ap_log_error(APLOG_MARK, APLOG_INFO, 0,
    45                              f->c->base_server,
    46                              "GnuTLS handshake failed: HTTP spoken on HTTPS port; "
    47                              "trying to send HTML error page");
    48 
    49                 ctxt->status = -1;
    50 
    51                 /* fake the request line */
    52                 bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc);
    53                 break;
    54 
    55         default:
    56                 return status;
    57         }
    58 
    59         APR_BRIGADE_INSERT_TAIL(bb, bucket);
    60         bucket = apr_bucket_eos_create(f->c->bucket_alloc);
    61         APR_BRIGADE_INSERT_TAIL(bb, bucket);
    62 
    63         return APR_SUCCESS;
    64 }
    65 
    66 static int char_buffer_read(mgs_char_buffer_t * buffer, char *in, int inl)
    67 {
    68         if (!buffer->length) {
    69                 return 0;
    70         }
    71 
    72         if (buffer->length > inl) {
    73                 /* we have have enough to fill the caller's buffer */
    74                 memmove(in, buffer->value, inl);
    75                 buffer->value += inl;
    76                 buffer->length -= inl;
    77         } else {
    78                 /* swallow remainder of the buffer */
    79                 memmove(in, buffer->value, buffer->length);
    80                 inl = buffer->length;
    81                 buffer->value = NULL;
    82                 buffer->length = 0;
    83         }
    84 
    85         return inl;
    86 }
    87 
    88 static int char_buffer_write(mgs_char_buffer_t * buffer, char *in, int inl)
    89 {
    90         buffer->value = in;
    91         buffer->length = inl;
    92         return inl;
     37        apr_bucket_brigade * bb,
     38        apr_status_t status) {
     39    mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
     40    apr_bucket *bucket;
     41
     42    switch (status) {
     43        case HTTP_BAD_REQUEST:
     44            /* log the situation */
     45            ap_log_error(APLOG_MARK, APLOG_INFO, 0,
     46                    f->c->base_server,
     47                    "GnuTLS handshake failed: HTTP spoken on HTTPS port; "
     48                    "trying to send HTML error page");
     49
     50            ctxt->status = -1;
     51
     52            /* fake the request line */
     53            bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc);
     54            break;
     55
     56        default:
     57            return status;
     58    }
     59
     60    APR_BRIGADE_INSERT_TAIL(bb, bucket);
     61    bucket = apr_bucket_eos_create(f->c->bucket_alloc);
     62    APR_BRIGADE_INSERT_TAIL(bb, bucket);
     63
     64    return APR_SUCCESS;
     65}
     66
     67static int char_buffer_read(mgs_char_buffer_t * buffer, char *in, int inl) {
     68    if (!buffer->length) {
     69        return 0;
     70    }
     71
     72    if (buffer->length > inl) {
     73        /* we have have enough to fill the caller's buffer */
     74        memmove(in, buffer->value, inl);
     75        buffer->value += inl;
     76        buffer->length -= inl;
     77    } else {
     78        /* swallow remainder of the buffer */
     79        memmove(in, buffer->value, buffer->length);
     80        inl = buffer->length;
     81        buffer->value = NULL;
     82        buffer->length = 0;
     83    }
     84
     85    return inl;
     86}
     87
     88static int char_buffer_write(mgs_char_buffer_t * buffer, char *in, int inl) {
     89    buffer->value = in;
     90    buffer->length = inl;
     91    return inl;
    9392}
    9493
     
    9998 */
    10099static apr_status_t brigade_consume(apr_bucket_brigade * bb,
    101                                     apr_read_type_e block,
    102                                     char *c, apr_size_t * len)
    103 {
    104         apr_size_t actual = 0;
    105         apr_status_t status = APR_SUCCESS;
    106 
    107         while (!APR_BRIGADE_EMPTY(bb)) {
    108                 apr_bucket *b = APR_BRIGADE_FIRST(bb);
    109                 const char *str;
    110                 apr_size_t str_len;
    111                 apr_size_t consume;
    112 
    113                 /* Justin points out this is an http-ism that might
    114                  * not fit if brigade_consume is added to APR.  Perhaps
    115                  * apr_bucket_read(eos_bucket) should return APR_EOF?
    116                  * Then this becomes mainline instead of a one-off.
    117                  */
    118                 if (APR_BUCKET_IS_EOS(b)) {
    119                         status = APR_EOF;
    120                         break;
    121                 }
    122 
    123                 /* The reason I'm not offering brigade_consume yet
    124                  * across to apr-util is that the following call
    125                  * illustrates how borked that API really is.  For
    126                  * this sort of case (caller provided buffer) it
    127                  * would be much more trivial for apr_bucket_consume
    128                  * to do all the work that follows, based on the
    129                  * particular characteristics of the bucket we are
    130                  * consuming here.
    131                  */
    132                 status = apr_bucket_read(b, &str, &str_len, block);
    133 
    134                 if (status != APR_SUCCESS) {
    135                         if (APR_STATUS_IS_EOF(status)) {
    136                                 /* This stream bucket was consumed */
    137                                 apr_bucket_delete(b);
    138                                 continue;
    139                         }
    140                         break;
    141                 }
    142 
    143                 if (str_len > 0) {
    144                         /* Do not block once some data has been consumed */
    145                         block = APR_NONBLOCK_READ;
    146 
    147                         /* Assure we don't overflow. */
    148                         consume =
    149                             (str_len + actual >
    150                              *len) ? *len - actual : str_len;
    151 
    152                         memcpy(c, str, consume);
    153 
    154                         c += consume;
    155                         actual += consume;
    156 
    157                         if (consume >= b->length) {
    158                                 /* This physical bucket was consumed */
    159                                 apr_bucket_delete(b);
    160                         } else {
    161                                 /* Only part of this physical bucket was consumed */
    162                                 b->start += consume;
    163                                 b->length -= consume;
    164                         }
    165                 } else if (b->length == 0) {
    166                         apr_bucket_delete(b);
    167                 }
    168 
    169                 /* This could probably be actual == *len, but be safe from stray
    170                  * photons. */
    171                 if (actual >= *len) {
    172                         break;
    173                 }
    174         }
    175 
    176         *len = actual;
    177         return status;
    178 }
    179 
     100        apr_read_type_e block,
     101        char *c, apr_size_t * len) {
     102    apr_size_t actual = 0;
     103    apr_status_t status = APR_SUCCESS;
     104
     105    while (!APR_BRIGADE_EMPTY(bb)) {
     106        apr_bucket *b = APR_BRIGADE_FIRST(bb);
     107        const char *str;
     108        apr_size_t str_len;
     109        apr_size_t consume;
     110
     111        /* Justin points out this is an http-ism that might
     112         * not fit if brigade_consume is added to APR.  Perhaps
     113         * apr_bucket_read(eos_bucket) should return APR_EOF?
     114         * Then this becomes mainline instead of a one-off.
     115         */
     116        if (APR_BUCKET_IS_EOS(b)) {
     117            status = APR_EOF;
     118            break;
     119        }
     120
     121        /* The reason I'm not offering brigade_consume yet
     122         * across to apr-util is that the following call
     123         * illustrates how borked that API really is.  For
     124         * this sort of case (caller provided buffer) it
     125         * would be much more trivial for apr_bucket_consume
     126         * to do all the work that follows, based on the
     127         * particular characteristics of the bucket we are
     128         * consuming here.
     129         */
     130        status = apr_bucket_read(b, &str, &str_len, block);
     131
     132        if (status != APR_SUCCESS) {
     133            if (APR_STATUS_IS_EOF(status)) {
     134                /* This stream bucket was consumed */
     135                apr_bucket_delete(b);
     136                continue;
     137            }
     138            break;
     139        }
     140
     141        if (str_len > 0) {
     142            /* Do not block once some data has been consumed */
     143            block = APR_NONBLOCK_READ;
     144
     145            /* Assure we don't overflow. */
     146            consume =
     147                    (str_len + actual >
     148                    *len) ? *len - actual : str_len;
     149
     150            memcpy(c, str, consume);
     151
     152            c += consume;
     153            actual += consume;
     154
     155            if (consume >= b->length) {
     156                /* This physical bucket was consumed */
     157                apr_bucket_delete(b);
     158            } else {
     159                /* Only part of this physical bucket was consumed */
     160                b->start += consume;
     161                b->length -= consume;
     162            }
     163        } else if (b->length == 0) {
     164            apr_bucket_delete(b);
     165        }
     166
     167        /* This could probably be actual == *len, but be safe from stray
     168         * photons. */
     169        if (actual >= *len) {
     170            break;
     171        }
     172    }
     173
     174    *len = actual;
     175    return status;
     176}
    180177
    181178static apr_status_t gnutls_io_input_read(mgs_handle_t * ctxt,
    182                                          char *buf, apr_size_t * len)
    183 {
    184         apr_size_t wanted = *len;
    185         apr_size_t bytes = 0;
    186         int rc;
    187 
    188         *len = 0;
    189 
    190         /* If we have something leftover from last time, try that first. */
    191         if ((bytes = char_buffer_read(&ctxt->input_cbuf, buf, wanted))) {
    192                 *len = bytes;
    193                 if (ctxt->input_mode == AP_MODE_SPECULATIVE) {
    194                         /* We want to rollback this read. */
    195                         if (ctxt->input_cbuf.length > 0) {
    196                                 ctxt->input_cbuf.value -= bytes;
    197                                 ctxt->input_cbuf.length += bytes;
    198                         } else {
    199                                 char_buffer_write(&ctxt->input_cbuf, buf,
    200                                                   (int) bytes);
    201                         }
    202                         return APR_SUCCESS;
    203                 }
    204                 /* This could probably be *len == wanted, but be safe from stray
    205                  * photons.
    206                  */
    207                 if (*len >= wanted) {
    208                         return APR_SUCCESS;
    209                 }
    210                 if (ctxt->input_mode == AP_MODE_GETLINE) {
    211                         if (memchr(buf, APR_ASCII_LF, *len)) {
    212                                 return APR_SUCCESS;
    213                         }
    214                 } else {
    215                         /* Down to a nonblock pattern as we have some data already
    216                          */
    217                         ctxt->input_block = APR_NONBLOCK_READ;
    218                 }
    219         }
    220 
    221         if (ctxt->session == NULL) {
    222                 return APR_EGENERAL;
    223         }
    224 
    225         while (1) {
    226 
    227                 rc = gnutls_record_recv(ctxt->session, buf + bytes,
    228                                         wanted - bytes);
    229 
    230                 if (rc > 0) {
    231                         *len += rc;
    232                         if (ctxt->input_mode == AP_MODE_SPECULATIVE) {
    233                                 /* We want to rollback this read. */
    234                                 char_buffer_write(&ctxt->input_cbuf, buf,
    235                                                   rc);
    236                         }
    237                         return ctxt->input_rc;
    238                 } else if (rc == 0) {
    239                         /* If EAGAIN, we will loop given a blocking read,
    240                          * otherwise consider ourselves at EOF.
    241                          */
    242                         if (APR_STATUS_IS_EAGAIN(ctxt->input_rc)
    243                             || APR_STATUS_IS_EINTR(ctxt->input_rc)) {
    244                                 /* Already read something, return APR_SUCCESS instead.
    245                                  * On win32 in particular, but perhaps on other kernels,
    246                                  * a blocking call isn't 'always' blocking.
    247                                  */
    248                                 if (*len > 0) {
    249                                         ctxt->input_rc = APR_SUCCESS;
    250                                         break;
    251                                 }
    252                                 if (ctxt->input_block == APR_NONBLOCK_READ) {
    253                                         break;
    254                                 }
    255                         } else {
    256                                 if (*len > 0) {
    257                                         ctxt->input_rc = APR_SUCCESS;
    258                                 } else {
    259                                         ctxt->input_rc = APR_EOF;
    260                                 }
    261                                 break;
    262                         }
    263                 } else {        /* (rc < 0) */
    264 
    265                         if (rc == GNUTLS_E_REHANDSHAKE) {
    266                                 /* A client has asked for a new Hankshake. Currently, we don't do it */
    267                                 ap_log_error(APLOG_MARK, APLOG_INFO,
    268                                              ctxt->input_rc,
    269                                              ctxt->c->base_server,
    270                                              "GnuTLS: Error reading data. Client Requested a New Handshake."
    271                                              " (%d) '%s'", rc,
    272                                              gnutls_strerror(rc));
    273                         } else if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
    274                                 rc = gnutls_alert_get(ctxt->session);
    275                                 ap_log_error(APLOG_MARK, APLOG_INFO,
    276                                              ctxt->input_rc,
    277                                              ctxt->c->base_server,
    278                                              "GnuTLS: Warning Alert From Client: "
    279                                              " (%d) '%s'", rc,
    280                                              gnutls_alert_get_name(rc));
    281                         } else if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
    282                                 rc = gnutls_alert_get(ctxt->session);
    283                                 ap_log_error(APLOG_MARK, APLOG_INFO,
    284                                              ctxt->input_rc,
    285                                              ctxt->c->base_server,
    286                                              "GnuTLS: Fatal Alert From Client: "
    287                                              "(%d) '%s'", rc,
    288                                              gnutls_alert_get_name(rc));
    289                                 ctxt->input_rc = APR_EGENERAL;
    290                                 break;
    291                         } else {
    292                                 /* Some Other Error. Report it. Die. */
    293                                 if (gnutls_error_is_fatal(rc)) {
    294                                         ap_log_error(APLOG_MARK,
    295                                                      APLOG_INFO,
    296                                                      ctxt->input_rc,
    297                                                      ctxt->c->base_server,
    298                                                      "GnuTLS: Error reading data. (%d) '%s'",
    299                                                      rc,
    300                                                      gnutls_strerror(rc));
    301                                 } else if (*len > 0) {
    302                                         ctxt->input_rc = APR_SUCCESS;
    303                                         break;
    304                                 }
    305                         }
    306 
    307                         if (ctxt->input_rc == APR_SUCCESS) {
    308                                 ctxt->input_rc = APR_EGENERAL;
    309                         }
    310                         break;
    311                 }
    312         }
    313         return ctxt->input_rc;
     179        char *buf, apr_size_t * len) {
     180    apr_size_t wanted = *len;
     181    apr_size_t bytes = 0;
     182    int rc;
     183
     184    *len = 0;
     185
     186    /* If we have something leftover from last time, try that first. */
     187    if ((bytes = char_buffer_read(&ctxt->input_cbuf, buf, wanted))) {
     188        *len = bytes;
     189        if (ctxt->input_mode == AP_MODE_SPECULATIVE) {
     190            /* We want to rollback this read. */
     191            if (ctxt->input_cbuf.length > 0) {
     192                ctxt->input_cbuf.value -= bytes;
     193                ctxt->input_cbuf.length += bytes;
     194            } else {
     195                char_buffer_write(&ctxt->input_cbuf, buf,
     196                        (int) bytes);
     197            }
     198            return APR_SUCCESS;
     199        }
     200        /* This could probably be *len == wanted, but be safe from stray
     201         * photons.
     202         */
     203        if (*len >= wanted) {
     204            return APR_SUCCESS;
     205        }
     206        if (ctxt->input_mode == AP_MODE_GETLINE) {
     207            if (memchr(buf, APR_ASCII_LF, *len)) {
     208                return APR_SUCCESS;
     209            }
     210        } else {
     211            /* Down to a nonblock pattern as we have some data already
     212             */
     213            ctxt->input_block = APR_NONBLOCK_READ;
     214        }
     215    }
     216
     217    if (ctxt->session == NULL) {
     218        return APR_EGENERAL;
     219    }
     220
     221    while (1) {
     222
     223        rc = gnutls_record_recv(ctxt->session, buf + bytes,
     224                wanted - bytes);
     225
     226        if (rc > 0) {
     227            *len += rc;
     228            if (ctxt->input_mode == AP_MODE_SPECULATIVE) {
     229                /* We want to rollback this read. */
     230                char_buffer_write(&ctxt->input_cbuf, buf,
     231                        rc);
     232            }
     233            return ctxt->input_rc;
     234        } else if (rc == 0) {
     235            /* If EAGAIN, we will loop given a blocking read,
     236             * otherwise consider ourselves at EOF.
     237             */
     238            if (APR_STATUS_IS_EAGAIN(ctxt->input_rc)
     239                    || APR_STATUS_IS_EINTR(ctxt->input_rc)) {
     240                /* Already read something, return APR_SUCCESS instead.
     241                 * On win32 in particular, but perhaps on other kernels,
     242                 * a blocking call isn't 'always' blocking.
     243                 */
     244                if (*len > 0) {
     245                    ctxt->input_rc = APR_SUCCESS;
     246                    break;
     247                }
     248                if (ctxt->input_block == APR_NONBLOCK_READ) {
     249                    break;
     250                }
     251            } else {
     252                if (*len > 0) {
     253                    ctxt->input_rc = APR_SUCCESS;
     254                } else {
     255                    ctxt->input_rc = APR_EOF;
     256                }
     257                break;
     258            }
     259        } else { /* (rc < 0) */
     260
     261            if (rc == GNUTLS_E_REHANDSHAKE) {
     262                /* A client has asked for a new Hankshake. Currently, we don't do it */
     263                ap_log_error(APLOG_MARK, APLOG_INFO,
     264                        ctxt->input_rc,
     265                        ctxt->c->base_server,
     266                        "GnuTLS: Error reading data. Client Requested a New Handshake."
     267                        " (%d) '%s'", rc,
     268                        gnutls_strerror(rc));
     269            } else if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
     270                rc = gnutls_alert_get(ctxt->session);
     271                ap_log_error(APLOG_MARK, APLOG_INFO,
     272                        ctxt->input_rc,
     273                        ctxt->c->base_server,
     274                        "GnuTLS: Warning Alert From Client: "
     275                        " (%d) '%s'", rc,
     276                        gnutls_alert_get_name(rc));
     277            } else if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
     278                rc = gnutls_alert_get(ctxt->session);
     279                ap_log_error(APLOG_MARK, APLOG_INFO,
     280                        ctxt->input_rc,
     281                        ctxt->c->base_server,
     282                        "GnuTLS: Fatal Alert From Client: "
     283                        "(%d) '%s'", rc,
     284                        gnutls_alert_get_name(rc));
     285                ctxt->input_rc = APR_EGENERAL;
     286                break;
     287            } else {
     288                /* Some Other Error. Report it. Die. */
     289                if (gnutls_error_is_fatal(rc)) {
     290                    ap_log_error(APLOG_MARK,
     291                            APLOG_INFO,
     292                            ctxt->input_rc,
     293                            ctxt->c->base_server,
     294                            "GnuTLS: Error reading data. (%d) '%s'",
     295                            rc,
     296                            gnutls_strerror(rc));
     297                } else if (*len > 0) {
     298                    ctxt->input_rc = APR_SUCCESS;
     299                    break;
     300                }
     301            }
     302
     303            if (ctxt->input_rc == APR_SUCCESS) {
     304                ctxt->input_rc = APR_EGENERAL;
     305            }
     306            break;
     307        }
     308    }
     309    return ctxt->input_rc;
    314310}
    315311
    316312static apr_status_t gnutls_io_input_getline(mgs_handle_t * ctxt,
    317                                             char *buf, apr_size_t * len)
    318 {
    319         const char *pos = NULL;
    320         apr_status_t status;
    321         apr_size_t tmplen = *len, buflen = *len, offset = 0;
    322 
    323         *len = 0;
    324 
    325         while (tmplen > 0) {
    326                 status = gnutls_io_input_read(ctxt, buf + offset, &tmplen);
    327 
    328                 if (status != APR_SUCCESS) {
    329                         return status;
    330                 }
    331 
    332                 *len += tmplen;
    333 
    334                 if ((pos = memchr(buf, APR_ASCII_LF, *len))) {
    335                         break;
    336                 }
    337 
    338                 offset += tmplen;
    339                 tmplen = buflen - offset;
    340         }
    341 
    342         if (pos) {
    343                 char *value;
    344                 int length;
    345                 apr_size_t bytes = pos - buf;
    346 
    347                 bytes += 1;
    348                 value = buf + bytes;
    349                 length = *len - bytes;
    350 
    351                 char_buffer_write(&ctxt->input_cbuf, value, length);
    352 
    353                 *len = bytes;
    354         }
    355 
    356         return APR_SUCCESS;
     313        char *buf, apr_size_t * len) {
     314    const char *pos = NULL;
     315    apr_status_t status;
     316    apr_size_t tmplen = *len, buflen = *len, offset = 0;
     317
     318    *len = 0;
     319
     320    while (tmplen > 0) {
     321        status = gnutls_io_input_read(ctxt, buf + offset, &tmplen);
     322
     323        if (status != APR_SUCCESS) {
     324            return status;
     325        }
     326
     327        *len += tmplen;
     328
     329        if ((pos = memchr(buf, APR_ASCII_LF, *len))) {
     330            break;
     331        }
     332
     333        offset += tmplen;
     334        tmplen = buflen - offset;
     335    }
     336
     337    if (pos) {
     338        char *value;
     339        int length;
     340        apr_size_t bytes = pos - buf;
     341
     342        bytes += 1;
     343        value = buf + bytes;
     344        length = *len - bytes;
     345
     346        char_buffer_write(&ctxt->input_cbuf, value, length);
     347
     348        *len = bytes;
     349    }
     350
     351    return APR_SUCCESS;
    357352}
    358353
    359354#define HANDSHAKE_MAX_TRIES 1024
    360 static int gnutls_do_handshake(mgs_handle_t * ctxt)
    361 {
    362         int ret;
    363         int errcode;
    364         int maxtries = HANDSHAKE_MAX_TRIES;
    365 
    366         if (ctxt->status != 0 || ctxt->session == NULL) {
    367                 return -1;
    368         }
    369 
    370       tryagain:
    371         do {
    372                 ret = gnutls_handshake(ctxt->session);
    373                 maxtries--;
    374         } while ((ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
    375                 && maxtries > 0);
    376 
    377         if (maxtries < 1) {
    378                 ctxt->status = -1;
     355
     356static int gnutls_do_handshake(mgs_handle_t * ctxt) {
     357    int ret;
     358    int errcode;
     359    int maxtries = HANDSHAKE_MAX_TRIES;
     360
     361    if (ctxt->status != 0 || ctxt->session == NULL) {
     362        return -1;
     363    }
     364
     365tryagain:
     366    do {
     367        ret = gnutls_handshake(ctxt->session);
     368        maxtries--;
     369    } while ((ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
     370            && maxtries > 0);
     371
     372    if (maxtries < 1) {
     373        ctxt->status = -1;
    379374#if USING_2_1_RECENT
    380                 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c,
    381                               "GnuTLS: Handshake Failed. Hit Maximum Attempts");
     375        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c,
     376                "GnuTLS: Handshake Failed. Hit Maximum Attempts");
    382377#else
    383                 ap_log_error(APLOG_MARK, APLOG_ERR, 0,
    384                              ctxt->c->base_server,
    385                              "GnuTLS: Handshake Failed. Hit Maximum Attempts");
     378        ap_log_error(APLOG_MARK, APLOG_ERR, 0,
     379                ctxt->c->base_server,
     380                "GnuTLS: Handshake Failed. Hit Maximum Attempts");
    386381#endif
    387                 if (ctxt->session) {
    388                         gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL,
    389                                           gnutls_error_to_alert
    390                                           (GNUTLS_E_INTERNAL_ERROR, NULL));
    391                         gnutls_deinit(ctxt->session);
    392                 }
    393                 ctxt->session = NULL;
    394                 return -1;
    395         }
    396 
    397         if (ret < 0) {
    398                 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
    399                     || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
    400                         errcode = gnutls_alert_get(ctxt->session);
    401                         ap_log_error(APLOG_MARK, APLOG_INFO, 0,
    402                                      ctxt->c->base_server,
    403                                      "GnuTLS: Hanshake Alert (%d) '%s'.",
    404                                      errcode,
    405                                      gnutls_alert_get_name(errcode));
    406                 }
    407 
    408                 if (!gnutls_error_is_fatal(ret)) {
    409                         ap_log_error(APLOG_MARK, APLOG_INFO, 0,
    410                                      ctxt->c->base_server,
    411                                      "GnuTLS: Non-Fatal Handshake Error: (%d) '%s'",
    412                                      ret, gnutls_strerror(ret));
    413                         goto tryagain;
    414                 }
     382        if (ctxt->session) {
     383            gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL,
     384                    gnutls_error_to_alert
     385                    (GNUTLS_E_INTERNAL_ERROR, NULL));
     386            gnutls_deinit(ctxt->session);
     387        }
     388        ctxt->session = NULL;
     389        return -1;
     390    }
     391
     392    if (ret < 0) {
     393        if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
     394                || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
     395            errcode = gnutls_alert_get(ctxt->session);
     396            ap_log_error(APLOG_MARK, APLOG_INFO, 0,
     397                    ctxt->c->base_server,
     398                    "GnuTLS: Hanshake Alert (%d) '%s'.",
     399                    errcode,
     400                    gnutls_alert_get_name(errcode));
     401        }
     402
     403        if (!gnutls_error_is_fatal(ret)) {
     404            ap_log_error(APLOG_MARK, APLOG_INFO, 0,
     405                    ctxt->c->base_server,
     406                    "GnuTLS: Non-Fatal Handshake Error: (%d) '%s'",
     407                    ret, gnutls_strerror(ret));
     408            goto tryagain;
     409        }
    415410#if USING_2_1_RECENT
    416                 ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
    417                               "GnuTLS: Handshake Failed (%d) '%s'", ret,
    418                               gnutls_strerror(ret));
     411        ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
     412                "GnuTLS: Handshake Failed (%d) '%s'", ret,
     413                gnutls_strerror(ret));
    419414#else
    420                 ap_log_error(APLOG_MARK, APLOG_INFO, 0,
    421                              ctxt->c->base_server,
    422                              "GnuTLS: Handshake Failed (%d) '%s'", ret,
    423                              gnutls_strerror(ret));
     415        ap_log_error(APLOG_MARK, APLOG_INFO, 0,
     416                ctxt->c->base_server,
     417                "GnuTLS: Handshake Failed (%d) '%s'", ret,
     418                gnutls_strerror(ret));
    424419#endif
    425                 ctxt->status = -1;
    426                 if (ctxt->session) {
    427                         gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL,
    428                                           gnutls_error_to_alert(ret,
    429                                                                 NULL));
    430                         gnutls_deinit(ctxt->session);
    431                 }
    432                 ctxt->session = NULL;
    433                 return ret;
    434         } else {
    435                 /* all done with the handshake */
    436                 ctxt->status = 1;
    437                 /* If the session was resumed, we did not set the correct
    438                  * server_rec in ctxt->sc.  Go Find it. (ick!)
    439                  */
    440                 if (gnutls_session_is_resumed(ctxt->session)) {
    441                         mgs_srvconf_rec *sc;
    442                         sc = mgs_find_sni_server(ctxt->session);
    443                         if (sc) {
    444                                 ctxt->sc = sc;
    445                         }
    446                 }
    447                 return 0;
    448         }
    449 }
    450 
    451 int mgs_rehandshake(mgs_handle_t * ctxt)
    452 {
    453         int rv;
    454 
    455         if (ctxt->session == NULL)
    456                 return -1;
    457 
    458         rv = gnutls_rehandshake(ctxt->session);
    459 
    460         if (rv != 0) {
    461                 /* the client did not want to rehandshake. goodbye */
    462                 ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
    463                              ctxt->c->base_server,
    464                              "GnuTLS: Client Refused Rehandshake request.");
    465                 return -1;
    466         }
    467 
    468         ctxt->status = 0;
    469 
    470         rv = gnutls_do_handshake(ctxt);
    471 
    472         return rv;
    473 }
    474 
     420        ctxt->status = -1;
     421        if (ctxt->session) {
     422            gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL,
     423                    gnutls_error_to_alert(ret,
     424                    NULL));
     425            gnutls_deinit(ctxt->session);
     426        }
     427        ctxt->session = NULL;
     428        return ret;
     429    } else {
     430        /* all done with the handshake */
     431        ctxt->status = 1;
     432        /* If the session was resumed, we did not set the correct
     433         * server_rec in ctxt->sc.  Go Find it. (ick!)
     434         */
     435        if (gnutls_session_is_resumed(ctxt->session)) {
     436            mgs_srvconf_rec *sc;
     437            sc = mgs_find_sni_server(ctxt->session);
     438            if (sc) {
     439                ctxt->sc = sc;
     440            }
     441        }
     442        return 0;
     443    }
     444}
     445
     446int mgs_rehandshake(mgs_handle_t * ctxt) {
     447    int rv;
     448
     449    if (ctxt->session == NULL)
     450        return -1;
     451
     452    rv = gnutls_rehandshake(ctxt->session);
     453
     454    if (rv != 0) {
     455        /* the client did not want to rehandshake. goodbye */
     456        ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
     457                ctxt->c->base_server,
     458                "GnuTLS: Client Refused Rehandshake request.");
     459        return -1;
     460    }
     461
     462    ctxt->status = 0;
     463
     464    rv = gnutls_do_handshake(ctxt);
     465
     466    return rv;
     467}
    475468
    476469apr_status_t mgs_filter_input(ap_filter_t * f,
    477                               apr_bucket_brigade * bb,
    478                               ap_input_mode_t mode,
    479                               apr_read_type_e block, apr_off_t readbytes)
    480 {
    481         apr_status_t status = APR_SUCCESS;
    482         mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
    483         apr_size_t len = sizeof(ctxt->input_buffer);
    484 
    485         if (f->c->aborted) {
    486                 apr_bucket *bucket =
    487                     apr_bucket_eos_create(f->c->bucket_alloc);
    488                 APR_BRIGADE_INSERT_TAIL(bb, bucket);
    489                 return APR_ECONNABORTED;
    490         }
    491 
    492         if (ctxt->status == 0) {
    493                 gnutls_do_handshake(ctxt);
    494         }
    495 
    496         if (ctxt->status < 0) {
    497                 return ap_get_brigade(f->next, bb, mode, block, readbytes);
    498         }
    499 
    500         /* XXX: we don't currently support anything other than these modes. */
    501         if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE &&
    502             mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) {
    503                 return APR_ENOTIMPL;
    504         }
    505 
    506         ctxt->input_mode = mode;
    507         ctxt->input_block = block;
    508 
    509         if (ctxt->input_mode == AP_MODE_READBYTES ||
    510             ctxt->input_mode == AP_MODE_SPECULATIVE) {
    511                 /* Err. This is bad. readbytes *can* be a 64bit int! len.. is NOT */
    512                 if (readbytes < len) {
    513                         len = (apr_size_t) readbytes;
    514                 }
    515                 status =
    516                     gnutls_io_input_read(ctxt, ctxt->input_buffer, &len);
    517         } else if (ctxt->input_mode == AP_MODE_GETLINE) {
    518                 status =
    519                     gnutls_io_input_getline(ctxt, ctxt->input_buffer,
    520                                             &len);
    521         } else {
    522                 /* We have no idea what you are talking about, so return an error. */
    523                 return APR_ENOTIMPL;
    524         }
    525 
    526         if (status != APR_SUCCESS) {
    527                 return gnutls_io_filter_error(f, bb, status);
    528         }
    529 
    530         /* Create a transient bucket out of the decrypted data. */
    531         if (len > 0) {
    532                 apr_bucket *bucket =
    533                     apr_bucket_transient_create(ctxt->input_buffer, len,
    534                                                 f->c->bucket_alloc);
    535                 APR_BRIGADE_INSERT_TAIL(bb, bucket);
    536         }
    537 
    538         return status;
    539 }
    540 
    541 static ssize_t write_flush(mgs_handle_t * ctxt)
    542 {
    543         apr_bucket *e;
    544 
    545         if (!(ctxt->output_blen || ctxt->output_length)) {
    546                 ctxt->output_rc = APR_SUCCESS;
    547                 return 1;
    548         }
    549 
    550         if (ctxt->output_blen) {
    551                 e = apr_bucket_transient_create(ctxt->output_buffer,
    552                                                 ctxt->output_blen,
    553                                                 ctxt->output_bb->
    554                                                 bucket_alloc);
    555                 /* we filled this buffer first so add it to the
    556  *               * head of the brigade
    557  *                               */
    558                 APR_BRIGADE_INSERT_HEAD(ctxt->output_bb, e);
    559                 ctxt->output_blen = 0;
    560         }
    561 
    562         ctxt->output_length = 0;
    563         e = apr_bucket_flush_create(ctxt->output_bb->bucket_alloc);
    564         APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e);