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