/* * Baltisot * Copyright (C) 1999-2008 Nicolas "Pixel" Noble * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Domain.h" #include "LuaHttp.h" #include "LuaHandle.h" #include "LuaTask.h" #include "Base64.h" #include "HashFunction.h" #include "RandISAAC.h" class LuaDomain : public Domain { public: LuaDomain(Lua * _L, String r); virtual ~LuaDomain(); virtual void Do(const HttpRequest & req, HttpResponse * res) throw (GeneralException); private: Lua * L; static int max_id; int id; }; class LuaLuaDomain : public LuaObject { public: static void pushstatics(Lua *) throw (GeneralException); LuaLuaDomain(LuaDomain *); protected: virtual void pushmembers(Lua *); LuaDomain * d; }; LuaLuaDomain::LuaLuaDomain(LuaDomain * _d) : d(_d) { } enum LuaDomain_methods_t { LUADOMAIN_ONTOP = 0, LUADOMAIN_GETPATTERN, }; enum LuaDomain_functions_t { LUADOMAIN_NEWDOMAIN = 0, LUADOMAIN_IDOMAIN, LUADOMAIN_NDOMAIN, }; struct lua_functypes_t LuaDomain_methods[] = { { LUADOMAIN_ONTOP, "OnTop", 0, 0, { } }, { LUADOMAIN_GETPATTERN, "GetPattern", 0, 0, { } }, { -1, 0, 0, 0, 0 }, }; struct lua_functypes_t LuaDomain_functions[] = { { LUADOMAIN_NEWDOMAIN, "Domain", 2, 2, { BLUA_STRING, BLUA_FUNCTION } }, { LUADOMAIN_IDOMAIN, "iDomain", 0, 0, { } }, { LUADOMAIN_NDOMAIN, "nDomain", 2, 2, { BLUA_USERDATA, BLUA_STRING | BLUA_NIL } }, { -1, 0, 0, 0, 0 }, }; class sLua_LuaDomain : public Base { public: DECLARE_METHOD(LuaDomain, LUADOMAIN_ONTOP); DECLARE_METHOD(LuaDomain, LUADOMAIN_GETPATTERN); DECLARE_FUNCTION(LuaDomain, LUADOMAIN_NEWDOMAIN); DECLARE_FUNCTION(LuaDomain, LUADOMAIN_IDOMAIN); DECLARE_FUNCTION(LuaDomain, LUADOMAIN_NDOMAIN); private: static int LuaDomain_proceed(Lua * L, int n, LuaDomain * obj, int caller); static int LuaDomain_proceed_statics(Lua * L, int n, int caller); }; void LuaLuaDomain::pushmembers(Lua * L) { pushme(L, d, "LuaDomain"); PUSH_METHOD(LuaDomain, LUADOMAIN_ONTOP); PUSH_METHOD(LuaDomain, LUADOMAIN_GETPATTERN); } void LuaLuaDomain::pushstatics(Lua * L) throw (GeneralException) { CHECK_METHODS(LuaDomain); CHECK_FUNCTIONS(LuaDomain); PUSH_FUNCTION(LuaDomain, LUADOMAIN_NEWDOMAIN); PUSH_FUNCTION(LuaDomain, LUADOMAIN_IDOMAIN); PUSH_FUNCTION(LuaDomain, LUADOMAIN_NDOMAIN); } #define DOMAIN_REGISTRY "DOMAINS_KEYS" #define export_enum(L, n) \ L->push(#n); \ L->push((lua_Number) HttpResponse::n); \ L->settable(LUA_GLOBALSINDEX); LuaHttpResponse::LuaHttpResponse(HttpResponse * _r) : r(_r) { } enum HttpResponse_method_t { HTTPRESPONSE_INDEX = 0, HTTPRESPONSE_NEWINDEX, }; enum HttpResponse_functions_t { HTTPRESPONSE_NEWHTTPRESPONSE = 0, HTTPRESPONSE_BASE64_ENCODE, HTTPRESPONSE_BASE64_DECODE, HTTPRESPONSE_BASE64_DECODE_BIN, HTTPRESPONSE_MD5, HTTPRESPONSE_SHA1, HTTPRESPONSE_SHA256, HTTPRESPONSE_GENTICKET, }; struct lua_functypes_t HttpResponse_methods[] = { { HTTPRESPONSE_INDEX, "index", 1, 1, { BLUA_STRING } }, { HTTPRESPONSE_NEWINDEX, "newindex", 2, 2, { BLUA_STRING, BLUA_ANY } }, { -1, 0, 0, 0, 0 } }; struct lua_functypes_t HttpResponse_functions[] = { { HTTPRESPONSE_NEWHTTPRESPONSE, "HttpResponse", 0, 0, { } }, { HTTPRESPONSE_BASE64_ENCODE, "Base64Encode", 1, 1, { BLUA_STRING | BLUA_OBJECT } }, { HTTPRESPONSE_BASE64_DECODE, "Base64Decode", 1, 1, { BLUA_STRING } }, { HTTPRESPONSE_BASE64_DECODE_BIN, "Base64DecodeBin", 2, 2, { BLUA_STRING | BLUA_OBJECT } }, { HTTPRESPONSE_MD5, "MD5", 1, 1, { BLUA_STRING | BLUA_OBJECT } }, { HTTPRESPONSE_SHA1, "SHA1", 1, 1, { BLUA_STRING | BLUA_OBJECT } }, { HTTPRESPONSE_SHA256, "SHA256", 1, 1, { BLUA_STRING | BLUA_OBJECT } }, { HTTPRESPONSE_GENTICKET, "GenTicket", 0, 1, { BLUA_NUMBER } }, { -1, 0, 0, 0, 0 } }; class sLua_HttpResponse : public Base { public: DECLARE_METHOD(HttpResponse, HTTPRESPONSE_INDEX); DECLARE_METHOD(HttpResponse, HTTPRESPONSE_NEWINDEX); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_NEWHTTPRESPONSE); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_BASE64_ENCODE); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_BASE64_DECODE); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_BASE64_DECODE_BIN); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_MD5); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_SHA1); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_SHA256); DECLARE_FUNCTION(HttpResponse, HTTPRESPONSE_GENTICKET); private: static int HttpResponse_proceed(Lua * L, int n, HttpResponse * obj, int caller); static int HttpResponse_proceed_statics(Lua * L, int n, int caller); }; void LuaHttpResponse::pushmembers(Lua * L) { pushme(L, r, "HttpResponse"); PUSH_METAMETHOD(HttpResponse, HTTPRESPONSE_INDEX); PUSH_METAMETHOD(HttpResponse, HTTPRESPONSE_NEWINDEX); } void LuaHttpResponse::pushstatics(Lua * L) throw (GeneralException) { CHECK_METHODS(HttpResponse); CHECK_FUNCTIONS(HttpResponse); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_NEWHTTPRESPONSE); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_BASE64_ENCODE); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_BASE64_DECODE); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_BASE64_DECODE_BIN); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_MD5); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_SHA1); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_SHA256); PUSH_FUNCTION(HttpResponse, HTTPRESPONSE_GENTICKET); export_enum(L, HTTP_200_OK); export_enum(L, HTTP_301_PERM_MOVED); export_enum(L, HTTP_302_FOUND); export_enum(L, HTTP_400_BAD_REQUEST); export_enum(L, HTTP_401_UNAUTHORIZED); export_enum(L, HTTP_403_FORBIDDEN); export_enum(L, HTTP_404_NOT_FOUND); export_enum(L, HTTP_500_INTERNAL_ERROR); export_enum(L, HTTP_503_SERVICE_UNAVAILABLE); L->push(DOMAIN_REGISTRY); L->newtable(); L->settable(LUA_REGISTRYINDEX); LuaLuaDomain::pushstatics(L); } int sLua_HttpResponse::HttpResponse_proceed(Lua * L, int n, HttpResponse * res, int caller) { String i; int r = 0; switch (caller) { case HTTPRESPONSE_INDEX: i = L->tostring(2); if (i == "mime_type") { L->push(res->mime_type); } else if (i == "location") { L->push(res->location); } else if (i == "domain") { L->push(res->domain); } else if (i == "file_name") { L->push(res->file_name); } else if (i == "server_name") { L->push(res->server_name); } else if (i == "return_code") { L->push((lua_Number) res->return_code); } else if (i == "last_modified") { L->push((lua_Number) res->last_modified); } else if (i == "contents") { { LuaBuffer b(&res->contents); b.push(L); } } else if (i == "cache") { L->push(res->cache); } else if (i == "cookies_path") { L->push(res->cookies_path); } else if (i == "cookies") { L->error("Can't read cookies (for now)"); } else { L->error("Unknow field in HttpResponse object: " + i); } r = 1; break; case HTTPRESPONSE_NEWINDEX: i = L->tostring(2); if (i == "mime_type") { res->mime_type = L->tostring(3); } else if (i == "location") { res->location = L->tostring(3); } else if (i == "domain") { res->domain = L->tostring(3); } else if (i == "file_name") { res->file_name = L->tostring(3); } else if (i == "server_name") { res->server_name = L->tostring(3); } else if (i == "return_code") { res->return_code = (HttpResponse::return_code_t)(int)L->tonumber(3); } else if (i == "last_modified") { res->last_modified = L->tonumber(3); } else if (i == "contents") { L->error("Can't alter field buffer in HttpResponse."); } else if (i == "cache") { res->cache = L->toboolean(3); } else if (i == "cookies_path") { res->cookies_path = L->tostring(3); } else if (i == "cookies") { String cookie = L->tostring(3), key, value; int pos = cookie.strchr('='); if (pos < 0) { L->error("Malformed cookie."); } key = cookie.extract(0, pos - 1).trim(); value = cookie.extract(pos + 1).trim(); std::pair e(key, value); res->cookies.push_back(e); } else { L->error("Unknow field in HttpResponse object: " + i); } break; } return r; } Random rand_gen; static const char ticket_chars[] = "Q52VHu0JfkgQP2IjCpWIOldzwiGU1Ery49H7Z6tgYB8UpGuM4P@rFrBL_qvf3utE" "dJRaXT8WVcvD6JSjcTNW9mqbnNRcoAlh7naMZJqDBRRgs@Tep_2p3@vcw1Bk7hex" "D2Y_syYIWUbFyfXAiSN9xXn15evI4zXM9r1VHKbkAKfs8POd0nQ5Ch4adqumOhig" "SlVTmQFC0AGMFY33ZENE6@CjlKatLox6xZ07jw5LePGy_LoHKbi8zStwOUkmoDsz"; int sLua_HttpResponse::HttpResponse_proceed_statics(Lua * L, int n, int caller) { int r = 0, l, i, size = 32; String enc, dec; char * enc_t; const char * dec_t; switch (caller) { case HTTPRESPONSE_NEWHTTPRESPONSE: { LuaHttpResponse r(new HttpResponse()); r.pushdestruct(L); } r = 1; break; case HTTPRESPONSE_BASE64_ENCODE: if (L->isstring()) { dec = L->tostring(); dec_t = dec.to_charp(); L->push(Base64::encode(dec_t, dec.strlen())); } else { Handle * hdata = (Handle *) LuaObject::getme(L, 1); int size = hdata->GetSize(); char * data = (char *) malloc(size); hdata->read(data, size); L->push(Base64::encode(data, size)); free(data); } r = 1; break; case HTTPRESPONSE_BASE64_DECODE: enc_t = (char *) Base64::decode(L->tostring(), &l); enc_t[l] = 0; L->push(enc_t, l); free(enc_t); r = 1; break; case HTTPRESPONSE_BASE64_DECODE_BIN: { Handle * out = lua_recast(L, 2); if (!out) L->error("Need an output handle to Base64DecodeBin") enc_t = (char *) Base64::decode(L->tostring(), &l); out->write(enc_t, l); free(enc_t); } break; case HTTPRESPONSE_MD5: if (L->isstring()) { dec = L->tostring(); MD5 h; h.Update(dec); L->push(h.Finish()); } else { Handle * hdata = (Handle *) LuaObject::getme(L, 1); MD5 h; h.Update(hdata); L->push(h.Finish()); } r = 1; break; case HTTPRESPONSE_SHA1: if (L->isstring()) { dec = L->tostring(); SHA1 h; h.Update(dec); L->push(h.Finish()); } else { Handle * hdata = (Handle *) LuaObject::getme(L, 1); SHA1 h; h.Update(hdata); L->push(h.Finish()); } r = 1; break; case HTTPRESPONSE_SHA256: if (L->isstring()) { dec = L->tostring(); SHA256 h; h.Update(dec); L->push(h.Finish()); } else { Handle * hdata = (Handle *) LuaObject::getme(L, 1); SHA256 h; h.Update(hdata); L->push(h.Finish()); } r = 1; break; case HTTPRESPONSE_GENTICKET: if (n == 1) size = L->tonumber(); enc_t = (char *) malloc(size + 1); for (i = 0; i < size; i++) { enc_t[i] = ticket_chars[rand_gen.get() % 256]; } enc_t[size] = 0; L->push(String(enc_t)); r = 1; break; } return r; } LuaDomain::LuaDomain(Lua * _L, String r) : Domain(r), L(_L->Father()) { id = max_id++; /***FIXME***/ L->push(DOMAIN_REGISTRY); L->gettable(LUA_REGISTRYINDEX); L->push((lua_Number) id); L->copy(2); L->settable(); L->pop(); } LuaDomain::~LuaDomain() { L->push(DOMAIN_REGISTRY); L->gettable(LUA_REGISTRYINDEX); L->push((lua_Number) id); L->push(); L->settable(); L->pop(); } void LuaDomain::Do(const HttpRequest & req, HttpResponse * res) throw (GeneralException) { int i, nmatches = 1; Lua * oldL = L; Lua * L = oldL->thread(true); oldL->pop(); L->push(DOMAIN_REGISTRY); L->gettable(LUA_REGISTRYINDEX); L->push((lua_Number) id); L->gettable(); L->remove(); L->newtable(); L->push("vars"); L->newtable(); for (i = 0; i < req.vars->GetNb(); i++) { char * v = (*(req.vars))[i].strdup(), * p; p = strchr(v, '='); if (!p) { L->push(v); L->push(true); } else { *p = 0; p++; L->push(v); L->push(p); } L->settable(); free(v); } L->settable(); L->push("headers"); L->newtable(); for (i = 0; i < req.headers->GetNb(); i++) { char * v = (*(req.headers))[i].strdup(), * p; p = strchr(v, '='); if (!p) { free(v); continue; } *p = 0; p++; L->push(v); L->push(p); L->settable(); free(v); } L->settable(); L->push("method"); L->push(req.method); L->settable(); L->push("uri"); L->push(req.uri); L->settable(); L->push("login"); L->push(req.login); L->settable(); L->push("password"); L->push(req.password); L->settable(); L->push("lip"); L->push((lua_Number) req.lip); L->settable(); L->push("dip"); L->push((lua_Number) req.dip); L->settable(); L->push("lport"); L->push((lua_Number) req.lport); L->settable(); L->push("dport"); L->push((lua_Number) req.dport); L->settable(); L->push("matches"); L->newtable(); for (i = 1; i < MAX_MATCHES; i++) { if (req.pmatches[i].rm_so == -1) continue; L->push((lua_Number) nmatches++); L->newtable(); L->push("start"); L->push((lua_Number) req.pmatches[i].rm_so + 1); L->settable(); L->push("size"); L->push((lua_Number) req.pmatches[i].rm_eo - req.pmatches[i].rm_so); L->settable(); L->settable(); } L->settable(); LuaHttpResponse r(res); r.push(L); res->builder = new LuaTask(L, 2, true); } int LuaDomain::max_id = 1; int sLua_LuaDomain::LuaDomain_proceed(Lua * L, int n, LuaDomain * obj, int caller) { int r = 0; switch (caller) { case LUADOMAIN_ONTOP: obj->OnTop(); break; case LUADOMAIN_GETPATTERN: L->push(obj->GetPattern()); r = 1; break; } return r; } int sLua_LuaDomain::LuaDomain_proceed_statics(Lua * L, int n, int caller) { int r = 0; Domain ** p; switch (caller) { case LUADOMAIN_NEWDOMAIN: { LuaLuaDomain lld(new LuaDomain(L, L->tostring(1))); lld.pushdestruct(L); r = 1; } break; case LUADOMAIN_IDOMAIN: L->getglobal("nDomain"); p = (Domain **) L->newuser(sizeof(Domain *)); *p = 0; L->push(); r = 3; break; case LUADOMAIN_NDOMAIN: p = (Domain **) L->touserdata(1); if (*p) { *p = (*p)->Next(); } else { *p = Domain::First(); } if (*p) { L->push((*p)->GetPattern()); } else { L->push(); } r = 1; break; } return r; }