From c7a86d69efc198736f613cf9ebdf77536c5e9b07 Mon Sep 17 00:00:00 2001 From: onefang Date: Thu, 19 Mar 2020 21:56:38 +1000 Subject: Plug a lot of leaks. Still some left, mostly in the database code. Some of the remaining leaks I think are in the third party libraries. --- src/sledjchisl/sledjchisl.c | 460 +++++++++++++++++++++++++++----------------- 1 file changed, 279 insertions(+), 181 deletions(-) (limited to 'src/sledjchisl/sledjchisl.c') diff --git a/src/sledjchisl/sledjchisl.c b/src/sledjchisl/sledjchisl.c index 6a971c8..11b5fb2 100644 --- a/src/sledjchisl/sledjchisl.c +++ b/src/sledjchisl/sledjchisl.c @@ -318,6 +318,7 @@ static void newValidFunc(char *name, char *title, fieldValidFunc func) validFunc *vf = xmalloc(sizeof(validFunc)); vf->name = name; vf->title = title; vf->func = func; fieldValidFuncs->put(fieldValidFuncs, vf->name, vf, sizeof(validFunc)); + free(vf); } typedef void *(*pageFunction) (char *file, reqData *Rd, HTMLfile *thisFile); @@ -333,6 +334,7 @@ static void newDynPage(char *name, pageFunction func) dynPage *dp = xmalloc(sizeof(dynPage)); dp->name = name; dp->func = func; dynPages->put(dynPages, dp->name, dp, sizeof(dynPage)); + free(dp); } typedef void *(*pageBuildFunction) (reqData *Rd, char *message); @@ -348,6 +350,7 @@ static void newBuildPage(char *name, pageBuildFunction func, pageBuildFunction e buildPage *bp = xmalloc(sizeof(buildPage)); bp->name = name; bp->func = func; bp->eFunc = eFunc; buildPages->put(buildPages, bp->name, bp, sizeof(buildPage)); + free(bp); } @@ -434,6 +437,10 @@ static void showSesh(qgrow_t *reply, sesh *shs) char toybuf[4096]; +lua_State *L; +qhashtbl_t *configs; +MYSQL *database, *dbconn; +gridStats *stats; boolean isTmux = 0; boolean isWeb = 0; char *pwd = ""; @@ -460,6 +467,7 @@ int newbieTimeOut = 30; float loadAverageInc = 0.5; int simTimeOut = 45; qhashtbl_t *mimeTypes; +qlist_t *dbRequests; // TODO - log to file. The problem is we don't know where to log until after we have loaded the configs, and before that we are spewing log messages. @@ -941,6 +949,7 @@ d("Getting field metadata for %s", table); fld->flags = fields[i].flags; fld->decimals = fields[i].decimals; ret->put(ret, fld->name, fld, sizeof(*fld)); + free(fld); } tables->put(tables, table, ret, sizeof(*ret)); } @@ -958,9 +967,11 @@ void dbFreeFields(qlisttbl_t *flds) qlisttbl_obj_t obj; memset((void *) &obj, 0, sizeof(obj)); flds->lock(flds); +d("Freeing fields."); while(flds->getnext(flds, &obj, NULL, false) == true) { dbField *fld = (dbField *) obj.data; +d("Freeing field %s", fld->name); free(fld->name); } flds->unlock(flds); @@ -1014,6 +1025,7 @@ void dbDoSomething(dbRequest *req, boolean count, ...) } if (0 == i) { + free(select); if (count) select = xmprintf(",Count(*)"); else @@ -1505,6 +1517,7 @@ d("Execute %s", req->sql); { char *t = xmprintf("%d", (int) *((int *) req->outBind[i].buffer)); flds->putstr(flds, req->rows->fieldNames[i], t); + free(t); break; } @@ -1512,6 +1525,7 @@ d("Execute %s", req->sql); { char *t = xmprintf("%d", (int) *((int *) req->outBind[i].buffer)); flds->putstr(flds, req->rows->fieldNames[i], t); + free(t); break; } @@ -1525,6 +1539,7 @@ d("Execute %s", req->sql); char *t = xmprintf("%d", (int) *((int *) (req->outBind[i].buffer))); //d("Setting %i %s %s", i, fld->name, t); flds->putstr(flds, req->rows->fieldNames[i], t); + free(t); break; } @@ -1532,6 +1547,7 @@ d("Execute %s", req->sql); { char *t = xmprintf("%d", (int) *((int *) req->outBind[i].buffer)); flds->putstr(flds, req->rows->fieldNames[i], t); + free(t); break; } @@ -1584,11 +1600,10 @@ d("Execute %s", req->sql); } } else - { D("Not setting data %s, coz it's NULL", fld->name); - } } - req->rows->rows->addlast(req->rows->rows, flds, sizeof(*flds)); + req->rows->rows->addlast(req->rows->rows, flds, sizeof(qhashtbl_t)); + free(flds); } } @@ -1618,22 +1633,22 @@ void dbPull(reqData *Rd, char *table, rowData *rows) memset((void*)&obj, 0, sizeof(obj)); me->lock(me); - while(me->getnext(me, &obj, true) == true) + while(me->getnext(me, &obj, false) == true) { where = xmprintf("%s.%s", table, obj.name); Rd->database->putstr(Rd->database, where, (char *) obj.data); - me->remove(me, obj.name); +// me->remove(me, obj.name); free(where); } me->unlock(me); - free(me); + me->free(me); } -/* void dbFreeRequest(dbRequest *req) { int i; + D("Cleaning up prepared database request %s - %s", req->table, req->where); if (NULL != req->outBind) { for (i = 0; i < req->outCount; i++) @@ -1649,6 +1664,7 @@ void dbFreeRequest(dbRequest *req) { for (i = 0; i < req->inCount; i++) { +// TODO - this leaks for some bizare reason. if (NULL != req->inBind[i].buffer) free(req->inBind[i].buffer); if (NULL != req->inBind[i].length) free(req->inBind[i].length); if (NULL != req->inBind[i].error) free(req->inBind[i].error); @@ -1659,9 +1675,13 @@ void dbFreeRequest(dbRequest *req) if (req->freeOutParams) free(req->outParams); if (NULL != req->sql) free(req->sql); - if (NULL != req->prep) mysql_stmt_close(req->prep); + if (NULL != req->prep) + { + if (0 != mysql_stmt_close(req->prep)) + C("Unable to close the prepared statement!"); + free(req->prep); + } } -*/ my_ulonglong dbCount(MYSQL *db, char *table, char *where) { @@ -1908,15 +1928,14 @@ gridStats *getStats(MYSQL *db, gridStats *stats) rgnSizes->inParams = szi; rgnSizes->outParams = szo; rgnSizes->where = "sizeX != 0"; + dbRequests->addfirst(dbRequests, rgnSizes, sizeof(*rgnSizes)); } dbDoSomething(rgnSizes, FALSE); rowData *rows = rgnSizes->rows; - qlist_obj_t obj; - memset((void*)&obj, 0, sizeof(obj)); // must be cleared before call - rows->rows->lock(rows->rows); - while (rows->rows->getnext(rows->rows, &obj, false) == true) + + qhashtbl_t *row; + while (NULL != (row = rows->rows->getat(rows->rows, 0, NULL, true))) { - qhashtbl_t *row = (qhashtbl_t *) obj.data; my_ulonglong x = 0, y = 0; tmp = row->getstr(row, "sizeX", false); @@ -1930,11 +1949,13 @@ gridStats *getStats(MYSQL *db, gridStats *stats) else y = atoll(tmp); simSize += x * y; - free(row); +// TODO - I can't win. valgrind complains that either something is being freed twice, or not freed at all, no matter what I do. +// This seems to keep the memory loss down to a minimum. + row->free(row); + rows->rows->removefirst(rows->rows); } - rows->rows->unlock(rows->rows); - free(rows->rows); free(rows->fieldNames); + rows->rows->free(rows->rows); free(rows); tmp = xmprintf("%lu", simSize); @@ -1986,7 +2007,7 @@ void santize(qhashtbl_t *tbl, bool decode) memset((void*)&obj, 0, sizeof(obj)); tbl->lock(tbl); - while(tbl->getnext(tbl, &obj, true) == true) + while(tbl->getnext(tbl, &obj, false) == true) { char *n = obj.name, *o = (char *) obj.data; @@ -2004,7 +2025,6 @@ void santize(qhashtbl_t *tbl, bool decode) } tbl->putstr(tbl, n, o); - free(o); } tbl->unlock(tbl); } @@ -2033,7 +2053,7 @@ enum cookieSame typedef struct _cookie cookie; struct _cookie { - char *cookie, *value, *domain, *path; + char *value, *domain, *path; // char *expires; // Use maxAge instead, it's far simpler to figure out. int maxAge; boolean secure, httpOnly; @@ -2043,23 +2063,30 @@ struct _cookie cookie *setCookie(reqData *Rd, char *cki, char *value) { cookie *ret = xzalloc(sizeof(cookie)); + char *cook = xstrdup(cki); int l, i; - ret->cookie = xstrdup(cki); // Validate this, as there is a limited set of characters allowed. - qstrreplace("tr", ret->cookie, "()<>@,;:\\\"/[]?={} \t", "_"); - l = strlen(ret->cookie); + qstrreplace("tr", cook, "()<>@,;:\\\"/[]?={} \t", "_"); + l = strlen(cook); for (i = 0; i < l; i++) { - if (iscntrl(ret->cookie[i]) != 0) - ret->cookie[i] = '_'; + if (iscntrl(cook[i]) != 0) + cook[i] = '_'; } - ret->value = qurl_encode(value, strlen(value)); + l = strlen(value); + if (0 != l) + ret->value = qurl_encode(value, l); + else + ret->value = value; ret->httpOnly = TRUE; ret->site = CS_STRICT; ret->secure = TRUE; - ret->path = xstrdup(getStrH(Rd->headers, "SCRIPT_NAME")); - Rd->Rcookies->put(Rd->Rcookies, cki, ret, sizeof(*ret)); + ret->path = getStrH(Rd->headers, "SCRIPT_NAME"); + Rd->Rcookies->put(Rd->Rcookies, cook, ret, sizeof(cookie)); + free(ret); + ret = Rd->Rcookies->get(Rd->Rcookies, cook, NULL, false); + free(cook); return ret; } @@ -2388,6 +2415,7 @@ static void HTMLfooter(qgrow_t *reply) fragment *newFragment(enum fragmentType type, char *text, int len) { fragment *frg = xmalloc(sizeof(fragment)); + frg->type = type; frg->length = len; frg->text = xmalloc(len + 1); @@ -2435,8 +2463,10 @@ qlist_t *fragize(char *mm, size_t length) i += 4; } frg0 = newFragment(FT_TEXT, &mm[k], m - k); - fragments->addlast(fragments, frg0, sizeof(*frg0)); - fragments->addlast(fragments, frg1, sizeof(*frg1)); + fragments->addlast(fragments, frg0, sizeof(fragment)); + fragments->addlast(fragments, frg1, sizeof(fragment)); + free(frg0); + free(frg1); k = i; break; } @@ -2450,11 +2480,12 @@ qlist_t *fragize(char *mm, size_t length) } frg0 = newFragment(FT_TEXT, &mm[k], length - k); fragments->addlast(fragments, frg0, sizeof(*frg0)); + free(frg0); return fragments; } -void unfragize(qlist_t *fragments, reqData *Rd) +void unfragize(qlist_t *fragments, reqData *Rd, boolean fre) { qlist_obj_t lobj; memset((void *) &lobj, 0, sizeof(lobj)); @@ -2468,8 +2499,12 @@ void unfragize(qlist_t *fragments, reqData *Rd) continue; } HTMLfill(Rd, frg->type, frg->text, frg->length); + if (fre) + free(frg->text); } fragments->unlock(fragments); + if (fre) + fragments->free(fragments); } HTMLfile *checkHTMLcache(char *file) @@ -2876,6 +2911,7 @@ static void freeSesh(reqData *Rd, boolean linky, boolean wipe) } else shs->leaf[0] = '\0'; + free(file); } static void setToken_n_munchie(reqData *Rd, boolean linky) @@ -2900,8 +2936,8 @@ static void setToken_n_munchie(reqData *Rd, boolean linky) if (!linky) { - cookie *ck = setCookie(Rd, "toke_n_munchie", shs->toke_n_munchie); - cookie *ckh = setCookie(Rd, "hashish", shs->hashish); + setCookie(Rd, "toke_n_munchie", shs->toke_n_munchie); + setCookie(Rd, "hashish", shs->hashish); } char *tnm0 = xmprintf( "toke_n_munchie = \n" "{\n" @@ -2953,6 +2989,8 @@ t("stuff %s = %s", obj.name, (char *) obj.data); // Set the mtime on the file. futimens(fd, shs->timeStamp); xclose(fd); + free(tnm1); + free(tnm0); free(file); } @@ -3052,14 +3090,18 @@ d("New sesh"); } else { - qstrcpy(ret->salt, sizeof(ret->salt), qhex_encode(buf, sizeof(buf))); + t0 = qhex_encode(buf, sizeof(buf)); + qstrcpy(ret->salt, sizeof(ret->salt), t0); + free(t0); //d("salt %s", ret->salt); numBytes = getrandom((void *)buf, sizeof(buf), GRND_NONBLOCK); if (-1 == numBytes) perror_msg("Unable to generate a suitable random number."); else { - qstrcpy(ret->seshID, sizeof(ret->seshID), qhex_encode(buf, sizeof(buf))); + t0 = qhex_encode(buf, sizeof(buf)); + qstrcpy(ret->seshID, sizeof(ret->seshID), t0); + free(t0); //d("seshID %s", ret->seshID); ret->timeStamp[0].tv_nsec = UTIME_OMIT; @@ -3079,14 +3121,17 @@ d("New sesh"); qstrcpy(ret->munchie, sizeof(ret->munchie), munchie); //d("munchie %s", ret->munchie); t0 = xmprintf("%s%s", getStrH(Rd->stuff, "UUID"), munchie); + free(munchie); toke_n_munchie = myHMAC(t0, FALSE); free(t0); qstrcpy(ret->toke_n_munchie, sizeof(ret->toke_n_munchie), toke_n_munchie); //d("toke_n_munchie %s", ret->toke_n_munchie); hashish = myHMACkey(ret->salt, toke_n_munchie, FALSE); + free(toke_n_munchie); qstrcpy(ret->hashish, sizeof(ret->hashish), hashish); //d("hashish %s", ret->hashish); t0 = myHMACkey(getStrH(Rd->configs, "pepper"), hashish, TRUE); + free(hashish); qstrcpy(ret->leaf, sizeof(ret->leaf), t0); //d("leaf %s", ret->leaf); free(t0); @@ -3182,9 +3227,7 @@ static int validateSesh(reqData *Rd, qhashtbl_t *data, char *name) return ret; } - char *toke_n_munchie = "", *munchie = "", *hashish = "", - *leaf, *timeStamp = "", *seshion = "", *seshID = "", - *t0, *t1; + char *toke_n_munchie = "", *munchie = "", *hashish = "", *leaf = "", *timeStamp = "", *seshion = "", *seshID = "", *t0, *t1; // In this case the session stuff has to come from specific places. hashish = getStrH(Rd->queries, "hashish"); @@ -3224,141 +3267,143 @@ static int validateSesh(reqData *Rd, qhashtbl_t *data, char *name) if (0 == ret) { + // 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 + // Includes various reasons why it's bad. + // Another good reason why it is bad, TOR. + // So should make this a user option, like Mantis does. + if (strcmp(getStrH(Rd->headers, "REMOTE_ADDR"), getStrH(tnm, "IP")) != 0) { - { - // 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 - // Includes various reasons why it's bad. - // Another good reason why it is bad, TOR. - // So should make this a user option, like Mantis does. - if (strcmp(getStrH(Rd->headers, "REMOTE_ADDR"), getStrH(tnm, "IP")) != 0) + bitchSession(Rd, "Wrong IP for session.", "Session IP doesn't match."); + ret++; + } + else + { + timeStamp = xmprintf("%ld.%ld", (long) st.st_mtim.tv_sec, st.st_mtim.tv_nsec); +//d("timeStamp %s", timeStamp); + seshion = xmprintf("%s%s", tnm->getstr(tnm, "seshID", false), timeStamp); +//d("sesh %s", seshion); + t0 = myHMAC(seshion, FALSE); + munchie = xmprintf("%s%s", t0, timeStamp); +//d("munchie %s", munchie); + free(t0); + free(timeStamp); + t1 = getStrH(Rd->body, "munchie"); + if ('\0' != t1[0]) + { + if (strcmp(t1, munchie) != 0) { - bitchSession(Rd, "Wrong IP for session.", "Session IP doesn't match."); + bitchSession(Rd, "Wrong munchie for session.", "HMAC(seshID + timeStamp) != munchie"); ret++; } else { - timeStamp = xmprintf("%ld.%ld", (long) st.st_mtim.tv_sec, st.st_mtim.tv_nsec); -//d("timeStamp %s", timeStamp); - seshion = xmprintf("%s%s", tnm->getstr(tnm, "seshID", false), timeStamp); -//d("sesh %s", seshion); - t0 = myHMAC(seshion, FALSE); - munchie = xmprintf("%s%s", t0, timeStamp); -//d("munchie %s", munchie); + t0 = xmprintf("%s%s", getStrH(tnm, "UUID"), munchie); + t1 = myHMAC(t0, FALSE); free(t0); - t1 = getStrH(Rd->body, "munchie"); - if ('\0' != t1[0]) - { - if (strcmp(t1, munchie) != 0) - { - bitchSession(Rd, "Wrong munchie for session.", "HMAC(seshID + timeStamp) != munchie"); - ret++; - } - else - { - t0 = xmprintf("%s%s", getStrH(tnm, "UUID"), munchie); - t1 = myHMAC(t0, FALSE); - free(t0); //d("toke_n_munchie %s", t1); - if (strcmp(t1, toke_n_munchie) != 0) - { - bitchSession(Rd, "Wrong toke_n_munchie for session.", "HMAC(UUID + munchie) != toke_n_munchie"); - ret++; - } - free(t1); - } + if (strcmp(t1, toke_n_munchie) != 0) + { + bitchSession(Rd, "Wrong toke_n_munchie for session.", "HMAC(UUID + munchie) != toke_n_munchie"); + ret++; } + free(t1); + } + } - if (0 == ret) - { - if (linky) - { - t0 = xmprintf("%s%s", getStrH(tnm, "UUID"), munchie); - t1 = myHMAC(t0, FALSE); - free(t0); - toke_n_munchie = t1; + if (0 == ret) + { + if (linky) + { + t0 = xmprintf("%s%s", getStrH(tnm, "UUID"), munchie); + t1 = myHMAC(t0, FALSE); + free(t0); + toke_n_munchie = t1; //d("toke_n_munchie %s", t1); - } - t1 = myHMACkey(getStrH(tnm, "salt"), toke_n_munchie, FALSE); + } + t1 = myHMACkey(getStrH(tnm, "salt"), toke_n_munchie, FALSE); //d("hashish %s", t1); - if (strcmp(t1, hashish) != 0) - { - bitchSession(Rd, "Wrong hashish for session.", "HMAC(toke_n_munchie + salt) != hashish"); - ret++; - } + if (strcmp(t1, hashish) != 0) + { + bitchSession(Rd, "Wrong hashish for session.", "HMAC(toke_n_munchie + salt) != hashish"); + ret++; + } + free(t1); - if (now.tv_sec > st.st_mtim.tv_sec + idleTimeOut) - { - W("Session idled out."); - Rd->vegOut = TRUE; - } - else - { - if (now.tv_sec > st.st_mtim.tv_sec + seshTimeOut) - { - W("Session timed out."); - Rd->vegOut = TRUE; - } - else - { + if (now.tv_sec > st.st_mtim.tv_sec + idleTimeOut) + { + W("Session idled out."); + Rd->vegOut = TRUE; + } + else + { + if (now.tv_sec > st.st_mtim.tv_sec + seshTimeOut) + { + W("Session timed out."); + Rd->vegOut = TRUE; + } + else + { W("Validated session."); - sesh *shs = &Rd->shs; + sesh *shs = &Rd->shs; - qstrcpy(shs->leaf, sizeof(shs->leaf), leaf); - if (linky) - { + 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); - Rd->chillOut = TRUE; - freeSesh(Rd, linky, FALSE); - qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), ""); - Rd->func = (pageBuildFunction) loginPage; - Rd->doit = "logout"; + 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); + Rd->chillOut = TRUE; + freeSesh(Rd, linky, FALSE); + qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), ""); + Rd->func = (pageBuildFunction) loginPage; + Rd->doit = "logout"; // 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 - { - 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->timeStamp[0].tv_nsec = UTIME_OMIT; - shs->timeStamp[0].tv_sec = UTIME_OMIT; - memcpy(&shs->timeStamp[1], &st.st_mtim, sizeof(struct timespec)); - t0 = tnm->getstr(tnm, "linky-hashish", false); - if (NULL != t0) - Rd->stuff->putstr(Rd->stuff, "linky-hashish", t0); - } - } + } + else + { + 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->timeStamp[0].tv_nsec = UTIME_OMIT; + shs->timeStamp[0].tv_sec = UTIME_OMIT; + memcpy(&shs->timeStamp[1], &st.st_mtim, sizeof(struct timespec)); + t0 = tnm->getstr(tnm, "linky-hashish", false); + if (NULL != t0) + Rd->stuff->putstr(Rd->stuff, "linky-hashish", t0); + } + } - 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)) - { + if ((strcmp("salt", n) != 0) && (strcmp("seshID", n) != 0)) + { t("Lua %s = %s", n, (char *) obj.data); - Rd->stuff->putstr(Rd->stuff, obj.name, (char *) obj.data); - } - } - tnm->unlock(tnm); - Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", tnm->getstr(tnm, "UUID", true)); - } + Rd->stuff->putstr(Rd->stuff, obj.name, (char *) obj.data); } + } + tnm->unlock(tnm); + Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", tnm->getstr(tnm, "UUID", true)); } } + free(munchie); + free(seshion); } } + free(leaf); + tnm->free(tnm); } return ret; @@ -3597,6 +3642,7 @@ static int validateName(reqData *Rd, qhashtbl_t *data, char *nm) acnts->inParams = szi; acnts->outParams = szo; acnts->where = "FirstName=? and LastName=?"; + dbRequests->addfirst(dbRequests, acnts, sizeof(*acnts)); } dbDoSomething(acnts, FALSE, name, s); rowData *rows = acnts->rows; @@ -3621,8 +3667,8 @@ static int validateName(reqData *Rd, qhashtbl_t *data, char *nm) } else { - W("More than one UserAccounts record with that name."); - ret++; + W("More than one UserAccounts record with that name."); + ret++; } bitch(Rd, "Login failed.", "Could not find user record."); } @@ -3645,8 +3691,8 @@ static int validateName(reqData *Rd, qhashtbl_t *data, char *nm) Rd->database->putstr(Rd->database, "auth.passwordHash", getStrH(tnm, "passwordHash")); tnm->free(tnm); } - Rd->stuff->putstr(Rd->stuff, "UUID", xstrdup(getStrH(Rd->database, "UserAccounts.PrincipalID"))); - Rd->stuff->putstr(Rd->stuff, "level", xstrdup(getStrH(Rd->database, "UserAccounts.Userlevel"))); + Rd->stuff->putstr(Rd->stuff, "UUID", getStrH(Rd->database, "UserAccounts.PrincipalID")); + Rd->stuff->putstr(Rd->stuff, "level", getStrH(Rd->database, "UserAccounts.Userlevel")); if (s) {s--; *s = ' '; s++;} Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name)); if (s) {s--; *s = '\0'; s++;} @@ -3696,12 +3742,14 @@ static int validateName(reqData *Rd, qhashtbl_t *data, char *nm) Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name)); } } - free(rows->rows); free(rows->fieldNames); + rows->rows->free(rows->rows); free(rows); + tnm->free(tnm); if (s) {s--; *s = ' '; s++;} } } + free(name); badBoy(ret, Rd, data, "name", NULL); return ret; @@ -3733,6 +3781,7 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name) auth->inParams = szi; auth->outParams = szo; auth->where = "UUID=?"; + dbRequests->addfirst(dbRequests, auth, sizeof(*auth)); } dbDoSomething(auth, FALSE, UUID); rowData *rows = auth->rows; @@ -3776,11 +3825,15 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name) ret++; } Rd->stuff->putstr(Rd->stuff, "passwordHash", md5ascii); - free(md5ascii); } + free(md5ascii); free(where); } + free(me); } + free(rows->fieldNames); + rows->rows->free(rows->rows); + free(rows); } } else if (create) @@ -3827,6 +3880,7 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name) } else { + free(salt); salt = qhex_encode(md5hash, 16); hash = xmprintf("%s:%s", salt, getStrH(Rd->stuff, "passwordSalt")); if (!qhashmd5((void *) hash, strlen(hash), md5hash)) @@ -3836,10 +3890,13 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name) } else { + free(hash); hash = qhex_encode(md5hash, 16); Rd->stuff->putstr(Rd->stuff, "passwordHash", hash); Rd->chillOut = TRUE; } + free(hash); + free(salt); } } } @@ -3866,7 +3923,7 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name) { pswd = qhex_encode(md5hash, 16); hash = xmprintf("%s:%s", pswd, Osalt); - + free(pswd); if (!qhashmd5((void *) hash, strlen(hash), md5hash)) { bitch(Rd, "Internal session error.", "Confirm - qhashmd5(passwordSalt) failed."); @@ -3874,12 +3931,14 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name) } else { + free(hash); hash = qhex_encode(md5hash, 16); if (strcmp(hash, Ohash) != 0) { bitch(Rd, "Passwords are not the same.", ""); ret++; } + free(hash); } } } @@ -3920,6 +3979,7 @@ static int validateUUID(reqData *Rd, qhashtbl_t *data, char *name) uuids->inParams = szi; uuids->outParams = szo; uuids->where = "PrincipalID=?"; + dbRequests->addfirst(dbRequests, uuids, sizeof(*uuids)); } if ((strcmp("cancel", Rd->doit) == 0) || (strcmp("logout", Rd->doit) == 0)) @@ -4017,13 +4077,14 @@ static int validateUUID(reqData *Rd, qhashtbl_t *data, char *name) void loginPage(reqData *Rd, char *message) { - char *name = xstrdup(getStrH(Rd->stuff, "name")); + char *name = xstrdup(getStrH(Rd->stuff, "name")), *linky = checkLinky(Rd); Rd->stuff->remove(Rd->stuff, "UUID"); HTMLheader(Rd->reply, " account manager"); HTMLdebug(Rd->reply); Rd->reply->addstrf(Rd->reply, "

