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