aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authoronefang2020-05-07 11:15:43 +1000
committeronefang2020-05-07 11:15:43 +1000
commit2c62c8f69fecda58aa4af9267fb77879d7006837 (patch)
tree895d47a4fc45e65d5dbb098e1d2a1f696a4b9b95
parentComment out database debugging stuff for now. (diff)
downloadopensim-SC_OLD-2c62c8f69fecda58aa4af9267fb77879d7006837.zip
opensim-SC_OLD-2c62c8f69fecda58aa4af9267fb77879d7006837.tar.gz
opensim-SC_OLD-2c62c8f69fecda58aa4af9267fb77879d7006837.tar.bz2
opensim-SC_OLD-2c62c8f69fecda58aa4af9267fb77879d7006837.tar.xz
Rewrite the web session stuff.
-rw-r--r--src/.sledjChisl.conf.lua5
-rw-r--r--src/sledjchisl/sledjchisl.c397
2 files changed, 254 insertions, 148 deletions
diff --git a/src/.sledjChisl.conf.lua b/src/.sledjChisl.conf.lua
index 59cb833..be5bd4b 100644
--- a/src/.sledjChisl.conf.lua
+++ b/src/.sledjChisl.conf.lua
@@ -21,8 +21,9 @@ config =
21 ["webHost"] = "localhost"; 21 ["webHost"] = "localhost";
22 ["URL"] = "sledjchisl.fcgi"; 22 ["URL"] = "sledjchisl.fcgi";
23 ["webIframers"] = ""; -- Space separated list of hosts allowed to iFrame us, coz someone asked. Include the "https://" bit. 23 ["webIframers"] = ""; -- Space separated list of hosts allowed to iFrame us, coz someone asked. Include the "https://" bit.
24 ["seshTimeOut"] = 30 * 60; -- seconds 24 ["seshRenew"] = 10 * 60; -- seconds
25 ["idleTimeOut"] = 24 * 60 * 60; -- seconds 25 ["idleTimeOut"] = 30 * 60; -- seconds
26 ["seshTimeOut"] = 24 * 60 * 60; -- seconds
26 ["newbieTimeOut"] = 30; -- days 27 ["newbieTimeOut"] = 30; -- days
27 ["pepper"] = "My long beard is salt and pepper coloured, though there are no birds in it, only breakfast."; 28 ["pepper"] = "My long beard is salt and pepper coloured, though there are no birds in it, only breakfast.";
28 ["ToS"] = [[ 29 ["ToS"] = [[
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
368 368
369#define HMACSIZE EVP_MAX_MD_SIZE * 2 369#define HMACSIZE EVP_MAX_MD_SIZE * 2
370#define HMACSIZE64 88 370#define HMACSIZE64 88
371
372// Session details about the logged in web user. A sorta state machine. Ish.
373enum reqSessionStatus // Status of the session. Refresh and wipe / nuke -> delete the old session file first.
374{
375 SHS_UNKNOWN = 0, // Haven't looked at the session yet. -> validate it
376 SHS_NONE, // No session at all. -> logout
377 SHS_BOGUS, // Looked at the session, it's bogus. -> nuke and logout
378 SHS_PROBLEM, // Some other problem with the session. -> nuke and logout
379 SHS_VALID, // Session is valid. -> continue
380
381 SHS_LOGIN, // User has just logged in, add UUID to session. -> wipe, add UUID
382
383 SHS_RENEW, // Refresh the session based on timer. -> continue
384 SHS_REFRESH, // Refresh the session for other reason. -> continue
385 SHS_IDLE, // Session has been idle too long. -> relogin
386 SHS_ANCIENT, // Session is way too old. -> nuke and logout
387
388 SHS_SECURITY, // High security task needs users name & password. ->
389 SHS_RELOGIN, // Ask user to login again. ->
390
391 SHS_KEEP, // Keep the session. -> continue
392 SHS_WIPE, // Wipe the session, use users UUID. -> continue
393 SHS_NUKE // Wipe the session, no UUID. -> logout
394};
395
371typedef struct _sesh sesh; 396typedef struct _sesh sesh;
372// Details about the logged in web user.
373struct _sesh 397struct _sesh
374{ 398{
375 char salt[256 + 1], seshID[256 + 1], 399 char salt[256 + 1], seshID[256 + 1],
@@ -377,6 +401,7 @@ struct _sesh
377 leaf[HMACSIZE64 + 6 + 1], *UUID, *name; 401 leaf[HMACSIZE64 + 6 + 1], *UUID, *name;
378 struct timespec timeStamp[2]; 402 struct timespec timeStamp[2];
379 short level; 403 short level;
404 enum reqSessionStatus status;
380 boolean isLinky; 405 boolean isLinky;
381}; 406};
382 407
@@ -394,7 +419,6 @@ struct _reqData
394// pageBuildFunction func; 419// pageBuildFunction func;
395 struct timespec then; 420 struct timespec then;
396 boolean fromDb; 421 boolean fromDb;
397// boolean chillOut, vegOut;
398}; 422};
399 423
400static void showSesh(qgrow_t *reply, sesh *shs) 424static void showSesh(qgrow_t *reply, sesh *shs)
@@ -447,8 +471,9 @@ char *webRoot = "/var/www/html";
447char *URL = "fcgi-bin/sledjchisl.fcgi"; 471char *URL = "fcgi-bin/sledjchisl.fcgi";
448char *ToS = "Be good."; 472char *ToS = "Be good.";
449char *webIframers = ""; 473char *webIframers = "";
450int seshTimeOut = 30 * 60; 474int seshRenew = 10 * 60;
451int idleTimeOut = 24 * 60 * 60; 475int idleTimeOut = 30 * 60;
476int seshTimeOut = 24 * 60 * 60;
452int newbieTimeOut = 30; 477int newbieTimeOut = 30;
453float loadAverageInc = 0.5; 478float loadAverageInc = 0.5;
454int simTimeOut = 45; 479int simTimeOut = 45;
@@ -2910,7 +2935,7 @@ HTMLfile *checkHTMLcache(char *file)
2910. Let them do things as normal, in case this was just someone being mean to them, coz their email addy might be public. 2935. Let them do things as normal, in case this was just someone being mean to them, coz their email addy might be public.
2911. Including the usual logging out and in again with their old password. 2936. Including the usual logging out and in again with their old password.
2912. Warn them on login and any page refresh that there is an outstanding password reset awaiting them. 2937. Warn them on login and any page refresh that there is an outstanding password reset awaiting them.
2913+ email linky, which is some or all of the token result bits strung together, BASE64 encode the result. 2938. email linky, which is some or all of the token result bits strung together, BASE64 encode the result.
2914. regenerate the usual token 2939. regenerate the usual token
2915. user clicks on the linky (or just enters the linky in a field) 2940. user clicks on the linky (or just enters the linky in a field)
2916. validate the linky token. 2941. validate the linky token.
@@ -2930,10 +2955,10 @@ HTMLfile *checkHTMLcache(char *file)
2930 Should warn people on the accountCreationPage that DoB might be used this way. 2955 Should warn people on the accountCreationPage that DoB might be used this way.
2931 ask them for the new password, twice 2956 ask them for the new password, twice
2932 Create a new passwordSalt and passwordHash, store them in the auth table. 2957 Create a new passwordSalt and passwordHash, store them in the auth table.
2933 For validate new user page 2958. For validate new user page
2934. tell them they have validated 2959. tell them they have validated
2935 create their OpenSim account UserAccounts.UserTitle and auth tables, not GridUser table 2960. create their OpenSim account UserAccounts.UserTitle and auth tables, not GridUser table
2936 create their GridUser record. 2961. create their GridUser record.
2937. update their UserAccounts.Userlevel and UserAccounts.UserTitle 2962. update their UserAccounts.Userlevel and UserAccounts.UserTitle
2938. send them to the login page. 2963. send them to the login page.
2939. regenerate the usual token 2964. regenerate the usual token
@@ -3093,9 +3118,10 @@ I think this means send a new cookie.
3093*/ 3118*/
3094static void bitchSession(reqData *Rd, char *message, char *log) 3119static void bitchSession(reqData *Rd, char *message, char *log)
3095{ 3120{
3096 addStrL(Rd->errors, message); 3121 if ('\0' != message[0])
3122 addStrL(Rd->errors, message);
3097 C("%s %s %s - %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), Rd->shs.UUID, getStrH(Rd->stuff, "name"), message, log); 3123 C("%s %s %s - %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), Rd->shs.UUID, getStrH(Rd->stuff, "name"), message, log);
3098// Rd->vegOut = TRUE; 3124 Rd->shs.status = SHS_BOGUS;
3099} 3125}
3100 3126
3101 3127
@@ -3182,7 +3208,7 @@ int LuaToHash(reqData *Rd, char *file, char *var, qhashtbl_t *tnm, int ret, stru
3182 3208
3183 if (status) 3209 if (status)
3184 { 3210 {
3185 bitchSession(Rd, "No such thing.", "Can't load file."); 3211 bitch(Rd, "No such thing.", "Can't load file.");
3186 E("Couldn't load file: %s", lua_tostring(Rd->L, -1)); 3212 E("Couldn't load file: %s", lua_tostring(Rd->L, -1));
3187 ret++; 3213 ret++;
3188 } 3214 }
@@ -3192,7 +3218,7 @@ int LuaToHash(reqData *Rd, char *file, char *var, qhashtbl_t *tnm, int ret, stru
3192 3218
3193 if (result) 3219 if (result)
3194 { 3220 {
3195 bitchSession(Rd, "Broken thing.", "Can't run file."); 3221 bitch(Rd, "Broken thing.", "Can't run file.");
3196 E("Failed to run script: %s", lua_tostring(Rd->L, -1)); 3222 E("Failed to run script: %s", lua_tostring(Rd->L, -1));
3197 ret++; 3223 ret++;
3198 } 3224 }
@@ -4080,6 +4106,10 @@ static int sessionValidate(reqData *Rd, inputForm *iF, inputValue *iV)
4080 char *t = xstrdup(hashish); 4106 char *t = xstrdup(hashish);
4081 size_t sz = qB64_decode(t); 4107 size_t sz = qB64_decode(t);
4082 4108
4109// TODO - should validate the cookie version as well, if it was sent.
4110// 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.
4111// Though only if there's a munchie in the body?
4112 I("Validating LINKY hashish %s", hashish);
4083 free(hashish); 4113 free(hashish);
4084 hashish = qhex_encode(t, sz); 4114 hashish = qhex_encode(t, sz);
4085 linky = TRUE; 4115 linky = TRUE;
@@ -4093,15 +4123,18 @@ static int sessionValidate(reqData *Rd, inputForm *iF, inputValue *iV)
4093 { 4123 {
4094 if (strcmp("logout", Rd->doit) == 0) 4124 if (strcmp("logout", Rd->doit) == 0)
4095 { 4125 {
4096 d("Not checking session, coz we are logging out."); 4126 I("Not checking session, coz we are logging out.");
4127 Rd->shs.status = SHS_NUKE;
4097 return ret; 4128 return ret;
4098 } 4129 }
4099 bitchSession(Rd, "Invalid session.", "No or blank hashish or toke_n_munchie."); 4130 bitchSession(Rd, "Invalid session.", "No or blank hashish or toke_n_munchie.");
4131 Rd->shs.status = SHS_NONE;
4100 ret++; 4132 ret++;
4101 } 4133 }
4134 else
4135 I("Validating SESSION hashish %s", hashish);
4102 } 4136 }
4103 4137
4104//d("O hashish %s", hashish);
4105//d("O toke_n_munchie %s", toke_n_munchie); 4138//d("O toke_n_munchie %s", toke_n_munchie);
4106//d("O munchie %s", munchie); 4139//d("O munchie %s", munchie);
4107 if (0 == ret) 4140 if (0 == ret)
@@ -4120,7 +4153,15 @@ static int sessionValidate(reqData *Rd, inputForm *iF, inputValue *iV)
4120 ret = LuaToHash(Rd, t0, "toke_n_munchie", tnm, ret, &st, &now, "session"); 4153 ret = LuaToHash(Rd, t0, "toke_n_munchie", tnm, ret, &st, &now, "session");
4121 free(t0); 4154 free(t0);
4122 4155
4123 if (0 == ret) 4156 if (0 != ret)
4157 {
4158 // 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.
4159 // They might also have a stale doit and form cookie.
4160// bitchSession(Rd, "Invalid session.", "No session file.");
4161 bitchSession(Rd, "", "No session file.");
4162 ret++;
4163 }
4164 else
4124 { 4165 {
4125 // This is apparently controversial, I added it coz some of the various security docs suggested it's a good idea. 4166 // This is apparently controversial, I added it coz some of the various security docs suggested it's a good idea.
4126 // https://security.stackexchange.com/questions/139952/why-arent-sessions-exclusive-to-an-ip-address?rq=1 4167 // 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)
4148 { 4189 {
4149 if (strcmp(t1, munchie) != 0) 4190 if (strcmp(t1, munchie) != 0)
4150 { 4191 {
4151 bitchSession(Rd, "Wrong munchie for session.", "HMAC(seshID + timeStamp) != munchie"); 4192// 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.
4193 bitchSession(Rd, "Wrong munchie for session, may have been eaten, please try again.", "HMAC(seshID + timeStamp) != munchie");
4152 ret++; 4194 ret++;
4153 } 4195 }
4154 else 4196 else
@@ -4182,88 +4224,94 @@ static int sessionValidate(reqData *Rd, inputForm *iF, inputValue *iV)
4182 ret++; 4224 ret++;
4183 } 4225 }
4184 free(t1); 4226 free(t1);
4185
4186 } 4227 }
4187 4228
4229// TODO - should carefully review all of this, especially the moving of session data to and fro.
4188 if (0 == ret) 4230 if (0 == ret)
4189 { 4231 {
4190 if (now.tv_sec > st.st_mtim.tv_sec + idleTimeOut) 4232W("Validated session.");
4233 sesh *shs = &Rd->shs;
4234
4235 qstrcpy(shs->leaf, sizeof(shs->leaf), leaf);
4236 shs->name = tnm->getstr(tnm, "name", true); // LEAKY!
4237 shs->UUID = tnm->getstr(tnm, "UUID", true); // LEAKY!
4238 if (linky)
4191 { 4239 {
4192 W("Session idled out."); 4240W("Validated session linky.");
4193// Rd->vegOut = TRUE; 4241 addStrL(Rd->messages, "Congratulations, you have validated your new account. Now you can log onto the web site.");
4242 addStrL(Rd->messages, "NOTE - you wont be able to log onto the grid until your new account has been approved.");
4243 Rd->lnk = xzalloc(sizeof(sesh));
4244 Rd->lnk->status = SHS_NUKE;
4245 qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), leaf);
4246 freeSesh(Rd, linky, FALSE);
4247 qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), "");
4248 Rd->doit = "validate";
4249 Rd->output = "accountLogin";
4250 Rd->form = "accountLogin";
4251// TODO - we might want to delete their old .lua session as well. Maybe? Don't think we have any suitable codes to find it.
4194 } 4252 }
4195 else 4253 else
4196 { 4254 {
4255 char *level = tnm->getstr(tnm, "level", false);
4256
4257 // Check for session timeouts etc.
4197 if (now.tv_sec > st.st_mtim.tv_sec + seshTimeOut) 4258 if (now.tv_sec > st.st_mtim.tv_sec + seshTimeOut)
4198 { 4259 {
4199 W("Session timed out."); 4260 bitch(Rd, "Session timed out.", "No activity for longer than seshTimeOut, session is ancient.");
4200// Rd->vegOut = TRUE; 4261 ret++;
4262 Rd->shs.status = SHS_ANCIENT;
4201 } 4263 }
4202 else 4264 else if (now.tv_sec > st.st_mtim.tv_sec + idleTimeOut)
4203 { 4265 {
4204W("Validated session."); 4266 bitch(Rd, "Session idled out.", "No activity for longer than idleTimeOut, session is idle.");
4205 sesh *shs = &Rd->shs; 4267 ret++;
4206 4268 Rd->shs.status = SHS_IDLE;
4207 qstrcpy(shs->leaf, sizeof(shs->leaf), leaf);
4208 if (linky)
4209 {
4210W("Validated session linky.");
4211 addStrL(Rd->messages, "Congratulations, you have validated your new account. Now you can log onto the web site.");
4212 addStrL(Rd->messages, "NOTE - you wont be able to log onto the grid until your new account has been approved.");
4213 Rd->lnk = xzalloc(sizeof(sesh));
4214 qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), leaf);
4215 freeSesh(Rd, linky, FALSE);
4216 qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), "");
4217 Rd->doit = "validate";
4218 Rd->output = "accountLogin";
4219 Rd->form = "accountLogin";
4220// TODO - we might want to delete their old .lua session as well. Maybe? Don't think we have any suitable codes to find it.
4221 }
4222 else
4223 {
4224 char *level = tnm->getstr(tnm, "level", false);
4225
4226 if (NULL == level)
4227 level = "-256";
4228 qstrcpy(shs->sesh, sizeof(shs->sesh), seshion);
4229 qstrcpy(shs->toke_n_munchie, sizeof(shs->toke_n_munchie), toke_n_munchie);
4230 qstrcpy(shs->hashish, sizeof(shs->hashish), hashish);
4231 qstrcpy(shs->munchie, sizeof(shs->munchie), munchie);
4232 qstrcpy(shs->salt, sizeof(shs->salt), tnm->getstr(tnm, "salt", false));
4233 qstrcpy(shs->seshID, sizeof(shs->seshID), tnm->getstr(tnm, "seshID", false));
4234 shs->level = atoi(level);
4235// TODO - get level from somewhere and stuff it in shs.
4236 shs->timeStamp[0].tv_nsec = UTIME_OMIT;
4237 shs->timeStamp[0].tv_sec = UTIME_OMIT;
4238 memcpy(&shs->timeStamp[1], &st.st_mtim, sizeof(struct timespec));
4239 }
4240 shs->name = tnm->getstr(tnm, "name", true); // LEAKY!
4241 shs->UUID = tnm->getstr(tnm, "UUID", true); // LEAKY!
4242 } 4269 }
4270 else if (now.tv_sec > st.st_mtim.tv_sec + seshRenew)
4271 {
4272 D("Session needs renewing.");
4273 Rd->shs.status = SHS_RENEW;
4274 }
4275 else
4276 Rd->shs.status = SHS_VALID;
4277
4278 if (NULL == level)
4279 level = "-256";
4280 qstrcpy(shs->sesh, sizeof(shs->sesh), seshion);
4281 qstrcpy(shs->toke_n_munchie, sizeof(shs->toke_n_munchie), toke_n_munchie);
4282 qstrcpy(shs->hashish, sizeof(shs->hashish), hashish);
4283 qstrcpy(shs->munchie, sizeof(shs->munchie), munchie);
4284 qstrcpy(shs->salt, sizeof(shs->salt), tnm->getstr(tnm, "salt", false));
4285 qstrcpy(shs->seshID, sizeof(shs->seshID), tnm->getstr(tnm, "seshID", false));
4286 shs->level = atoi(level);
4287// TODO - get level from somewhere and stuff it in shs.
4288 shs->timeStamp[0].tv_nsec = UTIME_OMIT;
4289 shs->timeStamp[0].tv_sec = UTIME_OMIT;
4290 memcpy(&shs->timeStamp[1], &st.st_mtim, sizeof(struct timespec));
4291 }
4292 }
4243 4293
4244 qhashtbl_obj_t obj; 4294 qhashtbl_obj_t obj;
4245 4295
4246 memset((void*)&obj, 0, sizeof(obj)); 4296 memset((void*)&obj, 0, sizeof(obj));
4247 tnm->lock(tnm); 4297 tnm->lock(tnm);
4248 while(tnm->getnext(tnm, &obj, false) == true) 4298 while(tnm->getnext(tnm, &obj, false) == true)
4249 { 4299 {
4250 char *n = obj.name; 4300 char *n = obj.name;
4251 4301
4252 if ((strcmp("salt", n) != 0) && (strcmp("seshID", n) != 0) && (strcmp("UUID", n) != 0)) 4302 if ((strcmp("salt", n) != 0) && (strcmp("seshID", n) != 0) && (strcmp("UUID", n) != 0))
4253 { 4303 {
4254t("SessionValidate() Lua read %s = %s", n, (char *) obj.data); 4304t("SessionValidate() Lua read %s = %s", n, (char *) obj.data);
4255 Rd->stuff->putstr(Rd->stuff, obj.name, (char *) obj.data); 4305 Rd->stuff->putstr(Rd->stuff, obj.name, (char *) obj.data);
4256 }
4257 }
4258 tnm->unlock(tnm);
4259
4260// TODO - check this.
4261// Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", tnm->getstr(tnm, "UUID", false));
4262 } 4306 }
4263 } 4307 }
4264 free(munchie); 4308 tnm->unlock(tnm);
4265 free(seshion); 4309
4310// TODO - check this.
4311// Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", tnm->getstr(tnm, "UUID", false));
4266 } 4312 }
4313 free(munchie);
4314 free(seshion);
4267 } 4315 }
4268 free(leaf); 4316 free(leaf);
4269 tnm->free(tnm); 4317 tnm->free(tnm);
@@ -5121,13 +5169,13 @@ static int accountCreateSub(reqData *Rd, inputForm *iF, inputValue *iV)
5121 int ret = 0; 5169 int ret = 0;
5122 char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName"); 5170 char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName");
5123 int c = accountRead(Rd, uuid, first, last); 5171 int c = accountRead(Rd, uuid, first, last);
5124 boolean wipe = FALSE;
5125 5172
5126 if (strcmp("POST", Rd->Method) == 0) 5173 if (strcmp("POST", Rd->Method) == 0)
5127 { 5174 {
5128 if (0 != c) 5175 if (0 != c)
5129 { 5176 {
5130 bitch(Rd, "Cannot create account.", "Account exists."); 5177 bitch(Rd, "Cannot create account.", "Account exists.");
5178 Rd->shs.status = SHS_NUKE;
5131 ret++; 5179 ret++;
5132 } 5180 }
5133 else 5181 else
@@ -5142,22 +5190,13 @@ static int accountCreateSub(reqData *Rd, inputForm *iF, inputValue *iV)
5142 Rd->stuff->putstr(Rd->stuff, "passHash", h); 5190 Rd->stuff->putstr(Rd->stuff, "passHash", h);
5143 Rd->stuff->putstr(Rd->stuff, "passSalt", salt); 5191 Rd->stuff->putstr(Rd->stuff, "passSalt", salt);
5144 free(h); 5192 free(h);
5193 Rd->shs.status = SHS_REFRESH;
5145 } 5194 }
5146 free(salt); 5195 free(salt);
5147 if (0 != ret) 5196 if (0 != ret)
5148 { 5197 Rd->shs.status = SHS_NUKE;
5149 wipe = TRUE;
5150 if (NULL != Rd->shs.name) free(Rd->shs.name);
5151 Rd->shs.name = NULL;
5152 if (NULL != Rd->shs.UUID) free(Rd->shs.UUID);
5153 Rd->shs.UUID = NULL;
5154 Rd->shs.level = -256;
5155 Rd->output = "accountLogin";
5156 }
5157 } 5198 }
5158 } 5199 }
5159 freeSesh(Rd, FALSE, wipe);
5160 newSesh(Rd, FALSE);
5161 return ret; 5200 return ret;
5162} 5201}
5163 5202
@@ -5166,11 +5205,11 @@ static int accountAddSub(reqData *Rd, inputForm *iF, inputValue *iV)
5166 int ret = 0; 5205 int ret = 0;
5167 char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName"); 5206 char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName");
5168 int c = accountRead(Rd, uuid, first, last); 5207 int c = accountRead(Rd, uuid, first, last);
5169 boolean wipe = FALSE;
5170 5208
5171 if (0 != c) 5209 if (0 != c)
5172 { 5210 {
5173 bitch(Rd, "Cannot add account.", "Account exists."); 5211 bitch(Rd, "Cannot add account.", "Account exists.");
5212 Rd->shs.status = SHS_NUKE;
5174 ret++; 5213 ret++;
5175 } 5214 }
5176 else if ((0 == ret) && (strcmp("POST", Rd->Method) == 0)) 5215 else if ((0 == ret) && (strcmp("POST", Rd->Method) == 0))
@@ -5180,35 +5219,27 @@ static int accountAddSub(reqData *Rd, inputForm *iF, inputValue *iV)
5180 if (NULL == h) 5219 if (NULL == h)
5181 { 5220 {
5182 ret++; 5221 ret++;
5183 wipe = TRUE; 5222 Rd->shs.status = SHS_NUKE;
5184 if (NULL != Rd->shs.name) free(Rd->shs.name);
5185 Rd->shs.name = NULL;
5186 if (NULL != Rd->shs.UUID) free(Rd->shs.UUID);
5187 Rd->shs.UUID = NULL;
5188 Rd->shs.level = -256;
5189 Rd->output = "accountLogin";
5190 } 5223 }
5191 else 5224 else
5192 { 5225 {
5193
5194 free(h); 5226 free(h);
5195 generateAccountUUID(Rd); 5227 generateAccountUUID(Rd);
5196 Rd->stuff->putstr(Rd->stuff, "passwordHash", getStrH(Rd->stuff, "passHash")); 5228 Rd->stuff->putstr(Rd->stuff, "passwordHash", getStrH(Rd->stuff, "passHash"));
5197 Rd->stuff->putstr(Rd->stuff, "passwordSalt", getStrH(Rd->stuff, "passSalt")); 5229 Rd->stuff->putstr(Rd->stuff, "passwordSalt", getStrH(Rd->stuff, "passSalt"));
5198 Rd->shs.level = -200; 5230 Rd->shs.level = -200;
5199 Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", "-200"); 5231 Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", "-200");
5200 freeSesh(Rd, FALSE, wipe); 5232 // Generate the linky for the email.
5201 newSesh(Rd, TRUE); 5233 newSesh(Rd, TRUE);
5202 accountWrite(Rd); 5234 accountWrite(Rd);
5203// log them in 5235 // log them in
5204 I("Logged on %s %s Level %d %s", Rd->shs.UUID, getStrH(Rd->stuff, "name"), Rd->shs.level, getLevel(Rd->shs.level)); 5236 I("Logged on %s %s Level %d %s", Rd->shs.UUID, getStrH(Rd->stuff, "name"), Rd->shs.level, getLevel(Rd->shs.level));
5205 Rd->output = "accountView"; 5237 Rd->output = "accountView";
5206 Rd->form = "accountView"; 5238 Rd->form = "accountView";
5207 Rd->doit = "login"; 5239 Rd->doit = "login";
5240 Rd->shs.status = SHS_LOGIN;
5208 } 5241 }
5209 } 5242 }
5210 freeSesh(Rd, FALSE, wipe);
5211 newSesh(Rd, FALSE);
5212 return ret; 5243 return ret;
5213} 5244}
5214 5245
@@ -5217,7 +5248,6 @@ static int accountSaveSub(reqData *Rd, inputForm *iF, inputValue *iV)
5217 int ret = 0; 5248 int ret = 0;
5218 char *uuid = Rd->shs.UUID, *first = getStrH(Rd->body, "user"), *last = NULL; 5249 char *uuid = Rd->shs.UUID, *first = getStrH(Rd->body, "user"), *last = NULL;
5219 int c = accountRead(Rd, NULL, first, last); 5250 int c = accountRead(Rd, NULL, first, last);
5220 boolean wipe = FALSE;
5221 5251
5222 if (1 != c) 5252 if (1 != c)
5223 { 5253 {
@@ -5257,8 +5287,6 @@ static int accountSaveSub(reqData *Rd, inputForm *iF, inputValue *iV)
5257// TODO - this isn't being shown. 5287// TODO - this isn't being shown.
5258 addStrL(Rd->messages, "Account saved."); 5288 addStrL(Rd->messages, "Account saved.");
5259 } 5289 }
5260// freeSesh(Rd, FALSE, wipe);
5261// newSesh(Rd, FALSE);
5262 return ret; 5290 return ret;
5263} 5291}
5264 5292
@@ -5267,7 +5295,6 @@ static int accountValidateSub(reqData *Rd, inputForm *iF, inputValue *iV)
5267 int ret = 0; 5295 int ret = 0;
5268 char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName"); 5296 char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName");
5269 int c = accountRead(Rd, uuid, first, last); 5297 int c = accountRead(Rd, uuid, first, last);
5270 boolean wipe = FALSE;
5271 5298
5272 if (1 != c) 5299 if (1 != c)
5273 { 5300 {
@@ -5292,10 +5319,11 @@ static int accountValidateSub(reqData *Rd, inputForm *iF, inputValue *iV)
5292 Rd->shs.level = -100; 5319 Rd->shs.level = -100;
5293 Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", "-100"); 5320 Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", "-100");
5294 accountWrite(Rd); 5321 accountWrite(Rd);
5295 wipe = TRUE; 5322 Rd->doit = "logout";
5323 Rd->output = "accountLogin";
5324 Rd->form = "accountLogin";
5325 Rd->shs.status = SHS_NUKE;
5296 } 5326 }
5297 freeSesh(Rd, FALSE, wipe);
5298 newSesh(Rd, FALSE);
5299 return ret; 5327 return ret;
5300} 5328}
5301 5329
@@ -5305,20 +5333,13 @@ static int accountViewSub(reqData *Rd, inputForm *iF, inputValue *iV)
5305 int ret = 0; 5333 int ret = 0;
5306 char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName"); 5334 char *uuid = Rd->shs.UUID, *first = getStrH(Rd->stuff, "firstName"), *last = getStrH(Rd->stuff, "lastName");
5307 int c = accountRead(Rd, uuid, first, last); 5335 int c = accountRead(Rd, uuid, first, last);
5308 boolean wipe = FALSE;
5309 5336
5310d("Sub accountViewSub() %s %s %s", uuid, first, last); 5337d("Sub accountViewSub() %s %s %s", uuid, first, last);
5311 if (1 != c) 5338 if (1 != c)
5312 { 5339 {
5313 bitch(Rd, "Cannot view account.", "Account doesn't exist."); 5340 bitch(Rd, "Cannot view account.", "Account doesn't exist.");
5314 ret++; 5341 ret++;
5315 wipe = TRUE; 5342 Rd->shs.status = SHS_NUKE;
5316 if (NULL != Rd->shs.name) free(Rd->shs.name);
5317 Rd->shs.name = NULL;
5318 if (NULL != Rd->shs.UUID) free(Rd->shs.UUID);
5319 Rd->shs.UUID = NULL;
5320 Rd->shs.level = -256;
5321 Rd->output = "accountLogin";
5322 } 5343 }
5323 else 5344 else
5324 { 5345 {
@@ -5331,26 +5352,19 @@ d("Sub accountViewSub() %s %s %s", uuid, first, last);
5331 if (NULL == h) 5352 if (NULL == h)
5332 { 5353 {
5333 ret++; 5354 ret++;
5334 wipe = TRUE; 5355 Rd->shs.status = SHS_NUKE;
5335 if (NULL != Rd->shs.name) free(Rd->shs.name);
5336 Rd->shs.name = NULL;
5337 if (NULL != Rd->shs.UUID) free(Rd->shs.UUID);
5338 Rd->shs.UUID = NULL;
5339 Rd->shs.level = -256;
5340 Rd->output = "accountLogin";
5341 } 5356 }
5342 else 5357 else
5343 { 5358 {
5344 Rd->shs.level = atoi(getStrH(Rd->database, "UserAccounts.UserLevel")); 5359 Rd->shs.level = atoi(getStrH(Rd->database, "UserAccounts.UserLevel"));
5345 Rd->shs.name = Rd->database->getstr(Rd->database, "Lua.name", true); 5360 Rd->shs.name = Rd->database->getstr(Rd->database, "Lua.name", true);
5346 Rd->shs.UUID = Rd->database->getstr(Rd->database, "UserAccounts.PrincipalID", true); 5361 Rd->shs.UUID = Rd->database->getstr(Rd->database, "UserAccounts.PrincipalID", true);
5347 free(h); 5362 free(h);
5348 I("Logged on %s %s Level %d %s", Rd->shs.UUID, Rd->shs.name, Rd->shs.level, getLevel(Rd->shs.level)); 5363 I("Logged on %s %s Level %d %s", Rd->shs.UUID, Rd->shs.name, Rd->shs.level, getLevel(Rd->shs.level));
5364 Rd->shs.status = SHS_LOGIN;
5349 } 5365 }
5350 } 5366 }
5351 } 5367 }
5352 freeSesh(Rd, FALSE, wipe);
5353 newSesh(Rd, FALSE);
5354 5368
5355 return ret; 5369 return ret;
5356} 5370}
@@ -5392,19 +5406,8 @@ static int accountOutSub(reqData *Rd, inputForm *iF, inputValue *iV)
5392// bitch(Rd, "Cannot logout account.", "Account doesn't exist."); 5406// bitch(Rd, "Cannot logout account.", "Account doesn't exist.");
5393// ret++; 5407// ret++;
5394 } 5408 }
5395 else
5396 {
5397// log the user out if they are logged in
5398 if (NULL != Rd->shs.name) free(Rd->shs.name);
5399 Rd->shs.name = NULL;
5400 if (NULL != Rd->shs.UUID) free(Rd->shs.UUID);
5401 Rd->shs.UUID = NULL;
5402 Rd->shs.level = -256;
5403 Rd->output = "accountLogin";
5404 }
5405 5409
5406 freeSesh(Rd, FALSE, TRUE); 5410 Rd->shs.status = SHS_NUKE;
5407 newSesh(Rd, FALSE);
5408 return ret; 5411 return ret;
5409} 5412}
5410 5413
@@ -5741,6 +5744,34 @@ void listPage(reqData *Rd, char *message)
5741} 5744}
5742*/ 5745*/
5743 5746
5747
5748void sessionStateEngine(reqData *Rd, char *type)
5749{
5750 switch (Rd->shs.status)
5751 {
5752 case SHS_UNKNOWN: d("sessionStateEngine(SHS_UNKNOWN, %s)", type); break;
5753 case SHS_NONE: d("sessionStateEngine(SHS_NONE, %s)", type); break;
5754 case SHS_BOGUS: d("sessionStateEngine(SHS_BOGUS, %s)", type); break;
5755 case SHS_PROBLEM: d("sessionStateEngine(SHS_PROBLEM, %s)", type); break;
5756 case SHS_VALID: d("sessionStateEngine(SHS_VALID, %s)", type); break;
5757
5758 case SHS_LOGIN: d("sessionStateEngine(SHS_LOGIN, %s)", type); break;
5759
5760 case SHS_RENEW: d("sessionStateEngine(SHS_RENEW, %s)", type); break;
5761 case SHS_REFRESH: d("sessionStateEngine(SHS_REFRESH, %s)", type); break;
5762 case SHS_IDLE: d("sessionStateEngine(SHS_IDLE, %s)", type); break;
5763 case SHS_ANCIENT: d("sessionStateEngine(SHS_ANCIENT, %s)", type); break;
5764
5765 case SHS_SECURITY: d("sessionStateEngine(SHS_SECURITY, %s)", type); break;
5766 case SHS_RELOGIN: d("sessionStateEngine(SHS_RELOGIN, %s)", type); break;
5767
5768 case SHS_KEEP: d("sessionStateEngine(SHS_KEEP, %s)", type); break;
5769 case SHS_WIPE: d("sessionStateEngine(SHS_WIPE, %s)", type); break;
5770 case SHS_NUKE: d("sessionStateEngine(SHS_NUKE, %s)", type); break;
5771 }
5772}
5773
5774
5744void account_html(char *file, reqData *Rd, HTMLfile *thisFile) 5775void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
5745{ 5776{
5746 inputForm *iF; 5777 inputForm *iF;
@@ -5777,6 +5808,7 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
5777 bitch(Rd, "Invalid referer.", ref); 5808 bitch(Rd, "Invalid referer.", ref);
5778 D("Invalid referer - %s isn't %s", ref, href); 5809 D("Invalid referer - %s isn't %s", ref, href);
5779 form = "accountLogin"; 5810 form = "accountLogin";
5811 Rd->shs.status = SHS_PROBLEM;
5780 } 5812 }
5781 free(href); 5813 free(href);
5782 } 5814 }
@@ -5790,6 +5822,7 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
5790 bitch(Rd, "Invalid HOST.", ref); 5822 bitch(Rd, "Invalid HOST.", ref);
5791 D("Invalid HOST - %s isn't %s", ref, href); 5823 D("Invalid HOST - %s isn't %s", ref, href);
5792 form = "accountLogin"; 5824 form = "accountLogin";
5825 Rd->shs.status = SHS_PROBLEM;
5793 } 5826 }
5794 5827
5795 // Redirect to HTTPS if it's HTTP. 5828 // Redirect to HTTPS if it's HTTP.
@@ -5892,11 +5925,17 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
5892 if ('\0' == form[0]) 5925 if ('\0' == form[0])
5893 form = getStrH(Rd->cookies, "form"); 5926 form = getStrH(Rd->cookies, "form");
5894 if ('\0' == form[0]) 5927 if ('\0' == form[0])
5928 {
5895 form = "accountLogin"; 5929 form = "accountLogin";
5930 Rd->shs.status = SHS_NUKE;
5931 }
5896 if ('\0' == doit[0]) 5932 if ('\0' == doit[0])
5897 doit = getStrH(Rd->cookies, "doit"); 5933 doit = getStrH(Rd->cookies, "doit");
5898 if ('\0' == doit[0]) 5934 if ('\0' == doit[0])
5935 {
5899 doit = "logout"; 5936 doit = "logout";
5937 Rd->shs.status = SHS_NUKE;
5938 }
5900 if ('\0' != doit[0]) 5939 if ('\0' != doit[0])
5901 { 5940 {
5902 setCookie(Rd, "doit", doit); 5941 setCookie(Rd, "doit", doit);
@@ -5909,6 +5948,7 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
5909 E("No such account page - %s", form); 5948 E("No such account page - %s", form);
5910 form = "accountLogin"; 5949 form = "accountLogin";
5911 doit = "logout"; 5950 doit = "logout";
5951 Rd->shs.status = SHS_PROBLEM;
5912 iF = accountPages->get(accountPages, form, NULL, false); 5952 iF = accountPages->get(accountPages, form, NULL, false);
5913 } 5953 }
5914 sub = iF->subs->get(iF->subs, doit, NULL, false); 5954 sub = iF->subs->get(iF->subs, doit, NULL, false);
@@ -5917,11 +5957,12 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
5917 E("No such account action - %s", doit); 5957 E("No such account action - %s", doit);
5918 form = "accountLogin"; 5958 form = "accountLogin";
5919 doit = "logout"; 5959 doit = "logout";
5960 Rd->shs.status = SHS_PROBLEM;
5920 iF = accountPages->get(accountPages, form, NULL, false); 5961 iF = accountPages->get(accountPages, form, NULL, false);
5921 sub = iF->subs->get(iF->subs, doit, NULL, false); 5962 sub = iF->subs->get(iF->subs, doit, NULL, false);
5922 } 5963 }
5923 5964
5924 // Special for showing another users details. 5965 // Special for showing a users details.
5925 if ('\0' != getStrH(Rd->queries, "user")[0]) 5966 if ('\0' != getStrH(Rd->queries, "user")[0])
5926 { 5967 {
5927 doit = "edit"; 5968 doit = "edit";
@@ -5941,6 +5982,8 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
5941 inputValue *iV = xzalloc(count * sizeof(inputValue)); 5982 inputValue *iV = xzalloc(count * sizeof(inputValue));
5942 qlisttbl_obj_t obj; 5983 qlisttbl_obj_t obj;
5943 5984
5985 sessionStateEngine(Rd, "collected");
5986
5944 if (strcmp("cancel", sub->name) != 0) 5987 if (strcmp("cancel", sub->name) != 0)
5945 { 5988 {
5946 5989
@@ -5995,6 +6038,8 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
5995 form = Rd->form; 6038 form = Rd->form;
5996 } 6039 }
5997 6040
6041 sessionStateEngine(Rd, "validated");
6042
5998 // Submit the data. Reload input form and sub in case things got changed by the validation functions. 6043 // Submit the data. Reload input form and sub in case things got changed by the validation functions.
5999 iF = accountPages->get(accountPages, Rd->form, NULL, false); 6044 iF = accountPages->get(accountPages, Rd->form, NULL, false);
6000 sub = iF->subs->get(iF->subs, Rd->doit, NULL, false); 6045 sub = iF->subs->get(iF->subs, Rd->doit, NULL, false);
@@ -6010,6 +6055,63 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
6010 free(iV); 6055 free(iV);
6011 6056
6012 } 6057 }
6058 else
6059 {
6060 sessionStateEngine(Rd, "CANCELLED");
6061 }
6062
6063 sessionStateEngine(Rd, "submited");
6064 switch (Rd->shs.status)
6065 {
6066 case SHS_RENEW:
6067 case SHS_REFRESH:
6068 {
6069 freeSesh(Rd, FALSE, FALSE);
6070 newSesh(Rd, FALSE);
6071 break;
6072 }
6073
6074 case SHS_VALID:
6075 case SHS_KEEP:
6076 {
6077 // Do nothing here.
6078 break;
6079 }
6080
6081 case SHS_LOGIN:
6082 case SHS_WIPE:
6083 {
6084// TODO - should wipe the old one, and create this new one with the users UUID.
6085// I think that's what we are doing anyway.
6086 freeSesh(Rd, FALSE, FALSE);
6087 newSesh(Rd, FALSE);
6088 break;
6089 }
6090
6091// 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.
6092 case SHS_IDLE:
6093 case SHS_SECURITY:
6094 case SHS_RELOGIN:
6095
6096 case SHS_UNKNOWN:
6097 case SHS_NONE:
6098 case SHS_BOGUS:
6099 case SHS_PROBLEM:
6100 case SHS_ANCIENT:
6101 case SHS_NUKE:
6102 {
6103 freeSesh(Rd, FALSE, TRUE); // Wipe mode clears out all of Rd->database, selected Rd->stuff, and the above commented out Rd->shs.
6104 newSesh(Rd, FALSE);
6105 form = "accountLogin";
6106 doit = "logout";
6107 Rd->doit = doit;
6108 Rd->form = form;
6109 iF = accountPages->get(accountPages, Rd->form, NULL, false);
6110 sub = iF->subs->get(iF->subs, Rd->doit, NULL, false);
6111 Rd->output = sub->outputForm;
6112 break;
6113 }
6114 }
6013 6115
6014 // Return the result. 6116 // Return the result.
6015 if (0 == e) 6117 if (0 == e)
@@ -6305,8 +6407,9 @@ jit library is loaded or the JIT compiler will not be activated.
6305 if ((tmp = configs->getstr(configs, "Ttab", false)) != NULL) {Ttab = tmp; D("Setting Ttab = %s", Ttab);} 6407 if ((tmp = configs->getstr(configs, "Ttab", false)) != NULL) {Ttab = tmp; D("Setting Ttab = %s", Ttab);}
6306 if ((tmp = configs->getstr(configs, "webRoot", false)) != NULL) {webRoot = tmp; D("Setting webRoot = %s", webRoot);} 6408 if ((tmp = configs->getstr(configs, "webRoot", false)) != NULL) {webRoot = tmp; D("Setting webRoot = %s", webRoot);}
6307 if ((tmp = configs->getstr(configs, "URL", false)) != NULL) {URL = tmp; D("Setting URL = %s", URL);} 6409 if ((tmp = configs->getstr(configs, "URL", false)) != NULL) {URL = tmp; D("Setting URL = %s", URL);}
6308 if ((vd = configs->get (configs, "seshTimeOut", NULL, false)) != NULL) {seshTimeOut = (int) *((float *) vd); D("Setting seshTimeOut = %d", seshTimeOut);} 6410 if ((vd = configs->get (configs, "seshRenew", NULL, false)) != NULL) {seshRenew = (int) *((float *) vd); D("Setting seshRenew = %d", seshRenew);}
6309 if ((vd = configs->get (configs, "idleTimeOut", NULL, false)) != NULL) {idleTimeOut = (int) *((float *) vd); D("Setting idleTimeOut = %d", idleTimeOut);} 6411 if ((vd = configs->get (configs, "idleTimeOut", NULL, false)) != NULL) {idleTimeOut = (int) *((float *) vd); D("Setting idleTimeOut = %d", idleTimeOut);}
6412 if ((vd = configs->get (configs, "seshTimeOut", NULL, false)) != NULL) {seshTimeOut = (int) *((float *) vd); D("Setting seshTimeOut = %d", seshTimeOut);}
6310 if ((vd = configs->get (configs, "newbieTimeOut", NULL, false)) != NULL) {newbieTimeOut = (int) *((float *) vd); D("Setting newbieTimeOut = %d", newbieTimeOut);} 6413 if ((vd = configs->get (configs, "newbieTimeOut", NULL, false)) != NULL) {newbieTimeOut = (int) *((float *) vd); D("Setting newbieTimeOut = %d", newbieTimeOut);}
6311 if ((tmp = configs->getstr(configs, "ToS", false)) != NULL) {ToS = tmp; D("Setting ToS = %s", ToS);} 6414 if ((tmp = configs->getstr(configs, "ToS", false)) != NULL) {ToS = tmp; D("Setting ToS = %s", ToS);}
6312 if ((tmp = configs->getstr(configs, "webIframers", false)) != NULL) {webIframers = tmp; D("Setting webIframers = %s", webIframers);} 6415 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.
6542 while (FCGI_Accept() != -1) 6645 while (FCGI_Accept() != -1)
6543 { 6646 {
6544 reqData *Rd = xzalloc(sizeof(reqData)); 6647 reqData *Rd = xzalloc(sizeof(reqData));
6648
6545 if (-1 == clock_gettime(CLOCK_REALTIME, &Rd->then)) 6649 if (-1 == clock_gettime(CLOCK_REALTIME, &Rd->then))
6546 perror_msg("Unable to get the time."); 6650 perror_msg("Unable to get the time.");
6547 Rd->L = L; 6651 Rd->L = L;
@@ -6561,6 +6665,7 @@ jit library is loaded or the JIT compiler will not be activated.
6561 Rd->messages = qlist(0); 6665 Rd->messages = qlist(0);
6562 Rd->reply = qgrow(QGROW_THREADSAFE); 6666 Rd->reply = qgrow(QGROW_THREADSAFE);
6563 Rd->outQuery = xstrdup(""); 6667 Rd->outQuery = xstrdup("");
6668 Rd->shs.status = SHS_UNKNOWN;
6564 qhashtbl_obj_t hobj; 6669 qhashtbl_obj_t hobj;
6565 qlist_obj_t lobj; 6670 qlist_obj_t lobj;
6566 6671