From f6e5f4a2ea01452e49062ac807c9c763fbe7b2a0 Mon Sep 17 00:00:00 2001 From: onefang Date: Fri, 30 Jul 2021 14:00:10 +1000 Subject: Shift Lua functions up near the top. --- src/sledjchisl/sledjchisl.c | 551 +++++++++++++++++++++++--------------------- 1 file changed, 288 insertions(+), 263 deletions(-) (limited to 'src/sledjchisl') diff --git a/src/sledjchisl/sledjchisl.c b/src/sledjchisl/sledjchisl.c index 16876f0..b88b1a5 100644 --- a/src/sledjchisl/sledjchisl.c +++ b/src/sledjchisl/sledjchisl.c @@ -581,6 +581,28 @@ static char *getStrH(qhashtbl_t *hash, char *key) } +static void bitch(reqData *Rd, char *message, char *log) +{ + addStrL(Rd->errors, message); + E("%s %s %s - %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), Rd->shs.UUID, Rd->shs.name, message, log); +} + +/* "A token cookie that references a non-existent session, its value should be replaced immediately to prevent session fixation." +https://owasp.org/www-community/attacks/Session_fixation + Which describes the problem, but offers no solution. + See https://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication?rq=1. +I think this means send a new cookie. + I clear out the cookies and send blank ones with -1 maxAge, so they should get deleted. +*/ +static void bitchSession(reqData *Rd, char *message, char *log) +{ + if ('\0' != message[0]) + addStrL(Rd->errors, message); + C("%s %s %s - %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), Rd->shs.UUID, Rd->shs.name, message, log); + Rd->shs.status = SHS_BOGUS; +} + + char *myHMAC(char *in, boolean b64) { EVP_MD_CTX *mdctx = EVP_MD_CTX_create(); // Gets renamed to EVP_MD_CTX_new() in later versions. @@ -629,6 +651,272 @@ void PrintTable(lua_State *L) } } +typedef struct _qLua qLua; +struct _qLua +{ + int type; + union + { + boolean b; + int i; + float f; + char *s; + qtreetbl_t *t; + } v; +}; + +qLua *qLuaGet(qtreetbl_t *tree, char *key) +{ + return (qLua *) tree->get(tree, key, NULL, false); +} + +qtreetbl_t *lua2tree() +{ + qtreetbl_t *ret = qtreetbl(0); + + if (NULL != ret) + { + qLua q; + + lua_pushnil(L); // +1 nil, first key + while(lua_next(L, -2) != 0) // -1 key, +2 next key, value (or 0 if nothing left in table) + { + // stack now contains: -1 => value; -2 => key; -3 => table + // copy the key so that lua_tostring does not modify the original + lua_pushvalue(L, -2); + // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table + char *n = (char *) lua_tostring(L, -1); // 0, modifies key copy + q.type = lua_type(L, -2); // 0 + // Numbers can convert to strings, so check for numbers before checking for strings. + // On the other hand, strings that can be converted to numbers also pass lua_isnumber(). sigh + switch(q.type) + { + case LUA_TBOOLEAN : {q.v.b = lua_toboolean(L, -2); break;} + case LUA_TINTEGER : {q.v.i = lua_tointeger(L, -2); break;} + case LUA_TNUMBER : {q.v.f = lua_tonumber(L, -2); break;} + case LUA_TSTRING : {q.v.s = (char *) lua_tostring(L, -2); break;} + case LUA_TTABLE : {lua_pushvalue(L, -2); q.v.t = lua2tree(); lua_pop(L, 1); break;} + + default : + { + q.v.s = (char *) lua_tostring(L, -2); // 0 + E("Unknown Lua variable type for %s = %s is %d", n, q.v.s, q.type); + break; + } + } + ret->put(ret, n, &q, sizeof(qLua)); + // pop value + copy of key, leaving original key + lua_pop(L, 2); // -2 value and copy of key + // stack now contains: -1 => key; -2 => table + } + } + else + { + D("No memory left."); + perror_msg("Unable to allocate memory"); + } + + return ret; +} + +qtreetbl_t *Lua2tree(char *file, char *var) +{ + qtreetbl_t *ret = NULL; + struct stat st; + + if (0 != lstat(file, &st)) + { + D("No %s file.", file); + perror_msg("Unable to stat %s", file); + } + else + { + if (luaL_loadfile(L, file)) // +1 the chunk or an error message. If something went wrong, error message is at the top of the stack. + E("Couldn't load Lua file: %s", lua_tostring(L, -1)); // 0 + else + { + if (lua_pcall(L, 0, LUA_MULTRET, 0)) // +1 result or an error message. Except we get 0 or error? + { + E("Failed to run Lua script: %s", lua_tostring(L, -1)); // 0 + lua_pop(L, 1); // -1 chunk or error message + } + else + { + lua_getglobal(L, var); // +1 the value of var + ret = lua2tree(); + lua_pop(L, 1); // -1 var + } + } + lua_pop(L, 1); // -1 chunk or error message + } + return ret; +} + + +int Lua2hashtbl(char *file, qhashtbl_t *hash, char *var) +{ + int ret = FALSE; + struct stat st; + + if (0 != lstat(file, &st)) + { + D("No %s file.", file); + perror_msg("Unable to stat %s", file); + return FALSE; + } + else + { + int status = luaL_loadfile(L, file); // +1 the chunk or an error message. + if (status) // If something went wrong, error message is at the top of the stack. + E("Couldn't load Lua file: %s", lua_tostring(L, -1)); // 0 + else + { + int result = lua_pcall(L, 0, LUA_MULTRET, 0); // +1 result or an error message. Except we get 0 or error? + if (result) + { + E("Failed to run Lua script: %s", lua_tostring(L, -1)); // 0 + lua_pop(L, 1); // -1 chunk or error message + } + else + { + lua_getglobal(L, var); // +1 the value of var + lua_pushnil(L); // +1 nil, first key + while(lua_next(L, -2) != 0) // -1 key, +2 next key, value (or 0 if nothing left in table) + { + char *n = (char *) lua_tostring(L, -2); // 0 + + // Numbers can convert to strings, so check for numbers before checking for strings. + // On the other hand, strings that can be converted to numbers also pass lua_isnumber(). sigh + if (lua_isnumber(L, -1)) // 0 + { + float v = lua_tonumber(L, -1); // 0 + hash->put(hash, n, &v, sizeof(float)); + } + else if (lua_isstring(L, -1)) // 0 + hash->putstr(hash, n, (char *) lua_tostring(L, -1)); // 0 + else if (lua_isboolean(L, -1)) // 0 + { + int v = lua_toboolean(L, -1); // 0 + hash->putint(hash, n, v); + } + else + { + char *v = (char *) lua_tostring(L, -1); // 0 + E("Unknown Lua variable type for %s = %s", n, v); + } + lua_pop(L, 1); // -1 value + } + lua_pop(L, 1); // -1 var + ret = TRUE; + } + } + } + lua_pop(L, 1); // -1 chunk or error message + return ret; +} + +int LuaToHash(reqData *Rd, char *file, char *var, qhashtbl_t *tnm, int ret, struct stat *st, struct timespec *now, char *type) +{ + struct timespec then; + + if (-1 == clock_gettime(CLOCK_REALTIME, &then)) + perror_msg("Unable to get the time."); + I("Reading %s file %s", type, file); + if (!Lua2hashtbl(file, tnm, var)) + { + bitch(Rd, "Broken thing.", "Can't run file."); + ret++; + } + else + { + if (-1 == clock_gettime(CLOCK_REALTIME, now)) + perror_msg("Unable to get the time."); + double n = (now->tv_sec * 1000000000.0) + now->tv_nsec; + double t = (then.tv_sec * 1000000000.0) + then.tv_nsec; + T("Reading %s file took %lf seconds", type, (n - t) / 1000000000.0); + } + + return ret; +} + + +boolean writeLuaDouble(reqData *Rd, int fd, char *file, char *name, double number) +{ + boolean ret = TRUE; +// TODO - putting these in Lua as numbers causes lua_tolstring to barf when we read them. Though Lua is supposed to convert between numbers and strings. + char *t = xmprintf(" ['%s'] = '%f',\n", name, number); // NOTE - default precision is 6 decimal places. + size_t l = strlen(t); + + if (l != writeall(fd, t, l)) + { + perror_msg("Writing %s", file); + ret = FALSE; + } + free(t); + return ret; +} + +boolean writeLuaInteger(reqData *Rd, int fd, char *file, char *name, long number) +{ + boolean ret = TRUE; +// TODO - putting these in Lua as numbers causes lua_tolstring to barf when we read them. Though Lua is supposed to convert between numbers and strings. + char *t = xmprintf(" ['%s'] = '%ld',\n", name, number); + size_t l = strlen(t); + + if (l != writeall(fd, t, l)) + { + perror_msg("Writing %s", file); + ret = FALSE; + } + free(t); + return ret; +} + +boolean writeLuaString(reqData *Rd, int fd, char *file, char *name, char *string) +{ + boolean ret = TRUE; + + if (NULL == string) + string = getStrH(Rd->stuff, name); + + size_t l = strlen(string); + char *t0 = xmalloc(l * 2 + 1); + int i, j = 0; + +// TODO - maybe escape other non printables as well? + for (i = 0; i < l; i++) + { + // We don't need to escape [] here, coz we are using '' below. Same applies to ", but do it anyway. + switch(string[i]) + { + case '\n': + case '\\': + case '\'': + case '"': + t0[j++] = '\\'; break; + } + if ('\n' == string[i]) + t0[j++] = 'n'; + else if ('\r' == string[i]) + ; + else + t0[j++] = string[i]; + } + t0[j] = '\0'; + + char *t1 = xmprintf(" ['%s'] = '%s',\n", name, t0); + + l = strlen(t1); + if (l != writeall(fd, t1, l)) + { + perror_msg("Writing %s to %s", name, file); + ret = FALSE; + } + free(t1); + free(t0); + return ret; +} + void doTmuxCmd(char *format, ...) { @@ -3478,28 +3766,6 @@ https://stackoverflow.com/questions/16891729/best-practices-salting-peppering-pa qlisttbl_t *accountLevels = NULL; -static void bitch(reqData *Rd, char *message, char *log) -{ - addStrL(Rd->errors, message); - E("%s %s %s - %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), Rd->shs.UUID, Rd->shs.name, message, log); -} - -/* "A token cookie that references a non-existent session, its value should be replaced immediately to prevent session fixation." -https://owasp.org/www-community/attacks/Session_fixation - Which describes the problem, but offers no solution. - See https://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication?rq=1. -I think this means send a new cookie. - I clear out the cookies and send blank ones with -1 maxAge, so they should get deleted. -*/ -static void bitchSession(reqData *Rd, char *message, char *log) -{ - if ('\0' != message[0]) - addStrL(Rd->errors, message); - C("%s %s %s - %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), Rd->shs.UUID, Rd->shs.name, message, log); - Rd->shs.status = SHS_BOGUS; -} - - // The ancient, insecure since 2011, Second Life / OpenSim password hashing algorithm. char *newSLOSsalt(reqData *Rd) { @@ -3564,169 +3830,6 @@ t("checkSLOSpassword(%s, %s, %s, ", password, salt, passwordHash, fail); } -typedef struct _qLua qLua; -struct _qLua -{ - int type; - union - { - boolean b; - int i; - float f; - char *s; - qtreetbl_t *t; - } v; -}; - -qLua *qLuaGet(qtreetbl_t *tree, char *key) -{ - return (qLua *) tree->get(tree, key, NULL, false); -} - -qtreetbl_t *lua2tree() -{ - qtreetbl_t *ret = qtreetbl(0); - - if (NULL != ret) - { - qLua q; - - lua_pushnil(L); // +1 nil, first key - while(lua_next(L, -2) != 0) // -1 key, +2 next key, value (or 0 if nothing left in table) - { - char *n = (char *) lua_tostring(L, -2); // 0 - - q.type = lua_type(L, -1); // 0 - // Numbers can convert to strings, so check for numbers before checking for strings. - // On the other hand, strings that can be converted to numbers also pass lua_isnumber(). sigh - switch(q.type) - { - case LUA_TBOOLEAN : {q.v.b = lua_toboolean(L, -1); break;} - case LUA_TINTEGER : {q.v.i = lua_tointeger(L, -1); break;} - case LUA_TNUMBER : {q.v.f = lua_tonumber(L, -1); break;} - case LUA_TSTRING : {q.v.s = (char *) lua_tostring(L, -1); break;} - case LUA_TTABLE : {q.v.t = lua2tree(); break;} - - default : - { - q.v.s = (char *) lua_tostring(L, -1); // 0 - E("Unknown Lua variable type for %s = %s is %d", n, q.v.s, q.type); - break; - } - } - ret->put(ret, n, &q, sizeof(qLua)); - lua_pop(L, 1); // -1 value - } - } - else - { - D("No memory left."); - perror_msg("Unable to allocate memory"); - } - - return ret; -} - -qtreetbl_t *Lua2tree(char *file, char *var) -{ - qtreetbl_t *ret = NULL; - struct stat st; - - if (0 != lstat(file, &st)) - { - D("No %s file.", file); - perror_msg("Unable to stat %s", file); - } - else - { - if (luaL_loadfile(L, file)) // +1 the chunk or an error message. If something went wrong, error message is at the top of the stack. - E("Couldn't load Lua file: %s", lua_tostring(L, -1)); // 0 - else - { - if (lua_pcall(L, 0, LUA_MULTRET, 0)) // +1 result or an error message. Except we get 0 or error? - { - E("Failed to run Lua script: %s", lua_tostring(L, -1)); // 0 - lua_pop(L, 1); // -1 chunk or error message - } - else - { - lua_getglobal(L, var); // +1 the value of var - ret = lua2tree(); - lua_pop(L, 1); // -1 var - } - } - lua_pop(L, 1); // -1 chunk or error message - } - return ret; -} - - -int LuaToHash(reqData *Rd, char *file, char *var, qhashtbl_t *tnm, int ret, struct stat *st, struct timespec *now, char *type) -{ - struct timespec then; - - if (-1 == clock_gettime(CLOCK_REALTIME, &then)) - perror_msg("Unable to get the time."); - I("Reading %s file %s", type, file); - if (0 != stat(file, st)) - { - D("No %s file.", file); - perror_msg("Unable to stat %s", file); - ret++; - } - else - { - int status = luaL_loadfile(Rd->L, file), result; - - if (status) - { - bitch(Rd, "No such thing.", "Can't load file."); - E("Couldn't load file: %s", lua_tostring(Rd->L, -1)); - ret++; - } - else - { - result = lua_pcall(Rd->L, 0, LUA_MULTRET, 0); - - if (result) - { - bitch(Rd, "Broken thing.", "Can't run file."); - E("Failed to run script: %s", lua_tostring(Rd->L, -1)); - ret++; - } - else - { - lua_getglobal(Rd->L, var); - lua_pushnil(Rd->L); - - while(lua_next(Rd->L, -2) != 0) - { - char *n = (char *) lua_tostring(Rd->L, -2); - - if (lua_isstring(Rd->L, -1)) - { - tnm->putstr(tnm, n, (char *) lua_tostring(Rd->L, -1)); -d("Lua reading (%s) %s = %s", type, n, getStrH(tnm, n)); - } - else - { - char *v = (char *) lua_tostring(Rd->L, -1); - W("Unknown Lua variable type for %s = %s", n, v); - } - lua_pop(Rd->L, 1); - } - - if (-1 == clock_gettime(CLOCK_REALTIME, now)) - perror_msg("Unable to get the time."); - double n = (now->tv_sec * 1000000000.0) + now->tv_nsec; - double t = (then.tv_sec * 1000000000.0) + then.tv_nsec; - T("Reading %s file took %lf seconds", type, (n - t) / 1000000000.0); - } - } - } - - return ret; -} char *checkLinky(reqData *Rd) @@ -4113,84 +4216,6 @@ systemFolders sysFolders[] = {"Trash", 14}, {NULL, -1} }; - -boolean writeLuaDouble(reqData *Rd, int fd, char *file, char *name, double number) -{ - boolean ret = TRUE; -// TODO - putting these in Lua as numbers causes lua_tolstring to barf when we read them. Though Lua is supposed to convert between numbers and strings. - char *t = xmprintf(" ['%s'] = '%f',\n", name, number); // NOTE - default precision is 6 decimal places. - size_t l = strlen(t); - - if (l != writeall(fd, t, l)) - { - perror_msg("Writing %s", file); - ret = FALSE; - } - free(t); - return ret; -} - -boolean writeLuaInteger(reqData *Rd, int fd, char *file, char *name, long number) -{ - boolean ret = TRUE; -// TODO - putting these in Lua as numbers causes lua_tolstring to barf when we read them. Though Lua is supposed to convert between numbers and strings. - char *t = xmprintf(" ['%s'] = '%ld',\n", name, number); - size_t l = strlen(t); - - if (l != writeall(fd, t, l)) - { - perror_msg("Writing %s", file); - ret = FALSE; - } - free(t); - return ret; -} - -boolean writeLuaString(reqData *Rd, int fd, char *file, char *name, char *string) -{ - boolean ret = TRUE; - - if (NULL == string) - string = getStrH(Rd->stuff, name); - - size_t l = strlen(string); - char *t0 = xmalloc(l * 2 + 1); - int i, j = 0; - -// TODO - maybe escape other non printables as well? - for (i = 0; i < l; i++) - { - // We don't need to escape [] here, coz we are using '' below. Same applies to ", but do it anyway. - switch(string[i]) - { - case '\n': - case '\\': - case '\'': - case '"': - t0[j++] = '\\'; break; - } - if ('\n' == string[i]) - t0[j++] = 'n'; - else if ('\r' == string[i]) - ; - else - t0[j++] = string[i]; - } - t0[j] = '\0'; - - char *t1 = xmprintf(" ['%s'] = '%s',\n", name, t0); - - l = strlen(t1); - if (l != writeall(fd, t1, l)) - { - perror_msg("Writing %s to %s", name, file); - ret = FALSE; - } - free(t1); - free(t0); - return ret; -} - static void accountWrite(reqData *Rd) { char *uuid = getStrH(Rd->database, "UserAccounts.PrincipalID"); -- cgit v1.1