From 2c62c8f69fecda58aa4af9267fb77879d7006837 Mon Sep 17 00:00:00 2001 From: onefang Date: Thu, 7 May 2020 11:15:43 +1000 Subject: Rewrite the web session stuff. --- src/sledjchisl/sledjchisl.c | 397 ++++++++++++++++++++++++++++---------------- 1 file changed, 251 insertions(+), 146 deletions(-) (limited to 'src/sledjchisl') diff --git a/src/sledjchisl/sledjchisl.c b/src/sledjchisl/sledjchisl.c index 95724df..c1f6f13 100644 --- a/src/sledjchisl/sledjchisl.c +++ b/src/sledjchisl/sledjchisl.c @@ -368,8 +368,32 @@ static void newBuildPage(char *name, pageBuildFunction func, pageBuildFunction e #define HMACSIZE EVP_MAX_MD_SIZE * 2 #define HMACSIZE64 88 + +// Session details about the logged in web user. A sorta state machine. Ish. +enum reqSessionStatus // Status of the session. Refresh and wipe / nuke -> delete the old session file first. +{ + SHS_UNKNOWN = 0, // Haven't looked at the session yet. -> validate it + SHS_NONE, // No session at all. -> logout + SHS_BOGUS, // Looked at the session, it's bogus. -> nuke and logout + SHS_PROBLEM, // Some other problem with the session. -> nuke and logout + SHS_VALID, // Session is valid. -> continue + + SHS_LOGIN, // User has just logged in, add UUID to session. -> wipe, add UUID + + SHS_RENEW, // Refresh the session based on timer. -> continue + SHS_REFRESH, // Refresh the session for other reason. -> continue + SHS_IDLE, // Session has been idle too long. -> relogin + SHS_ANCIENT, // Session is way too old. -> nuke and logout + + SHS_SECURITY, // High security task needs users name & password. -> + SHS_RELOGIN, // Ask user to login again. -> + + SHS_KEEP, // Keep the session. -> continue + SHS_WIPE, // Wipe the session, use users UUID. -> continue + SHS_NUKE // Wipe the session, no UUID. -> logout +}; + typedef struct _sesh sesh; -// Details about the logged in web user. struct _sesh { char salt[256 + 1], seshID[256 + 1], @@ -377,6 +401,7 @@ struct _sesh leaf[HMACSIZE64 + 6 + 1], *UUID, *name; struct timespec timeStamp[2]; short level; + enum reqSessionStatus status; boolean isLinky; }; @@ -394,7 +419,6 @@ struct _reqData // pageBuildFunction func; struct timespec then; boolean fromDb; -// boolean chillOut, vegOut; }; static void showSesh(qgrow_t *reply, sesh *shs) @@ -447,8 +471,9 @@ char *webRoot = "/var/www/html"; char *URL = "fcgi-bin/sledjchisl.fcgi"; char *ToS = "Be good."; char *webIframers = ""; -int seshTimeOut = 30 * 60; -int idleTimeOut = 24 * 60 * 60; +int seshRenew = 10 * 60; +int idleTimeOut = 30 * 60; +int seshTimeOut = 24 * 60 * 60; int newbieTimeOut = 30; float loadAverageInc = 0.5; int simTimeOut = 45; @@ -2910,7 +2935,7 @@ HTMLfile *checkHTMLcache(char *file) . Let them do things as normal, in case this was just someone being mean to them, coz their email addy might be public. . Including the usual logging out and in again with their old password. . Warn them on login and any page refresh that there is an outstanding password reset awaiting them. -+ email linky, which is some or all of the token result bits strung together, BASE64 encode the result. +. email linky, which is some or all of the token result bits strung together, BASE64 encode the result. . regenerate the usual token . user clicks on the linky (or just enters the linky in a field) . validate the linky token. @@ -2930,10 +2955,10 @@ HTMLfile *checkHTMLcache(char *file) Should warn people on the accountCreationPage that DoB might be used this way. ask them for the new password, twice Create a new passwordSalt and passwordHash, store them in the auth table. - For validate new user page +. For validate new user page . tell them they have validated - create their OpenSim account UserAccounts.UserTitle and auth tables, not GridUser table - create their GridUser record. +. create their OpenSim account UserAccounts.UserTitle and auth tables, not GridUser table +. create their GridUser record. . update their UserAccounts.Userlevel and UserAccounts.UserTitle . send them to the login page. . regenerate the usual token @@ -3093,9 +3118,10 @@ I think this means send a new cookie. */ static void bitchSession(reqData *Rd, char *message, char *log) { - addStrL(Rd->errors, message); + if ('\0' != message[0]) + addStrL(Rd->errors, message); C("%s %s %s - %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), Rd->shs.UUID, getStrH(Rd->stuff, "name"), message, log); -// Rd->vegOut = TRUE; + Rd->shs.status = SHS_BOGUS; } @@ -3182,7 +3208,7 @@ int LuaToHash(reqData *Rd, char *file, char *var, qhashtbl_t *tnm, int ret, stru if (status) { - bitchSession(Rd, "No such thing.", "Can't load file."); + bitch(Rd, "No such thing.", "Can't load file."); E("Couldn't load file: %s", lua_tostring(Rd->L, -1)); ret++; } @@ -3192,7 +3218,7 @@ int LuaToHash(reqData *Rd, char *file, char *var, qhashtbl_t *tnm, int ret, stru if (result) { - bitchSession(Rd, "Broken thing.", "Can't run file."); + bitch(Rd, "Broken thing.", "Can't run file."); E("Failed to run script: %s", lua_tostring(Rd->L, -1)); ret++; } @@ -4080,6 +4106,10 @@ static int sessionValidate(reqData *Rd, inputForm *iF, inputValue *iV) char *t = xstrdup(hashish); size_t sz = qB64_decode(t); +// TODO - should validate the cookie version as well, if it was sent. +// Coz it later tries to delete the linky as if it was the cookie session, and might give us a chance to delete the old session. +// Though only if there's a munchie in the body? + I("Validating LINKY hashish %s", hashish); free(hashish); hashish = qhex_encode(t, sz); linky = TRUE; @@ -4093,15 +4123,18 @@ static int sessionValidate(reqData *Rd, inputForm *iF, inputValue *iV) { if (strcmp("logout", Rd->doit) == 0) { - d("Not checking session, coz we are logging out."); + I("Not checking session, coz we are logging out."); + Rd->shs.status = SHS_NUKE; return ret; } bitchSession(Rd, "Invalid session.", "No or blank hashish or toke_n_munchie."); + Rd->shs.status = SHS_NONE; ret++; } + else + I("Validating SESSION hashish %s", hashish); } -//d("O hashish %s", hashish); //d("O toke_n_munchie %s", toke_n_munchie); //d("O munchie %s", munchie); if (0 == ret) @@ -4120,7 +4153,15 @@ static int sessionValidate(reqData *Rd, inputForm *iF, inputValue *iV) ret = LuaToHash(Rd, t0, "toke_n_munchie", tnm, ret, &st, &now, "session"); free(t0); - if (0 == ret) + if (0 != ret) + { + // This might be coz it's a stale session that was deleted already, so shouldn't complain really if they are just getting the login page. + // They might also have a stale doit and form cookie. +// bitchSession(Rd, "Invalid session.", "No session file."); + bitchSession(Rd, "", "No session file."); + ret++; + } + else { // This is apparently controversial, I added it coz some of the various security docs suggested it's a good idea. // https://security.stackexchange.com/questions/139952/why-arent-sessions-exclusive-to-an-ip-address?rq=1 @@ -4148,7 +4189,8 @@ static int sessionValidate(reqData *Rd, inputForm *iF, inputValue *iV) { if (strcmp(t1, munchie) != 0) { - bitchSession(Rd, "Wrong munchie for session.", "HMAC(seshID + timeStamp) != munchie"); +// TODO if newbie user has not logged out, but clicks the email linky, and they end up on a new browser tab, they'll see this on the logged in tab. + bitchSession(Rd, "Wrong munchie for session, may have been eaten, please try again.", "HMAC(seshID + timeStamp) != munchie"); ret++; } else @@ -4182,88 +4224,94 @@ static int sessionValidate(reqData *Rd, inputForm *iF, inputValue *iV) ret++; } free(t1); - } +// TODO - should carefully review all of this, especially the moving of session data to and fro. if (0 == ret) { - if (now.tv_sec > st.st_mtim.tv_sec + idleTimeOut) +W("Validated session."); + sesh *shs = &Rd->shs; + + qstrcpy(shs->leaf, sizeof(shs->leaf), leaf); + shs->name = tnm->getstr(tnm, "name", true); // LEAKY! + shs->UUID = tnm->getstr(tnm, "UUID", true); // LEAKY! + if (linky) { - W("Session idled out."); -// Rd->vegOut = TRUE; +W("Validated session linky."); + addStrL(Rd->messages, "Congratulations, you have validated your new account. Now you can log onto the web site."); + addStrL(Rd->messages, "NOTE - you wont be able to log onto the grid until your new account has been approved."); + Rd->lnk = xzalloc(sizeof(sesh)); + Rd->lnk->status = SHS_NUKE; + qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), leaf); + freeSesh(Rd, linky, FALSE); + qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), ""); + Rd->doit = "validate"; + Rd->output = "accountLogin"; + Rd->form = "accountLogin"; +// TODO - we might want to delete their old .lua session as well. Maybe? Don't think we have any suitable codes to find it. } else { + char *level = tnm->getstr(tnm, "level", false); + + // Check for session timeouts etc. if (now.tv_sec > st.st_mtim.tv_sec + seshTimeOut) { - W("Session timed out."); -// Rd->vegOut = TRUE; + bitch(Rd, "Session timed out.", "No activity for longer than seshTimeOut, session is ancient."); + ret++; + Rd->shs.status = SHS_ANCIENT; } - else + else if (now.tv_sec > st.st_mtim.tv_sec + idleTimeOut) { -W("Validated session."); - sesh *shs = &Rd->shs; - - qstrcpy(shs->leaf, sizeof(shs->leaf), leaf); - if (linky) - { -W("Validated session linky."); - addStrL(Rd->messages, "Congratulations, you have validated your new account. Now you can log onto the web site."); - addStrL(Rd->messages, "NOTE - you wont be able to log onto the grid until your new account has been approved."); - Rd->lnk = xzalloc(sizeof(sesh)); - qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), leaf); - freeSesh(Rd, linky, FALSE); - qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), ""); - Rd->doit = "validate"; - Rd->output = "accountLogin"; - Rd->form = "accountLogin"; -// TODO - we might want to delete their old .lua session as well. Maybe? Don't think we have any suitable codes to find it. - } - else - { - char *level = tnm->getstr(tnm, "level", false); - - if (NULL == level) - level = "-256"; - qstrcpy(shs->sesh, sizeof(shs->sesh), seshion); - qstrcpy(shs->toke_n_munchie, sizeof(shs->toke_n_munchie), toke_n_munchie); - qstrcpy(shs->hashish, sizeof(shs->hashish), hashish); - qstrcpy(shs->munchie, sizeof(shs->munchie), munchie); - qstrcpy(shs->salt, sizeof(shs->salt), tnm->getstr(tnm, "salt", false)); - qstrcpy(shs->seshID, sizeof(shs->seshID), tnm->getstr(tnm, "seshID", false)); - shs->level = atoi(level); -// TODO - get level from somewhere and stuff it in shs. - shs->timeStamp[0].tv_nsec = UTIME_OMIT; - shs->timeStamp[0].tv_sec = UTIME_OMIT; - memcpy(&shs->timeStamp[1], &st.st_mtim, sizeof(struct timespec)); - } - shs->name = tnm->getstr(tnm, "name", true); // LEAKY! - shs->UUID = tnm->getstr(tnm, "UUID", true); // LEAKY! + bitch(Rd, "Session idled out.", "No activity for longer than idleTimeOut, session is idle."); + ret++; + Rd->shs.status = SHS_IDLE; } + else if (now.tv_sec > st.st_mtim.tv_sec + seshRenew) + { + D("Session needs renewing."); + Rd->shs.status = SHS_RENEW; + } + else + Rd->shs.status = SHS_VALID; + + if (NULL == level) + level = "-256"; + qstrcpy(shs->sesh, sizeof(shs->sesh), seshion); + qstrcpy(shs->toke_n_munchie, sizeof(shs->toke_n_munchie), toke_n_munchie); + qstrcpy(shs->hashish, sizeof(shs->hashish), hashish); + qstrcpy(shs->munchie, sizeof(shs->munchie), munchie); + qstrcpy(shs->salt, sizeof(shs->salt), tnm->getstr(tnm, "salt", false)); + qstrcpy(shs->seshID, sizeof(shs->seshID), tnm->getstr(tnm, "seshID", false)); + shs->level = atoi(level); +// TODO - get level from somewhere and stuff it in shs. + shs->timeStamp[0].tv_nsec = UTIME_OMIT; + shs->timeStamp[0].tv_sec = UTIME_OMIT; + memcpy(&shs->timeStamp[1], &st.st_mtim, sizeof(struct timespec)); + } + } - qhashtbl_obj_t obj; + qhashtbl_obj_t obj; - memset((void*)&obj, 0, sizeof(obj)); - tnm->lock(tnm); - while(tnm->getnext(tnm, &obj, false) == true) - { - char *n = obj.name; + memset((void*)&obj, 0, sizeof(obj)); + tnm->lock(tnm); + while(tnm->getnext(tnm, &obj, false) == true) + { + char *n = obj.name; - if ((strcmp("salt", n) != 0) && (strcmp("seshID", n) != 0) && (strcmp("UUID", n) != 0)) - { + if ((strcmp("salt", n) != 0) && (strcmp("seshID", n) != 0) && (strcmp("UUID", n) != 0)) + { t("SessionValidate() Lua read %s = %s", n, (char *) obj.data); - Rd->stuff->putstr(Rd->stuff, obj.name, (char *) obj.data); - } - } - tnm->unlock(tnm); - -// TODO - check this. -// Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", tnm->getstr(tnm, "UUID", false)); + Rd->stuff->putstr(Rd->stuff, obj.name, (char *) obj.data); } } - free(munchie); - free(seshion); + tnm->unlock(tnm); + +// TODO - check this. +// Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", tnm->getstr(tnm, "UUID", false)); } + free(munchie); + free(seshion); } free(leaf); tnm->free(tnm); @@ -5121,13 +5169,13 @@ static int accountCreateSub(reqData *Rd, inputForm *iF, inputValue *iV) int ret = 0; char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName"); int c = accountRead(Rd, uuid, first, last); - boolean wipe = FALSE; if (strcmp("POST", Rd->Method) == 0) { if (0 != c) { bitch(Rd, "Cannot create account.", "Account exists."); + Rd->shs.status = SHS_NUKE; ret++; } else @@ -5142,22 +5190,13 @@ static int accountCreateSub(reqData *Rd, inputForm *iF, inputValue *iV) Rd->stuff->putstr(Rd->stuff, "passHash", h); Rd->stuff->putstr(Rd->stuff, "passSalt", salt); free(h); + Rd->shs.status = SHS_REFRESH; } free(salt); if (0 != ret) - { - wipe = TRUE; - if (NULL != Rd->shs.name) free(Rd->shs.name); - Rd->shs.name = NULL; - if (NULL != Rd->shs.UUID) free(Rd->shs.UUID); - Rd->shs.UUID = NULL; - Rd->shs.level = -256; - Rd->output = "accountLogin"; - } + Rd->shs.status = SHS_NUKE; } } - freeSesh(Rd, FALSE, wipe); - newSesh(Rd, FALSE); return ret; } @@ -5166,11 +5205,11 @@ static int accountAddSub(reqData *Rd, inputForm *iF, inputValue *iV) int ret = 0; char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName"); int c = accountRead(Rd, uuid, first, last); - boolean wipe = FALSE; if (0 != c) { bitch(Rd, "Cannot add account.", "Account exists."); + Rd->shs.status = SHS_NUKE; ret++; } else if ((0 == ret) && (strcmp("POST", Rd->Method) == 0)) @@ -5180,35 +5219,27 @@ static int accountAddSub(reqData *Rd, inputForm *iF, inputValue *iV) if (NULL == h) { ret++; - wipe = TRUE; - if (NULL != Rd->shs.name) free(Rd->shs.name); - Rd->shs.name = NULL; - if (NULL != Rd->shs.UUID) free(Rd->shs.UUID); - Rd->shs.UUID = NULL; - Rd->shs.level = -256; - Rd->output = "accountLogin"; + Rd->shs.status = SHS_NUKE; } else { - free(h); generateAccountUUID(Rd); Rd->stuff->putstr(Rd->stuff, "passwordHash", getStrH(Rd->stuff, "passHash")); Rd->stuff->putstr(Rd->stuff, "passwordSalt", getStrH(Rd->stuff, "passSalt")); Rd->shs.level = -200; Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", "-200"); - freeSesh(Rd, FALSE, wipe); + // Generate the linky for the email. newSesh(Rd, TRUE); accountWrite(Rd); -// log them in + // log them in I("Logged on %s %s Level %d %s", Rd->shs.UUID, getStrH(Rd->stuff, "name"), Rd->shs.level, getLevel(Rd->shs.level)); Rd->output = "accountView"; Rd->form = "accountView"; Rd->doit = "login"; + Rd->shs.status = SHS_LOGIN; } } - freeSesh(Rd, FALSE, wipe); - newSesh(Rd, FALSE); return ret; } @@ -5217,7 +5248,6 @@ static int accountSaveSub(reqData *Rd, inputForm *iF, inputValue *iV) int ret = 0; char *uuid = Rd->shs.UUID, *first = getStrH(Rd->body, "user"), *last = NULL; int c = accountRead(Rd, NULL, first, last); - boolean wipe = FALSE; if (1 != c) { @@ -5257,8 +5287,6 @@ static int accountSaveSub(reqData *Rd, inputForm *iF, inputValue *iV) // TODO - this isn't being shown. addStrL(Rd->messages, "Account saved."); } -// freeSesh(Rd, FALSE, wipe); -// newSesh(Rd, FALSE); return ret; } @@ -5267,7 +5295,6 @@ static int accountValidateSub(reqData *Rd, inputForm *iF, inputValue *iV) int ret = 0; char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName"); int c = accountRead(Rd, uuid, first, last); - boolean wipe = FALSE; if (1 != c) { @@ -5292,10 +5319,11 @@ static int accountValidateSub(reqData *Rd, inputForm *iF, inputValue *iV) Rd->shs.level = -100; Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", "-100"); accountWrite(Rd); - wipe = TRUE; + Rd->doit = "logout"; + Rd->output = "accountLogin"; + Rd->form = "accountLogin"; + Rd->shs.status = SHS_NUKE; } - freeSesh(Rd, FALSE, wipe); - newSesh(Rd, FALSE); return ret; } @@ -5305,20 +5333,13 @@ static int accountViewSub(reqData *Rd, inputForm *iF, inputValue *iV) int ret = 0; char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName"); int c = accountRead(Rd, uuid, first, last); - boolean wipe = FALSE; d("Sub accountViewSub() %s %s %s", uuid, first, last); if (1 != c) { bitch(Rd, "Cannot view account.", "Account doesn't exist."); ret++; - wipe = TRUE; - if (NULL != Rd->shs.name) free(Rd->shs.name); - Rd->shs.name = NULL; - if (NULL != Rd->shs.UUID) free(Rd->shs.UUID); - Rd->shs.UUID = NULL; - Rd->shs.level = -256; - Rd->output = "accountLogin"; + Rd->shs.status = SHS_NUKE; } else { @@ -5331,26 +5352,19 @@ d("Sub accountViewSub() %s %s %s", uuid, first, last); if (NULL == h) { ret++; - wipe = TRUE; - if (NULL != Rd->shs.name) free(Rd->shs.name); - Rd->shs.name = NULL; - if (NULL != Rd->shs.UUID) free(Rd->shs.UUID); - Rd->shs.UUID = NULL; - Rd->shs.level = -256; - Rd->output = "accountLogin"; + Rd->shs.status = SHS_NUKE; } else { - Rd->shs.level = atoi(getStrH(Rd->database, "UserAccounts.UserLevel")); - Rd->shs.name = Rd->database->getstr(Rd->database, "Lua.name", true); - Rd->shs.UUID = Rd->database->getstr(Rd->database, "UserAccounts.PrincipalID", true); - free(h); - I("Logged on %s %s Level %d %s", Rd->shs.UUID, Rd->shs.name, Rd->shs.level, getLevel(Rd->shs.level)); + Rd->shs.level = atoi(getStrH(Rd->database, "UserAccounts.UserLevel")); + Rd->shs.name = Rd->database->getstr(Rd->database, "Lua.name", true); + Rd->shs.UUID = Rd->database->getstr(Rd->database, "UserAccounts.PrincipalID", true); + free(h); + I("Logged on %s %s Level %d %s", Rd->shs.UUID, Rd->shs.name, Rd->shs.level, getLevel(Rd->shs.level)); + Rd->shs.status = SHS_LOGIN; } } } - freeSesh(Rd, FALSE, wipe); - newSesh(Rd, FALSE); return ret; } @@ -5392,19 +5406,8 @@ static int accountOutSub(reqData *Rd, inputForm *iF, inputValue *iV) // bitch(Rd, "Cannot logout account.", "Account doesn't exist."); // ret++; } - else - { -// log the user out if they are logged in - if (NULL != Rd->shs.name) free(Rd->shs.name); - Rd->shs.name = NULL; - if (NULL != Rd->shs.UUID) free(Rd->shs.UUID); - Rd->shs.UUID = NULL; - Rd->shs.level = -256; - Rd->output = "accountLogin"; - } - freeSesh(Rd, FALSE, TRUE); - newSesh(Rd, FALSE); + Rd->shs.status = SHS_NUKE; return ret; } @@ -5741,6 +5744,34 @@ void listPage(reqData *Rd, char *message) } */ + +void sessionStateEngine(reqData *Rd, char *type) +{ + switch (Rd->shs.status) + { + case SHS_UNKNOWN: d("sessionStateEngine(SHS_UNKNOWN, %s)", type); break; + case SHS_NONE: d("sessionStateEngine(SHS_NONE, %s)", type); break; + case SHS_BOGUS: d("sessionStateEngine(SHS_BOGUS, %s)", type); break; + case SHS_PROBLEM: d("sessionStateEngine(SHS_PROBLEM, %s)", type); break; + case SHS_VALID: d("sessionStateEngine(SHS_VALID, %s)", type); break; + + case SHS_LOGIN: d("sessionStateEngine(SHS_LOGIN, %s)", type); break; + + case SHS_RENEW: d("sessionStateEngine(SHS_RENEW, %s)", type); break; + case SHS_REFRESH: d("sessionStateEngine(SHS_REFRESH, %s)", type); break; + case SHS_IDLE: d("sessionStateEngine(SHS_IDLE, %s)", type); break; + case SHS_ANCIENT: d("sessionStateEngine(SHS_ANCIENT, %s)", type); break; + + case SHS_SECURITY: d("sessionStateEngine(SHS_SECURITY, %s)", type); break; + case SHS_RELOGIN: d("sessionStateEngine(SHS_RELOGIN, %s)", type); break; + + case SHS_KEEP: d("sessionStateEngine(SHS_KEEP, %s)", type); break; + case SHS_WIPE: d("sessionStateEngine(SHS_WIPE, %s)", type); break; + case SHS_NUKE: d("sessionStateEngine(SHS_NUKE, %s)", type); break; + } +} + + void account_html(char *file, reqData *Rd, HTMLfile *thisFile) { inputForm *iF; @@ -5777,6 +5808,7 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) bitch(Rd, "Invalid referer.", ref); D("Invalid referer - %s isn't %s", ref, href); form = "accountLogin"; + Rd->shs.status = SHS_PROBLEM; } free(href); } @@ -5790,6 +5822,7 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) bitch(Rd, "Invalid HOST.", ref); D("Invalid HOST - %s isn't %s", ref, href); form = "accountLogin"; + Rd->shs.status = SHS_PROBLEM; } // Redirect to HTTPS if it's HTTP. @@ -5892,11 +5925,17 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) if ('\0' == form[0]) form = getStrH(Rd->cookies, "form"); if ('\0' == form[0]) + { form = "accountLogin"; + Rd->shs.status = SHS_NUKE; + } if ('\0' == doit[0]) doit = getStrH(Rd->cookies, "doit"); if ('\0' == doit[0]) + { doit = "logout"; + Rd->shs.status = SHS_NUKE; + } if ('\0' != doit[0]) { setCookie(Rd, "doit", doit); @@ -5909,6 +5948,7 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) E("No such account page - %s", form); form = "accountLogin"; doit = "logout"; + Rd->shs.status = SHS_PROBLEM; iF = accountPages->get(accountPages, form, NULL, false); } sub = iF->subs->get(iF->subs, doit, NULL, false); @@ -5917,11 +5957,12 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) E("No such account action - %s", doit); form = "accountLogin"; doit = "logout"; + Rd->shs.status = SHS_PROBLEM; iF = accountPages->get(accountPages, form, NULL, false); sub = iF->subs->get(iF->subs, doit, NULL, false); } - // Special for showing another users details. + // Special for showing a users details. if ('\0' != getStrH(Rd->queries, "user")[0]) { doit = "edit"; @@ -5941,6 +5982,8 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) inputValue *iV = xzalloc(count * sizeof(inputValue)); qlisttbl_obj_t obj; + sessionStateEngine(Rd, "collected"); + if (strcmp("cancel", sub->name) != 0) { @@ -5995,6 +6038,8 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) form = Rd->form; } + sessionStateEngine(Rd, "validated"); + // Submit the data. Reload input form and sub in case things got changed by the validation functions. iF = accountPages->get(accountPages, Rd->form, NULL, false); sub = iF->subs->get(iF->subs, Rd->doit, NULL, false); @@ -6010,6 +6055,63 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) free(iV); } + else + { + sessionStateEngine(Rd, "CANCELLED"); + } + + sessionStateEngine(Rd, "submited"); + switch (Rd->shs.status) + { + case SHS_RENEW: + case SHS_REFRESH: + { + freeSesh(Rd, FALSE, FALSE); + newSesh(Rd, FALSE); + break; + } + + case SHS_VALID: + case SHS_KEEP: + { + // Do nothing here. + break; + } + + case SHS_LOGIN: + case SHS_WIPE: + { +// TODO - should wipe the old one, and create this new one with the users UUID. +// I think that's what we are doing anyway. + freeSesh(Rd, FALSE, FALSE); + newSesh(Rd, FALSE); + break; + } + +// TODO - these three should store state, so they can go back to where the user was (or where they where going) before asking them to confirm their login credentials. + case SHS_IDLE: + case SHS_SECURITY: + case SHS_RELOGIN: + + case SHS_UNKNOWN: + case SHS_NONE: + case SHS_BOGUS: + case SHS_PROBLEM: + case SHS_ANCIENT: + case SHS_NUKE: + { + freeSesh(Rd, FALSE, TRUE); // Wipe mode clears out all of Rd->database, selected Rd->stuff, and the above commented out Rd->shs. + newSesh(Rd, FALSE); + form = "accountLogin"; + doit = "logout"; + Rd->doit = doit; + Rd->form = form; + iF = accountPages->get(accountPages, Rd->form, NULL, false); + sub = iF->subs->get(iF->subs, Rd->doit, NULL, false); + Rd->output = sub->outputForm; + break; + } + } // Return the result. if (0 == e) @@ -6305,8 +6407,9 @@ jit library is loaded or the JIT compiler will not be activated. if ((tmp = configs->getstr(configs, "Ttab", false)) != NULL) {Ttab = tmp; D("Setting Ttab = %s", Ttab);} if ((tmp = configs->getstr(configs, "webRoot", false)) != NULL) {webRoot = tmp; D("Setting webRoot = %s", webRoot);} if ((tmp = configs->getstr(configs, "URL", false)) != NULL) {URL = tmp; D("Setting URL = %s", URL);} - if ((vd = configs->get (configs, "seshTimeOut", NULL, false)) != NULL) {seshTimeOut = (int) *((float *) vd); D("Setting seshTimeOut = %d", seshTimeOut);} + if ((vd = configs->get (configs, "seshRenew", NULL, false)) != NULL) {seshRenew = (int) *((float *) vd); D("Setting seshRenew = %d", seshRenew);} if ((vd = configs->get (configs, "idleTimeOut", NULL, false)) != NULL) {idleTimeOut = (int) *((float *) vd); D("Setting idleTimeOut = %d", idleTimeOut);} + if ((vd = configs->get (configs, "seshTimeOut", NULL, false)) != NULL) {seshTimeOut = (int) *((float *) vd); D("Setting seshTimeOut = %d", seshTimeOut);} if ((vd = configs->get (configs, "newbieTimeOut", NULL, false)) != NULL) {newbieTimeOut = (int) *((float *) vd); D("Setting newbieTimeOut = %d", newbieTimeOut);} if ((tmp = configs->getstr(configs, "ToS", false)) != NULL) {ToS = tmp; D("Setting ToS = %s", ToS);} if ((tmp = configs->getstr(configs, "webIframers", false)) != NULL) {webIframers = tmp; D("Setting webIframers = %s", webIframers);} @@ -6542,6 +6645,7 @@ jit library is loaded or the JIT compiler will not be activated. while (FCGI_Accept() != -1) { reqData *Rd = xzalloc(sizeof(reqData)); + if (-1 == clock_gettime(CLOCK_REALTIME, &Rd->then)) perror_msg("Unable to get the time."); Rd->L = L; @@ -6561,6 +6665,7 @@ jit library is loaded or the JIT compiler will not be activated. Rd->messages = qlist(0); Rd->reply = qgrow(QGROW_THREADSAFE); Rd->outQuery = xstrdup(""); + Rd->shs.status = SHS_UNKNOWN; qhashtbl_obj_t hobj; qlist_obj_t lobj; -- cgit v1.1