- Timestamp:
- Sep 27, 2004, 3:46:17 PM (19 years ago)
- Branches:
- asyncio, debian/master, debian/stretch-backports, jessie-backports, main, master, msva, proxy-ticket, upstream
- Children:
- 2e12226
- Parents:
- aa99b13
- Location:
- src
- Files:
-
- 1 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Makefile.am
raa99b13 r7e2b223 1 1 CLEANFILES = .libs/libmod_gnutls *~ 2 2 3 libmod_gnutls_la_SOURCES = mod_gnutls.c 3 libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c 4 4 libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS} 5 5 libmod_gnutls_la_LDFLAGS = ${MODULE_LIBS} -
src/mod_gnutls.c
raa99b13 r7e2b223 16 16 */ 17 17 18 #include "httpd.h" 19 #include "http_config.h" 20 #include "http_protocol.h" 21 #include "http_connection.h" 22 #include "http_core.h" 23 #include "http_log.h" 24 #include "apr_buckets.h" 25 #include "apr_strings.h" 26 #include "apr_tables.h" 27 28 #include <gcrypt.h> 29 #include <gnutls/gnutls.h> 18 #include "mod_gnutls.h" 30 19 31 20 #if APR_HAS_THREADS 32 21 GCRY_THREAD_OPTION_PTHREAD_IMPL; 33 22 #endif 34 35 module AP_MODULE_DECLARE_DATA gnutls_module;36 37 #ifdef GNUTLS_AS_FILTER38 #define GNUTLS_OUTPUT_FILTER_NAME "GnuTLS Output Filter"39 #define GNUTLS_INPUT_FILTER_NAME "GnuTLS Input Filter"40 #endif41 42 #define GNUTLS_ENABLED_FALSE 043 #define GNUTLS_ENABLED_TRUE 144 45 46 typedef struct {47 gnutls_certificate_credentials_t certs;48 gnutls_anon_server_credentials_t anoncred;49 char *key_file;50 char *cert_file;51 int enabled;52 int ciphers[16];53 int key_exchange[16];54 int macs[16];55 int protocol[16];56 int compression[16];57 } gnutls_srvconf_rec;58 59 typedef struct gnutls_handle_t gnutls_handle_t;60 struct gnutls_handle_t61 {62 gnutls_srvconf_rec *sc;63 gnutls_session_t session;64 ap_filter_t *input_filter;65 apr_bucket_brigade *input_bb;66 apr_read_type_e input_block;67 int status;68 int non_https;69 };70 71 static apr_status_t gnutls_filter_input(ap_filter_t * f,72 apr_bucket_brigade * bb,73 ap_input_mode_t mode,74 apr_read_type_e block,75 apr_off_t readbytes)76 {77 apr_status_t status = APR_SUCCESS;78 gnutls_handle_t *ctxt = (gnutls_handle_t *) f->ctx;79 80 if (f->c->aborted) {81 apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc);82 APR_BRIGADE_INSERT_TAIL(bb, bucket);83 return APR_ECONNABORTED;84 }85 86 87 for (b = APR_BRIGADE_FIRST(bb);88 b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {89 if (APR_BUCKET_IS_EOS(b)) {90 /* end of connection */91 }92 else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)93 == APR_SUCCESS) {94 /* more data */95 }96 }97 98 return status;99 }100 101 #define HANDSHAKE_ATTEMPTS 10102 103 static apr_status_t gnutls_filter_output(ap_filter_t * f,104 apr_bucket_brigade * bb)105 {106 int ret, i;107 const char *buf = 0;108 apr_size_t bytes = 0;109 gnutls_handle_t *ctxt = (gnutls_handle_t *) f->ctx;110 apr_status_t status = APR_SUCCESS;111 apr_read_type_e rblock = APR_NONBLOCK_READ;112 113 if (f->c->aborted) {114 apr_brigade_cleanup(bb);115 return APR_ECONNABORTED;116 }117 118 if(ctxt->status == 0) {119 for (i=HANDSHAKE_ATTEMPTS; i>0; i--){120 ret = gnutls_handshake(ctxt->session);121 122 if(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN){123 continue;124 }125 126 if (ret < 0) {127 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {128 ret = gnutls_alert_get(ctxt->session);129 ap_log_error(APLOG_MARK, APLOG_ERR, 0, f->c->base_server,130 "GnuTLS: Hanshake Alert (%d) '%s'.\n", ret, gnutls_alert_get_name(ret));131 }132 133 if (gnutls_error_is_fatal(ret) != 0) {134 gnutls_deinit(ctxt->session);135 ap_log_error(APLOG_MARK, APLOG_ERR, 0, f->c->base_server,136 "GnuTLS: Handshake Failed (%d) '%s'",ret, gnutls_strerror(ret));137 ctxt->status = -1;138 break;139 }140 }141 else {142 ctxt->status = 1;143 break; /* all done with the handshake */144 }145 }146 }147 148 if (ctxt->status < 0) {149 return ap_pass_brigade(f->next, bb);150 }151 152 while (!APR_BRIGADE_EMPTY(bb)) {153 apr_bucket *bucket = APR_BRIGADE_FIRST(bb);154 if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) {155 /** TODO: GnuTLS doesn't have a special flush method? **/156 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {157 return status;158 }159 break;160 }161 else if(AP_BUCKET_IS_EOC(bucket)) {162 gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);163 164 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {165 return status;166 }167 break;168 }169 else {170 /* filter output */171 const char *data;172 apr_size_t len;173 174 status = apr_bucket_read(bucket, &data, &len, rblock);175 176 if (APR_STATUS_IS_EAGAIN(status)) {177 rblock = APR_BLOCK_READ;178 continue; /* and try again with a blocking read. */179 }180 181 rblock = APR_NONBLOCK_READ;182 183 if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) {184 break;185 }186 187 ret = gnutls_record_send(ctxt->session, data, len);188 status = ssl_filter_write(f, data, len);189 if(ret < 0) {190 /* error sending output */191 }192 else if ((apr_size_t)res != len) {193 /* not all of the data was sent. */194 /* mod_ssl basicly errors out here.. this doesn't seem right? */195 }196 else {197 /* send complete */198 199 }200 201 apr_bucket_delete(bucket);202 203 if (status != APR_SUCCESS) {204 break;205 }206 207 }208 }209 210 return status;211 }212 23 213 24 static apr_status_t gnutls_cleanup_pre_config(void *data) … … 254 65 for (s = base_server; s; s = s->next) { 255 66 sc = (gnutls_srvconf_rec *) ap_get_module_config(s->module_config, 256 &gnutls_module);67 &gnutls_module); 257 68 if (sc->cert_file != NULL && sc->key_file != NULL) { 258 69 gnutls_certificate_set_x509_key_file(sc->certs, sc->cert_file, … … 262 73 // gnutls_certificate_set_dh_params(sc->certs, dh_params); 263 74 } 264 else if (sc->enabled == GNUTLS_ENABLED_TRUE ){75 else if (sc->enabled == GNUTLS_ENABLED_TRUE) { 265 76 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, 266 77 "[GnuTLS] - Host '%s:%d' is missing a Cert and Key File!", … … 278 89 gnutls_srvconf_rec *sc = 279 90 (gnutls_srvconf_rec *) ap_get_module_config(r->server->module_config, 280 &gnutls_module);91 &gnutls_module); 281 92 282 93 if (sc->enabled == GNUTLS_ENABLED_FALSE) { … … 291 102 gnutls_srvconf_rec *sc = 292 103 (gnutls_srvconf_rec *) ap_get_module_config(r->server->module_config, 293 &gnutls_module);104 &gnutls_module); 294 105 295 106 if (sc->enabled == GNUTLS_ENABLED_FALSE) { … … 300 111 } 301 112 302 /**303 * From mod_ssl / ssl_engine_io.c304 * This function will read from a brigade and discard the read buckets as it305 * proceeds. It will read at most *len bytes.306 */307 static apr_status_t brigade_consume(apr_bucket_brigade * bb,308 apr_read_type_e block,309 char *c, apr_size_t * len)310 {311 apr_size_t actual = 0;312 apr_status_t status = APR_SUCCESS;313 314 while (!APR_BRIGADE_EMPTY(bb)) {315 apr_bucket *b = APR_BRIGADE_FIRST(bb);316 const char *str;317 apr_size_t str_len;318 apr_size_t consume;319 320 /* Justin points out this is an http-ism that might321 * not fit if brigade_consume is added to APR. Perhaps322 * apr_bucket_read(eos_bucket) should return APR_EOF?323 * Then this becomes mainline instead of a one-off.324 */325 if (APR_BUCKET_IS_EOS(b)) {326 status = APR_EOF;327 break;328 }329 330 /* The reason I'm not offering brigade_consume yet331 * across to apr-util is that the following call332 * illustrates how borked that API really is. For333 * this sort of case (caller provided buffer) it334 * would be much more trivial for apr_bucket_consume335 * to do all the work that follows, based on the336 * particular characteristics of the bucket we are337 * consuming here.338 */339 status = apr_bucket_read(b, &str, &str_len, block);340 341 if (status != APR_SUCCESS) {342 if (APR_STATUS_IS_EOF(status)) {343 /* This stream bucket was consumed */344 apr_bucket_delete(b);345 continue;346 }347 break;348 }349 350 if (str_len > 0) {351 /* Do not block once some data has been consumed */352 block = APR_NONBLOCK_READ;353 354 /* Assure we don't overflow. */355 consume = (str_len + actual > *len) ? *len - actual : str_len;356 357 memcpy(c, str, consume);358 359 c += consume;360 actual += consume;361 362 if (consume >= b->length) {363 /* This physical bucket was consumed */364 apr_bucket_delete(b);365 }366 else {367 /* Only part of this physical bucket was consumed */368 b->start += consume;369 b->length -= consume;370 }371 }372 else if (b->length == 0) {373 apr_bucket_delete(b);374 }375 376 /* This could probably be actual == *len, but be safe from stray377 * photons. */378 if (actual >= *len) {379 break;380 }381 }382 383 *len = actual;384 return status;385 }386 387 388 static ssize_t gnutls_transport_read(gnutls_transport_ptr_t ptr,389 void *buffer, size_t len)390 {391 gnutls_handle_t *ctxt = ptr;392 apr_status_t rc;393 apr_size_t in = len;394 /* If Len = 0, we don't do anything. */395 if (!len)396 return 0;397 398 if (APR_BRIGADE_EMPTY(ctxt->input_bb)) {399 400 rc = ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb,401 AP_MODE_READBYTES, ctxt->input_block, in);402 403 /* Not a problem, there was simply no data ready yet.404 */405 if (APR_STATUS_IS_EAGAIN(rc) || APR_STATUS_IS_EINTR(rc)406 || (rc == APR_SUCCESS && APR_BRIGADE_EMPTY(ctxt->input_bb))) {407 return 0;408 }409 410 if (rc != APR_SUCCESS) {411 /* Unexpected errors discard the brigade */412 apr_brigade_cleanup(ctxt->input_bb);413 ctxt->input_bb = NULL;414 return -1;415 }416 }417 418 // brigade_consume(ctxt->input_bb, ctxt->input_block, buffer, &len);419 420 421 ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb,422 AP_MODE_READBYTES, ctxt->input_block, len);423 424 return len;425 }426 427 static ssize_t gnutls_transport_write(gnutls_transport_ptr_t ptr,428 const void *buffer, size_t len)429 {430 gnutls_handle_t *ctxt = ptr;431 432 // apr_bucket *bucket = apr_bucket_transient_create(in, inl,433 // outctx->bb->434 // bucket_alloc);435 436 // outctx->length += inl;437 //APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket);438 return 0;439 }440 441 113 static int gnutls_hook_pre_connection(conn_rec * c, void *csd) 442 114 { … … 444 116 gnutls_srvconf_rec *sc = 445 117 (gnutls_srvconf_rec *) ap_get_module_config(c->base_server-> 446 module_config,447 &gnutls_module);118 module_config, 119 &gnutls_module); 448 120 449 121 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) { … … 471 143 472 144 // gnutls_dh_set_prime_bits(ctxt->session, DH_BITS); 473 145 474 146 475 147 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 476 148 477 gnutls_transport_set_pull_function(ctxt->session, gnutls_transport_read); 478 gnutls_transport_set_push_function(ctxt->session, gnutls_transport_write); 149 gnutls_transport_set_pull_function(ctxt->session, 150 mod_gnutls_transport_read); 151 gnutls_transport_set_push_function(ctxt->session, 152 mod_gnutls_transport_write); 479 153 gnutls_transport_set_ptr(ctxt->session, ctxt); 480 154 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c); … … 485 159 486 160 static const char *gnutls_set_cert_file(cmd_parms * parms, void *dummy, 487 const char *arg)161 const char *arg) 488 162 { 489 163 gnutls_srvconf_rec *sc = 490 164 (gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 491 module_config,492 &gnutls_module);165 module_config, 166 &gnutls_module); 493 167 sc->cert_file = apr_pstrdup(parms->pool, arg); 494 168 return NULL; … … 496 170 497 171 static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy, 498 const char *arg)172 const char *arg) 499 173 { 500 174 gnutls_srvconf_rec *sc = 501 175 (gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 502 module_config,503 &gnutls_module);504 sc->key_file = 176 module_config, 177 &gnutls_module); 178 sc->key_file = apr_pstrdup(parms->pool, arg); 505 179 return NULL; 506 180 } … … 511 185 gnutls_srvconf_rec *sc = 512 186 (gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 513 module_config,514 &gnutls_module);187 module_config, 188 &gnutls_module); 515 189 if (!strcasecmp(arg, "On")) { 516 190 sc->enabled = GNUTLS_ENABLED_TRUE; … … 536 210 "SSL Server Certificate file"), 537 211 AP_INIT_TAKE1("GnuTLSEnable", gnutls_set_enabled, 538 NULL, RSRC_CONF,539 "Whether this server has GnuTLS Enabled. Default: Off"),212 NULL, RSRC_CONF, 213 "Whether this server has GnuTLS Enabled. Default: Off"), 540 214 541 215 {NULL} … … 563 237 * ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5); 564 238 */ 565 ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME, gnutls_filter_input, 566 NULL, AP_FTYPE_CONNECTION + 5); 567 ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME, gnutls_filter_output, 568 NULL, AP_FTYPE_CONNECTION + 5); 239 ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME, 240 mod_gnutls_filter_input, NULL, 241 AP_FTYPE_CONNECTION + 5); 242 ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME, 243 mod_gnutls_filter_output, NULL, 244 AP_FTYPE_CONNECTION + 5); 569 245 } 570 246 … … 575 251 576 252 sc->enabled = GNUTLS_ENABLED_FALSE; 577 sc->non_https = 0;578 253 579 254 gnutls_certificate_allocate_credentials(&sc->certs); … … 587 262 sc->ciphers[i++] = GNUTLS_CIPHER_3DES_CBC; 588 263 sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_40; 589 sc->ciphers[i] 264 sc->ciphers[i] = 0; 590 265 591 266 i = 0;
Note: See TracChangeset
for help on using the changeset viewer.