1/** 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18#include "mod_lua.h" 19#include <string.h> 20#include <stdlib.h> 21#include <ctype.h> 22#include <apr_thread_mutex.h> 23 24#include "lua_apr.h" 25#include "lua_config.h" 26#include "apr_optional.h" 27#include "mod_ssl.h" 28#include "mod_auth.h" 29 30#ifdef APR_HAS_THREADS 31#include "apr_thread_proc.h" 32#endif 33 34APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap_lua, AP_LUA, int, lua_open, 35 (lua_State *L, apr_pool_t *p), 36 (L, p), OK, DECLINED) 37 38APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap_lua, AP_LUA, int, lua_request, 39 (lua_State *L, request_rec *r), 40 (L, r), OK, DECLINED) 41static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *lua_ssl_val = NULL; 42static APR_OPTIONAL_FN_TYPE(ssl_is_https) *lua_ssl_is_https = NULL; 43 44module AP_MODULE_DECLARE_DATA lua_module; 45 46#define AP_LUA_HOOK_FIRST (APR_HOOK_FIRST - 1) 47#define AP_LUA_HOOK_LAST (APR_HOOK_LAST + 1) 48 49typedef struct { 50 const char *name; 51 const char *file_name; 52 const char *function_name; 53 ap_lua_vm_spec *spec; 54 apr_array_header_t *args; 55} lua_authz_provider_spec; 56 57apr_hash_t *lua_authz_providers; 58 59typedef struct 60{ 61 apr_bucket_brigade *tmpBucket; 62 lua_State *L; 63 ap_lua_vm_spec *spec; 64 int broken; 65} lua_filter_ctx; 66 67apr_thread_mutex_t* lua_ivm_mutex = NULL; 68 69/** 70 * error reporting if lua has an error. 71 * Extracts the error from lua stack and prints 72 */ 73static void report_lua_error(lua_State *L, request_rec *r) 74{ 75 const char *lua_response; 76 r->status = HTTP_INTERNAL_SERVER_ERROR; 77 r->content_type = "text/html"; 78 ap_rputs("<b>Error!</b>\n", r); 79 ap_rputs("<p>", r); 80 lua_response = lua_tostring(L, -1); 81 ap_rputs(lua_response, r); 82 ap_rputs("</p>\n", r); 83 84 ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, r->pool, APLOGNO(01471) "Lua error: %s", 85 lua_response); 86} 87 88static void lua_open_callback(lua_State *L, apr_pool_t *p, void *ctx) 89{ 90 ap_lua_init(L, p); 91 ap_lua_load_apache2_lmodule(L); 92 ap_lua_load_request_lmodule(L, p); 93 ap_lua_load_config_lmodule(L); 94} 95 96static int lua_open_hook(lua_State *L, apr_pool_t *p) 97{ 98 lua_open_callback(L, p, NULL); 99 return OK; 100} 101 102static const char *scope_to_string(unsigned int scope) 103{ 104 switch (scope) { 105 case AP_LUA_SCOPE_ONCE: 106 case AP_LUA_SCOPE_UNSET: 107 return "once"; 108 case AP_LUA_SCOPE_REQUEST: 109 return "request"; 110 case AP_LUA_SCOPE_CONN: 111 return "conn"; 112#if APR_HAS_THREADS 113 case AP_LUA_SCOPE_THREAD: 114 return "thread"; 115 case AP_LUA_SCOPE_SERVER: 116 return "server"; 117#endif 118 default: 119 ap_assert(0); 120 return 0; 121 } 122} 123 124static void ap_lua_release_state(lua_State* L, ap_lua_vm_spec* spec, request_rec* r) { 125 char *hash; 126 apr_reslist_t* reslist = NULL; 127 if (spec->scope == AP_LUA_SCOPE_SERVER) { 128 ap_lua_server_spec* sspec = NULL; 129 lua_settop(L, 0); 130 lua_getfield(L, LUA_REGISTRYINDEX, "Apache2.Lua.server_spec"); 131 sspec = (ap_lua_server_spec*) lua_touserdata(L, 1); 132 hash = apr_psprintf(r->pool, "reslist:%s", spec->file); 133 if (apr_pool_userdata_get((void **)&reslist, hash, 134 r->server->process->pool) == APR_SUCCESS) { 135 AP_DEBUG_ASSERT(sspec != NULL); 136 if (reslist != NULL) { 137 apr_reslist_release(reslist, sspec); 138 } 139 } 140 } 141} 142 143static ap_lua_vm_spec *create_vm_spec(apr_pool_t **lifecycle_pool, 144 request_rec *r, 145 const ap_lua_dir_cfg *cfg, 146 const ap_lua_server_cfg *server_cfg, 147 const char *filename, 148 const char *bytecode, 149 apr_size_t bytecode_len, 150 const char *function, 151 const char *what) 152{ 153 apr_pool_t *pool; 154 ap_lua_vm_spec *spec = apr_pcalloc(r->pool, sizeof(ap_lua_vm_spec)); 155 156 spec->scope = cfg->vm_scope; 157 spec->pool = r->pool; 158 spec->package_paths = cfg->package_paths; 159 spec->package_cpaths = cfg->package_cpaths; 160 spec->cb = &lua_open_callback; 161 spec->cb_arg = NULL; 162 spec->bytecode = bytecode; 163 spec->bytecode_len = bytecode_len; 164 spec->codecache = (cfg->codecache == AP_LUA_CACHE_UNSET) ? AP_LUA_CACHE_STAT : cfg->codecache; 165 spec->vm_min = cfg->vm_min ? cfg->vm_min : 1; 166 spec->vm_max = cfg->vm_max ? cfg->vm_max : 1; 167 168 if (filename) { 169 char *file; 170 apr_filepath_merge(&file, server_cfg->root_path, 171 filename, APR_FILEPATH_NOTRELATIVE, r->pool); 172 spec->file = file; 173 } 174 else { 175 spec->file = r->filename; 176 } 177 ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, APLOGNO(02313) 178 "%s details: scope: %s, file: %s, func: %s", 179 what, scope_to_string(spec->scope), spec->file, 180 function ? function : "-"); 181 182 switch (spec->scope) { 183 case AP_LUA_SCOPE_ONCE: 184 case AP_LUA_SCOPE_UNSET: 185 apr_pool_create(&pool, r->pool); 186 break; 187 case AP_LUA_SCOPE_REQUEST: 188 pool = r->pool; 189 break; 190 case AP_LUA_SCOPE_CONN: 191 pool = r->connection->pool; 192 break; 193#if APR_HAS_THREADS 194 case AP_LUA_SCOPE_THREAD: 195 pool = apr_thread_pool_get(r->connection->current_thread); 196 break; 197 case AP_LUA_SCOPE_SERVER: 198 pool = r->server->process->pool; 199 break; 200#endif 201 default: 202 ap_assert(0); 203 } 204 205 *lifecycle_pool = pool; 206 return spec; 207} 208 209static const char* ap_lua_interpolate_string(apr_pool_t* pool, const char* string, const char** values) 210{ 211 char *stringBetween; 212 const char* ret; 213 int srclen,x,y; 214 srclen = strlen(string); 215 ret = ""; 216 y = 0; 217 for (x=0; x < srclen; x++) { 218 if (string[x] == '$' && x != srclen-1 && string[x+1] >= '0' && string[x+1] <= '9') { 219 int v = *(string+x+1) - '0'; 220 if (x-y > 0) { 221 stringBetween = apr_pstrndup(pool, string+y, x-y); 222 } 223 else { 224 stringBetween = ""; 225 } 226 ret = apr_pstrcat(pool, ret, stringBetween, values[v], NULL); 227 y = ++x+1; 228 } 229 } 230 231 if (x-y > 0 && y > 0) { 232 stringBetween = apr_pstrndup(pool, string+y, x-y); 233 ret = apr_pstrcat(pool, ret, stringBetween, NULL); 234 } 235 /* If no replacement was made, just return the original string */ 236 else if (y == 0) { 237 return string; 238 } 239 return ret; 240} 241 242 243 244/** 245 * "main" 246 */ 247static int lua_handler(request_rec *r) 248{ 249 int rc = OK; 250 if (strcmp(r->handler, "lua-script")) { 251 return DECLINED; 252 } 253 /* Decline the request if the script does not exist (or is a directory), 254 * rather than just returning internal server error */ 255 if ( 256 (r->finfo.filetype == APR_NOFILE) 257 || (r->finfo.filetype & APR_DIR) 258 ) { 259 return DECLINED; 260 } 261 ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(01472) 262 "handling [%s] in mod_lua", r->filename); 263 264 /* XXX: This seems wrong because it may generate wrong headers for HEAD requests */ 265 if (!r->header_only) { 266 lua_State *L; 267 apr_pool_t *pool; 268 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config, 269 &lua_module); 270 ap_lua_vm_spec *spec = create_vm_spec(&pool, r, cfg, NULL, NULL, NULL, 271 0, "handle", "request handler"); 272 273 L = ap_lua_get_lua_state(pool, spec, r); 274 if (!L) { 275 /* TODO annotate spec with failure reason */ 276 r->status = HTTP_INTERNAL_SERVER_ERROR; 277 ap_rputs("Unable to compile VM, see logs", r); 278 ap_lua_release_state(L, spec, r); 279 return HTTP_INTERNAL_SERVER_ERROR; 280 } 281 ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, APLOGNO(01474) "got a vm!"); 282 lua_getglobal(L, "handle"); 283 if (!lua_isfunction(L, -1)) { 284 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01475) 285 "lua: Unable to find function %s in %s", 286 "handle", 287 spec->file); 288 ap_lua_release_state(L, spec, r); 289 return HTTP_INTERNAL_SERVER_ERROR; 290 } 291 ap_lua_run_lua_request(L, r); 292 if (lua_pcall(L, 1, 1, 0)) { 293 report_lua_error(L, r); 294 } 295 if (lua_isnumber(L, -1)) { 296 rc = lua_tointeger(L, -1); 297 } 298 ap_lua_release_state(L, spec, r); 299 } 300 return rc; 301} 302 303 304/* ------------------- Input/output content filters ------------------- */ 305 306 307static apr_status_t lua_setup_filter_ctx(ap_filter_t* f, request_rec* r, lua_filter_ctx** c) { 308 apr_pool_t *pool; 309 ap_lua_vm_spec *spec; 310 int n, rc; 311 lua_State *L; 312 lua_filter_ctx *ctx; 313 ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config, 314 &lua_module); 315 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config, 316 &lua_module); 317 318 ctx = apr_pcalloc(r->pool, sizeof(lua_filter_ctx)); 319 ctx->broken = 0; 320 *c = ctx; 321 /* Find the filter that was called. 322 * XXX: If we were wired with mod_filter, the filter (mod_filters name) 323 * and the provider (our underlying filters name) need to have matched. 324 */ 325 for (n = 0; n < cfg->mapped_filters->nelts; n++) { 326 ap_lua_filter_handler_spec *hook_spec = 327 ((ap_lua_filter_handler_spec **) cfg->mapped_filters->elts)[n]; 328 329 if (hook_spec == NULL) { 330 continue; 331 } 332 if (!strcasecmp(hook_spec->filter_name, f->frec->name)) { 333 spec = create_vm_spec(&pool, r, cfg, server_cfg, 334 hook_spec->file_name, 335 NULL, 336 0, 337 hook_spec->function_name, 338 "filter"); 339 L = ap_lua_get_lua_state(pool, spec, r); 340 if (L) { 341 L = lua_newthread(L); 342 } 343 344 if (!L) { 345 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02328) 346 "lua: Failed to obtain lua interpreter for %s %s", 347 hook_spec->function_name, hook_spec->file_name); 348 ap_lua_release_state(L, spec, r); 349 return APR_EGENERAL; 350 } 351 if (hook_spec->function_name != NULL) { 352 lua_getglobal(L, hook_spec->function_name); 353 if (!lua_isfunction(L, -1)) { 354 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02329) 355 "lua: Unable to find function %s in %s", 356 hook_spec->function_name, 357 hook_spec->file_name); 358 ap_lua_release_state(L, spec, r); 359 return APR_EGENERAL; 360 } 361 362 ap_lua_run_lua_request(L, r); 363 } 364 else { 365 int t; 366 ap_lua_run_lua_request(L, r); 367 368 t = lua_gettop(L); 369 lua_setglobal(L, "r"); 370 lua_settop(L, t); 371 } 372 ctx->L = L; 373 ctx->spec = spec; 374 375 /* If a Lua filter is interested in filtering a request, it must first do a yield, 376 * otherwise we'll assume that it's not interested and pretend we didn't find it. 377 */ 378 rc = lua_resume(L, 1); 379 if (rc == LUA_YIELD) { 380 if (f->frec->providers == NULL) { 381 /* Not wired by mod_filter */ 382 apr_table_unset(r->headers_out, "Content-Length"); 383 apr_table_unset(r->headers_out, "Content-MD5"); 384 apr_table_unset(r->headers_out, "ETAG"); 385 } 386 return OK; 387 } 388 else { 389 ap_lua_release_state(L, spec, r); 390 return APR_ENOENT; 391 } 392 } 393 } 394 return APR_ENOENT; 395} 396 397static apr_status_t lua_output_filter_handle(ap_filter_t *f, apr_bucket_brigade *pbbIn) { 398 request_rec *r = f->r; 399 int rc; 400 lua_State *L; 401 lua_filter_ctx* ctx; 402 conn_rec *c = r->connection; 403 apr_bucket *pbktIn; 404 apr_status_t rv; 405 406 /* Set up the initial filter context and acquire the function. 407 * The corresponding Lua function should yield here. 408 */ 409 if (!f->ctx) { 410 rc = lua_setup_filter_ctx(f,r,&ctx); 411 if (rc == APR_EGENERAL) { 412 return HTTP_INTERNAL_SERVER_ERROR; 413 } 414 if (rc == APR_ENOENT) { 415 /* No filter entry found (or the script declined to filter), just pass on the buckets */ 416 ap_remove_output_filter(f); 417 return ap_pass_brigade(f->next,pbbIn); 418 } 419 else { 420 /* We've got a willing lua filter, setup and check for a prefix */ 421 size_t olen; 422 apr_bucket *pbktOut; 423 const char* output = lua_tolstring(ctx->L, 1, &olen); 424 425 f->ctx = ctx; 426 ctx->tmpBucket = apr_brigade_create(r->pool, c->bucket_alloc); 427 428 if (olen > 0) { 429 pbktOut = apr_bucket_heap_create(output, olen, NULL, c->bucket_alloc); 430 APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut); 431 rv = ap_pass_brigade(f->next, ctx->tmpBucket); 432 apr_brigade_cleanup(ctx->tmpBucket); 433 if (rv != APR_SUCCESS) { 434 return rv; 435 } 436 } 437 } 438 } 439 ctx = (lua_filter_ctx*) f->ctx; 440 L = ctx->L; 441 /* While the Lua function is still yielding, pass in buckets to the coroutine */ 442 if (!ctx->broken) { 443 for (pbktIn = APR_BRIGADE_FIRST(pbbIn); 444 pbktIn != APR_BRIGADE_SENTINEL(pbbIn); 445 pbktIn = APR_BUCKET_NEXT(pbktIn)) 446 { 447 const char *data; 448 apr_size_t len; 449 apr_bucket *pbktOut; 450 451 /* read the bucket */ 452 apr_bucket_read(pbktIn,&data,&len,APR_BLOCK_READ); 453 454 /* Push the bucket onto the Lua stack as a global var */ 455 lua_pushlstring(L, data, len); 456 lua_setglobal(L, "bucket"); 457 458 /* If Lua yielded, it means we have something to pass on */ 459 if (lua_resume(L, 0) == LUA_YIELD) { 460 size_t olen; 461 const char* output = lua_tolstring(L, 1, &olen); 462 if (olen > 0) { 463 pbktOut = apr_bucket_heap_create(output, olen, NULL, 464 c->bucket_alloc); 465 APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut); 466 rv = ap_pass_brigade(f->next, ctx->tmpBucket); 467 apr_brigade_cleanup(ctx->tmpBucket); 468 if (rv != APR_SUCCESS) { 469 return rv; 470 } 471 } 472 } 473 else { 474 ctx->broken = 1; 475 ap_lua_release_state(L, ctx->spec, r); 476 ap_remove_output_filter(f); 477 apr_brigade_cleanup(pbbIn); 478 apr_brigade_cleanup(ctx->tmpBucket); 479 return HTTP_INTERNAL_SERVER_ERROR; 480 } 481 } 482 /* If we've safely reached the end, do a final call to Lua to allow for any 483 finishing moves by the script, such as appending a tail. */ 484 if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pbbIn))) { 485 apr_bucket *pbktEOS; 486 lua_pushnil(L); 487 lua_setglobal(L, "bucket"); 488 if (lua_resume(L, 0) == LUA_YIELD) { 489 apr_bucket *pbktOut; 490 size_t olen; 491 const char* output = lua_tolstring(L, 1, &olen); 492 if (olen > 0) { 493 pbktOut = apr_bucket_heap_create(output, olen, NULL, 494 c->bucket_alloc); 495 APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut); 496 } 497 } 498 pbktEOS = apr_bucket_eos_create(c->bucket_alloc); 499 APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktEOS); 500 ap_lua_release_state(L, ctx->spec, r); 501 rv = ap_pass_brigade(f->next, ctx->tmpBucket); 502 apr_brigade_cleanup(ctx->tmpBucket); 503 if (rv != APR_SUCCESS) { 504 return rv; 505 } 506 } 507 } 508 /* Clean up */ 509 apr_brigade_cleanup(pbbIn); 510 return APR_SUCCESS; 511} 512 513 514 515static apr_status_t lua_input_filter_handle(ap_filter_t *f, 516 apr_bucket_brigade *pbbOut, 517 ap_input_mode_t eMode, 518 apr_read_type_e eBlock, 519 apr_off_t nBytes) 520{ 521 request_rec *r = f->r; 522 int rc, lastCall = 0; 523 lua_State *L; 524 lua_filter_ctx* ctx; 525 conn_rec *c = r->connection; 526 apr_status_t ret; 527 528 /* Set up the initial filter context and acquire the function. 529 * The corresponding Lua function should yield here. 530 */ 531 if (!f->ctx) { 532 rc = lua_setup_filter_ctx(f,r,&ctx); 533 f->ctx = ctx; 534 if (rc == APR_EGENERAL) { 535 ctx->broken = 1; 536 ap_remove_input_filter(f); 537 return HTTP_INTERNAL_SERVER_ERROR; 538 } 539 if (rc == APR_ENOENT ) { 540 ap_remove_input_filter(f); 541 ctx->broken = 1; 542 } 543 if (rc == APR_SUCCESS) { 544 ctx->tmpBucket = apr_brigade_create(r->pool, c->bucket_alloc); 545 } 546 } 547 ctx = (lua_filter_ctx*) f->ctx; 548 L = ctx->L; 549 /* If the Lua script broke or denied serving the request, just pass the buckets through */ 550 if (ctx->broken) { 551 return ap_get_brigade(f->next, pbbOut, eMode, eBlock, nBytes); 552 } 553 554 if (APR_BRIGADE_EMPTY(ctx->tmpBucket)) { 555 ret = ap_get_brigade(f->next, ctx->tmpBucket, eMode, eBlock, nBytes); 556 if (eMode == AP_MODE_EATCRLF || ret != APR_SUCCESS) 557 return ret; 558 } 559 560 /* While the Lua function is still yielding, pass buckets to the coroutine */ 561 if (!ctx->broken) { 562 lastCall = 0; 563 while(!APR_BRIGADE_EMPTY(ctx->tmpBucket)) { 564 apr_bucket *pbktIn = APR_BRIGADE_FIRST(ctx->tmpBucket); 565 apr_bucket *pbktOut; 566 const char *data; 567 apr_size_t len; 568 569 if (APR_BUCKET_IS_EOS(pbktIn)) { 570 APR_BUCKET_REMOVE(pbktIn); 571 break; 572 } 573 574 /* read the bucket */ 575 ret = apr_bucket_read(pbktIn, &data, &len, eBlock); 576 if (ret != APR_SUCCESS) 577 return ret; 578 579 /* Push the bucket onto the Lua stack as a global var */ 580 lastCall++; 581 lua_pushlstring(L, data, len); 582 lua_setglobal(L, "bucket"); 583 584 /* If Lua yielded, it means we have something to pass on */ 585 if (lua_resume(L, 0) == LUA_YIELD) { 586 size_t olen; 587 const char* output = lua_tolstring(L, 1, &olen); 588 pbktOut = apr_bucket_heap_create(output, olen, 0, c->bucket_alloc); 589 APR_BRIGADE_INSERT_TAIL(pbbOut, pbktOut); 590 apr_bucket_delete(pbktIn); 591 return APR_SUCCESS; 592 } 593 else { 594 ctx->broken = 1; 595 ap_lua_release_state(L, ctx->spec, r); 596 ap_remove_input_filter(f); 597 apr_bucket_delete(pbktIn); 598 return HTTP_INTERNAL_SERVER_ERROR; 599 } 600 } 601 /* If we've safely reached the end, do a final call to Lua to allow for any 602 finishing moves by the script, such as appending a tail. */ 603 if (lastCall == 0) { 604 apr_bucket *pbktEOS = apr_bucket_eos_create(c->bucket_alloc); 605 lua_pushnil(L); 606 lua_setglobal(L, "bucket"); 607 if (lua_resume(L, 0) == LUA_YIELD) { 608 apr_bucket *pbktOut; 609 size_t olen; 610 const char* output = lua_tolstring(L, 1, &olen); 611 pbktOut = apr_bucket_heap_create(output, olen, 0, c->bucket_alloc); 612 APR_BRIGADE_INSERT_TAIL(pbbOut, pbktOut); 613 } 614 APR_BRIGADE_INSERT_TAIL(pbbOut,pbktEOS); 615 ap_lua_release_state(L, ctx->spec, r); 616 } 617 } 618 return APR_SUCCESS; 619} 620 621 622/* ---------------- Configury stuff --------------- */ 623 624/** harnesses for magic hooks **/ 625 626static int lua_request_rec_hook_harness(request_rec *r, const char *name, int apr_hook_when) 627{ 628 int rc; 629 apr_pool_t *pool; 630 lua_State *L; 631 ap_lua_vm_spec *spec; 632 ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config, 633 &lua_module); 634 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config, 635 &lua_module); 636 const char *key = apr_psprintf(r->pool, "%s_%d", name, apr_hook_when); 637 apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key, 638 APR_HASH_KEY_STRING); 639 if (hook_specs) { 640 int i; 641 for (i = 0; i < hook_specs->nelts; i++) { 642 ap_lua_mapped_handler_spec *hook_spec = 643 ((ap_lua_mapped_handler_spec **) hook_specs->elts)[i]; 644 645 if (hook_spec == NULL) { 646 continue; 647 } 648 spec = create_vm_spec(&pool, r, cfg, server_cfg, 649 hook_spec->file_name, 650 hook_spec->bytecode, 651 hook_spec->bytecode_len, 652 hook_spec->function_name, 653 "request hook"); 654 655 L = ap_lua_get_lua_state(pool, spec, r); 656 657 if (!L) { 658 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01477) 659 "lua: Failed to obtain lua interpreter for %s %s", 660 hook_spec->function_name, hook_spec->file_name); 661 return HTTP_INTERNAL_SERVER_ERROR; 662 } 663 664 if (hook_spec->function_name != NULL) { 665 lua_getglobal(L, hook_spec->function_name); 666 if (!lua_isfunction(L, -1)) { 667 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01478) 668 "lua: Unable to find function %s in %s", 669 hook_spec->function_name, 670 hook_spec->file_name); 671 ap_lua_release_state(L, spec, r); 672 return HTTP_INTERNAL_SERVER_ERROR; 673 } 674 675 ap_lua_run_lua_request(L, r); 676 } 677 else { 678 int t; 679 ap_lua_run_lua_request(L, r); 680 681 t = lua_gettop(L); 682 lua_setglobal(L, "r"); 683 lua_settop(L, t); 684 } 685 686 if (lua_pcall(L, 1, 1, 0)) { 687 report_lua_error(L, r); 688 ap_lua_release_state(L, spec, r); 689 return HTTP_INTERNAL_SERVER_ERROR; 690 } 691 rc = DECLINED; 692 if (lua_isnumber(L, -1)) { 693 rc = lua_tointeger(L, -1); 694 ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "Lua hook %s:%s for phase %s returned %d", 695 hook_spec->file_name, hook_spec->function_name, name, rc); 696 } 697 else { 698 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, "Lua hook %s:%s for phase %s did not return a numeric value", 699 hook_spec->file_name, hook_spec->function_name, name); 700 return HTTP_INTERNAL_SERVER_ERROR; 701 } 702 if (rc != DECLINED) { 703 ap_lua_release_state(L, spec, r); 704 return rc; 705 } 706 ap_lua_release_state(L, spec, r); 707 } 708 } 709 return DECLINED; 710} 711 712static int lua_map_handler_fixups(request_rec *r) 713{ 714 /* If there is no handler set yet, this might be a LuaMapHandler request */ 715 if (r->handler == NULL) { 716 int n = 0; 717 ap_regmatch_t match[10]; 718 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config, 719 &lua_module); 720 for (n = 0; n < cfg->mapped_handlers->nelts; n++) { 721 ap_lua_mapped_handler_spec *hook_spec = 722 ((ap_lua_mapped_handler_spec **) cfg->mapped_handlers->elts)[n]; 723 724 if (hook_spec == NULL) { 725 continue; 726 } 727 if (!ap_regexec(hook_spec->uri_pattern, r->uri, 10, match, 0)) { 728 r->handler = apr_pstrdup(r->pool, "lua-map-handler"); 729 return OK; 730 } 731 } 732 } 733 return DECLINED; 734} 735 736static int lua_map_handler(request_rec *r) 737{ 738 int rc, n = 0; 739 apr_pool_t *pool; 740 lua_State *L; 741 const char *filename, *function_name; 742 const char *values[10]; 743 ap_lua_vm_spec *spec; 744 ap_regmatch_t match[10]; 745 ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config, 746 &lua_module); 747 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config, 748 &lua_module); 749 for (n = 0; n < cfg->mapped_handlers->nelts; n++) { 750 ap_lua_mapped_handler_spec *hook_spec = 751 ((ap_lua_mapped_handler_spec **) cfg->mapped_handlers->elts)[n]; 752 753 if (hook_spec == NULL) { 754 continue; 755 } 756 if (!ap_regexec(hook_spec->uri_pattern, r->uri, 10, match, 0)) { 757 int i; 758 for (i=0 ; i < 10; i++) { 759 if (match[i].rm_eo >= 0) { 760 values[i] = apr_pstrndup(r->pool, r->uri+match[i].rm_so, match[i].rm_eo - match[i].rm_so); 761 } 762 else values[i] = ""; 763 } 764 filename = ap_lua_interpolate_string(r->pool, hook_spec->file_name, values); 765 function_name = ap_lua_interpolate_string(r->pool, hook_spec->function_name, values); 766 spec = create_vm_spec(&pool, r, cfg, server_cfg, 767 filename, 768 hook_spec->bytecode, 769 hook_spec->bytecode_len, 770 function_name, 771 "mapped handler"); 772 L = ap_lua_get_lua_state(pool, spec, r); 773 774 if (!L) { 775 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02330) 776 "lua: Failed to obtain lua interpreter for %s %s", 777 function_name, filename); 778 ap_lua_release_state(L, spec, r); 779 return HTTP_INTERNAL_SERVER_ERROR; 780 } 781 782 if (function_name != NULL) { 783 lua_getglobal(L, function_name); 784 if (!lua_isfunction(L, -1)) { 785 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02331) 786 "lua: Unable to find function %s in %s", 787 function_name, 788 filename); 789 ap_lua_release_state(L, spec, r); 790 return HTTP_INTERNAL_SERVER_ERROR; 791 } 792 793 ap_lua_run_lua_request(L, r); 794 } 795 else { 796 int t; 797 ap_lua_run_lua_request(L, r); 798 799 t = lua_gettop(L); 800 lua_setglobal(L, "r"); 801 lua_settop(L, t); 802 } 803 804 if (lua_pcall(L, 1, 1, 0)) { 805 report_lua_error(L, r); 806 ap_lua_release_state(L, spec, r); 807 return HTTP_INTERNAL_SERVER_ERROR; 808 } 809 rc = DECLINED; 810 if (lua_isnumber(L, -1)) { 811 rc = lua_tointeger(L, -1); 812 } 813 else { 814 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02483) 815 "lua: Lua handler %s in %s did not return a value, assuming apache2.OK", 816 function_name, 817 filename); 818 rc = OK; 819 } 820 ap_lua_release_state(L, spec, r); 821 if (rc != DECLINED) { 822 return rc; 823 } 824 } 825 } 826 return DECLINED; 827} 828 829 830static apr_size_t config_getstr(ap_configfile_t *cfg, char *buf, 831 size_t bufsiz) 832{ 833 apr_size_t i = 0; 834 835 if (cfg->getstr) { 836 apr_status_t rc = (cfg->getstr) (buf, bufsiz, cfg->param); 837 if (rc == APR_SUCCESS) { 838 i = strlen(buf); 839 if (i && buf[i - 1] == '\n') 840 ++cfg->line_number; 841 } 842 else { 843 buf[0] = '\0'; 844 i = 0; 845 } 846 } 847 else { 848 while (i < bufsiz) { 849 char ch; 850 apr_status_t rc = (cfg->getch) (&ch, cfg->param); 851 if (rc != APR_SUCCESS) 852 break; 853 buf[i++] = ch; 854 if (ch == '\n') { 855 ++cfg->line_number; 856 break; 857 } 858 } 859 } 860 return i; 861} 862 863typedef struct cr_ctx 864{ 865 cmd_parms *cmd; 866 ap_configfile_t *cfp; 867 size_t startline; 868 const char *endstr; 869 char buf[HUGE_STRING_LEN]; 870} cr_ctx; 871 872 873/* Okay, this deserves a little explaination -- in order for the errors that lua 874 * generates to be 'accuarate', including line numbers, we basically inject 875 * N line number new lines into the 'top' of the chunk reader..... 876 * 877 * be happy. this is cool. 878 * 879 */ 880static const char *lf = 881 "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; 882#define N_LF 32 883 884static const char *direct_chunkreader(lua_State *lvm, void *udata, 885 size_t *plen) 886{ 887 const char *p; 888 struct cr_ctx *ctx = udata; 889 890 if (ctx->startline) { 891 *plen = ctx->startline > N_LF ? N_LF : ctx->startline; 892 ctx->startline -= *plen; 893 return lf; 894 } 895 *plen = config_getstr(ctx->cfp, ctx->buf, HUGE_STRING_LEN); 896 897 for (p = ctx->buf; isspace(*p); ++p); 898 if (p[0] == '<' && p[1] == '/') { 899 apr_size_t i = 0; 900 while (i < strlen(ctx->endstr)) { 901 if (tolower(p[i + 2]) != ctx->endstr[i]) 902 return ctx->buf; 903 ++i; 904 } 905 *plen = 0; 906 return NULL; 907 } 908 /*fprintf(stderr, "buf read: %s\n", ctx->buf); */ 909 return ctx->buf; 910} 911 912static int ldump_writer(lua_State *L, const void *b, size_t size, void *B) 913{ 914 (void) L; 915 luaL_addlstring((luaL_Buffer *) B, (const char *) b, size); 916 return 0; 917} 918 919typedef struct hack_section_baton 920{ 921 const char *name; 922 ap_lua_mapped_handler_spec *spec; 923 int apr_hook_when; 924} hack_section_baton; 925 926/* You can be unhappy now. 927 * 928 * This is uncool. 929 * 930 * When you create a <Section handler in httpd, the only 'easy' way to create 931 * a directory context is to parse the section, and convert it into a 'normal' 932 * Configureation option, and then collapse the entire section, in memory, 933 * back into the parent section -- from which you can then get the new directive 934 * invoked.... anyways. evil. Rici taught me how to do this hack :-) 935 */ 936static const char *hack_section_handler(cmd_parms *cmd, void *_cfg, 937 const char *arg) 938{ 939 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg; 940 ap_directive_t *directive = cmd->directive; 941 hack_section_baton *baton = directive->data; 942 const char *key = apr_psprintf(cmd->pool, "%s_%d", baton->name, baton->apr_hook_when); 943 944 apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key, 945 APR_HASH_KEY_STRING); 946 if (!hook_specs) { 947 hook_specs = apr_array_make(cmd->pool, 2, 948 sizeof(ap_lua_mapped_handler_spec *)); 949 apr_hash_set(cfg->hooks, key, 950 APR_HASH_KEY_STRING, hook_specs); 951 } 952 953 baton->spec->scope = cfg->vm_scope; 954 955 *(ap_lua_mapped_handler_spec **) apr_array_push(hook_specs) = baton->spec; 956 957 return NULL; 958} 959 960static const char *register_named_block_function_hook(const char *name, 961 cmd_parms *cmd, 962 void *mconfig, 963 const char *line) 964{ 965 const char *function = NULL; 966 ap_lua_mapped_handler_spec *spec; 967 int when = APR_HOOK_MIDDLE; 968 const char *endp = ap_strrchr_c(line, '>'); 969 970 if (endp == NULL) { 971 return apr_pstrcat(cmd->pool, cmd->cmd->name, 972 "> directive missing closing '>'", NULL); 973 } 974 975 line = apr_pstrndup(cmd->temp_pool, line, endp - line); 976 977 if (line[0]) { 978 const char *word; 979 word = ap_getword_conf(cmd->temp_pool, &line); 980 if (*word) { 981 function = apr_pstrdup(cmd->pool, word); 982 } 983 word = ap_getword_conf(cmd->temp_pool, &line); 984 if (*word) { 985 if (!strcasecmp("early", word)) { 986 when = AP_LUA_HOOK_FIRST; 987 } 988 else if (!strcasecmp("late", word)) { 989 when = AP_LUA_HOOK_LAST; 990 } 991 else { 992 return apr_pstrcat(cmd->pool, cmd->cmd->name, 993 "> 2nd argument must be 'early' or 'late'", NULL); 994 } 995 } 996 } 997 998 spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec)); 999 1000 { 1001 cr_ctx ctx; 1002 lua_State *lvm; 1003 char *tmp; 1004 int rv; 1005 ap_directive_t **current; 1006 hack_section_baton *baton; 1007 1008 spec->file_name = apr_psprintf(cmd->pool, "%s:%u", 1009 cmd->config_file->name, 1010 cmd->config_file->line_number); 1011 if (function) { 1012 spec->function_name = (char *) function; 1013 } 1014 else { 1015 function = NULL; 1016 } 1017 1018 ctx.cmd = cmd; 1019 tmp = apr_pstrdup(cmd->pool, cmd->err_directive->directive + 1); 1020 ap_str_tolower(tmp); 1021 ctx.endstr = tmp; 1022 ctx.cfp = cmd->config_file; 1023 ctx.startline = cmd->config_file->line_number; 1024 1025 /* This lua State is used only to compile the input strings -> bytecode, so we don't need anything extra. */ 1026 lvm = luaL_newstate(); 1027 1028 lua_settop(lvm, 0); 1029 1030 rv = lua_load(lvm, direct_chunkreader, &ctx, spec->file_name); 1031 1032 if (rv != 0) { 1033 const char *errstr = apr_pstrcat(cmd->pool, "Lua Error:", 1034 lua_tostring(lvm, -1), NULL); 1035 lua_close(lvm); 1036 return errstr; 1037 } 1038 else { 1039 luaL_Buffer b; 1040 luaL_buffinit(lvm, &b); 1041 lua_dump(lvm, ldump_writer, &b); 1042 luaL_pushresult(&b); 1043 spec->bytecode_len = lua_strlen(lvm, -1); 1044 spec->bytecode = apr_pstrmemdup(cmd->pool, lua_tostring(lvm, -1), 1045 spec->bytecode_len); 1046 lua_close(lvm); 1047 } 1048 1049 current = mconfig; 1050 1051 /* Here, we have to replace our current config node for the next pass */ 1052 if (!*current) { 1053 *current = apr_pcalloc(cmd->pool, sizeof(**current)); 1054 } 1055 1056 baton = apr_pcalloc(cmd->pool, sizeof(hack_section_baton)); 1057 baton->name = name; 1058 baton->spec = spec; 1059 baton->apr_hook_when = when; 1060 1061 (*current)->filename = cmd->config_file->name; 1062 (*current)->line_num = cmd->config_file->line_number; 1063 (*current)->directive = apr_pstrdup(cmd->pool, "Lua_____ByteCodeHack"); 1064 (*current)->args = NULL; 1065 (*current)->data = baton; 1066 } 1067 1068 return NULL; 1069} 1070 1071static const char *register_named_file_function_hook(const char *name, 1072 cmd_parms *cmd, 1073 void *_cfg, 1074 const char *file, 1075 const char *function, 1076 int apr_hook_when) 1077{ 1078 ap_lua_mapped_handler_spec *spec; 1079 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg; 1080 const char *key = apr_psprintf(cmd->pool, "%s_%d", name, apr_hook_when); 1081 apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key, 1082 APR_HASH_KEY_STRING); 1083 1084 if (!hook_specs) { 1085 hook_specs = apr_array_make(cmd->pool, 2, 1086 sizeof(ap_lua_mapped_handler_spec *)); 1087 apr_hash_set(cfg->hooks, key, APR_HASH_KEY_STRING, hook_specs); 1088 } 1089 1090 spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec)); 1091 spec->file_name = apr_pstrdup(cmd->pool, file); 1092 spec->function_name = apr_pstrdup(cmd->pool, function); 1093 spec->scope = cfg->vm_scope; 1094 1095 *(ap_lua_mapped_handler_spec **) apr_array_push(hook_specs) = spec; 1096 return NULL; 1097} 1098static const char *register_mapped_file_function_hook(const char *pattern, 1099 cmd_parms *cmd, 1100 void *_cfg, 1101 const char *file, 1102 const char *function) 1103{ 1104 ap_lua_mapped_handler_spec *spec; 1105 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg; 1106 ap_regex_t *regex = apr_pcalloc(cmd->pool, sizeof(ap_regex_t)); 1107 if (ap_regcomp(regex, pattern,0)) { 1108 return "Invalid regex pattern!"; 1109 } 1110 1111 spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec)); 1112 spec->file_name = apr_pstrdup(cmd->pool, file); 1113 spec->function_name = apr_pstrdup(cmd->pool, function); 1114 spec->scope = cfg->vm_scope; 1115 spec->uri_pattern = regex; 1116 1117 *(ap_lua_mapped_handler_spec **) apr_array_push(cfg->mapped_handlers) = spec; 1118 return NULL; 1119} 1120static const char *register_filter_function_hook(const char *filter, 1121 cmd_parms *cmd, 1122 void *_cfg, 1123 const char *file, 1124 const char *function, 1125 int direction) 1126{ 1127 ap_lua_filter_handler_spec *spec; 1128 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg; 1129 1130 spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_filter_handler_spec)); 1131 spec->file_name = apr_pstrdup(cmd->pool, file); 1132 spec->function_name = apr_pstrdup(cmd->pool, function); 1133 spec->filter_name = filter; 1134 1135 *(ap_lua_filter_handler_spec **) apr_array_push(cfg->mapped_filters) = spec; 1136 /* TODO: Make it work on other types than just AP_FTYPE_RESOURCE? */ 1137 if (direction == AP_LUA_FILTER_OUTPUT) { 1138 spec->direction = AP_LUA_FILTER_OUTPUT; 1139 ap_register_output_filter_protocol(filter, lua_output_filter_handle, NULL, AP_FTYPE_RESOURCE, 1140 AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH); 1141 } 1142 else { 1143 spec->direction = AP_LUA_FILTER_INPUT; 1144 ap_register_input_filter(filter, lua_input_filter_handle, NULL, AP_FTYPE_RESOURCE); 1145 } 1146 return NULL; 1147} 1148static int lua_check_user_id_harness_first(request_rec *r) 1149{ 1150 return lua_request_rec_hook_harness(r, "check_user_id", AP_LUA_HOOK_FIRST); 1151} 1152static int lua_check_user_id_harness(request_rec *r) 1153{ 1154 return lua_request_rec_hook_harness(r, "check_user_id", APR_HOOK_MIDDLE); 1155} 1156static int lua_check_user_id_harness_last(request_rec *r) 1157{ 1158 return lua_request_rec_hook_harness(r, "check_user_id", AP_LUA_HOOK_LAST); 1159} 1160 1161static int lua_translate_name_harness_first(request_rec *r) 1162{ 1163 return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_FIRST); 1164} 1165static int lua_translate_name_harness(request_rec *r) 1166{ 1167 return lua_request_rec_hook_harness(r, "translate_name", APR_HOOK_MIDDLE); 1168} 1169static int lua_translate_name_harness_last(request_rec *r) 1170{ 1171 return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_LAST); 1172} 1173 1174static int lua_fixup_harness(request_rec *r) 1175{ 1176 return lua_request_rec_hook_harness(r, "fixups", APR_HOOK_MIDDLE); 1177} 1178 1179static int lua_map_to_storage_harness(request_rec *r) 1180{ 1181 return lua_request_rec_hook_harness(r, "map_to_storage", APR_HOOK_MIDDLE); 1182} 1183 1184static int lua_type_checker_harness(request_rec *r) 1185{ 1186 return lua_request_rec_hook_harness(r, "type_checker", APR_HOOK_MIDDLE); 1187} 1188 1189static int lua_access_checker_harness_first(request_rec *r) 1190{ 1191 return lua_request_rec_hook_harness(r, "access_checker", AP_LUA_HOOK_FIRST); 1192} 1193static int lua_access_checker_harness(request_rec *r) 1194{ 1195 return lua_request_rec_hook_harness(r, "access_checker", APR_HOOK_MIDDLE); 1196} 1197static int lua_access_checker_harness_last(request_rec *r) 1198{ 1199 return lua_request_rec_hook_harness(r, "access_checker", AP_LUA_HOOK_LAST); 1200} 1201 1202static int lua_auth_checker_harness_first(request_rec *r) 1203{ 1204 return lua_request_rec_hook_harness(r, "auth_checker", AP_LUA_HOOK_FIRST); 1205} 1206static int lua_auth_checker_harness(request_rec *r) 1207{ 1208 return lua_request_rec_hook_harness(r, "auth_checker", APR_HOOK_MIDDLE); 1209} 1210static int lua_auth_checker_harness_last(request_rec *r) 1211{ 1212 return lua_request_rec_hook_harness(r, "auth_checker", AP_LUA_HOOK_LAST); 1213} 1214static void lua_insert_filter_harness(request_rec *r) 1215{ 1216 /* ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "LuaHookInsertFilter not yet implemented"); */ 1217} 1218 1219static int lua_log_transaction_harness(request_rec *r) 1220{ 1221 return lua_request_rec_hook_harness(r, "log_transaction", APR_HOOK_FIRST); 1222} 1223 1224static int lua_quick_harness(request_rec *r, int lookup) 1225{ 1226 if (lookup) { 1227 return DECLINED; 1228 } 1229 return lua_request_rec_hook_harness(r, "quick", APR_HOOK_MIDDLE); 1230} 1231 1232static const char *register_translate_name_hook(cmd_parms *cmd, void *_cfg, 1233 const char *file, 1234 const char *function, 1235 const char *when) 1236{ 1237 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES| 1238 NOT_IN_HTACCESS); 1239 int apr_hook_when = APR_HOOK_MIDDLE; 1240 if (err) { 1241 return err; 1242 } 1243 1244 if (when) { 1245 if (!strcasecmp(when, "early")) { 1246 apr_hook_when = AP_LUA_HOOK_FIRST; 1247 } 1248 else if (!strcasecmp(when, "late")) { 1249 apr_hook_when = AP_LUA_HOOK_LAST; 1250 } 1251 else { 1252 return "Third argument must be 'early' or 'late'"; 1253 } 1254 } 1255 1256 return register_named_file_function_hook("translate_name", cmd, _cfg, 1257 file, function, apr_hook_when); 1258} 1259 1260static const char *register_translate_name_block(cmd_parms *cmd, void *_cfg, 1261 const char *line) 1262{ 1263 return register_named_block_function_hook("translate_name", cmd, _cfg, 1264 line); 1265} 1266 1267 1268static const char *register_fixups_hook(cmd_parms *cmd, void *_cfg, 1269 const char *file, 1270 const char *function) 1271{ 1272 return register_named_file_function_hook("fixups", cmd, _cfg, file, 1273 function, APR_HOOK_MIDDLE); 1274} 1275static const char *register_fixups_block(cmd_parms *cmd, void *_cfg, 1276 const char *line) 1277{ 1278 return register_named_block_function_hook("fixups", cmd, _cfg, line); 1279} 1280 1281static const char *register_map_to_storage_hook(cmd_parms *cmd, void *_cfg, 1282 const char *file, 1283 const char *function) 1284{ 1285 return register_named_file_function_hook("map_to_storage", cmd, _cfg, 1286 file, function, APR_HOOK_MIDDLE); 1287} 1288 1289static const char *register_log_transaction_hook(cmd_parms *cmd, void *_cfg, 1290 const char *file, 1291 const char *function) 1292{ 1293 return register_named_file_function_hook("log_transaction", cmd, _cfg, 1294 file, function, APR_HOOK_FIRST); 1295} 1296 1297static const char *register_map_to_storage_block(cmd_parms *cmd, void *_cfg, 1298 const char *line) 1299{ 1300 return register_named_block_function_hook("map_to_storage", cmd, _cfg, 1301 line); 1302} 1303 1304 1305static const char *register_check_user_id_hook(cmd_parms *cmd, void *_cfg, 1306 const char *file, 1307 const char *function, 1308 const char *when) 1309{ 1310 int apr_hook_when = APR_HOOK_MIDDLE; 1311 1312 if (when) { 1313 if (!strcasecmp(when, "early")) { 1314 apr_hook_when = AP_LUA_HOOK_FIRST; 1315 } 1316 else if (!strcasecmp(when, "late")) { 1317 apr_hook_when = AP_LUA_HOOK_LAST; 1318 } 1319 else { 1320 return "Third argument must be 'early' or 'late'"; 1321 } 1322 } 1323 1324 return register_named_file_function_hook("check_user_id", cmd, _cfg, file, 1325 function, apr_hook_when); 1326} 1327static const char *register_check_user_id_block(cmd_parms *cmd, void *_cfg, 1328 const char *line) 1329{ 1330 return register_named_block_function_hook("check_user_id", cmd, _cfg, 1331 line); 1332} 1333 1334static const char *register_type_checker_hook(cmd_parms *cmd, void *_cfg, 1335 const char *file, 1336 const char *function) 1337{ 1338 return register_named_file_function_hook("type_checker", cmd, _cfg, file, 1339 function, APR_HOOK_MIDDLE); 1340} 1341static const char *register_type_checker_block(cmd_parms *cmd, void *_cfg, 1342 const char *line) 1343{ 1344 return register_named_block_function_hook("type_checker", cmd, _cfg, 1345 line); 1346} 1347 1348static const char *register_access_checker_hook(cmd_parms *cmd, void *_cfg, 1349 const char *file, 1350 const char *function, 1351 const char *when) 1352{ 1353 int apr_hook_when = APR_HOOK_MIDDLE; 1354 1355 if (when) { 1356 if (!strcasecmp(when, "early")) { 1357 apr_hook_when = AP_LUA_HOOK_FIRST; 1358 } 1359 else if (!strcasecmp(when, "late")) { 1360 apr_hook_when = AP_LUA_HOOK_LAST; 1361 } 1362 else { 1363 return "Third argument must be 'early' or 'late'"; 1364 } 1365 } 1366 1367 return register_named_file_function_hook("access_checker", cmd, _cfg, 1368 file, function, apr_hook_when); 1369} 1370static const char *register_access_checker_block(cmd_parms *cmd, void *_cfg, 1371 const char *line) 1372{ 1373 1374 return register_named_block_function_hook("access_checker", cmd, _cfg, 1375 line); 1376} 1377 1378static const char *register_auth_checker_hook(cmd_parms *cmd, void *_cfg, 1379 const char *file, 1380 const char *function, 1381 const char *when) 1382{ 1383 int apr_hook_when = APR_HOOK_MIDDLE; 1384 1385 if (when) { 1386 if (!strcasecmp(when, "early")) { 1387 apr_hook_when = AP_LUA_HOOK_FIRST; 1388 } 1389 else if (!strcasecmp(when, "late")) { 1390 apr_hook_when = AP_LUA_HOOK_LAST; 1391 } 1392 else { 1393 return "Third argument must be 'early' or 'late'"; 1394 } 1395 } 1396 1397 return register_named_file_function_hook("auth_checker", cmd, _cfg, file, 1398 function, apr_hook_when); 1399} 1400static const char *register_auth_checker_block(cmd_parms *cmd, void *_cfg, 1401 const char *line) 1402{ 1403 return register_named_block_function_hook("auth_checker", cmd, _cfg, 1404 line); 1405} 1406 1407static const char *register_insert_filter_hook(cmd_parms *cmd, void *_cfg, 1408 const char *file, 1409 const char *function) 1410{ 1411 return "LuaHookInsertFilter not yet implemented"; 1412} 1413 1414static const char *register_quick_hook(cmd_parms *cmd, void *_cfg, 1415 const char *file, const char *function) 1416{ 1417 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES| 1418 NOT_IN_HTACCESS); 1419 if (err) { 1420 return err; 1421 } 1422 return register_named_file_function_hook("quick", cmd, _cfg, file, 1423 function, APR_HOOK_MIDDLE); 1424} 1425static const char *register_map_handler(cmd_parms *cmd, void *_cfg, 1426 const char* match, const char *file, const char *function) 1427{ 1428 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES| 1429 NOT_IN_HTACCESS); 1430 if (err) { 1431 return err; 1432 } 1433 if (!function) function = "handle"; 1434 return register_mapped_file_function_hook(match, cmd, _cfg, file, 1435 function); 1436} 1437static const char *register_output_filter(cmd_parms *cmd, void *_cfg, 1438 const char* filter, const char *file, const char *function) 1439{ 1440 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES| 1441 NOT_IN_HTACCESS); 1442 if (err) { 1443 return err; 1444 } 1445 if (!function) function = "handle"; 1446 return register_filter_function_hook(filter, cmd, _cfg, file, 1447 function, AP_LUA_FILTER_OUTPUT); 1448} 1449static const char *register_input_filter(cmd_parms *cmd, void *_cfg, 1450 const char* filter, const char *file, const char *function) 1451{ 1452 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES| 1453 NOT_IN_HTACCESS); 1454 if (err) { 1455 return err; 1456 } 1457 if (!function) function = "handle"; 1458 return register_filter_function_hook(filter, cmd, _cfg, file, 1459 function, AP_LUA_FILTER_INPUT); 1460} 1461static const char *register_quick_block(cmd_parms *cmd, void *_cfg, 1462 const char *line) 1463{ 1464 return register_named_block_function_hook("quick", cmd, _cfg, 1465 line); 1466} 1467 1468 1469 1470static const char *register_package_helper(cmd_parms *cmd, 1471 const char *arg, 1472 apr_array_header_t *dir_array) 1473{ 1474 apr_status_t rv; 1475 1476 ap_lua_server_cfg *server_cfg = 1477 ap_get_module_config(cmd->server->module_config, &lua_module); 1478 1479 char *fixed_filename; 1480 rv = apr_filepath_merge(&fixed_filename, 1481 server_cfg->root_path, 1482 arg, 1483 APR_FILEPATH_NOTRELATIVE, 1484 cmd->pool); 1485 1486 if (rv != APR_SUCCESS) { 1487 return apr_psprintf(cmd->pool, 1488 "Unable to build full path to file, %s", arg); 1489 } 1490 1491 *(const char **) apr_array_push(dir_array) = fixed_filename; 1492 return NULL; 1493} 1494 1495 1496/** 1497 * Called for config directive which looks like 1498 * LuaPackagePath /lua/package/path/mapped/thing/like/this/?.lua 1499 */ 1500static const char *register_package_dir(cmd_parms *cmd, void *_cfg, 1501 const char *arg) 1502{ 1503 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg; 1504 1505 return register_package_helper(cmd, arg, cfg->package_paths); 1506} 1507 1508/** 1509 * Called for config directive which looks like 1510 * LuaPackageCPath /lua/package/path/mapped/thing/like/this/?.so 1511 */ 1512static const char *register_package_cdir(cmd_parms *cmd, 1513 void *_cfg, 1514 const char *arg) 1515{ 1516 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg; 1517 1518 return register_package_helper(cmd, arg, cfg->package_cpaths); 1519} 1520 1521static const char *register_lua_inherit(cmd_parms *cmd, 1522 void *_cfg, 1523 const char *arg) 1524{ 1525 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg; 1526 1527 if (strcasecmp("none", arg) == 0) { 1528 cfg->inherit = AP_LUA_INHERIT_NONE; 1529 } 1530 else if (strcasecmp("parent-first", arg) == 0) { 1531 cfg->inherit = AP_LUA_INHERIT_PARENT_FIRST; 1532 } 1533 else if (strcasecmp("parent-last", arg) == 0) { 1534 cfg->inherit = AP_LUA_INHERIT_PARENT_LAST; 1535 } 1536 else { 1537 return apr_psprintf(cmd->pool, 1538 "LuaInherit type of '%s' not recognized, valid " 1539 "options are 'none', 'parent-first', and 'parent-last'", 1540 arg); 1541 } 1542 return NULL; 1543} 1544static const char *register_lua_codecache(cmd_parms *cmd, 1545 void *_cfg, 1546 const char *arg) 1547{ 1548 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg; 1549 1550 if (strcasecmp("never", arg) == 0) { 1551 cfg->codecache = AP_LUA_CACHE_NEVER; 1552 } 1553 else if (strcasecmp("stat", arg) == 0) { 1554 cfg->codecache = AP_LUA_CACHE_STAT; 1555 } 1556 else if (strcasecmp("forever", arg) == 0) { 1557 cfg->codecache = AP_LUA_CACHE_FOREVER; 1558 } 1559 else { 1560 return apr_psprintf(cmd->pool, 1561 "LuaCodeCache type of '%s' not recognized, valid " 1562 "options are 'never', 'stat', and 'forever'", 1563 arg); 1564 } 1565 return NULL; 1566} 1567static const char *register_lua_scope(cmd_parms *cmd, 1568 void *_cfg, 1569 const char *scope, 1570 const char *min, 1571 const char *max) 1572{ 1573 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg; 1574 if (strcmp("once", scope) == 0) { 1575 cfg->vm_scope = AP_LUA_SCOPE_ONCE; 1576 } 1577 else if (strcmp("request", scope) == 0) { 1578 cfg->vm_scope = AP_LUA_SCOPE_REQUEST; 1579 } 1580 else if (strcmp("conn", scope) == 0) { 1581 cfg->vm_scope = AP_LUA_SCOPE_CONN; 1582 } 1583 else if (strcmp("thread", scope) == 0) { 1584#if !APR_HAS_THREADS 1585 return apr_psprintf(cmd->pool, 1586 "Scope type of '%s' cannot be used because this " 1587 "server does not have threading support " 1588 "(APR_HAS_THREADS)" 1589 scope); 1590#endif 1591 cfg->vm_scope = AP_LUA_SCOPE_THREAD; 1592 } 1593 else if (strcmp("server", scope) == 0) { 1594 unsigned int vmin, vmax; 1595#if !APR_HAS_THREADS 1596 return apr_psprintf(cmd->pool, 1597 "Scope type of '%s' cannot be used because this " 1598 "server does not have threading support " 1599 "(APR_HAS_THREADS)" 1600 scope); 1601#endif 1602 cfg->vm_scope = AP_LUA_SCOPE_SERVER; 1603 vmin = min ? atoi(min) : 1; 1604 vmax = max ? atoi(max) : 1; 1605 if (vmin == 0) { 1606 vmin = 1; 1607 } 1608 if (vmax < vmin) { 1609 vmax = vmin; 1610 } 1611 cfg->vm_min = vmin; 1612 cfg->vm_max = vmax; 1613 } 1614 else { 1615 return apr_psprintf(cmd->pool, 1616 "Invalid value for LuaScope, '%s', acceptable " 1617 "values are: 'once', 'request', 'conn'" 1618#if APR_HAS_THREADS 1619 ", 'thread', 'server'" 1620#endif 1621 ,scope); 1622 } 1623 1624 return NULL; 1625} 1626 1627 1628 1629static const char *register_lua_root(cmd_parms *cmd, void *_cfg, 1630 const char *root) 1631{ 1632 /* ap_lua_dir_cfg* cfg = (ap_lua_dir_cfg*)_cfg; */ 1633 ap_lua_server_cfg *cfg = ap_get_module_config(cmd->server->module_config, 1634 &lua_module); 1635 1636 cfg->root_path = root; 1637 return NULL; 1638} 1639 1640const char *ap_lua_ssl_val(apr_pool_t *p, server_rec *s, conn_rec *c, 1641 request_rec *r, const char *var) 1642{ 1643 if (lua_ssl_val) { 1644 return (const char *)lua_ssl_val(p, s, c, r, (char *)var); 1645 } 1646 return NULL; 1647} 1648 1649int ap_lua_ssl_is_https(conn_rec *c) 1650{ 1651 return lua_ssl_is_https ? lua_ssl_is_https(c) : 0; 1652} 1653 1654/*******************************/ 1655 1656static const char *lua_authz_parse(cmd_parms *cmd, const char *require_line, 1657 const void **parsed_require_line) 1658{ 1659 const char *provider_name; 1660 lua_authz_provider_spec *spec; 1661 1662 apr_pool_userdata_get((void**)&provider_name, AUTHZ_PROVIDER_NAME_NOTE, 1663 cmd->temp_pool); 1664 ap_assert(provider_name != NULL); 1665 1666 spec = apr_hash_get(lua_authz_providers, provider_name, APR_HASH_KEY_STRING); 1667 ap_assert(spec != NULL); 1668 1669 if (require_line && *require_line) { 1670 const char *arg; 1671 spec->args = apr_array_make(cmd->pool, 2, sizeof(const char *)); 1672 while ((arg = ap_getword_conf(cmd->pool, &require_line)) && *arg) { 1673 APR_ARRAY_PUSH(spec->args, const char *) = arg; 1674 } 1675 } 1676 1677 *parsed_require_line = spec; 1678 return NULL; 1679} 1680 1681static authz_status lua_authz_check(request_rec *r, const char *require_line, 1682 const void *parsed_require_line) 1683{ 1684 apr_pool_t *pool; 1685 ap_lua_vm_spec *spec; 1686 lua_State *L; 1687 ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config, 1688 &lua_module); 1689 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config, 1690 &lua_module); 1691 const lua_authz_provider_spec *prov_spec = parsed_require_line; 1692 int result; 1693 int nargs = 0; 1694 1695 spec = create_vm_spec(&pool, r, cfg, server_cfg, prov_spec->file_name, 1696 NULL, 0, prov_spec->function_name, "authz provider"); 1697 1698 L = ap_lua_get_lua_state(pool, spec, r); 1699 if (L == NULL) { 1700 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02314) 1701 "Unable to compile VM for authz provider %s", prov_spec->name); 1702 return AUTHZ_GENERAL_ERROR; 1703 } 1704 lua_getglobal(L, prov_spec->function_name); 1705 if (!lua_isfunction(L, -1)) { 1706 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02319) 1707 "Unable to find function %s in %s", 1708 prov_spec->function_name, prov_spec->file_name); 1709 ap_lua_release_state(L, spec, r); 1710 return AUTHZ_GENERAL_ERROR; 1711 } 1712 ap_lua_run_lua_request(L, r); 1713 if (prov_spec->args) { 1714 int i; 1715 if (!lua_checkstack(L, prov_spec->args->nelts)) { 1716 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02315) 1717 "Error: authz provider %s: too many arguments", prov_spec->name); 1718 ap_lua_release_state(L, spec, r); 1719 return AUTHZ_GENERAL_ERROR; 1720 } 1721 for (i = 0; i < prov_spec->args->nelts; i++) { 1722 const char *arg = APR_ARRAY_IDX(prov_spec->args, i, const char *); 1723 lua_pushstring(L, arg); 1724 } 1725 nargs = prov_spec->args->nelts; 1726 } 1727 if (lua_pcall(L, 1 + nargs, 1, 0)) { 1728 const char *err = lua_tostring(L, -1); 1729 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02316) 1730 "Error executing authz provider %s: %s", prov_spec->name, err); 1731 ap_lua_release_state(L, spec, r); 1732 return AUTHZ_GENERAL_ERROR; 1733 } 1734 if (!lua_isnumber(L, -1)) { 1735 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02317) 1736 "Error: authz provider %s did not return integer", prov_spec->name); 1737 ap_lua_release_state(L, spec, r); 1738 return AUTHZ_GENERAL_ERROR; 1739 } 1740 result = lua_tointeger(L, -1); 1741 ap_lua_release_state(L, spec, r); 1742 switch (result) { 1743 case AUTHZ_DENIED: 1744 case AUTHZ_GRANTED: 1745 case AUTHZ_NEUTRAL: 1746 case AUTHZ_GENERAL_ERROR: 1747 case AUTHZ_DENIED_NO_USER: 1748 return result; 1749 default: 1750 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02318) 1751 "Error: authz provider %s: invalid return value %d", 1752 prov_spec->name, result); 1753 } 1754 return AUTHZ_GENERAL_ERROR; 1755} 1756 1757static const authz_provider lua_authz_provider = 1758{ 1759 &lua_authz_check, 1760 &lua_authz_parse, 1761}; 1762 1763static const char *register_authz_provider(cmd_parms *cmd, void *_cfg, 1764 const char *name, const char *file, 1765 const char *function) 1766{ 1767 lua_authz_provider_spec *spec; 1768 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); 1769 if (err) 1770 return err; 1771 1772 spec = apr_pcalloc(cmd->pool, sizeof(*spec)); 1773 spec->name = name; 1774 spec->file_name = file; 1775 spec->function_name = function; 1776 1777 apr_hash_set(lua_authz_providers, name, APR_HASH_KEY_STRING, spec); 1778 ap_register_auth_provider(cmd->pool, AUTHZ_PROVIDER_GROUP, name, 1779 AUTHZ_PROVIDER_VERSION, 1780 &lua_authz_provider, 1781 AP_AUTH_INTERNAL_PER_CONF); 1782 return NULL; 1783} 1784 1785 1786command_rec lua_commands[] = { 1787 1788 AP_INIT_TAKE1("LuaRoot", register_lua_root, NULL, OR_ALL, 1789 "Specify the base path for resolving relative paths for mod_lua directives"), 1790 1791 AP_INIT_TAKE1("LuaPackagePath", register_package_dir, NULL, OR_ALL, 1792 "Add a directory to lua's package.path"), 1793 1794 AP_INIT_TAKE1("LuaPackageCPath", register_package_cdir, NULL, OR_ALL, 1795 "Add a directory to lua's package.cpath"), 1796 1797 AP_INIT_TAKE3("LuaAuthzProvider", register_authz_provider, NULL, RSRC_CONF|EXEC_ON_READ, 1798 "Provide an authorization provider"), 1799 1800 AP_INIT_TAKE23("LuaHookTranslateName", register_translate_name_hook, NULL, 1801 OR_ALL, 1802 "Provide a hook for the translate name phase of request processing"), 1803 1804 AP_INIT_RAW_ARGS("<LuaHookTranslateName", register_translate_name_block, 1805 NULL, 1806 EXEC_ON_READ | OR_ALL, 1807 "Provide a hook for the translate name phase of request processing"), 1808 1809 AP_INIT_TAKE2("LuaHookFixups", register_fixups_hook, NULL, OR_ALL, 1810 "Provide a hook for the fixups phase of request processing"), 1811 AP_INIT_RAW_ARGS("<LuaHookFixups", register_fixups_block, NULL, 1812 EXEC_ON_READ | OR_ALL, 1813 "Provide a inline hook for the fixups phase of request processing"), 1814 1815 /* todo: test */ 1816 AP_INIT_TAKE2("LuaHookMapToStorage", register_map_to_storage_hook, NULL, 1817 OR_ALL, 1818 "Provide a hook for the map_to_storage phase of request processing"), 1819 AP_INIT_RAW_ARGS("<LuaHookMapToStorage", register_map_to_storage_block, 1820 NULL, 1821 EXEC_ON_READ | OR_ALL, 1822 "Provide a hook for the map_to_storage phase of request processing"), 1823 1824 /* todo: test */ 1825 AP_INIT_TAKE23("LuaHookCheckUserID", register_check_user_id_hook, NULL, 1826 OR_ALL, 1827 "Provide a hook for the check_user_id phase of request processing"), 1828 AP_INIT_RAW_ARGS("<LuaHookCheckUserID", register_check_user_id_block, 1829 NULL, 1830 EXEC_ON_READ | OR_ALL, 1831 "Provide a hook for the check_user_id phase of request processing"), 1832 1833 /* todo: test */ 1834 AP_INIT_TAKE2("LuaHookTypeChecker", register_type_checker_hook, NULL, 1835 OR_ALL, 1836 "Provide a hook for the type_checker phase of request processing"), 1837 AP_INIT_RAW_ARGS("<LuaHookTypeChecker", register_type_checker_block, NULL, 1838 EXEC_ON_READ | OR_ALL, 1839 "Provide a hook for the type_checker phase of request processing"), 1840 1841 /* todo: test */ 1842 AP_INIT_TAKE23("LuaHookAccessChecker", register_access_checker_hook, NULL, 1843 OR_ALL, 1844 "Provide a hook for the access_checker phase of request processing"), 1845 AP_INIT_RAW_ARGS("<LuaHookAccessChecker", register_access_checker_block, 1846 NULL, 1847 EXEC_ON_READ | OR_ALL, 1848 "Provide a hook for the access_checker phase of request processing"), 1849 1850 /* todo: test */ 1851 AP_INIT_TAKE23("LuaHookAuthChecker", register_auth_checker_hook, NULL, 1852 OR_ALL, 1853 "Provide a hook for the auth_checker phase of request processing"), 1854 AP_INIT_RAW_ARGS("<LuaHookAuthChecker", register_auth_checker_block, NULL, 1855 EXEC_ON_READ | OR_ALL, 1856 "Provide a hook for the auth_checker phase of request processing"), 1857 1858 /* todo: test */ 1859 AP_INIT_TAKE2("LuaHookInsertFilter", register_insert_filter_hook, NULL, 1860 OR_ALL, 1861 "Provide a hook for the insert_filter phase of request processing"), 1862 1863 AP_INIT_TAKE2("LuaHookLog", register_log_transaction_hook, NULL, 1864 OR_ALL, 1865 "Provide a hook for the logging phase of request processing"), 1866 1867 AP_INIT_TAKE123("LuaScope", register_lua_scope, NULL, OR_ALL, 1868 "One of once, request, conn, server -- default is once"), 1869 1870 AP_INIT_TAKE1("LuaInherit", register_lua_inherit, NULL, OR_ALL, 1871 "Controls how Lua scripts in parent contexts are merged with the current " 1872 " context: none|parent-last|parent-first (default: parent-first) "), 1873 1874 AP_INIT_TAKE1("LuaCodeCache", register_lua_codecache, NULL, OR_ALL, 1875 "Controls the behavior of the in-memory code cache " 1876 " context: stat|forever|never (default: stat) "), 1877 1878 AP_INIT_TAKE2("LuaQuickHandler", register_quick_hook, NULL, OR_ALL, 1879 "Provide a hook for the quick handler of request processing"), 1880 AP_INIT_RAW_ARGS("<LuaQuickHandler", register_quick_block, NULL, 1881 EXEC_ON_READ | OR_ALL, 1882 "Provide a hook for the quick handler of request processing"), 1883 AP_INIT_RAW_ARGS("Lua_____ByteCodeHack", hack_section_handler, NULL, 1884 OR_ALL, 1885 "(internal) Byte code handler"), 1886 AP_INIT_TAKE23("LuaMapHandler", register_map_handler, NULL, OR_ALL, 1887 "Maps a path to a lua handler"), 1888 AP_INIT_TAKE3("LuaOutputFilter", register_output_filter, NULL, OR_ALL, 1889 "Registers a Lua function as an output filter"), 1890 AP_INIT_TAKE3("LuaInputFilter", register_input_filter, NULL, OR_ALL, 1891 "Registers a Lua function as an input filter"), 1892 {NULL} 1893}; 1894 1895 1896static void *create_dir_config(apr_pool_t *p, char *dir) 1897{ 1898 ap_lua_dir_cfg *cfg = apr_pcalloc(p, sizeof(ap_lua_dir_cfg)); 1899 cfg->package_paths = apr_array_make(p, 2, sizeof(char *)); 1900 cfg->package_cpaths = apr_array_make(p, 2, sizeof(char *)); 1901 cfg->mapped_handlers = 1902 apr_array_make(p, 1, sizeof(ap_lua_mapped_handler_spec *)); 1903 cfg->mapped_filters = 1904 apr_array_make(p, 1, sizeof(ap_lua_filter_handler_spec *)); 1905 cfg->pool = p; 1906 cfg->hooks = apr_hash_make(p); 1907 cfg->dir = apr_pstrdup(p, dir); 1908 cfg->vm_scope = AP_LUA_SCOPE_UNSET; 1909 cfg->codecache = AP_LUA_CACHE_UNSET; 1910 cfg->vm_min = 0; 1911 cfg->vm_max = 0; 1912 1913 return cfg; 1914} 1915 1916static int create_request_config(request_rec *r) 1917{ 1918 ap_lua_request_cfg *cfg = apr_palloc(r->pool, sizeof(ap_lua_request_cfg)); 1919 cfg->mapped_request_details = NULL; 1920 cfg->request_scoped_vms = apr_hash_make(r->pool); 1921 ap_set_module_config(r->request_config, &lua_module, cfg); 1922 return OK; 1923} 1924 1925static void *create_server_config(apr_pool_t *p, server_rec *s) 1926{ 1927 1928 ap_lua_server_cfg *cfg = apr_pcalloc(p, sizeof(ap_lua_server_cfg)); 1929 cfg->vm_reslists = apr_hash_make(p); 1930 apr_thread_rwlock_create(&cfg->vm_reslists_lock, p); 1931 cfg->root_path = NULL; 1932 1933 return cfg; 1934} 1935 1936static int lua_request_hook(lua_State *L, request_rec *r) 1937{ 1938 ap_lua_push_request(L, r); 1939 return OK; 1940} 1941 1942static int lua_post_config(apr_pool_t *pconf, apr_pool_t *plog, 1943 apr_pool_t *ptemp, server_rec *s) 1944{ 1945 lua_ssl_val = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); 1946 lua_ssl_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); 1947 return OK; 1948} 1949static void *overlay_hook_specs(apr_pool_t *p, 1950 const void *key, 1951 apr_ssize_t klen, 1952 const void *overlay_val, 1953 const void *base_val, 1954 const void *data) 1955{ 1956 const apr_array_header_t *overlay_info = (const apr_array_header_t*)overlay_val; 1957 const apr_array_header_t *base_info = (const apr_array_header_t*)base_val; 1958 return apr_array_append(p, base_info, overlay_info); 1959} 1960 1961static void *merge_dir_config(apr_pool_t *p, void *basev, void *overridesv) 1962{ 1963 ap_lua_dir_cfg *a, *base, *overrides; 1964 1965 a = (ap_lua_dir_cfg *)apr_pcalloc(p, sizeof(ap_lua_dir_cfg)); 1966 base = (ap_lua_dir_cfg*)basev; 1967 overrides = (ap_lua_dir_cfg*)overridesv; 1968 1969 a->pool = overrides->pool; 1970 a->dir = apr_pstrdup(p, overrides->dir); 1971 1972 a->vm_scope = (overrides->vm_scope == AP_LUA_SCOPE_UNSET) ? base->vm_scope: overrides->vm_scope; 1973 a->inherit = (overrides->inherit == AP_LUA_INHERIT_UNSET) ? base->inherit : overrides->inherit; 1974 a->codecache = (overrides->codecache == AP_LUA_CACHE_UNSET) ? base->codecache : overrides->codecache; 1975 1976 a->vm_min = (overrides->vm_min == 0) ? base->vm_min : overrides->vm_min; 1977 a->vm_max = (overrides->vm_max == 0) ? base->vm_max : overrides->vm_max; 1978 1979 if (a->inherit == AP_LUA_INHERIT_UNSET || a->inherit == AP_LUA_INHERIT_PARENT_FIRST) { 1980 a->package_paths = apr_array_append(p, base->package_paths, overrides->package_paths); 1981 a->package_cpaths = apr_array_append(p, base->package_cpaths, overrides->package_cpaths); 1982 a->mapped_handlers = apr_array_append(p, base->mapped_handlers, overrides->mapped_handlers); 1983 a->mapped_filters = apr_array_append(p, base->mapped_filters, overrides->mapped_filters); 1984 a->hooks = apr_hash_merge(p, overrides->hooks, base->hooks, overlay_hook_specs, NULL); 1985 } 1986 else if (a->inherit == AP_LUA_INHERIT_PARENT_LAST) { 1987 a->package_paths = apr_array_append(p, overrides->package_paths, base->package_paths); 1988 a->package_cpaths = apr_array_append(p, overrides->package_cpaths, base->package_cpaths); 1989 a->mapped_handlers = apr_array_append(p, overrides->mapped_handlers, base->mapped_handlers); 1990 a->mapped_filters = apr_array_append(p, overrides->mapped_filters, base->mapped_filters); 1991 a->hooks = apr_hash_merge(p, base->hooks, overrides->hooks, overlay_hook_specs, NULL); 1992 } 1993 else { 1994 a->package_paths = overrides->package_paths; 1995 a->package_cpaths = overrides->package_cpaths; 1996 a->mapped_handlers= overrides->mapped_handlers; 1997 a->mapped_filters= overrides->mapped_filters; 1998 a->hooks= overrides->hooks; 1999 } 2000 2001 return a; 2002} 2003 2004static void lua_register_hooks(apr_pool_t *p) 2005{ 2006 /* ap_register_output_filter("luahood", luahood, NULL, AP_FTYPE_RESOURCE); */ 2007 ap_hook_handler(lua_handler, NULL, NULL, APR_HOOK_MIDDLE); 2008 ap_hook_create_request(create_request_config, NULL, NULL, 2009 APR_HOOK_MIDDLE); 2010 2011 /* http_request.h hooks */ 2012 ap_hook_translate_name(lua_translate_name_harness_first, NULL, NULL, 2013 AP_LUA_HOOK_FIRST); 2014 ap_hook_translate_name(lua_translate_name_harness, NULL, NULL, 2015 APR_HOOK_MIDDLE); 2016 ap_hook_translate_name(lua_translate_name_harness_last, NULL, NULL, 2017 AP_LUA_HOOK_LAST); 2018 2019 ap_hook_fixups(lua_fixup_harness, NULL, NULL, APR_HOOK_MIDDLE); 2020 ap_hook_map_to_storage(lua_map_to_storage_harness, NULL, NULL, 2021 APR_HOOK_MIDDLE); 2022 2023 ap_hook_check_user_id(lua_check_user_id_harness_first, NULL, NULL, 2024 AP_LUA_HOOK_FIRST); 2025 ap_hook_check_user_id(lua_check_user_id_harness, NULL, NULL, 2026 APR_HOOK_MIDDLE); 2027 ap_hook_check_user_id(lua_check_user_id_harness_last, NULL, NULL, 2028 AP_LUA_HOOK_LAST); 2029 2030 ap_hook_type_checker(lua_type_checker_harness, NULL, NULL, 2031 APR_HOOK_MIDDLE); 2032 2033 ap_hook_access_checker(lua_access_checker_harness_first, NULL, NULL, 2034 AP_LUA_HOOK_FIRST); 2035 ap_hook_access_checker(lua_access_checker_harness, NULL, NULL, 2036 APR_HOOK_MIDDLE); 2037 ap_hook_access_checker(lua_access_checker_harness_last, NULL, NULL, 2038 AP_LUA_HOOK_LAST); 2039 ap_hook_auth_checker(lua_auth_checker_harness_first, NULL, NULL, 2040 AP_LUA_HOOK_FIRST); 2041 ap_hook_auth_checker(lua_auth_checker_harness, NULL, NULL, 2042 APR_HOOK_MIDDLE); 2043 ap_hook_auth_checker(lua_auth_checker_harness_last, NULL, NULL, 2044 AP_LUA_HOOK_LAST); 2045 2046 ap_hook_insert_filter(lua_insert_filter_harness, NULL, NULL, 2047 APR_HOOK_MIDDLE); 2048 ap_hook_quick_handler(lua_quick_harness, NULL, NULL, APR_HOOK_FIRST); 2049 2050 ap_hook_post_config(lua_post_config, NULL, NULL, APR_HOOK_MIDDLE); 2051 2052 APR_OPTIONAL_HOOK(ap_lua, lua_open, lua_open_hook, NULL, NULL, 2053 APR_HOOK_REALLY_FIRST); 2054 2055 APR_OPTIONAL_HOOK(ap_lua, lua_request, lua_request_hook, NULL, NULL, 2056 APR_HOOK_REALLY_FIRST); 2057 ap_hook_handler(lua_map_handler, NULL, NULL, AP_LUA_HOOK_FIRST); 2058 /* Hook this right before FallbackResource kicks in */ 2059 ap_hook_fixups(lua_map_handler_fixups, NULL, NULL, AP_LUA_HOOK_LAST-2); 2060#if APR_HAS_THREADS 2061 ap_hook_child_init(ap_lua_init_mutex, NULL, NULL, APR_HOOK_MIDDLE); 2062#endif 2063 /* providers */ 2064 lua_authz_providers = apr_hash_make(p); 2065 2066 /* ivm mutex */ 2067 apr_thread_mutex_create(&lua_ivm_mutex, APR_THREAD_MUTEX_DEFAULT, p); 2068 2069 /* Logging catcher */ 2070 ap_hook_log_transaction(lua_log_transaction_harness,NULL,NULL, 2071 APR_HOOK_FIRST); 2072} 2073 2074AP_DECLARE_MODULE(lua) = { 2075 STANDARD20_MODULE_STUFF, 2076 create_dir_config, /* create per-dir config structures */ 2077 merge_dir_config, /* merge per-dir config structures */ 2078 create_server_config, /* create per-server config structures */ 2079 NULL, /* merge per-server config structures */ 2080 lua_commands, /* table of config file commands */ 2081 lua_register_hooks /* register hooks */ 2082}; 2083