summaryrefslogtreecommitdiffstatsabout
path: root/src/gnutls_lua.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gnutls_lua.c')
-rw-r--r--src/gnutls_lua.c292
1 files changed, 292 insertions, 0 deletions
diff --git a/src/gnutls_lua.c b/src/gnutls_lua.c
new file mode 100644
index 0000000..6d80574
--- /dev/null
+++ b/src/gnutls_lua.c
@@ -0,0 +1,292 @@
1/**
2 * Copyright 2004-2005 Paul Querna
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18#include "mod_gnutls.h"
19
20#include "lua.h"
21#include "lualib.h"
22#include "lauxlib.h"
23
24#include <ctype.h>
25
26static char *MGS_LUA_RRKEY = "request_rec";
27
28static request_rec *mgs_lua_getrr(lua_State *lvm)
29{
30 request_rec *r;
31
32 /* Push the request_rec off the registry, onto the stack. */
33 lua_pushlightuserdata(lvm, MGS_LUA_RRKEY);
34 lua_gettable(lvm, LUA_REGISTRYINDEX);
35 r = lua_touserdata(lvm, -1);
36 lua_pop(lvm, 1);
37 return r;
38}
39
40static int get_request_table(lua_State *lvm, long offset)
41{
42 const char *key;
43 request_rec *r;
44 const char *value;
45 apr_table_t *t;
46 key = luaL_checkstring(lvm, 1);
47
48 r = mgs_lua_getrr(lvm);
49
50 t = *(apr_table_t **)((char *)r + offset);
51
52 value = apr_table_get(t, key);
53
54 if (value) {
55 lua_pushstring(lvm, value);
56 return 1;
57 }
58 else {
59 return 0;
60 }
61}
62
63static int mgs_lua_getenv(lua_State *lvm)
64{
65 return get_request_table(lvm, APR_OFFSETOF(request_rec, subprocess_env));
66}
67
68static int mgs_lua_getheader(lua_State *lvm)
69{
70 return get_request_table(lvm, APR_OFFSETOF(request_rec, headers_in));
71}
72
73static const luaL_reg mgs_lua_reg[] = {
74 {"getenv", mgs_lua_getenv},
75 {"header", mgs_lua_getheader},
76 {NULL, NULL}
77};
78
79lua_State* get_luastate()
80{
81 lua_State* lvm = lua_open();
82 luaopen_base(lvm);
83 luaopen_io(lvm);
84 luaopen_table(lvm);
85 luaopen_string(lvm);
86 luaopen_math(lvm);
87 luaopen_loadlib(lvm);
88 luaL_openlib(lvm, "ap", mgs_lua_reg, 0);
89
90 return lvm;
91}
92
93int mgs_authz_lua(request_rec* r)
94{
95 int rv;
96 lua_State* lvm;
97 mgs_dirconf_rec *dc = ap_get_module_config(r->per_dir_config,
98 &gnutls_module);
99
100 if (dc->lua_bytecode_len <= 0) {
101 return 0;
102 }
103
104 lvm = get_luastate();
105 lua_pushlightuserdata(lvm, MGS_LUA_RRKEY);
106 lua_pushlightuserdata(lvm, r);
107 lua_settable(lvm, LUA_REGISTRYINDEX);
108
109 /* Push Bytecode onto the stack */
110 rv = luaL_loadbuffer(lvm, dc->lua_bytecode, dc->lua_bytecode_len, "gnutls-lua");
111
112 if (rv != 0) {
113 /* Get the Error message */
114 const char* error = lua_tostring(lvm, -1);
115 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
116 "GnuTLS: Error Loading Lua Bytecode: %s", error);
117 lua_pop(lvm, 1);
118 return -1;
119 }
120
121 rv = lua_pcall(lvm, 0, 1, 0);
122 if (rv != 0) {
123 /* Get the Error message */
124 const char* error = lua_tostring(lvm, -1);
125 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
126 "GnuTLS: Error Running Lua: %s", error);
127 lua_pop(lvm, 1);
128 return -1;
129 }
130
131 rv = (int)lua_tonumber(lvm, -1);
132 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
133 "GnuTLS: (%d) Lua Return: %d",
134 dc->lua_bytecode_len, rv);
135 lua_pop(lvm, 1);
136 lua_close(lvm);
137 return rv;
138}
139
140static apr_size_t config_getstr(ap_configfile_t *cfg, char *buf, size_t bufsiz)
141{
142 apr_size_t i = 0;
143
144 if (cfg->getstr) {
145 const char *res = (cfg->getstr)(buf, bufsiz, cfg->param);
146 if (res) {
147 i = strlen(buf);
148 if (i && buf[i - 1] == '\n') ++cfg->line_number;
149 }
150 else {
151 buf[0] = '\0';
152 i = 0;
153 }
154 }
155 else {
156 while (i < bufsiz) {
157 int ch = (cfg->getch)(cfg->param);
158 if (ch == EOF) break;
159 buf[i++] = ch;
160 if (ch == '\n') {
161 ++cfg->line_number;
162 break;
163 }
164 }
165 }
166 return i;
167}
168
169struct cr_ctx {
170 ap_configfile_t *cfp;
171 size_t startline;
172 char buf[HUGE_STRING_LEN];
173};
174
175static const char *LUACMD = "gnutlsrequire";
176static const char *lf = "\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";
177#define N_LF 32
178
179static const char *direct_chunkreader(lua_State *lvm, void *udata, size_t *plen)
180{
181 const char *p;
182 struct cr_ctx *ctx = udata;
183
184 if (ctx->startline) {
185 *plen = ctx->startline > N_LF ? N_LF : ctx->startline;
186 ctx->startline -= *plen;
187 return lf;
188 }
189 *plen = config_getstr(ctx->cfp, ctx->buf, HUGE_STRING_LEN);
190
191 for (p = ctx->buf; isspace(*p); ++p);
192 if (p[0] == '<' && p[1] == '/') {
193 int i = 0;
194 while (i < strlen(LUACMD)) {
195 if (tolower(p[i + 2]) != LUACMD[i]) return ctx->buf;
196 ++i;
197 }
198 *plen = 0;
199 return NULL;
200 }
201 return ctx->buf;
202}
203
204static int ldump_writer (lua_State *L, const void* b, size_t size, void* B) {
205 (void)L;
206 luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
207 return 1;
208}
209
210/* a bytecode buffer*/
211typedef struct bcbuf_ctx {
212 apr_size_t buflen;
213 char* buf;
214} bcbuf_ctx;
215
216const char *mgs_set_require_section(cmd_parms *cmd, void *mconfig, const char *arg)
217{
218 apr_size_t bytecode_len;
219 const char* bytecode;
220 bcbuf_ctx* bcbuf;
221 luaL_Buffer b;
222 ap_directive_t **current = mconfig;
223 struct cr_ctx ctx[1];
224 int result;
225 const char *filename = apr_psprintf(cmd->pool, "@%s", cmd->config_file->name);
226 // get a word argument
227 const char *word;
228 apr_size_t wordlen;
229 lua_State *lvm = get_luastate();
230
231 word = ap_getword_conf(cmd->pool, &arg);
232 wordlen = strlen(word);
233 do {
234 if (wordlen) {
235 if (word[wordlen - 1] == '>') {
236 --wordlen;
237 break;
238 }
239 if (*arg == '>') break;
240 }
241 return apr_pstrcat(cmd->pool, "<", LUACMD, "> takes exactly one argument", NULL);
242 } while (0);
243
244 ctx->cfp = cmd->config_file;
245 ctx->startline = cmd->config_file->line_number;
246 lua_settop(lvm, 0);
247 result = lua_load(lvm, direct_chunkreader, ctx, filename);
248
249 if (result != 0) {
250 word = apr_pstrcat(cmd->pool, "Lua Error:", lua_tostring(lvm, -1), NULL);
251 lua_close(lvm);
252 return word;
253 }
254 else {
255 luaL_buffinit(lvm, &b);
256 lua_dump(lvm, ldump_writer, &b);
257 luaL_pushresult(&b);
258 bytecode = lua_tostring(lvm, -1);
259 bytecode_len = lua_strlen(lvm, -1);
260 }
261
262 /* Here, we have to replace our current config node for the next pass */
263 if (!*current) {
264 *current = apr_pcalloc(cmd->pool, sizeof(**current));
265 }
266
267 (*current)->filename = cmd->config_file->name;
268 (*current)->line_num = ctx->startline;
269 (*current)->directive = apr_pstrdup(cmd->pool, "GnuTLSRequireByteCode");
270 (*current)->args = NULL;
271
272 bcbuf = apr_pcalloc(cmd->pool, sizeof(bcbuf));
273 bcbuf->buflen = bytecode_len;
274 bcbuf->buf = apr_pstrmemdup(cmd->pool, bytecode, bytecode_len);
275
276 (*current)->data = bcbuf;
277 lua_close(lvm);
278 return NULL;
279}
280
281const char *mgs_set_require_bytecode(cmd_parms *cmd, void *mconfig, const char *arg)
282{
283 bcbuf_ctx* bcbuf;
284 ap_directive_t *directive = cmd->directive;
285 mgs_dirconf_rec *dc = mconfig;
286
287 bcbuf = directive->data;
288 dc->lua_bytecode_len = bcbuf->buflen;
289 dc->lua_bytecode = apr_pstrmemdup(cmd->pool, bcbuf->buf, bcbuf->buflen);
290
291 return NULL;
292}