account manager

\n"); - Rd->reply->addstr(Rd->reply, checkLinky(Rd)); + Rd->reply->addstr(Rd->reply, linky); + free(linky); if (0 != Rd->errors->size(Rd->messages)) HTMLlist(Rd->reply, "messages -", Rd->messages); HTMLform(Rd->reply, "", Rd->shs.munchie); @@ -4044,7 +4105,7 @@ void loginPage(reqData *Rd, char *message) void accountCreationPage(reqData *Rd, char *message) { - char *name = getStrH(Rd->body, "name"); + char *name = getStrH(Rd->body, "name"), *linky = checkLinky(Rd); char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie"); char *tmp = xmalloc(16), *t; int i, d; @@ -4058,7 +4119,8 @@ void accountCreationPage(reqData *Rd, char *message) HTMLdebug(Rd->reply); Rd->reply->addstrf(Rd->reply, "

account manager

\n"); Rd->reply->addstrf(Rd->reply, "

Creating account for %s

\n", name); - Rd->reply->addstr(Rd->reply, checkLinky(Rd)); + Rd->reply->addstr(Rd->reply, linky); + free(linky); if (0 != Rd->errors->size(Rd->messages)) HTMLlist(Rd->reply, "messages -", Rd->messages); // TODO - set this to autocomplete="off". @@ -4124,14 +4186,15 @@ void accountCreationPage(reqData *Rd, char *message) void loggedOnPage(reqData *Rd, char *message) { - char *name = getStrH(Rd->stuff, "name"); + char *name = getStrH(Rd->stuff, "name"), *linky = checkLinky(Rd); char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie"); HTMLheader(Rd->reply, " account manager"); HTMLdebug(Rd->reply); Rd->reply->addstrf(Rd->reply, "

account manager

\n"); Rd->reply->addstrf(Rd->reply, "

account for %s

\n", name); - Rd->reply->addstr(Rd->reply, checkLinky(Rd)); + Rd->reply->addstr(Rd->reply, linky); + free(linky); if (0 != Rd->errors->size(Rd->messages)) HTMLlist(Rd->reply, "messages -", Rd->messages); HTMLform(Rd->reply, "", Rd->shs.munchie); @@ -4163,14 +4226,15 @@ void loggedOnPage(reqData *Rd, char *message) void listPage(reqData *Rd, char *message) { // TODO - should check if the user is a god before allowing this. - char *name = getStrH(Rd->stuff, "name"); + char *name = getStrH(Rd->stuff, "name"), *linky = checkLinky(Rd); char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie"); HTMLheader(Rd->reply, " account manager"); HTMLdebug(Rd->reply); Rd->reply->addstrf(Rd->reply, "

account manager

\n"); Rd->reply->addstrf(Rd->reply, "

member accounts

\n"); - Rd->reply->addstr(Rd->reply, checkLinky(Rd)); + Rd->reply->addstr(Rd->reply, linky); + free(linky); if (0 != Rd->errors->size(Rd->messages)) HTMLlist(Rd->reply, "messages -", Rd->messages); HTMLtable(Rd->reply, Rd->db, @@ -4368,24 +4432,59 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) } +static void cleanup(void) +{ + C("Caught signal, cleaning up."); + dbRequest *req = NULL; + + while (NULL != (req = (dbRequest *) dbRequests->getat(dbRequests, 0, NULL, false))) + { + if (NULL != req->flds) + dbFreeFields(req->flds); + else + D("No fields to clean up for %s - %s.", req->table, req->where); + dbFreeRequest(req); + dbRequests->removefirst(dbRequests); + } + if (fieldValidFuncs) fieldValidFuncs->free(fieldValidFuncs); + if (dynPages) dynPages->free(dynPages); + if (buildPages) buildPages->free(buildPages); + if (HTMLfileCache) HTMLfileCache->free(HTMLfileCache); + if (HTMLfileCache) mimeTypes->free(mimeTypes); + if (dbRequests) dbRequests->free(dbRequests); + if (database) mysql_close(database); + mysql_library_end(); + lua_close(L); + if (stats) + { + if (stats->stats) stats->stats->free(stats->stats); + free(stats); + } + if (configs) configs->free(configs); +} + void sledjchisl_main(void) { char *cmd = *toys.optargs; char *tmp; - qhashtbl_t *configs = qhashtbl(0, 0); - lua_State *L = luaL_newstate(); MYSQL *database = NULL, *dbconn = NULL; gridStats *stats = NULL; struct stat statbuf; int status, result, i; void *vd; + configs = qhashtbl(0, 0); + L = luaL_newstate(); + I("libfcgi version: %s", FCGI_VERSION); I("Lua version: %s", LUA_RELEASE); I("LuaJIT version: %s", LUAJIT_VERSION); I("MariaDB / MySQL client version: %s", mysql_get_client_info()); I("toybox version: %s", TOYBOX_VERSION); + dbRequests = qlist(0); + sigatexit(cleanup); + pwd = getcwd(0, 0); if (-1 == fstat(STDIN_FILENO, &statbuf)) @@ -4594,6 +4693,7 @@ jit library is loaded or the JIT compiler will not be activated. if ((! qfile_exist(scLog)) && (! qfile_mkdir(scLog, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", scLog); tmp = xmprintf("%s/sessions", scCache); if ((! qfile_exist(tmp)) && (! qfile_mkdir(tmp, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", tmp); + free(tmp); tmp = xmprintf("%s/users", scData); if ((! qfile_exist(tmp)) && (! qfile_mkdir(tmp, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP, true))) C("Unable to create path %s", tmp); free(tmp); @@ -4632,6 +4732,7 @@ jit library is loaded or the JIT compiler will not be activated. // TODO - it looks like OpenSim invented their own half arsed backwards INI file include system. // I doubt qlibc supports it, like it supports what seems to be the standard include system. // Not sure if we need to worry about it just yet. +// TODO - this leaks memory, but I suspect it's a bug in qLib. qlisttbl_t *qconfig = qconfig_parse_file(NULL, toybuf, '='); if (NULL == qconfig) { @@ -4688,10 +4789,10 @@ jit library is loaded or the JIT compiler will not be activated. else { dbconn = mysql_real_connect(database, - configs->getstr(configs, "Data Source", true), - configs->getstr(configs, "User ID", true), - configs->getstr(configs, "Password", true), - configs->getstr(configs, "Database", true), + getStrH(configs, "Data Source"), + getStrH(configs, "User ID"), + getStrH(configs, "Password"), + getStrH(configs, "Database"), // 3036, "/var/run/mysqld/mysqld.sock", 0, NULL, CLIENT_FOUND_ROWS | CLIENT_LOCAL_FILES | CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS); @@ -4712,6 +4813,7 @@ jit library is loaded or the JIT compiler will not be activated. stats->stats->putstr(stats->stats, "uri", toybuf); } + qconfig->free(qconfig); } @@ -4779,6 +4881,7 @@ t("HEADERS"); { char *k = xstrdup(*envp); char *v = strchr(k, '='); + if (NULL != v) { *v = '\0'; @@ -4787,6 +4890,7 @@ t("HEADERS"); if ((strcmp("HTTP_COOKIE", ky) == 0) || (strcmp("CONTENT_LENGTH", ky) == 0) || (strcmp("QUERY_STRING", ky) == 0)) d(" %s = %s", ky, v + 1); } + free(k); } // The FCGI paramaters sent from the server, are converted to environment variablse for the fcgi2 SDK. @@ -4846,6 +4950,7 @@ t("QUERY"); Length = "0"; t("BODY"); Rd->body = toknize(Body, "=&"); + free(Body); santize(Rd->body, TRUE); @@ -4902,8 +5007,9 @@ t("BODY"); // TODO - maybe cache this? qlist_t *fragments = fragize(finl, Rd->reply->datasize(Rd->reply)); Rd->reply->free(Rd->reply); - Rd->reply = qgrow(QGROW_THREADSAFE); - unfragize(fragments, Rd); + Rd->reply = qgrow(QGROW_THREADSAFE); + unfragize(fragments, Rd, TRUE); + free(finl); goto sendReply; } @@ -4943,7 +5049,7 @@ goto sendReply; goto sendReply; getStats(database, stats); - unfragize(thisFile->fragments, Rd); + unfragize(thisFile->fragments, Rd, false); sendReply: /* Send headers. @@ -4969,7 +5075,7 @@ sendReply: while (Rd->Rcookies->getnext(Rd->Rcookies, &hobj, false) == true) { cookie *ck = (cookie *) hobj.data; - FCGI_printf("Set-Cookie: %s=%s", ck->cookie, ck->value); + FCGI_printf("Set-Cookie: %s=%s", hobj.name, ck->value); // if (NULL != ck->expires) FCGI_printf("; Expires=%s", ck->expires); if (NULL != ck->domain) FCGI_printf("; Domain=%s", ck->domain); if (NULL != ck->path) FCGI_printf("; Path=%s", ck->path); @@ -4981,7 +5087,6 @@ sendReply: if (CS_NONE == ck->site) FCGI_printf("; SameSite=None"); FCGI_printf("\r\n"); free(ck->value); - free(ck->cookie); } FCGI_printf("\r\n"); Rd->cookies->unlock(Rd->cookies); @@ -5028,6 +5133,7 @@ fcgiDone: double n = (now.tv_sec * 1000000000.0) + now.tv_nsec; double t = (Rd->then.tv_sec * 1000000000.0) + Rd->then.tv_nsec; I("Finished web request, took %lf seconds", (n - t) / 1000000000.0); + free(Rd); } FCGI_fprintf(FCGI_stderr, "Stopped SledjChisl web server.\n"); @@ -5209,13 +5315,5 @@ finished: puts(""); fflush(stdout); - if (database) mysql_close(database); - mysql_library_end(); - lua_close(L); - if (stats) - { - if (stats->stats) stats->stats->free(stats->stats); - free(stats); - } - if (configs) configs->free(configs); + cleanup(); } -- cgit v1.1