Changeset e02dd8c in mod_gnutls for src


Ignore:
Timestamp:
Oct 25, 2010, 3:21:04 PM (12 years ago)
Author:
Nikos Mavrogiannopoulos <nmav@…>
Branches:
asyncio, debian/master, debian/stretch-backports, jessie-backports, main, master, msva, proxy-ticket, upstream
Children:
b59327c
Parents:
62def2f
Message:

indented code

Location:
src
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_cache.c

    r62def2f re02dd8c  
    4545
    4646char *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;
     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;
    5959}
    6060
     
    6464 * to disallow resuming sessions on different servers
    6565 */
    66 static 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 = apr_psprintf(c->pool, "%s:%d.%s", c->base_server->server_hostname, c->base_server->port, sz);
    77     dbmkey->dsize = strlen( dbmkey->dptr);
    78    
    79     return 0;
     66static 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;
    8083}
    8184
     
    8386char *mgs_time2sz(time_t in_time, char *str, int strsize)
    8487{
    85     apr_time_exp_t vtm;
    86     apr_size_t ret_size;
    87     apr_time_t t;
    88    
    89  
    90     apr_time_ansi_put (&t, in_time);
    91     apr_time_exp_gmt (&vtm, t);
    92     apr_strftime(str, &ret_size, strsize-1, CTIME, &vtm);
    93 
    94     return str;
     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;
    9598}
    9699
     
    100103 * to disallow resuming sessions on different servers
    101104 */
    102 static char* mgs_session_id2mc(conn_rec* c, unsigned char *id, int idlen)
    103 {
    104 char buf[STR_SESSION_LEN];
    105 char *sz;
    106    
    107     sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf));
    108     if (sz == NULL)
    109       return NULL;
    110      
    111     return apr_psprintf(c->pool, MC_TAG"%s:%d.%s", c->base_server->server_hostname, c->base_server->port, sz);
     105static 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);
    112117}
    113118
     
    118123
    119124/* The underlying apr_memcache system is thread safe... woohoo */
    120 static apr_memcache_t* mc;
    121 
    122 static int mc_cache_child_init(apr_pool_t *p, server_rec *s,
    123                                 mgs_srvconf_rec *sc)
    124 {
    125     apr_status_t rv = APR_SUCCESS;
    126     int thread_limit = 0;
    127     int nservers = 0;
    128     char* cache_config;
    129     char* split;
    130     char* tok;
    131 
    132     ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
    133 
    134     /* Find all the servers in the first run to get a total count */
    135     cache_config = apr_pstrdup(p, sc->cache_config);
    136     split = apr_strtok(cache_config, " ", &tok);
    137     while (split) {
    138         nservers++;
    139         split = apr_strtok(NULL," ", &tok);
    140     }
    141 
    142     rv = apr_memcache_create(p, nservers, 0, &mc);
    143     if (rv != APR_SUCCESS) {
    144         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    145                         "[gnutls_cache] Failed to create Memcache Object of '%d' size.",
    146                          nservers);
    147         return rv;
    148     }
    149 
    150     /* Now add each server to the memcache */
    151     cache_config = apr_pstrdup(p, sc->cache_config);
    152     split = apr_strtok(cache_config, " ", &tok);
    153     while (split) {
    154         apr_memcache_server_t* st;
    155         char* host_str;
    156         char* scope_id;
    157         apr_port_t port;
    158 
    159         rv = apr_parse_addr_port(&host_str, &scope_id, &port, split, p);
    160         if (rv != APR_SUCCESS) {
    161             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    162                          "[gnutls_cache] Failed to Parse Server: '%s'", split);
    163             return rv;
    164         }
    165 
    166         if (host_str == NULL) {
    167             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    168                          "[gnutls_cache] Failed to Parse Server, "
    169                          "no hostname specified: '%s'", split);
    170             return rv;
    171         }
    172 
    173         if (port == 0) {
    174             port = 11211; /* default port */
    175         }
    176 
    177         /* Should Max Conns be (thread_limit / nservers) ? */
    178         rv = apr_memcache_server_create(p,
    179                                         host_str, port,
    180                                         0,
    181                                         1,
    182                                         thread_limit,
    183                                         600,
    184                                         &st);
    185         if (rv != APR_SUCCESS) {
    186             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    187                          "[gnutls_cache] Failed to Create Server: %s:%d",
    188                          host_str, port);
    189             return rv;
    190         }
    191 
    192         rv = apr_memcache_add_server(mc, st);
    193         if (rv != APR_SUCCESS) {
    194             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    195                          "[gnutls_cache] Failed to Add Server: %s:%d",
    196                          host_str, port);
    197             return rv;
    198         }
    199 
    200         split = apr_strtok(NULL," ", &tok);
    201     }
    202     return rv;
    203 }
    204 
    205 static int mc_cache_store(void* baton, gnutls_datum_t key,
    206                           gnutls_datum_t data)
    207 {
    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, data.data, data.size, timeout, 0);
    220 
    221     if (rv != APR_SUCCESS) {
    222         ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
    223                      ctxt->c->base_server,
    224                      "[gnutls_cache] error setting key '%s' "
    225                      "with %d bytes of data", strkey, data.size);
    226         return -1;
    227     }
    228 
    229     return 0;
    230 }
    231 
    232 static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key)
    233 {
    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) {
     125static apr_memcache_t *mc;
     126
     127static 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;
     207}
     208
     209static 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, 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
     237static 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) {
    250255#if MOD_GNUTLS_DEBUG
    251         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    252                      ctxt->c->base_server,
    253                      "[gnutls_cache] error fetching key '%s' ",
    254                      strkey);
     256                ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
     257                             ctxt->c->base_server,
     258                             "[gnutls_cache] error fetching key '%s' ",
     259                             strkey);
    255260#endif
    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 
    272 static int mc_cache_delete(void* baton, gnutls_datum_t key)
    273 {
    274     apr_status_t rv = APR_SUCCESS;
    275     mgs_handle_t *ctxt = baton;
    276     char* strkey = NULL;
    277 
    278     strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    279     if(!strkey)
    280         return -1;
    281 
    282     rv = apr_memcache_delete(mc, strkey, 0);
    283 
    284     if (rv != APR_SUCCESS) {
    285         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    286                      ctxt->c->base_server,
    287                      "[gnutls_cache] error deleting key '%s' ",
    288                       strkey);
    289         return -1;
    290     }
    291 
    292     return 0;
    293 }
    294 
    295 #endif /* have_apr_memcache */
    296 
    297 const char* db_type(mgs_srvconf_rec * sc)
    298 {
    299         if (sc->cache_type == mgs_cache_gdbm)
    300                 return "gdbm";
    301         else
    302                 return "db";
     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
     277static 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;
     298}
     299
     300#endif                          /* have_apr_memcache */
     301
     302const char *db_type(mgs_srvconf_rec * sc)
     303{
     304        if (sc->cache_type == mgs_cache_gdbm)
     305                return "gdbm";
     306        else
     307                return "db";
    303308}
    304309
    305310#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
    306311
    307 static void dbm_cache_expire(mgs_handle_t *ctxt)
    308 {
    309     apr_status_t rv;
    310     apr_dbm_t *dbm;
    311     apr_datum_t dbmkey;
    312     apr_datum_t dbmval;
    313     apr_time_t now;
    314     apr_time_t dtime;
    315     apr_pool_t* spool;
    316     int total, deleted;
    317 
    318     now = apr_time_now();
    319    
    320     if (now - ctxt->sc->last_cache_check < (ctxt->sc->cache_timeout)/2)
    321         return;
    322 
    323     ctxt->sc->last_cache_check = now;
    324 
    325     apr_pool_create(&spool, ctxt->c->pool);
    326 
    327     total = 0;
    328     deleted = 0;
    329 
    330     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), ctxt->sc->cache_config, APR_DBM_RWCREATE,
    331                       SSL_DBM_FILE_MODE, spool);
    332     if (rv != APR_SUCCESS) {
    333         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    334                      ctxt->c->base_server,
    335                      "[gnutls_cache] error opening cache searcher '%s'",
    336                      ctxt->sc->cache_config);
    337         apr_pool_destroy(spool);
    338         return;
    339     }
    340 
    341     apr_dbm_firstkey(dbm, &dbmkey);
    342     while (dbmkey.dptr != NULL) {
    343         apr_dbm_fetch(dbm, dbmkey, &dbmval);
    344         if (dbmval.dptr != NULL && 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 
    371 static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key)
    372 {
    373     gnutls_datum_t data = { NULL, 0 };
    374     apr_dbm_t *dbm;
    375     apr_datum_t dbmkey;
    376     apr_datum_t dbmval;
    377     mgs_handle_t *ctxt = baton;
    378     apr_status_t rv;
    379 
    380     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    381         return data;
    382 
    383     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), ctxt->sc->cache_config,
    384                       APR_DBM_READONLY, 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;
    421 }
    422 
    423 static int dbm_cache_store(void* baton, gnutls_datum_t key,
    424                           gnutls_datum_t data)
    425 {
    426     apr_dbm_t *dbm;
    427     apr_datum_t dbmkey;
    428     apr_datum_t dbmval;
    429     mgs_handle_t *ctxt = baton;
    430     apr_status_t rv;
    431     apr_time_t expiry;
    432     apr_pool_t* spool;
    433 
    434     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    435         return -1;
    436 
    437     /* we expire dbm only on every store
    438      */
    439     dbm_cache_expire(ctxt);
    440 
    441     apr_pool_create(&spool, ctxt->c->pool);
    442 
    443     /* create DBM value */
    444     dbmval.dsize = data.size + sizeof(apr_time_t);
    445     dbmval.dptr  = (char *)apr_palloc(spool, dbmval.dsize);
    446 
    447     expiry = apr_time_now() + ctxt->sc->cache_timeout;
    448 
    449     memcpy((char *)dbmval.dptr, &expiry, sizeof(apr_time_t));
    450     memcpy((char *)dbmval.dptr+sizeof(apr_time_t),
    451            data.data, data.size);
    452 
    453     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), ctxt->sc->cache_config,
    454                       APR_DBM_RWCREATE, 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 
    483 static int dbm_cache_delete(void* baton, gnutls_datum_t key)
    484 {
    485     apr_dbm_t *dbm;
    486     apr_datum_t dbmkey;
    487     mgs_handle_t *ctxt = baton;
    488     apr_status_t rv;
    489 
    490     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    491         return -1;
    492 
    493     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), ctxt->sc->cache_config,
    494                       APR_DBM_RWCREATE, 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;
    517 }
    518 
    519 static int dbm_cache_post_config(apr_pool_t *p, server_rec *s,
    520                                 mgs_srvconf_rec *sc)
    521 {
    522     apr_status_t rv;
    523     apr_dbm_t *dbm;
    524     const char* path1;
    525     const char* path2;
    526 
    527     rv = apr_dbm_open_ex(&dbm, db_type(sc), sc->cache_config, APR_DBM_RWCREATE,
    528                       SSL_DBM_FILE_MODE, p);
    529 
    530     if (rv != APR_SUCCESS) {
    531         ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
    532                      "GnuTLS: Cannot create DBM Cache at `%s'",
    533                      sc->cache_config);
    534         return rv;
    535     }
    536 
    537     apr_dbm_close(dbm);
    538 
    539     apr_dbm_get_usednames_ex(p, db_type(sc), sc->cache_config, &path1, &path2);
    540 
    541     /* The Following Code takes logic directly from mod_ssl's DBM Cache */
     312static 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
     379static 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;
     430}
     431
     432static 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
     493static 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;
     528}
     529
     530static 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 */
    542554#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
    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     }
     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        }
    550562#endif
    551563
    552     return rv;
    553 }
    554 
    555 int mgs_cache_post_config(apr_pool_t *p, server_rec *s,
    556                                  mgs_srvconf_rec *sc)
    557 {
    558     if (sc->cache_type == mgs_cache_dbm || sc->cache_type == mgs_cache_gdbm) {
    559         return dbm_cache_post_config(p, s, sc);
    560     }
    561     return 0;
    562 }
    563 
    564 int mgs_cache_child_init(apr_pool_t *p, server_rec *s,
    565                                 mgs_srvconf_rec *sc)
    566 {
    567     if (sc->cache_type == mgs_cache_dbm || sc->cache_type == mgs_cache_gdbm) {
    568         return 0;
    569     }
     564        return rv;
     565}
     566
     567int 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;
     575}
     576
     577int 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        }
    570584#if HAVE_APR_MEMCACHE
    571     else if (sc->cache_type == mgs_cache_memcache) {
    572         return mc_cache_child_init(p, s, sc);
    573     }
     585        else if (sc->cache_type == mgs_cache_memcache) {
     586                return mc_cache_child_init(p, s, sc);
     587        }
    574588#endif
    575     return 0;
    576 }
    577 
    578  #include <assert.h>
    579 
    580 int mgs_cache_session_init(mgs_handle_t *ctxt)
    581 {
    582     if (ctxt->sc->cache_type == mgs_cache_dbm || ctxt->sc->cache_type == mgs_cache_gdbm) {
    583         gnutls_db_set_retrieve_function(ctxt->session, dbm_cache_fetch);
    584         gnutls_db_set_remove_function(ctxt->session, dbm_cache_delete);
    585         gnutls_db_set_store_function(ctxt->session, dbm_cache_store);
    586         gnutls_db_set_ptr(ctxt->session, ctxt);
    587     }
     589        return 0;
     590}
     591
     592#include <assert.h>
     593
     594int 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        }
    588606#if HAVE_APR_MEMCACHE
    589     else if (ctxt->sc->cache_type == mgs_cache_memcache) {
    590         gnutls_db_set_retrieve_function(ctxt->session, mc_cache_fetch);
    591         gnutls_db_set_remove_function(ctxt->session, mc_cache_delete);
    592         gnutls_db_set_store_function(ctxt->session, mc_cache_store);
    593         gnutls_db_set_ptr(ctxt->session, ctxt);
    594     }
     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        }
    595616#endif
    596617
    597     return 0;
    598 }
     618        return 0;
     619}
  • src/gnutls_config.c

    r62def2f re02dd8c  
    2222                                const char *file, gnutls_datum_t * data)
    2323{
    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, APR_OS_DEFAULT,
    30                       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;
     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
     
    5656                            const char *arg)
    5757{
    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, "GnuTLS: Failed to initialize"
    79                             ": (%d) %s", ret, gnutls_strerror(ret));
    80     }
    81 
    82     ret =
    83         gnutls_dh_params_import_pkcs3(sc->dh_params, &data, GNUTLS_X509_FMT_PEM);
    84     if (ret < 0) {
    85         return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
    86                             "DH params '%s': (%d) %s", file, ret,
    87                             gnutls_strerror(ret));
    88     }
    89 
    90     apr_pool_destroy(spool);
    91 
    92     return NULL;
     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;
    9397}
    9498
     
    96100                                    const char *arg)
    97101{
    98     int ret;
    99     gnutls_datum_t data;
    100     const char *file;
    101     apr_pool_t *spool;
    102     mgs_srvconf_rec *sc =
    103         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    104                                                  module_config,
    105                                                  &gnutls_module);
    106 
    107     apr_pool_create(&spool, parms->pool);
    108 
    109     file = ap_server_root_relative(spool, arg);
    110 
    111     if (load_datum_from_file(spool, file, &data) != 0) {
    112         return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    113                             "RSA params '%s'", file);
    114     }
    115 
    116     ret = gnutls_rsa_params_init(&sc->rsa_params);
    117     if (ret < 0) {
    118         return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
    119                             ": (%d) %s", ret, gnutls_strerror(ret));
    120     }
    121 
    122     ret =
    123         gnutls_rsa_params_import_pkcs1(sc->rsa_params, &data, GNUTLS_X509_FMT_PEM);
    124     if (ret != 0) {
    125         return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
    126                             "RSA params '%s': (%d) %s", file, ret,
    127                             gnutls_strerror(ret));
    128     }
    129 
    130     apr_pool_destroy(spool);
    131     return NULL;
     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;
    132140}
    133141
     
    136144                              const char *arg)
    137145{
    138     int ret;
    139     gnutls_datum_t data;
    140     const char *file;
    141     apr_pool_t *spool;
    142     mgs_srvconf_rec *sc =
    143         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    144                                                  module_config,
    145                                                  &gnutls_module);
    146     apr_pool_create(&spool, parms->pool);
    147 
    148     file = ap_server_root_relative(spool, arg);
    149 
    150     if (load_datum_from_file(spool, file, &data) != 0) {
    151         return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    152                             "Certificate '%s'", file);
    153     }
    154 
    155     sc->certs_x509_num = MAX_CHAIN_SIZE;
    156     ret =
    157         gnutls_x509_crt_list_import(sc->certs_x509, &sc->certs_x509_num, &data, GNUTLS_X509_FMT_PEM, 0);
    158     if (ret < 0) {
    159         return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
    160                             "Certificate '%s': (%d) %s", file, ret,
    161                             gnutls_strerror(ret));
    162     }
    163 
    164     apr_pool_destroy(spool);
    165     return NULL;
     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;
    166177}
    167178
     
    169180                             const char *arg)
    170181{
    171     int ret;
    172     gnutls_datum_t data;
    173     const char *file;
    174     apr_pool_t *spool;
    175     mgs_srvconf_rec *sc =
    176         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    177                                                  module_config,
    178                                                  &gnutls_module);
    179     apr_pool_create(&spool, parms->pool);
    180 
    181     file = ap_server_root_relative(spool, arg);
    182 
    183     if (load_datum_from_file(spool, file, &data) != 0) {
    184         return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    185                             "Private Key '%s'", file);
    186     }
    187 
    188     ret = gnutls_x509_privkey_init(&sc->privkey_x509);
    189     if (ret < 0) {
    190         return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
    191                             ": (%d) %s", ret, gnutls_strerror(ret));
    192     }
    193 
    194     ret =
    195         gnutls_x509_privkey_import(sc->privkey_x509, &data,
    196                                    GNUTLS_X509_FMT_PEM);
    197 
    198     if (ret < 0)
    199         ret = gnutls_x509_privkey_import_pkcs8 (sc->privkey_x509, &data, GNUTLS_X509_FMT_PEM,
    200                                                         NULL, GNUTLS_PKCS_PLAIN);
    201 
    202     if (ret < 0) {
    203         return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
    204                             "Private Key '%s': (%d) %s", file, ret,
    205                             gnutls_strerror(ret));
    206     }
    207     apr_pool_destroy(spool);
    208     return NULL;
     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;
    209227}
    210228
    211229const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy,
    212                               const char *arg)
    213 {
    214     int ret;
    215     gnutls_datum_t data;
    216     const char *file;
    217     apr_pool_t *spool;
    218     mgs_srvconf_rec *sc =
    219         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    220                                                  module_config,
    221                                                  &gnutls_module);
    222     apr_pool_create(&spool, parms->pool);
    223 
    224     file = ap_server_root_relative(spool, arg);
    225 
    226     if (load_datum_from_file(spool, file, &data) != 0) {
    227         return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    228                             "Certificate '%s'", file);
    229     }
    230 
    231     ret = gnutls_openpgp_crt_init( &sc->cert_pgp);
    232     if (ret < 0) {
    233         return apr_psprintf(parms->pool, "GnuTLS: Failed to Init "
    234                             "PGP Certificate: (%d) %s", ret,
    235                             gnutls_strerror(ret));
    236     }
    237      
    238     ret =
    239         gnutls_openpgp_crt_import(sc->cert_pgp, &data, GNUTLS_OPENPGP_FMT_BASE64);
    240     if (ret < 0) {
    241         return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
    242                             "PGP Certificate '%s': (%d) %s", file, ret,
    243                             gnutls_strerror(ret));
    244     }
    245 
    246     apr_pool_destroy(spool);
    247     return NULL;
     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;
    248268}
    249269
    250270const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy,
    251                              const char *arg)
    252 {
    253     int ret;
    254     gnutls_datum_t data;
    255     const char *file;
    256     apr_pool_t *spool;
    257     mgs_srvconf_rec *sc =
    258         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    259                                                  module_config,
    260                                                  &gnutls_module);
    261     apr_pool_create(&spool, parms->pool);
    262 
    263     file = ap_server_root_relative(spool, arg);
    264 
    265     if (load_datum_from_file(spool, file, &data) != 0) {
    266         return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    267                             "Private Key '%s'", file);
    268     }
    269 
    270     ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp);
    271     if (ret < 0) {
    272         return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
    273                             ": (%d) %s", ret, gnutls_strerror(ret));
    274     }
    275 
    276     ret =
    277         gnutls_openpgp_privkey_import(sc->privkey_pgp, &data,
    278                                    GNUTLS_OPENPGP_FMT_BASE64, NULL, 0);
    279     if (ret != 0) {
    280         return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
    281                             "PGP Private Key '%s': (%d) %s", file, ret,
    282                             gnutls_strerror(ret));
    283     }
    284     apr_pool_destroy(spool);
    285     return NULL;
     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;
    286310}
    287311
    288312const char *mgs_set_tickets(cmd_parms * parms, void *dummy,
    289                                      const char *arg)
    290 {
    291     mgs_srvconf_rec *sc =
    292         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    293                                                  module_config,
    294                                                  &gnutls_module);
    295 
    296     sc->tickets = 0;
    297     if (strcasecmp("on", arg) == 0) {
    298         sc->tickets = 1;
    299     }
    300 
    301     return NULL;
     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;
    302326}
    303327
     
    308332                                     const char *arg)
    309333{
    310     mgs_srvconf_rec *sc =
    311         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    312                                                  module_config,
    313                                                  &gnutls_module);
    314 
    315     sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg);
    316 
    317     return NULL;
     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;
    318342}
    319343
     
    321345                                          const char *arg)
    322346{
    323     mgs_srvconf_rec *sc =
    324         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    325                                                  module_config,
    326                                                  &gnutls_module);
    327 
    328     sc->srp_tpasswd_conf_file = ap_server_root_relative(parms->pool, arg);
    329 
    330     return NULL;
     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;
    331356}
    332357
     
    336361                          const char *type, const char *arg)
    337362{
    338     const char *err;
    339     mgs_srvconf_rec *sc = ap_get_module_config(parms->server->
    340                                                module_config,
    341                                                &gnutls_module);
    342     if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
    343         return err;
    344     }
    345 
    346     if (strcasecmp("none", type) == 0) {
    347         sc->cache_type = mgs_cache_none;
    348     } else if (strcasecmp("dbm", type) == 0) {
    349         sc->cache_type = mgs_cache_dbm;
    350     }
    351     else if (strcasecmp("gdbm", type) == 0) {
    352         sc->cache_type = mgs_cache_gdbm;
    353     }
     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        } else if (strcasecmp("dbm", type) == 0) {
     374                sc->cache_type = mgs_cache_dbm;
     375        } else if (strcasecmp("gdbm", type) == 0) {
     376                sc->cache_type = mgs_cache_gdbm;
     377        }
    354378#if HAVE_APR_MEMCACHE
    355     else if (strcasecmp("memcache", type) == 0) {
    356         sc->cache_type = mgs_cache_memcache;
    357     }
     379        else if (strcasecmp("memcache", type) == 0) {
     380                sc->cache_type = mgs_cache_memcache;
     381        }
    358382#endif
    359     else {
    360         return "Invalid Type for GnuTLSCache!";
    361     }
    362 
    363     if (sc->cache_type == mgs_cache_dbm || sc->cache_type == mgs_cache_gdbm) {
    364         sc->cache_config = ap_server_root_relative(parms->pool, arg);
    365     } else {
    366         sc->cache_config = apr_pstrdup(parms->pool, arg);
    367     }
    368 
    369     return NULL;
     383        else {
     384                return "Invalid Type for GnuTLSCache!";
     385        }
     386
     387        if (sc->cache_type == mgs_cache_dbm
     388            || sc->cache_type == mgs_cache_gdbm) {
     389                sc->cache_config =
     390                    ap_server_root_relative(parms->pool, arg);
     391        } else {
     392                sc->cache_config = apr_pstrdup(parms->pool, arg);
     393        }
     394
     395        return NULL;
    370396}
    371397
     
    373399                                  const char *arg)
    374400{
    375     int argint;
    376     mgs_srvconf_rec *sc =
    377         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    378                                                  module_config,
    379                                                  &gnutls_module);
    380 
    381     argint = atoi(arg);
    382 
    383     if (argint < 0) {
    384         return "GnuTLSCacheTimeout: Invalid argument";
    385     } else if (argint == 0) {
    386         sc->cache_timeout = 0;
    387     } else {
    388         sc->cache_timeout = apr_time_from_sec(argint);
    389     }
    390 
    391     return NULL;
     401        int argint;
     402        mgs_srvconf_rec *sc =
     403            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     404                                                     module_config,
     405                                                     &gnutls_module);
     406
     407        argint = atoi(arg);
     408
     409        if (argint < 0) {
     410                return "GnuTLSCacheTimeout: Invalid argument";
     411        } else if (argint == 0) {
     412                sc->cache_timeout = 0;
     413        } else {
     414                sc->cache_timeout = apr_time_from_sec(argint);
     415        }
     416
     417        return NULL;
    392418}
    393419
     
    395421                                  const char *arg)
    396422{
    397     int mode;
    398 
    399     if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) {
    400         mode = GNUTLS_CERT_IGNORE;
    401     } else if (strcasecmp("optional", arg) == 0
    402                || strcasecmp("request", arg) == 0) {
    403         mode = GNUTLS_CERT_REQUEST;
    404     } else if (strcasecmp("require", arg) == 0) {
    405         mode = GNUTLS_CERT_REQUIRE;
    406     } else {
    407         return "GnuTLSClientVerify: Invalid argument";
    408     }
    409 
    410     /* This was set from a directory context */
    411     if (parms->path) {
    412         mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy;
    413         dc->client_verify_mode = mode;
    414     } else {
    415         mgs_srvconf_rec *sc =
    416             (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    417                                                      module_config,
    418                                                     &gnutls_module);
    419         sc->client_verify_mode = mode;
    420     }
    421 
    422     return NULL;
     423        int mode;
     424
     425        if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) {
     426                mode = GNUTLS_CERT_IGNORE;
     427        } else if (strcasecmp("optional", arg) == 0
     428                   || strcasecmp("request", arg) == 0) {
     429                mode = GNUTLS_CERT_REQUEST;
     430        } else if (strcasecmp("require", arg) == 0) {
     431                mode = GNUTLS_CERT_REQUIRE;
     432        } else {
     433                return "GnuTLSClientVerify: Invalid argument";
     434        }
     435
     436        /* This was set from a directory context */
     437        if (parms->path) {
     438                mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy;
     439                dc->client_verify_mode = mode;
     440        } else {
     441                mgs_srvconf_rec *sc =
     442                    (mgs_srvconf_rec *)
     443                    ap_get_module_config(parms->server->module_config,
     444                                        &gnutls_module);
     445                sc->client_verify_mode = mode;
     446        }
     447
     448        return NULL;
    423449}
    424450
     
    427453                                   const char *arg)
    428454{
    429     int rv;
    430     const char *file;
    431     apr_pool_t *spool;
    432     gnutls_datum_t data;
    433 
    434     mgs_srvconf_rec *sc =
    435         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    436                                                  module_config,
    437                                                  &gnutls_module);
    438     apr_pool_create(&spool, parms->pool);
    439 
    440     file = ap_server_root_relative(spool, arg);
    441 
    442     if (load_datum_from_file(spool, file, &data) != 0) {
    443         return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    444                             "Client CA File '%s'", file);
    445     }
    446 
    447     sc->ca_list_size = INIT_CA_SIZE;
    448     sc->ca_list = malloc(sc->ca_list_size * sizeof(*sc->ca_list));
    449     if (sc->ca_list == NULL) {
    450                 return apr_psprintf(parms->pool, "mod_gnutls: Memory allocation error");
    451     }
    452 
    453     rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size,
    454                                      &data, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
    455     if (rv < 0 && rv != GNUTLS_E_SHORT_MEMORY_BUFFER) {
    456                         return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
    457                             "Client CA File '%s': (%d) %s", file, rv,
    458                             gnutls_strerror(rv));
    459     }
    460    
    461     if (INIT_CA_SIZE < sc->ca_list_size) {
    462                     sc->ca_list = realloc(sc->ca_list, sc->ca_list_size*sizeof(*sc->ca_list));
    463                     if (sc->ca_list == NULL) {
    464                                 return apr_psprintf(parms->pool, "mod_gnutls: Memory allocation error");
    465                     }
    466 
    467                 /* re-read */
    468                 rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size,
    469                                      &data, GNUTLS_X509_FMT_PEM, 0);
    470 
    471                     if (rv < 0) {
    472                                         return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
    473                                             "Client CA File '%s': (%d) %s", file, rv,
    474                                             gnutls_strerror(rv));
    475                     }
    476     }
    477 
    478     apr_pool_destroy(spool);
    479     return NULL;
     455        int rv;
     456        const char *file;
     457        apr_pool_t *spool;
     458        gnutls_datum_t data;
     459
     460        mgs_srvconf_rec *sc =
     461            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     462                                                     module_config,
     463                                                     &gnutls_module);
     464        apr_pool_create(&spool, parms->pool);
     465
     466        file = ap_server_root_relative(spool, arg);
     467
     468        if (load_datum_from_file(spool, file, &data) != 0) {
     469                return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     470                                    "Client CA File '%s'", file);
     471        }
     472
     473        sc->ca_list_size = INIT_CA_SIZE;
     474        sc->ca_list = malloc(sc->ca_list_size * sizeof(*sc->ca_list));
     475        if (sc->ca_list == NULL) {
     476                return apr_psprintf(parms->pool,
     477                                    "mod_gnutls: Memory allocation error");
     478        }
     479
     480        rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size,
     481                                         &data, GNUTLS_X509_FMT_PEM,
     482                                         GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
     483        if (rv < 0 && rv != GNUTLS_E_SHORT_MEMORY_BUFFER) {
     484                return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
     485                                    "Client CA File '%s': (%d) %s", file,
     486                                    rv, gnutls_strerror(rv));
     487        }
     488
     489        if (INIT_CA_SIZE < sc->ca_list_size) {
     490                sc->ca_list =
     491                    realloc(sc->ca_list,
     492                            sc->ca_list_size * sizeof(*sc->ca_list));
     493                if (sc->ca_list == NULL) {
     494                        return apr_psprintf(parms->pool,
     495                                            "mod_gnutls: Memory allocation error");
     496                }
     497
     498                /* re-read */
     499                rv = gnutls_x509_crt_list_import(sc->ca_list,
     500                                                 &sc->ca_list_size, &data,
     501                                                 GNUTLS_X509_FMT_PEM, 0);
     502
     503                if (rv < 0) {
     504                        return apr_psprintf(parms->pool,
     505                                            "GnuTLS: Failed to load "
     506                                            "Client CA File '%s': (%d) %s",
     507                                            file, rv, gnutls_strerror(rv));
     508                }
     509        }
     510
     511        apr_pool_destroy(spool);
     512        return NULL;
    480513}
    481514
    482515const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
    483                                    const char *arg)
    484 {
    485     int rv;
    486     const char *file;
    487     apr_pool_t *spool;
    488     gnutls_datum_t data;
    489 
    490     mgs_srvconf_rec *sc =
    491         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    492                                                  module_config,
    493                                                  &gnutls_module);
    494     apr_pool_create(&spool, parms->pool);
    495 
    496     file = ap_server_root_relative(spool, arg);
    497 
    498     if (load_datum_from_file(spool, file, &data) != 0) {
    499         return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
    500                             "Keyring File '%s'", file);
    501     }
    502 
    503     rv = gnutls_openpgp_keyring_init(&sc->pgp_list);
    504     if (rv < 0) {
    505         return apr_psprintf(parms->pool, "GnuTLS: Failed to initialize"
    506                             "keyring: (%d) %s", rv, gnutls_strerror(rv));
    507     }
    508 
    509     rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data, GNUTLS_OPENPGP_FMT_BASE64);
    510     if (rv < 0) {
    511         return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
    512                             "Keyring File '%s': (%d) %s", file, rv,
    513                             gnutls_strerror(rv));
    514     }
    515 
    516     apr_pool_destroy(spool);
    517     return NULL;
     516                                 const char *arg)
     517{
     518        int rv;
     519        const char *file;
     520        apr_pool_t *spool;
     521        gnutls_datum_t data;
     522
     523        mgs_srvconf_rec *sc =
     524            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     525                                                     module_config,
     526                                                     &gnutls_module);
     527        apr_pool_create(&spool, parms->pool);
     528
     529        file = ap_server_root_relative(spool, arg);
     530
     531        if (load_datum_from_file(spool, file, &data) != 0) {
     532                return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
     533                                    "Keyring File '%s'", file);
     534        }
     535
     536        rv = gnutls_openpgp_keyring_init(&sc->pgp_list);
     537        if (rv < 0) {
     538                return apr_psprintf(parms->pool,
     539                                    "GnuTLS: Failed to initialize"
     540                                    "keyring: (%d) %s", rv,
     541                                    gnutls_strerror(rv));
     542        }
     543
     544        rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data,
     545                                           GNUTLS_OPENPGP_FMT_BASE64);
     546        if (rv < 0) {
     547                return apr_psprintf(parms->pool, "GnuTLS: Failed to load "
     548                                    "Keyring File '%s': (%d) %s", file, rv,
     549                                    gnutls_strerror(rv));
     550        }
     551
     552        apr_pool_destroy(spool);
     553        return NULL;
    518554}
    519555
     
    521557                            const char *arg)
    522558{
    523     mgs_srvconf_rec *sc =
    524         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    525                                                  module_config,
    526                                                  &gnutls_module);
    527     if (!strcasecmp(arg, "On")) {
    528         sc->enabled = GNUTLS_ENABLED_TRUE;
    529     } else if (!strcasecmp(arg, "Off")) {
     559        mgs_srvconf_rec *sc =
     560            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     561                                                     module_config,
     562                                                     &gnutls_module);
     563        if (!strcasecmp(arg, "On")) {
     564                sc->enabled = GNUTLS_ENABLED_TRUE;
     565        } else if (!strcasecmp(arg, "Off")) {
     566                sc->enabled = GNUTLS_ENABLED_FALSE;
     567        } else {
     568                return "GnuTLSEnable must be set to 'On' or 'Off'";
     569        }
     570
     571        return NULL;
     572}
     573
     574const char *mgs_set_export_certificates_enabled(cmd_parms * parms,
     575                                                void *dummy,
     576                                                const char *arg)
     577{
     578        mgs_srvconf_rec *sc =
     579            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     580                                                     module_config,
     581                                                     &gnutls_module);
     582        if (!strcasecmp(arg, "On")) {
     583                sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE;
     584        } else if (!strcasecmp(arg, "Off")) {
     585                sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE;
     586        } else {
     587                return
     588                    "GnuTLSExportCertificates must be set to 'On' or 'Off'";
     589        }
     590
     591        return NULL;
     592}
     593
     594
     595const char *mgs_set_priorities(cmd_parms * parms, void *dummy,
     596                               const char *arg)
     597{
     598        int ret;
     599        const char *err;
     600        mgs_srvconf_rec *sc =
     601            (mgs_srvconf_rec *) ap_get_module_config(parms->server->
     602                                                     module_config,
     603                                                     &gnutls_module);
     604
     605
     606        ret = gnutls_priority_init(&sc->priorities, arg, &err);
     607        if (ret < 0) {
     608                if (ret == GNUTLS_E_INVALID_REQUEST)
     609                        return apr_psprintf(parms->pool,
     610                                            "GnuTLS: Syntax error parsing priorities string at: %s",
     611                                            err);
     612                return "Error setting priorities";
     613        }
     614
     615        return NULL;
     616}
     617
     618void *mgs_config_server_create(apr_pool_t * p, server_rec * s)
     619{
     620        mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
     621        int ret;
     622
    530623        sc->enabled = GNUTLS_ENABLED_FALSE;
    531     } else {
    532         return "GnuTLSEnable must be set to 'On' or 'Off'";
    533     }
    534 
    535     return NULL;
    536 }
    537 
    538 const char *mgs_set_export_certificates_enabled(cmd_parms * parms, void *dummy,
    539                             const char *arg)
    540 {
    541     mgs_srvconf_rec *sc =
    542         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    543                                                  module_config,
    544                                                  &gnutls_module);
    545     if (!strcasecmp(arg, "On")) {
    546         sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE;
    547     } else if (!strcasecmp(arg, "Off")) {
    548         sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE;
    549     } else {
    550         return "GnuTLSExportCertificates must be set to 'On' or 'Off'";
    551     }
    552 
    553     return NULL;
    554 }
    555 
    556 
    557 const char *mgs_set_priorities(cmd_parms * parms, void *dummy, const char *arg)
    558 {
    559     int ret;
    560     const char *err;
    561     mgs_srvconf_rec *sc =
    562         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    563                                                  module_config,
    564                                                  &gnutls_module);
    565 
    566 
    567     ret = gnutls_priority_init( &sc->priorities, arg, &err);
    568     if (ret < 0) {
    569       if (ret == GNUTLS_E_INVALID_REQUEST)
    570         return apr_psprintf(parms->pool, "GnuTLS: Syntax error parsing priorities string at: %s", err);
    571       return "Error setting priorities";
    572     }
    573 
    574     return NULL;
    575 }
    576 
    577 void *mgs_config_server_create(apr_pool_t * p, server_rec * s)
    578 {
    579     mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
    580     int ret;
    581    
    582     sc->enabled = GNUTLS_ENABLED_FALSE;
    583 
    584     ret = gnutls_certificate_allocate_credentials(&sc->certs);
    585     if (ret < 0) {
    586         return apr_psprintf(p, "GnuTLS: Failed to initialize"
    587                             ": (%d) %s", ret, gnutls_strerror(ret));
    588     }
    589 
    590     ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds);
    591     if (ret < 0) {
    592         return apr_psprintf(p, "GnuTLS: Failed to initialize"
    593                             ": (%d) %s", ret, gnutls_strerror(ret));
    594     }
    595 
     624
     625        ret = gnutls_certificate_allocate_credentials(&sc->certs);
     626        if (ret < 0) {
     627                return apr_psprintf(p, "GnuTLS: Failed to initialize"
     628                                    ": (%d) %s", ret,
     629                                    gnutls_strerror(ret));
     630        }
     631
     632        ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds);
     633        if (ret < 0) {
     634                return apr_psprintf(p, "GnuTLS: Failed to initialize"
     635                                    ": (%d) %s", ret,
     636                                    gnutls_strerror(ret));
     637        }
    596638#ifdef ENABLE_SRP
    597     ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds);
    598     if (ret < 0) {
    599         return apr_psprintf(p, "GnuTLS: Failed to initialize"
    600                             ": (%d) %s", ret, gnutls_strerror(ret));
    601     }
    602 
    603     sc->srp_tpasswd_conf_file = NULL;
    604     sc->srp_tpasswd_file = NULL;
     639        ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds);
     640        if (ret < 0) {
     641                return apr_psprintf(p, "GnuTLS: Failed to initialize"
     642                                    ": (%d) %s", ret,
     643                                    gnutls_strerror(ret));
     644        }
     645
     646        sc->srp_tpasswd_conf_file = NULL;
     647        sc->srp_tpasswd_file = NULL;
    605648#endif
    606649
    607     sc->privkey_x509 = NULL;
    608     memset( sc->certs_x509, 0, sizeof(sc->certs_x509));
    609     sc->certs_x509_num = 0;
    610     sc->cache_timeout = apr_time_from_sec(300);
    611     sc->cache_type = mgs_cache_none;
    612     sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache");
    613     sc->tickets = 1; /* by default enable session tickets */
    614 
    615     sc->client_verify_mode = GNUTLS_CERT_IGNORE;
    616 
    617     return sc;
     650        sc->privkey_x509 = NULL;
     651        memset(sc->certs_x509, 0, sizeof(sc->certs_x509));
     652        sc->certs_x509_num = 0;
     653        sc->cache_timeout = apr_time_from_sec(300);
     654        sc->cache_type = mgs_cache_none;
     655        sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache");
     656        sc->tickets = 1;        /* by default enable session tickets */
     657
     658        sc->client_verify_mode = GNUTLS_CERT_IGNORE;
     659
     660        return sc;
    618661}
    619662
    620663void *mgs_config_dir_merge(apr_pool_t * p, void *basev, void *addv)
    621664{
    622     mgs_dirconf_rec *new;
     665        mgs_dirconf_rec *new;
    623666/*    mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */
    624     mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv;
    625 
    626     new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec));
    627     new->lua_bytecode = apr_pstrmemdup(p, add->lua_bytecode,
    628                                        add->lua_bytecode_len);
    629     new->lua_bytecode_len = add->lua_bytecode_len;
    630     new->client_verify_mode = add->client_verify_mode;
    631     return new;
     667        mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv;
     668
     669        new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec));
     670        new->lua_bytecode = apr_pstrmemdup(p, add->lua_bytecode,
     671                                           add->lua_bytecode_len);
     672        new->lua_bytecode_len = add->lua_bytecode_len;
     673        new->client_verify_mode = add->client_verify_mode;
     674        return new;
    632675}
    633676
    634677void *mgs_config_dir_create(apr_pool_t * p, char *dir)
    635678{
    636     mgs_dirconf_rec *dc = apr_palloc(p, sizeof(*dc));
    637 
    638     dc->client_verify_mode = -1;
    639     dc->lua_bytecode = NULL;
    640     dc->lua_bytecode_len = 0;
    641     return dc;
    642 }
     679        mgs_dirconf_rec *dc = apr_palloc(p, sizeof(*dc));
     680
     681        dc->client_verify_mode = -1;
     682        dc->lua_bytecode = NULL;
     683        dc->lua_bytecode_len = 0;
     684        return dc;
     685}
  • src/gnutls_hooks.c

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

    r62def2f re02dd8c  
    3333
    3434static 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,
    67                             int inl)
    68 {
    69     if (!buffer->length) {
    70         return 0;
    71     }
    72 
    73     if (buffer->length > inl) {
    74         /* we have have enough to fill the caller's buffer */
    75         memmove(in, buffer->value, inl);
    76         buffer->value += inl;
    77         buffer->length -= inl;
    78     }
    79     else {
    80         /* swallow remainder of the buffer */
    81         memmove(in, buffer->value, buffer->length);
    82         inl = buffer->length;
    83         buffer->value = NULL;
    84         buffer->length = 0;
    85     }
    86 
    87     return inl;
    88 }
    89 
    90 static int char_buffer_write(mgs_char_buffer_t * buffer, char *in,
    91                              int inl)
    92 {
    93     buffer->value = in;
    94     buffer->length = inl;
    95     return inl;
     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
     66static 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
     88static 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;
    9693}
    9794
     
    10299 */
    103100static apr_status_t brigade_consume(apr_bucket_brigade * bb,
    104                                     apr_read_type_e block,
    105                                     char *c, apr_size_t * len)
    106 {
    107     apr_size_t actual = 0;
    108     apr_status_t status = APR_SUCCESS;
    109 
    110     while (!APR_BRIGADE_EMPTY(bb)) {
    111         apr_bucket *b = APR_BRIGADE_FIRST(bb);
    112         const char *str;
    113         apr_size_t str_len;
    114         apr_size_t consume;
    115 
    116         /* Justin points out this is an http-ism that might
    117         * not fit if brigade_consume is added to APR.  Perhaps
    118         * apr_bucket_read(eos_bucket) should return APR_EOF?
    119         * Then this becomes mainline instead of a one-off.
    120         */
    121         if (APR_BUCKET_IS_EOS(b)) {
    122             status = APR_EOF;
    123             break;
    124         }
    125 
    126         /* The reason I'm not offering brigade_consume yet
    127         * across to apr-util is that the following call
    128         * illustrates how borked that API really is.  For
    129         * this sort of case (caller provided buffer) it
    130         * would be much more trivial for apr_bucket_consume
    131         * to do all the work that follows, based on the
    132         * particular characteristics of the bucket we are
    133         * consuming here.
    134         */
    135         status = apr_bucket_read(b, &str, &str_len, block);
    136 
    137         if (status != APR_SUCCESS) {
    138             if (APR_STATUS_IS_EOF(status)) {
    139                 /* This stream bucket was consumed */
    140                 apr_bucket_delete(b);
    141                 continue;
    142             }
    143             break;
    144         }
    145 
    146         if (str_len > 0) {
    147             /* Do not block once some data has been consumed */
    148             block = APR_NONBLOCK_READ;
    149 
    150             /* Assure we don't overflow. */
    151             consume = (str_len + actual > *len) ? *len - actual : str_len;
    152 
    153             memcpy(c, str, consume);
    154 
    155             c += consume;
    156             actual += consume;
    157 
    158             if (consume >= b->length) {
    159                 /* This physical bucket was consumed */
    160                 apr_bucket_delete(b);
    161             }
    162             else {
    163                 /* Only part of this physical bucket was consumed */
    164                 b->start += consume;
    165                 b->length -= consume;
    166             }
    167         }
    168         else if (b->length == 0) {
    169             apr_bucket_delete(b);
    170         }
    171 
    172         /* This could probably be actual == *len, but be safe from stray
    173         * photons. */
    174         if (actual >= *len) {
    175             break;
    176         }
    177     }
    178 
    179     *len = actual;
    180     return status;
     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;
    181178}
    182179
    183180
    184181static apr_status_t gnutls_io_input_read(mgs_handle_t * ctxt,
    185                                          char *buf, apr_size_t * len)
    186 {
    187     apr_size_t wanted = *len;
    188     apr_size_t bytes = 0;
    189     int rc;
    190 
    191     *len = 0;
    192 
    193     /* If we have something leftover from last time, try that first. */
    194     if ((bytes = char_buffer_read(&ctxt->input_cbuf, buf, wanted))) {
    195         *len = bytes;
    196         if (ctxt->input_mode == AP_MODE_SPECULATIVE) {
    197             /* We want to rollback this read. */
    198             if (ctxt->input_cbuf.length > 0) {
    199                 ctxt->input_cbuf.value -= bytes;
    200                 ctxt->input_cbuf.length += bytes;
    201             }
    202             else {
    203                 char_buffer_write(&ctxt->input_cbuf, buf, (int) bytes);
    204             }
    205             return APR_SUCCESS;
    206         }
    207         /* This could probably be *len == wanted, but be safe from stray
    208          * photons.
    209          */
    210         if (*len >= wanted) {
    211             return APR_SUCCESS;
    212         }
    213         if (ctxt->input_mode == AP_MODE_GETLINE) {
    214             if (memchr(buf, APR_ASCII_LF, *len)) {
    215                 return APR_SUCCESS;
    216             }
    217         }
    218         else {
    219             /* Down to a nonblock pattern as we have some data already
    220              */
    221             ctxt->input_block = APR_NONBLOCK_READ;
    222         }
    223     }
    224    
    225     if (ctxt->session == NULL) {
    226         return APR_EGENERAL;
    227     }
    228 
    229     while (1) {
    230 
    231         rc = gnutls_record_recv(ctxt->session, buf + bytes, wanted - bytes);
    232 
    233         if (rc > 0) {
    234             *len += rc;
    235             if (ctxt->input_mode == AP_MODE_SPECULATIVE) {
    236                 /* We want to rollback this read. */
    237                 char_buffer_write(&ctxt->input_cbuf, buf, rc);
    238             }
    239             return ctxt->input_rc;
    240         }
    241         else if (rc == 0) {
    242             /* If EAGAIN, we will loop given a blocking read,
    243              * otherwise consider ourselves at EOF.
    244              */
    245             if (APR_STATUS_IS_EAGAIN(ctxt->input_rc)
    246                 || APR_STATUS_IS_EINTR(ctxt->input_rc)) {
    247                 /* Already read something, return APR_SUCCESS instead.
    248                  * On win32 in particular, but perhaps on other kernels,
    249                  * a blocking call isn't 'always' blocking.
    250                  */
    251                 if (*len > 0) {
    252                     ctxt->input_rc = APR_SUCCESS;
    253                     break;
    254                 }
    255                 if (ctxt->input_block == APR_NONBLOCK_READ) {
    256                     break;
    257                 }
    258             }
    259             else {
    260                 if (*len > 0) {
    261                     ctxt->input_rc = APR_SUCCESS;
    262                 }
    263                 else {
    264                     ctxt->input_rc = APR_EOF;
    265                 }
    266                 break;
    267             }
    268         }
    269         else {                  /* (rc < 0) */
    270 
    271             if (rc == GNUTLS_E_REHANDSHAKE) {
    272                 /* A client has asked for a new Hankshake. Currently, we don't do it */
    273                 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc,
    274                              ctxt->c->base_server,
    275                              "GnuTLS: Error reading data. Client Requested a New Handshake."
    276                              " (%d) '%s'", rc, gnutls_strerror(rc));
    277             }
    278             else if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
    279                 rc = gnutls_alert_get(ctxt->session);
    280                 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc,
    281                              ctxt->c->base_server,
    282                              "GnuTLS: Warning Alert From Client: "
    283                              " (%d) '%s'", rc, gnutls_alert_get_name(rc));
    284             }
    285             else if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
    286                 rc = gnutls_alert_get(ctxt->session);
    287                 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc,
    288                              ctxt->c->base_server,
    289                              "GnuTLS: Fatal Alert From Client: "
    290                              "(%d) '%s'", rc, gnutls_alert_get_name(rc));
    291                 ctxt->input_rc = APR_EGENERAL;
    292                 break;
    293             }
    294             else {
    295                 /* Some Other Error. Report it. Die. */
    296                 if(gnutls_error_is_fatal(rc)) {
    297                     ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc,
    298                                  ctxt->c->base_server,
    299                                  "GnuTLS: Error reading data. (%d) '%s'", rc,
    300                                  gnutls_strerror(rc));
    301                 }
    302                 else if(*len > 0) {
    303                     ctxt->input_rc = APR_SUCCESS;
    304                     break;
    305                 }
    306             }
    307 
    308             if (ctxt->input_rc == APR_SUCCESS) {
    309                 ctxt->input_rc = APR_EGENERAL;
    310             }
    311             break;
    312         }
    313     }
    314     return ctxt->input_rc;
     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;
    315314}
    316315
    317316static apr_status_t gnutls_io_input_getline(mgs_handle_t * ctxt,
    318                                             char *buf, apr_size_t * len)
    319 {
    320     const char *pos = NULL;
    321     apr_status_t status;
    322     apr_size_t tmplen = *len, buflen = *len, offset = 0;
    323 
    324     *len = 0;
    325 
    326     while (tmplen > 0) {
    327         status = gnutls_io_input_read(ctxt, buf + offset, &tmplen);
    328 
    329         if (status != APR_SUCCESS) {
    330             return status;
    331         }
    332 
    333         *len += tmplen;
    334 
    335         if ((pos = memchr(buf, APR_ASCII_LF, *len))) {
    336             break;
    337         }
    338 
    339         offset += tmplen;
    340         tmplen = buflen - offset;
    341     }
    342 
    343     if (pos) {
    344         char *value;
    345         int length;
    346         apr_size_t bytes = pos - buf;
    347 
    348         bytes += 1;
    349         value = buf + bytes;
    350         length = *len - bytes;
    351 
    352         char_buffer_write(&ctxt->input_cbuf, value, length);
    353 
    354         *len = bytes;
    355     }
    356 
    357     return APR_SUCCESS;
     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;
    358357}
    359358
     
    361360static int gnutls_do_handshake(mgs_handle_t * ctxt)
    362361{
    363     int ret;
    364     int errcode;
    365     int maxtries = HANDSHAKE_MAX_TRIES;
    366 
    367     if (ctxt->status != 0 || ctxt->session == NULL) {
    368         return -1;
    369     }
    370 
    371 tryagain:
    372     do {
    373         ret = gnutls_handshake(ctxt->session);
    374         maxtries--;
    375     } while ((ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) && maxtries > 0);
    376 
    377     if (maxtries < 1) {
    378         ctxt->status = -1;
     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;
    379379#if USING_2_1_RECENT
    380         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c,
    381                      "GnuTLS: Handshake Failed. Hit Maximum Attempts");
     380                ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c,
     381                              "GnuTLS: Handshake Failed. Hit Maximum Attempts");
    382382#else
    383         ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctxt->c->base_server,
    384                      "GnuTLS: Handshake Failed. Hit Maximum Attempts");
     383                ap_log_error(APLOG_MARK, APLOG_ERR, 0,
     384                             ctxt->c->base_server,
     385                             "GnuTLS: Handshake Failed. Hit Maximum Attempts");
    385386#endif
    386         if (ctxt->session) {
    387             gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL,
    388                           gnutls_error_to_alert(GNUTLS_E_INTERNAL_ERROR, NULL));
    389             gnutls_deinit(ctxt->session);
    390         }
    391         ctxt->session = NULL;
    392         return -1;
    393     }
    394 
    395     if (ret < 0) {
    396         if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
    397             || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
    398             errcode = gnutls_alert_get(ctxt->session);
    399             ap_log_error(APLOG_MARK, APLOG_INFO, 0, ctxt->c->base_server,
    400                          "GnuTLS: Hanshake Alert (%d) '%s'.", errcode,
    401                          gnutls_alert_get_name(errcode));
    402         }
    403    
    404         if (!gnutls_error_is_fatal(ret)) {
    405             ap_log_error(APLOG_MARK, APLOG_INFO, 0, ctxt->c->base_server,
    406                      "GnuTLS: Non-Fatal Handshake Error: (%d) '%s'", ret,
    407                       gnutls_strerror(ret));
    408             goto tryagain;
    409         }
     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                }
    410415#if USING_2_1_RECENT
    411         ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
    412                      "GnuTLS: Handshake Failed (%d) '%s'", ret,
    413                       gnutls_strerror(ret));
     416                ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
     417                              "GnuTLS: Handshake Failed (%d) '%s'", ret,
     418                              gnutls_strerror(ret));
    414419#else
    415         ap_log_error(APLOG_MARK, APLOG_INFO, 0, ctxt->c->base_server,
    416                      "GnuTLS: Handshake Failed (%d) '%s'", ret,
    417                      gnutls_strerror(ret));
     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));
    418424#endif
    419         ctxt->status = -1;
    420         if (ctxt->session) {
    421             gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL,
    422                           gnutls_error_to_alert(ret, NULL));
    423             gnutls_deinit(ctxt->session);
    424         }
    425         ctxt->session = NULL;
    426         return ret;
    427     }
    428     else {
    429         /* all done with the handshake */
    430         ctxt->status = 1;
    431         /* If the session was resumed, we did not set the correct
    432         * server_rec in ctxt->sc.  Go Find it. (ick!)
    433         */
    434         if (gnutls_session_is_resumed(ctxt->session)) {
    435             mgs_srvconf_rec* sc;
    436             sc = mgs_find_sni_server(ctxt->session);
    437             if (sc) {
    438                 ctxt->sc = sc;
    439             }
    440         }
    441         return 0;
    442     }
     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        }
    443449}
    444450
    445451int mgs_rehandshake(mgs_handle_t * ctxt)
    446452{
    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, ctxt->c->base_server,
    457                      "GnuTLS: Client Refused Rehandshake request.");
    458         return -1;
    459     }
    460    
    461     ctxt->status = 0;
    462 
    463     rv = gnutls_do_handshake(ctxt);
    464 
    465     return rv;
    466 }
    467 
    468 
    469 apr_status_t mgs_filter_input(ap_filter_t* f,
    470                                      apr_bucket_brigade * bb,
    471                                      ap_input_mode_t mode,
    472                                      apr_read_type_e block,
    473                                      apr_off_t readbytes)
    474 {
    475     apr_status_t status = APR_SUCCESS;
    476     mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
    477     apr_size_t len = sizeof(ctxt->input_buffer);
    478 
    479     if (f->c->aborted) {
    480         apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc);
    481         APR_BRIGADE_INSERT_TAIL(bb, bucket);
    482         return APR_ECONNABORTED;
    483     }
    484 
    485     if (ctxt->status == 0) {
    486         gnutls_do_handshake(ctxt);
    487     }
    488 
    489     if (ctxt->status < 0) {
    490         return ap_get_brigade(f->next, bb, mode, block, readbytes);
    491     }
    492 
    493     /* XXX: we don't currently support anything other than these modes. */
    494     if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE &&
    495         mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) {
    496         return APR_ENOTIMPL;
    497     }
    498 
    499     ctxt->input_mode = mode;
    500     ctxt->input_block = block;
    501 
    502     if (ctxt->input_mode == AP_MODE_READBYTES ||
    503         ctxt->input_mode == AP_MODE_SPECULATIVE) {
    504         /* Err. This is bad. readbytes *can* be a 64bit int! len.. is NOT */
    505         if (readbytes < len) {
    506             len = (apr_size_t) readbytes;
    507         }
    508         status = gnutls_io_input_read(ctxt, ctxt->input_buffer, &len);
    509     }
    510     else if (ctxt->input_mode == AP_MODE_GETLINE) {
    511         status = gnutls_io_input_getline(ctxt, ctxt->input_buffer, &len);
    512     }
    513     else {
    514         /* We have no idea what you are talking about, so return an error. */
    515         return APR_ENOTIMPL;
    516     }
    517 
    518     if (status != APR_SUCCESS) {
    519         return gnutls_io_filter_error(f, bb, status);
    520     }
    521 
    522     /* Create a transient bucket out of the decrypted data. */
    523     if (len > 0) {
    524         apr_bucket *bucket =
    525             apr_bucket_transient_create(ctxt->input_buffer, len,
    526                                         f->c->bucket_alloc);
    527         APR_BRIGADE_INSERT_TAIL(bb, bucket);
    528     }
    529 
    530     return status;
    531 }
    532 
    533 apr_status_t mgs_filter_output(ap_filter_t * f,
    534                                       apr_bucket_brigade * bb)
    535 {
    536     apr_size_t ret;
    537     apr_bucket* e;
    538     mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
    539     apr_status_t status = APR_SUCCESS;
    540     apr_read_type_e rblock = APR_NONBLOCK_READ;
    541 
    542     if (f->c->aborted) {
    543         apr_brigade_cleanup(bb);
    544         return APR_ECONNABORTED;
    545     }
    546 
    547     if (ctxt->status == 0) {
    548         gnutls_do_handshake(ctxt);
    549     }
    550 
    551     if (ctxt->status < 0) {
    552         return ap_pass_brigade(f->next, bb);
    553     }
    554 
    555     while (!APR_BRIGADE_EMPTY(bb)) {
    556         apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
    557        
    558         if (AP_BUCKET_IS_EOC(bucket)) {
    559             if (ctxt->session != NULL) {
    560                 do {
    561                     ret = gnutls_bye( ctxt->session, GNUTLS_SHUT_WR);
    562                 } while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
    563             }
    564 
    565             apr_bucket_copy(bucket, &e);
    566             APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e);
    567  
    568             if ((status = ap_pass_brigade(f->next, ctxt->output_bb)) != APR_SUCCESS) {
    569                 apr_brigade_cleanup(ctxt->output_bb);
    570                 return status;
    571             }
    572 
    573             apr_brigade_cleanup(ctxt->output_bb);
    574             if (ctxt->session) {
    575                 gnutls_deinit(ctxt->session);
    576                 ctxt->session = NULL;
    577             }
    578             continue;
    579         } else if (APR_BUCKET_IS_FLUSH(bucket) || APR_BUCKET_IS_EOS(bucket)) {
    580 
    581             apr_bucket_copy(bucket, &e);
    582             APR_BRIGADE_INSERT_TAIL(ctxt->output_bb, e);
    583             if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
    584                 apr_brigade_cleanup(ctxt->output_bb);
    585                 return status;
    586             }
    587 
    588             apr_brigade_cleanup(ctxt->output_bb);
    589             continue;
    590         }
    591         else {
    592             /* filter output */
    593             const char *data;
    594             apr_size_t len;
    595 
    596             status = apr_bucket_read(bucket, &data, &len, rblock);
    597 
    598             if (APR_STATUS_IS_EAGAIN(status)) {
    599                 rblock = APR_BLOCK_READ;
    600                 continue;       /* and try again with a blocking read. */
    601             }
    602 
    603             rblock = APR_NONBLOCK_READ;
    604 
    605             if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) {
    606                 break;
    607             }
    608            
    609             if (len > 0) {
    610 
    611                 if (ctxt->session == NULL) {
    612                     ret = GNUTLS_E_INVALID_REQUEST;
    613                 } else {
    614                     do {
    615                         ret = gnutls_record_send(ctxt->session, data, len);
    616                     }
    617                     while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
    618                 }
    619 
    620                 if (ret < 0) {
    621                     /* error sending output */
    622                     ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->output_rc,
    623                              ctxt->c->base_server,
    624                              "GnuTLS: Error writing data."
    625                              " (%d) '%s'", (int)ret, gnutls_strerror(ret));
    626                     if (ctxt->output_rc == APR_SUCCESS) {
    627                         ctxt->output_rc = APR_EGENERAL;
    628                     }
    629                 }
    630                 else if (ret != len) {
    631                     /* Not able to send the entire bucket,
    632                        split it and send it again. */
    633                     apr_bucket_split(bucket, ret);
    634                 }
    635             }
    636 
    637             apr_bucket_delete(bucket);
    638 
    639             if (ctxt->output_rc != APR_SUCCESS) {
    640                 break;
    641             }
    642         }
    643     }
    644 
    645     return status;
     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
     475
     476apr_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. */