aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/sledjchisl/sledjchisl.c
diff options
context:
space:
mode:
authoronefang2020-03-19 21:56:38 +1000
committeronefang2020-03-19 21:56:38 +1000
commitc7a86d69efc198736f613cf9ebdf77536c5e9b07 (patch)
tree73ff8b6431fdc766d77c669c179a44bc8b88897e /src/sledjchisl/sledjchisl.c
parentMake HTML checkbox validation work. (diff)
downloadopensim-SC-c7a86d69efc198736f613cf9ebdf77536c5e9b07.zip
opensim-SC-c7a86d69efc198736f613cf9ebdf77536c5e9b07.tar.gz
opensim-SC-c7a86d69efc198736f613cf9ebdf77536c5e9b07.tar.bz2
opensim-SC-c7a86d69efc198736f613cf9ebdf77536c5e9b07.tar.xz
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.
Diffstat (limited to '')
-rw-r--r--src/sledjchisl/sledjchisl.c460
1 files changed, 279 insertions, 181 deletions
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)
318 validFunc *vf = xmalloc(sizeof(validFunc)); 318 validFunc *vf = xmalloc(sizeof(validFunc));
319 vf->name = name; vf->title = title; vf->func = func; 319 vf->name = name; vf->title = title; vf->func = func;
320 fieldValidFuncs->put(fieldValidFuncs, vf->name, vf, sizeof(validFunc)); 320 fieldValidFuncs->put(fieldValidFuncs, vf->name, vf, sizeof(validFunc));
321 free(vf);
321} 322}
322 323
323typedef void *(*pageFunction) (char *file, reqData *Rd, HTMLfile *thisFile); 324typedef void *(*pageFunction) (char *file, reqData *Rd, HTMLfile *thisFile);
@@ -333,6 +334,7 @@ static void newDynPage(char *name, pageFunction func)
333 dynPage *dp = xmalloc(sizeof(dynPage)); 334 dynPage *dp = xmalloc(sizeof(dynPage));
334 dp->name = name; dp->func = func; 335 dp->name = name; dp->func = func;
335 dynPages->put(dynPages, dp->name, dp, sizeof(dynPage)); 336 dynPages->put(dynPages, dp->name, dp, sizeof(dynPage));
337 free(dp);
336} 338}
337 339
338typedef void *(*pageBuildFunction) (reqData *Rd, char *message); 340typedef void *(*pageBuildFunction) (reqData *Rd, char *message);
@@ -348,6 +350,7 @@ static void newBuildPage(char *name, pageBuildFunction func, pageBuildFunction e
348 buildPage *bp = xmalloc(sizeof(buildPage)); 350 buildPage *bp = xmalloc(sizeof(buildPage));
349 bp->name = name; bp->func = func; bp->eFunc = eFunc; 351 bp->name = name; bp->func = func; bp->eFunc = eFunc;
350 buildPages->put(buildPages, bp->name, bp, sizeof(buildPage)); 352 buildPages->put(buildPages, bp->name, bp, sizeof(buildPage));
353 free(bp);
351} 354}
352 355
353 356
@@ -434,6 +437,10 @@ static void showSesh(qgrow_t *reply, sesh *shs)
434 437
435 438
436char toybuf[4096]; 439char toybuf[4096];
440lua_State *L;
441qhashtbl_t *configs;
442MYSQL *database, *dbconn;
443gridStats *stats;
437boolean isTmux = 0; 444boolean isTmux = 0;
438boolean isWeb = 0; 445boolean isWeb = 0;
439char *pwd = ""; 446char *pwd = "";
@@ -460,6 +467,7 @@ int newbieTimeOut = 30;
460float loadAverageInc = 0.5; 467float loadAverageInc = 0.5;
461int simTimeOut = 45; 468int simTimeOut = 45;
462qhashtbl_t *mimeTypes; 469qhashtbl_t *mimeTypes;
470qlist_t *dbRequests;
463 471
464 472
465// 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. 473// 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);
941 fld->flags = fields[i].flags; 949 fld->flags = fields[i].flags;
942 fld->decimals = fields[i].decimals; 950 fld->decimals = fields[i].decimals;
943 ret->put(ret, fld->name, fld, sizeof(*fld)); 951 ret->put(ret, fld->name, fld, sizeof(*fld));
952 free(fld);
944 } 953 }
945 tables->put(tables, table, ret, sizeof(*ret)); 954 tables->put(tables, table, ret, sizeof(*ret));
946 } 955 }
@@ -958,9 +967,11 @@ void dbFreeFields(qlisttbl_t *flds)
958 qlisttbl_obj_t obj; 967 qlisttbl_obj_t obj;
959 memset((void *) &obj, 0, sizeof(obj)); 968 memset((void *) &obj, 0, sizeof(obj));
960 flds->lock(flds); 969 flds->lock(flds);
970d("Freeing fields.");
961 while(flds->getnext(flds, &obj, NULL, false) == true) 971 while(flds->getnext(flds, &obj, NULL, false) == true)
962 { 972 {
963 dbField *fld = (dbField *) obj.data; 973 dbField *fld = (dbField *) obj.data;
974d("Freeing field %s", fld->name);
964 free(fld->name); 975 free(fld->name);
965 } 976 }
966 flds->unlock(flds); 977 flds->unlock(flds);
@@ -1014,6 +1025,7 @@ void dbDoSomething(dbRequest *req, boolean count, ...)
1014 } 1025 }
1015 if (0 == i) 1026 if (0 == i)
1016 { 1027 {
1028 free(select);
1017 if (count) 1029 if (count)
1018 select = xmprintf(",Count(*)"); 1030 select = xmprintf(",Count(*)");
1019 else 1031 else
@@ -1505,6 +1517,7 @@ d("Execute %s", req->sql);
1505 { 1517 {
1506 char *t = xmprintf("%d", (int) *((int *) req->outBind[i].buffer)); 1518 char *t = xmprintf("%d", (int) *((int *) req->outBind[i].buffer));
1507 flds->putstr(flds, req->rows->fieldNames[i], t); 1519 flds->putstr(flds, req->rows->fieldNames[i], t);
1520 free(t);
1508 break; 1521 break;
1509 } 1522 }
1510 1523
@@ -1512,6 +1525,7 @@ d("Execute %s", req->sql);
1512 { 1525 {
1513 char *t = xmprintf("%d", (int) *((int *) req->outBind[i].buffer)); 1526 char *t = xmprintf("%d", (int) *((int *) req->outBind[i].buffer));
1514 flds->putstr(flds, req->rows->fieldNames[i], t); 1527 flds->putstr(flds, req->rows->fieldNames[i], t);
1528 free(t);
1515 break; 1529 break;
1516 } 1530 }
1517 1531
@@ -1525,6 +1539,7 @@ d("Execute %s", req->sql);
1525 char *t = xmprintf("%d", (int) *((int *) (req->outBind[i].buffer))); 1539 char *t = xmprintf("%d", (int) *((int *) (req->outBind[i].buffer)));
1526//d("Setting %i %s %s", i, fld->name, t); 1540//d("Setting %i %s %s", i, fld->name, t);
1527 flds->putstr(flds, req->rows->fieldNames[i], t); 1541 flds->putstr(flds, req->rows->fieldNames[i], t);
1542 free(t);
1528 break; 1543 break;
1529 } 1544 }
1530 1545
@@ -1532,6 +1547,7 @@ d("Execute %s", req->sql);
1532 { 1547 {
1533 char *t = xmprintf("%d", (int) *((int *) req->outBind[i].buffer)); 1548 char *t = xmprintf("%d", (int) *((int *) req->outBind[i].buffer));
1534 flds->putstr(flds, req->rows->fieldNames[i], t); 1549 flds->putstr(flds, req->rows->fieldNames[i], t);
1550 free(t);
1535 break; 1551 break;
1536 } 1552 }
1537 1553
@@ -1584,11 +1600,10 @@ d("Execute %s", req->sql);
1584 } 1600 }
1585 } 1601 }
1586 else 1602 else
1587 {
1588 D("Not setting data %s, coz it's NULL", fld->name); 1603 D("Not setting data %s, coz it's NULL", fld->name);
1589 }
1590 } 1604 }
1591 req->rows->rows->addlast(req->rows->rows, flds, sizeof(*flds)); 1605 req->rows->rows->addlast(req->rows->rows, flds, sizeof(qhashtbl_t));
1606 free(flds);
1592 } 1607 }
1593 } 1608 }
1594 1609
@@ -1618,22 +1633,22 @@ void dbPull(reqData *Rd, char *table, rowData *rows)
1618 1633
1619 memset((void*)&obj, 0, sizeof(obj)); 1634 memset((void*)&obj, 0, sizeof(obj));
1620 me->lock(me); 1635 me->lock(me);
1621 while(me->getnext(me, &obj, true) == true) 1636 while(me->getnext(me, &obj, false) == true)
1622 { 1637 {
1623 where = xmprintf("%s.%s", table, obj.name); 1638 where = xmprintf("%s.%s", table, obj.name);
1624 Rd->database->putstr(Rd->database, where, (char *) obj.data); 1639 Rd->database->putstr(Rd->database, where, (char *) obj.data);
1625 me->remove(me, obj.name); 1640// me->remove(me, obj.name);
1626 free(where); 1641 free(where);
1627 } 1642 }
1628 me->unlock(me); 1643 me->unlock(me);
1629 free(me); 1644 me->free(me);
1630} 1645}
1631 1646
1632/*
1633void dbFreeRequest(dbRequest *req) 1647void dbFreeRequest(dbRequest *req)
1634{ 1648{
1635 int i; 1649 int i;
1636 1650
1651 D("Cleaning up prepared database request %s - %s", req->table, req->where);
1637 if (NULL != req->outBind) 1652 if (NULL != req->outBind)
1638 { 1653 {
1639 for (i = 0; i < req->outCount; i++) 1654 for (i = 0; i < req->outCount; i++)
@@ -1649,6 +1664,7 @@ void dbFreeRequest(dbRequest *req)
1649 { 1664 {
1650 for (i = 0; i < req->inCount; i++) 1665 for (i = 0; i < req->inCount; i++)
1651 { 1666 {
1667// TODO - this leaks for some bizare reason.
1652 if (NULL != req->inBind[i].buffer) free(req->inBind[i].buffer); 1668 if (NULL != req->inBind[i].buffer) free(req->inBind[i].buffer);
1653 if (NULL != req->inBind[i].length) free(req->inBind[i].length); 1669 if (NULL != req->inBind[i].length) free(req->inBind[i].length);
1654 if (NULL != req->inBind[i].error) free(req->inBind[i].error); 1670 if (NULL != req->inBind[i].error) free(req->inBind[i].error);
@@ -1659,9 +1675,13 @@ void dbFreeRequest(dbRequest *req)
1659 1675
1660 if (req->freeOutParams) free(req->outParams); 1676 if (req->freeOutParams) free(req->outParams);
1661 if (NULL != req->sql) free(req->sql); 1677 if (NULL != req->sql) free(req->sql);
1662 if (NULL != req->prep) mysql_stmt_close(req->prep); 1678 if (NULL != req->prep)
1679 {
1680 if (0 != mysql_stmt_close(req->prep))
1681 C("Unable to close the prepared statement!");
1682 free(req->prep);
1683 }
1663} 1684}
1664*/
1665 1685
1666my_ulonglong dbCount(MYSQL *db, char *table, char *where) 1686my_ulonglong dbCount(MYSQL *db, char *table, char *where)
1667{ 1687{
@@ -1908,15 +1928,14 @@ gridStats *getStats(MYSQL *db, gridStats *stats)
1908 rgnSizes->inParams = szi; 1928 rgnSizes->inParams = szi;
1909 rgnSizes->outParams = szo; 1929 rgnSizes->outParams = szo;
1910 rgnSizes->where = "sizeX != 0"; 1930 rgnSizes->where = "sizeX != 0";
1931 dbRequests->addfirst(dbRequests, rgnSizes, sizeof(*rgnSizes));
1911 } 1932 }
1912 dbDoSomething(rgnSizes, FALSE); 1933 dbDoSomething(rgnSizes, FALSE);
1913 rowData *rows = rgnSizes->rows; 1934 rowData *rows = rgnSizes->rows;
1914 qlist_obj_t obj; 1935
1915 memset((void*)&obj, 0, sizeof(obj)); // must be cleared before call 1936 qhashtbl_t *row;
1916 rows->rows->lock(rows->rows); 1937 while (NULL != (row = rows->rows->getat(rows->rows, 0, NULL, true)))
1917 while (rows->rows->getnext(rows->rows, &obj, false) == true)
1918 { 1938 {
1919 qhashtbl_t *row = (qhashtbl_t *) obj.data;
1920 my_ulonglong x = 0, y = 0; 1939 my_ulonglong x = 0, y = 0;
1921 1940
1922 tmp = row->getstr(row, "sizeX", false); 1941 tmp = row->getstr(row, "sizeX", false);
@@ -1930,11 +1949,13 @@ gridStats *getStats(MYSQL *db, gridStats *stats)
1930 else 1949 else
1931 y = atoll(tmp); 1950 y = atoll(tmp);
1932 simSize += x * y; 1951 simSize += x * y;
1933 free(row); 1952// TODO - I can't win. valgrind complains that either something is being freed twice, or not freed at all, no matter what I do.
1953// This seems to keep the memory loss down to a minimum.
1954 row->free(row);
1955 rows->rows->removefirst(rows->rows);
1934 } 1956 }
1935 rows->rows->unlock(rows->rows);
1936 free(rows->rows);
1937 free(rows->fieldNames); 1957 free(rows->fieldNames);
1958 rows->rows->free(rows->rows);
1938 free(rows); 1959 free(rows);
1939 1960
1940 tmp = xmprintf("%lu", simSize); 1961 tmp = xmprintf("%lu", simSize);
@@ -1986,7 +2007,7 @@ void santize(qhashtbl_t *tbl, bool decode)
1986 2007
1987 memset((void*)&obj, 0, sizeof(obj)); 2008 memset((void*)&obj, 0, sizeof(obj));
1988 tbl->lock(tbl); 2009 tbl->lock(tbl);
1989 while(tbl->getnext(tbl, &obj, true) == true) 2010 while(tbl->getnext(tbl, &obj, false) == true)
1990 { 2011 {
1991 char *n = obj.name, *o = (char *) obj.data; 2012 char *n = obj.name, *o = (char *) obj.data;
1992 2013
@@ -2004,7 +2025,6 @@ void santize(qhashtbl_t *tbl, bool decode)
2004 } 2025 }
2005 2026
2006 tbl->putstr(tbl, n, o); 2027 tbl->putstr(tbl, n, o);
2007 free(o);
2008 } 2028 }
2009 tbl->unlock(tbl); 2029 tbl->unlock(tbl);
2010} 2030}
@@ -2033,7 +2053,7 @@ enum cookieSame
2033typedef struct _cookie cookie; 2053typedef struct _cookie cookie;
2034struct _cookie 2054struct _cookie
2035{ 2055{
2036 char *cookie, *value, *domain, *path; 2056 char *value, *domain, *path;
2037 // char *expires; // Use maxAge instead, it's far simpler to figure out. 2057 // char *expires; // Use maxAge instead, it's far simpler to figure out.
2038 int maxAge; 2058 int maxAge;
2039 boolean secure, httpOnly; 2059 boolean secure, httpOnly;
@@ -2043,23 +2063,30 @@ struct _cookie
2043cookie *setCookie(reqData *Rd, char *cki, char *value) 2063cookie *setCookie(reqData *Rd, char *cki, char *value)
2044{ 2064{
2045 cookie *ret = xzalloc(sizeof(cookie)); 2065 cookie *ret = xzalloc(sizeof(cookie));
2066 char *cook = xstrdup(cki);
2046 int l, i; 2067 int l, i;
2047 2068
2048 ret->cookie = xstrdup(cki);
2049 // Validate this, as there is a limited set of characters allowed. 2069 // Validate this, as there is a limited set of characters allowed.
2050 qstrreplace("tr", ret->cookie, "()<>@,;:\\\"/[]?={} \t", "_"); 2070 qstrreplace("tr", cook, "()<>@,;:\\\"/[]?={} \t", "_");
2051 l = strlen(ret->cookie); 2071 l = strlen(cook);
2052 for (i = 0; i < l; i++) 2072 for (i = 0; i < l; i++)
2053 { 2073 {
2054 if (iscntrl(ret->cookie[i]) != 0) 2074 if (iscntrl(cook[i]) != 0)
2055 ret->cookie[i] = '_'; 2075 cook[i] = '_';
2056 } 2076 }
2057 ret->value = qurl_encode(value, strlen(value)); 2077 l = strlen(value);
2078 if (0 != l)
2079 ret->value = qurl_encode(value, l);
2080 else
2081 ret->value = value;
2058 ret->httpOnly = TRUE; 2082 ret->httpOnly = TRUE;
2059 ret->site = CS_STRICT; 2083 ret->site = CS_STRICT;
2060 ret->secure = TRUE; 2084 ret->secure = TRUE;
2061 ret->path = xstrdup(getStrH(Rd->headers, "SCRIPT_NAME")); 2085 ret->path = getStrH(Rd->headers, "SCRIPT_NAME");
2062 Rd->Rcookies->put(Rd->Rcookies, cki, ret, sizeof(*ret)); 2086 Rd->Rcookies->put(Rd->Rcookies, cook, ret, sizeof(cookie));
2087 free(ret);
2088 ret = Rd->Rcookies->get(Rd->Rcookies, cook, NULL, false);
2089 free(cook);
2063 2090
2064 return ret; 2091 return ret;
2065} 2092}
@@ -2388,6 +2415,7 @@ static void HTMLfooter(qgrow_t *reply)
2388fragment *newFragment(enum fragmentType type, char *text, int len) 2415fragment *newFragment(enum fragmentType type, char *text, int len)
2389{ 2416{
2390 fragment *frg = xmalloc(sizeof(fragment)); 2417 fragment *frg = xmalloc(sizeof(fragment));
2418
2391 frg->type = type; 2419 frg->type = type;
2392 frg->length = len; 2420 frg->length = len;
2393 frg->text = xmalloc(len + 1); 2421 frg->text = xmalloc(len + 1);
@@ -2435,8 +2463,10 @@ qlist_t *fragize(char *mm, size_t length)
2435 i += 4; 2463 i += 4;
2436 } 2464 }
2437 frg0 = newFragment(FT_TEXT, &mm[k], m - k); 2465 frg0 = newFragment(FT_TEXT, &mm[k], m - k);
2438 fragments->addlast(fragments, frg0, sizeof(*frg0)); 2466 fragments->addlast(fragments, frg0, sizeof(fragment));
2439 fragments->addlast(fragments, frg1, sizeof(*frg1)); 2467 fragments->addlast(fragments, frg1, sizeof(fragment));
2468 free(frg0);
2469 free(frg1);
2440 k = i; 2470 k = i;
2441 break; 2471 break;
2442 } 2472 }
@@ -2450,11 +2480,12 @@ qlist_t *fragize(char *mm, size_t length)
2450 } 2480 }
2451 frg0 = newFragment(FT_TEXT, &mm[k], length - k); 2481 frg0 = newFragment(FT_TEXT, &mm[k], length - k);
2452 fragments->addlast(fragments, frg0, sizeof(*frg0)); 2482 fragments->addlast(fragments, frg0, sizeof(*frg0));
2483 free(frg0);
2453 2484
2454 return fragments; 2485 return fragments;
2455} 2486}
2456 2487
2457void unfragize(qlist_t *fragments, reqData *Rd) 2488void unfragize(qlist_t *fragments, reqData *Rd, boolean fre)
2458{ 2489{
2459 qlist_obj_t lobj; 2490 qlist_obj_t lobj;
2460 memset((void *) &lobj, 0, sizeof(lobj)); 2491 memset((void *) &lobj, 0, sizeof(lobj));
@@ -2468,8 +2499,12 @@ void unfragize(qlist_t *fragments, reqData *Rd)
2468 continue; 2499 continue;
2469 } 2500 }
2470 HTMLfill(Rd, frg->type, frg->text, frg->length); 2501 HTMLfill(Rd, frg->type, frg->text, frg->length);
2502 if (fre)
2503 free(frg->text);
2471 } 2504 }
2472 fragments->unlock(fragments); 2505 fragments->unlock(fragments);
2506 if (fre)
2507 fragments->free(fragments);
2473} 2508}
2474 2509
2475HTMLfile *checkHTMLcache(char *file) 2510HTMLfile *checkHTMLcache(char *file)
@@ -2876,6 +2911,7 @@ static void freeSesh(reqData *Rd, boolean linky, boolean wipe)
2876 } 2911 }
2877 else 2912 else
2878 shs->leaf[0] = '\0'; 2913 shs->leaf[0] = '\0';
2914 free(file);
2879} 2915}
2880 2916
2881static void setToken_n_munchie(reqData *Rd, boolean linky) 2917static void setToken_n_munchie(reqData *Rd, boolean linky)
@@ -2900,8 +2936,8 @@ static void setToken_n_munchie(reqData *Rd, boolean linky)
2900 2936
2901 if (!linky) 2937 if (!linky)
2902 { 2938 {
2903 cookie *ck = setCookie(Rd, "toke_n_munchie", shs->toke_n_munchie); 2939 setCookie(Rd, "toke_n_munchie", shs->toke_n_munchie);
2904 cookie *ckh = setCookie(Rd, "hashish", shs->hashish); 2940 setCookie(Rd, "hashish", shs->hashish);
2905 } 2941 }
2906 char *tnm0 = xmprintf( "toke_n_munchie = \n" 2942 char *tnm0 = xmprintf( "toke_n_munchie = \n"
2907 "{\n" 2943 "{\n"
@@ -2953,6 +2989,8 @@ t("stuff %s = %s", obj.name, (char *) obj.data);
2953 // Set the mtime on the file. 2989 // Set the mtime on the file.
2954 futimens(fd, shs->timeStamp); 2990 futimens(fd, shs->timeStamp);
2955 xclose(fd); 2991 xclose(fd);
2992 free(tnm1);
2993 free(tnm0);
2956 free(file); 2994 free(file);
2957} 2995}
2958 2996
@@ -3052,14 +3090,18 @@ d("New sesh");
3052 } 3090 }
3053 else 3091 else
3054 { 3092 {
3055 qstrcpy(ret->salt, sizeof(ret->salt), qhex_encode(buf, sizeof(buf))); 3093 t0 = qhex_encode(buf, sizeof(buf));
3094 qstrcpy(ret->salt, sizeof(ret->salt), t0);
3095 free(t0);
3056//d("salt %s", ret->salt); 3096//d("salt %s", ret->salt);
3057 numBytes = getrandom((void *)buf, sizeof(buf), GRND_NONBLOCK); 3097 numBytes = getrandom((void *)buf, sizeof(buf), GRND_NONBLOCK);
3058 if (-1 == numBytes) 3098 if (-1 == numBytes)
3059 perror_msg("Unable to generate a suitable random number."); 3099 perror_msg("Unable to generate a suitable random number.");
3060 else 3100 else
3061 { 3101 {
3062 qstrcpy(ret->seshID, sizeof(ret->seshID), qhex_encode(buf, sizeof(buf))); 3102 t0 = qhex_encode(buf, sizeof(buf));
3103 qstrcpy(ret->seshID, sizeof(ret->seshID), t0);
3104 free(t0);
3063//d("seshID %s", ret->seshID); 3105//d("seshID %s", ret->seshID);
3064 3106
3065 ret->timeStamp[0].tv_nsec = UTIME_OMIT; 3107 ret->timeStamp[0].tv_nsec = UTIME_OMIT;
@@ -3079,14 +3121,17 @@ d("New sesh");
3079 qstrcpy(ret->munchie, sizeof(ret->munchie), munchie); 3121 qstrcpy(ret->munchie, sizeof(ret->munchie), munchie);
3080//d("munchie %s", ret->munchie); 3122//d("munchie %s", ret->munchie);
3081 t0 = xmprintf("%s%s", getStrH(Rd->stuff, "UUID"), munchie); 3123 t0 = xmprintf("%s%s", getStrH(Rd->stuff, "UUID"), munchie);
3124 free(munchie);
3082 toke_n_munchie = myHMAC(t0, FALSE); 3125 toke_n_munchie = myHMAC(t0, FALSE);
3083 free(t0); 3126 free(t0);
3084 qstrcpy(ret->toke_n_munchie, sizeof(ret->toke_n_munchie), toke_n_munchie); 3127 qstrcpy(ret->toke_n_munchie, sizeof(ret->toke_n_munchie), toke_n_munchie);
3085//d("toke_n_munchie %s", ret->toke_n_munchie); 3128//d("toke_n_munchie %s", ret->toke_n_munchie);
3086 hashish = myHMACkey(ret->salt, toke_n_munchie, FALSE); 3129 hashish = myHMACkey(ret->salt, toke_n_munchie, FALSE);
3130 free(toke_n_munchie);
3087 qstrcpy(ret->hashish, sizeof(ret->hashish), hashish); 3131 qstrcpy(ret->hashish, sizeof(ret->hashish), hashish);
3088//d("hashish %s", ret->hashish); 3132//d("hashish %s", ret->hashish);
3089 t0 = myHMACkey(getStrH(Rd->configs, "pepper"), hashish, TRUE); 3133 t0 = myHMACkey(getStrH(Rd->configs, "pepper"), hashish, TRUE);
3134 free(hashish);
3090 qstrcpy(ret->leaf, sizeof(ret->leaf), t0); 3135 qstrcpy(ret->leaf, sizeof(ret->leaf), t0);
3091//d("leaf %s", ret->leaf); 3136//d("leaf %s", ret->leaf);
3092 free(t0); 3137 free(t0);
@@ -3182,9 +3227,7 @@ static int validateSesh(reqData *Rd, qhashtbl_t *data, char *name)
3182 return ret; 3227 return ret;
3183 } 3228 }
3184 3229
3185 char *toke_n_munchie = "", *munchie = "", *hashish = "", 3230 char *toke_n_munchie = "", *munchie = "", *hashish = "", *leaf = "", *timeStamp = "", *seshion = "", *seshID = "", *t0, *t1;
3186 *leaf, *timeStamp = "", *seshion = "", *seshID = "",
3187 *t0, *t1;
3188 3231
3189 // In this case the session stuff has to come from specific places. 3232 // In this case the session stuff has to come from specific places.
3190 hashish = getStrH(Rd->queries, "hashish"); 3233 hashish = getStrH(Rd->queries, "hashish");
@@ -3224,141 +3267,143 @@ static int validateSesh(reqData *Rd, qhashtbl_t *data, char *name)
3224 3267
3225 if (0 == ret) 3268 if (0 == ret)
3226 { 3269 {
3270 // This is apparently controversial, I added it coz some of the various security docs suggested it's a good idea.
3271 // https://security.stackexchange.com/questions/139952/why-arent-sessions-exclusive-to-an-ip-address?rq=1
3272 // Includes various reasons why it's bad.
3273 // Another good reason why it is bad, TOR.
3274 // So should make this a user option, like Mantis does.
3275 if (strcmp(getStrH(Rd->headers, "REMOTE_ADDR"), getStrH(tnm, "IP")) != 0)
3227 { 3276 {
3228 { 3277 bitchSession(Rd, "Wrong IP for session.", "Session IP doesn't match.");
3229 // This is apparently controversial, I added it coz some of the various security docs suggested it's a good idea. 3278 ret++;
3230 // https://security.stackexchange.com/questions/139952/why-arent-sessions-exclusive-to-an-ip-address?rq=1 3279 }
3231 // Includes various reasons why it's bad. 3280 else
3232 // Another good reason why it is bad, TOR. 3281 {
3233 // So should make this a user option, like Mantis does. 3282 timeStamp = xmprintf("%ld.%ld", (long) st.st_mtim.tv_sec, st.st_mtim.tv_nsec);
3234 if (strcmp(getStrH(Rd->headers, "REMOTE_ADDR"), getStrH(tnm, "IP")) != 0) 3283//d("timeStamp %s", timeStamp);
3284 seshion = xmprintf("%s%s", tnm->getstr(tnm, "seshID", false), timeStamp);
3285//d("sesh %s", seshion);
3286 t0 = myHMAC(seshion, FALSE);
3287 munchie = xmprintf("%s%s", t0, timeStamp);
3288//d("munchie %s", munchie);
3289 free(t0);
3290 free(timeStamp);
3291 t1 = getStrH(Rd->body, "munchie");
3292 if ('\0' != t1[0])
3293 {
3294 if (strcmp(t1, munchie) != 0)
3235 { 3295 {
3236 bitchSession(Rd, "Wrong IP for session.", "Session IP doesn't match."); 3296 bitchSession(Rd, "Wrong munchie for session.", "HMAC(seshID + timeStamp) != munchie");
3237 ret++; 3297 ret++;
3238 } 3298 }
3239 else 3299 else
3240 { 3300 {
3241 timeStamp = xmprintf("%ld.%ld", (long) st.st_mtim.tv_sec, st.st_mtim.tv_nsec); 3301 t0 = xmprintf("%s%s", getStrH(tnm, "UUID"), munchie);
3242//d("timeStamp %s", timeStamp); 3302 t1 = myHMAC(t0, FALSE);
3243 seshion = xmprintf("%s%s", tnm->getstr(tnm, "seshID", false), timeStamp);
3244//d("sesh %s", seshion);
3245 t0 = myHMAC(seshion, FALSE);
3246 munchie = xmprintf("%s%s", t0, timeStamp);
3247//d("munchie %s", munchie);
3248 free(t0); 3303 free(t0);
3249 t1 = getStrH(Rd->body, "munchie");
3250 if ('\0' != t1[0])
3251 {
3252 if (strcmp(t1, munchie) != 0)
3253 {
3254 bitchSession(Rd, "Wrong munchie for session.", "HMAC(seshID + timeStamp) != munchie");
3255 ret++;
3256 }
3257 else
3258 {
3259 t0 = xmprintf("%s%s", getStrH(tnm, "UUID"), munchie);
3260 t1 = myHMAC(t0, FALSE);
3261 free(t0);
3262 3304
3263//d("toke_n_munchie %s", t1); 3305//d("toke_n_munchie %s", t1);
3264 if (strcmp(t1, toke_n_munchie) != 0) 3306 if (strcmp(t1, toke_n_munchie) != 0)
3265 { 3307 {
3266 bitchSession(Rd, "Wrong toke_n_munchie for session.", "HMAC(UUID + munchie) != toke_n_munchie"); 3308 bitchSession(Rd, "Wrong toke_n_munchie for session.", "HMAC(UUID + munchie) != toke_n_munchie");
3267 ret++; 3309 ret++;
3268 }
3269 free(t1);
3270 }
3271 } 3310 }
3311 free(t1);
3312 }
3313 }
3272 3314
3273 if (0 == ret) 3315 if (0 == ret)
3274 { 3316 {
3275 if (linky) 3317 if (linky)
3276 { 3318 {
3277 t0 = xmprintf("%s%s", getStrH(tnm, "UUID"), munchie); 3319 t0 = xmprintf("%s%s", getStrH(tnm, "UUID"), munchie);
3278 t1 = myHMAC(t0, FALSE); 3320 t1 = myHMAC(t0, FALSE);
3279 free(t0); 3321 free(t0);
3280 toke_n_munchie = t1; 3322 toke_n_munchie = t1;
3281//d("toke_n_munchie %s", t1); 3323//d("toke_n_munchie %s", t1);
3282 } 3324 }
3283 t1 = myHMACkey(getStrH(tnm, "salt"), toke_n_munchie, FALSE); 3325 t1 = myHMACkey(getStrH(tnm, "salt"), toke_n_munchie, FALSE);
3284//d("hashish %s", t1); 3326//d("hashish %s", t1);
3285 if (strcmp(t1, hashish) != 0) 3327 if (strcmp(t1, hashish) != 0)
3286 { 3328 {
3287 bitchSession(Rd, "Wrong hashish for session.", "HMAC(toke_n_munchie + salt) != hashish"); 3329 bitchSession(Rd, "Wrong hashish for session.", "HMAC(toke_n_munchie + salt) != hashish");
3288 ret++; 3330 ret++;
3289 } 3331 }
3332 free(t1);
3290 3333
3291 if (now.tv_sec > st.st_mtim.tv_sec + idleTimeOut) 3334 if (now.tv_sec > st.st_mtim.tv_sec + idleTimeOut)
3292 { 3335 {
3293 W("Session idled out."); 3336 W("Session idled out.");
3294 Rd->vegOut = TRUE; 3337 Rd->vegOut = TRUE;
3295 } 3338 }
3296 else 3339 else
3297 { 3340 {
3298 if (now.tv_sec > st.st_mtim.tv_sec + seshTimeOut) 3341 if (now.tv_sec > st.st_mtim.tv_sec + seshTimeOut)
3299 { 3342 {
3300 W("Session timed out."); 3343 W("Session timed out.");
3301 Rd->vegOut = TRUE; 3344 Rd->vegOut = TRUE;
3302 } 3345 }
3303 else 3346 else
3304 { 3347 {
3305W("Validated session."); 3348W("Validated session.");
3306 sesh *shs = &Rd->shs; 3349 sesh *shs = &Rd->shs;
3307 3350
3308 qstrcpy(shs->leaf, sizeof(shs->leaf), leaf); 3351 qstrcpy(shs->leaf, sizeof(shs->leaf), leaf);
3309 if (linky) 3352 if (linky)
3310 { 3353 {
3311W("Validated session linky."); 3354W("Validated session linky.");
3312 addStrL(Rd->messages, "Congratulations, you have validated your new account. Now you can log onto the web site."); 3355 addStrL(Rd->messages, "Congratulations, you have validated your new account. Now you can log onto the web site.");
3313 addStrL(Rd->messages, "NOTE - you wont be able to log onto the grid until your new account has been approved."); 3356 addStrL(Rd->messages, "NOTE - you wont be able to log onto the grid until your new account has been approved.");
3314 Rd->lnk = xzalloc(sizeof(sesh)); 3357 Rd->lnk = xzalloc(sizeof(sesh));
3315 qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), leaf); 3358 qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), leaf);
3316 Rd->chillOut = TRUE; 3359 Rd->chillOut = TRUE;
3317 freeSesh(Rd, linky, FALSE); 3360 freeSesh(Rd, linky, FALSE);
3318 qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), ""); 3361 qstrcpy(Rd->lnk->leaf, sizeof(Rd->lnk->leaf), "");
3319 Rd->func = (pageBuildFunction) loginPage; 3362 Rd->func = (pageBuildFunction) loginPage;
3320 Rd->doit = "logout"; 3363 Rd->doit = "logout";
3321// TODO - we might want to delete their old .lua session as well. Maybe? Don't think we have any suitable codes to find it. 3364// TODO - we might want to delete their old .lua session as well. Maybe? Don't think we have any suitable codes to find it.
3322 } 3365 }
3323 else 3366 else
3324 { 3367 {
3325 qstrcpy(shs->sesh, sizeof(shs->sesh), seshion); 3368 qstrcpy(shs->sesh, sizeof(shs->sesh), seshion);
3326 qstrcpy(shs->toke_n_munchie, sizeof(shs->toke_n_munchie), toke_n_munchie); 3369 qstrcpy(shs->toke_n_munchie, sizeof(shs->toke_n_munchie), toke_n_munchie);
3327 qstrcpy(shs->hashish, sizeof(shs->hashish), hashish); 3370 qstrcpy(shs->hashish, sizeof(shs->hashish), hashish);
3328 qstrcpy(shs->munchie, sizeof(shs->munchie), munchie); 3371 qstrcpy(shs->munchie, sizeof(shs->munchie), munchie);
3329 qstrcpy(shs->salt, sizeof(shs->salt), tnm->getstr(tnm, "salt", false)); 3372 qstrcpy(shs->salt, sizeof(shs->salt), tnm->getstr(tnm, "salt", false));
3330 qstrcpy(shs->seshID, sizeof(shs->seshID), tnm->getstr(tnm, "seshID", false)); 3373 qstrcpy(shs->seshID, sizeof(shs->seshID), tnm->getstr(tnm, "seshID", false));
3331 shs->timeStamp[0].tv_nsec = UTIME_OMIT; 3374 shs->timeStamp[0].tv_nsec = UTIME_OMIT;
3332 shs->timeStamp[0].tv_sec = UTIME_OMIT; 3375 shs->timeStamp[0].tv_sec = UTIME_OMIT;
3333 memcpy(&shs->timeStamp[1], &st.st_mtim, sizeof(struct timespec)); 3376 memcpy(&shs->timeStamp[1], &st.st_mtim, sizeof(struct timespec));
3334 t0 = tnm->getstr(tnm, "linky-hashish", false); 3377 t0 = tnm->getstr(tnm, "linky-hashish", false);
3335 if (NULL != t0) 3378 if (NULL != t0)
3336 Rd->stuff->putstr(Rd->stuff, "linky-hashish", t0); 3379 Rd->stuff->putstr(Rd->stuff, "linky-hashish", t0);
3337 } 3380 }
3338 } 3381 }
3339 3382
3340 qhashtbl_obj_t obj; 3383 qhashtbl_obj_t obj;
3341 3384
3342 memset((void*)&obj, 0, sizeof(obj)); 3385 memset((void*)&obj, 0, sizeof(obj));
3343 tnm->lock(tnm); 3386 tnm->lock(tnm);
3344 while(tnm->getnext(tnm, &obj, false) == true) 3387 while(tnm->getnext(tnm, &obj, false) == true)
3345 { 3388 {
3346 char *n = obj.name; 3389 char *n = obj.name;
3347 3390
3348 if ((strcmp("salt", n) != 0) && (strcmp("seshID", n) != 0)) 3391 if ((strcmp("salt", n) != 0) && (strcmp("seshID", n) != 0))
3349 { 3392 {
3350t("Lua %s = %s", n, (char *) obj.data); 3393t("Lua %s = %s", n, (char *) obj.data);
3351 Rd->stuff->putstr(Rd->stuff, obj.name, (char *) obj.data); 3394 Rd->stuff->putstr(Rd->stuff, obj.name, (char *) obj.data);
3352 }
3353 }
3354 tnm->unlock(tnm);
3355 Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", tnm->getstr(tnm, "UUID", true));
3356 }
3357 } 3395 }
3396 }
3397 tnm->unlock(tnm);
3398 Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", tnm->getstr(tnm, "UUID", true));
3358 } 3399 }
3359 } 3400 }
3401 free(munchie);
3402 free(seshion);
3360 } 3403 }
3361 } 3404 }
3405 free(leaf);
3406 tnm->free(tnm);
3362 } 3407 }
3363 3408
3364 return ret; 3409 return ret;
@@ -3597,6 +3642,7 @@ static int validateName(reqData *Rd, qhashtbl_t *data, char *nm)
3597 acnts->inParams = szi; 3642 acnts->inParams = szi;
3598 acnts->outParams = szo; 3643 acnts->outParams = szo;
3599 acnts->where = "FirstName=? and LastName=?"; 3644 acnts->where = "FirstName=? and LastName=?";
3645 dbRequests->addfirst(dbRequests, acnts, sizeof(*acnts));
3600 } 3646 }
3601 dbDoSomething(acnts, FALSE, name, s); 3647 dbDoSomething(acnts, FALSE, name, s);
3602 rowData *rows = acnts->rows; 3648 rowData *rows = acnts->rows;
@@ -3621,8 +3667,8 @@ static int validateName(reqData *Rd, qhashtbl_t *data, char *nm)
3621 } 3667 }
3622 else 3668 else
3623 { 3669 {
3624 W("More than one UserAccounts record with that name."); 3670 W("More than one UserAccounts record with that name.");
3625 ret++; 3671 ret++;
3626 } 3672 }
3627 bitch(Rd, "Login failed.", "Could not find user record."); 3673 bitch(Rd, "Login failed.", "Could not find user record.");
3628 } 3674 }
@@ -3645,8 +3691,8 @@ static int validateName(reqData *Rd, qhashtbl_t *data, char *nm)
3645 Rd->database->putstr(Rd->database, "auth.passwordHash", getStrH(tnm, "passwordHash")); 3691 Rd->database->putstr(Rd->database, "auth.passwordHash", getStrH(tnm, "passwordHash"));
3646 tnm->free(tnm); 3692 tnm->free(tnm);
3647 } 3693 }
3648 Rd->stuff->putstr(Rd->stuff, "UUID", xstrdup(getStrH(Rd->database, "UserAccounts.PrincipalID"))); 3694 Rd->stuff->putstr(Rd->stuff, "UUID", getStrH(Rd->database, "UserAccounts.PrincipalID"));
3649 Rd->stuff->putstr(Rd->stuff, "level", xstrdup(getStrH(Rd->database, "UserAccounts.Userlevel"))); 3695 Rd->stuff->putstr(Rd->stuff, "level", getStrH(Rd->database, "UserAccounts.Userlevel"));
3650 if (s) {s--; *s = ' '; s++;} 3696 if (s) {s--; *s = ' '; s++;}
3651 Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name)); 3697 Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name));
3652 if (s) {s--; *s = '\0'; s++;} 3698 if (s) {s--; *s = '\0'; s++;}
@@ -3696,12 +3742,14 @@ static int validateName(reqData *Rd, qhashtbl_t *data, char *nm)
3696 Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name)); 3742 Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name));
3697 } 3743 }
3698 } 3744 }
3699 free(rows->rows);
3700 free(rows->fieldNames); 3745 free(rows->fieldNames);
3746 rows->rows->free(rows->rows);
3701 free(rows); 3747 free(rows);
3748 tnm->free(tnm);
3702 if (s) {s--; *s = ' '; s++;} 3749 if (s) {s--; *s = ' '; s++;}
3703 } 3750 }
3704 } 3751 }
3752 free(name);
3705 3753
3706 badBoy(ret, Rd, data, "name", NULL); 3754 badBoy(ret, Rd, data, "name", NULL);
3707 return ret; 3755 return ret;
@@ -3733,6 +3781,7 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name)
3733 auth->inParams = szi; 3781 auth->inParams = szi;
3734 auth->outParams = szo; 3782 auth->outParams = szo;
3735 auth->where = "UUID=?"; 3783 auth->where = "UUID=?";
3784 dbRequests->addfirst(dbRequests, auth, sizeof(*auth));
3736 } 3785 }
3737 dbDoSomething(auth, FALSE, UUID); 3786 dbDoSomething(auth, FALSE, UUID);
3738 rowData *rows = auth->rows; 3787 rowData *rows = auth->rows;
@@ -3776,11 +3825,15 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name)
3776 ret++; 3825 ret++;
3777 } 3826 }
3778 Rd->stuff->putstr(Rd->stuff, "passwordHash", md5ascii); 3827 Rd->stuff->putstr(Rd->stuff, "passwordHash", md5ascii);
3779 free(md5ascii);
3780 } 3828 }
3829 free(md5ascii);
3781 free(where); 3830 free(where);
3782 } 3831 }
3832 free(me);
3783 } 3833 }
3834 free(rows->fieldNames);
3835 rows->rows->free(rows->rows);
3836 free(rows);
3784 } 3837 }
3785 } 3838 }
3786 else if (create) 3839 else if (create)
@@ -3827,6 +3880,7 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name)
3827 } 3880 }
3828 else 3881 else
3829 { 3882 {
3883 free(salt);
3830 salt = qhex_encode(md5hash, 16); 3884 salt = qhex_encode(md5hash, 16);
3831 hash = xmprintf("%s:%s", salt, getStrH(Rd->stuff, "passwordSalt")); 3885 hash = xmprintf("%s:%s", salt, getStrH(Rd->stuff, "passwordSalt"));
3832 if (!qhashmd5((void *) hash, strlen(hash), md5hash)) 3886 if (!qhashmd5((void *) hash, strlen(hash), md5hash))
@@ -3836,10 +3890,13 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name)
3836 } 3890 }
3837 else 3891 else
3838 { 3892 {
3893 free(hash);
3839 hash = qhex_encode(md5hash, 16); 3894 hash = qhex_encode(md5hash, 16);
3840 Rd->stuff->putstr(Rd->stuff, "passwordHash", hash); 3895 Rd->stuff->putstr(Rd->stuff, "passwordHash", hash);
3841 Rd->chillOut = TRUE; 3896 Rd->chillOut = TRUE;
3842 } 3897 }
3898 free(hash);
3899 free(salt);
3843 } 3900 }
3844 } 3901 }
3845 } 3902 }
@@ -3866,7 +3923,7 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name)
3866 { 3923 {
3867 pswd = qhex_encode(md5hash, 16); 3924 pswd = qhex_encode(md5hash, 16);
3868 hash = xmprintf("%s:%s", pswd, Osalt); 3925 hash = xmprintf("%s:%s", pswd, Osalt);
3869 3926 free(pswd);
3870 if (!qhashmd5((void *) hash, strlen(hash), md5hash)) 3927 if (!qhashmd5((void *) hash, strlen(hash), md5hash))
3871 { 3928 {
3872 bitch(Rd, "Internal session error.", "Confirm - qhashmd5(passwordSalt) failed."); 3929 bitch(Rd, "Internal session error.", "Confirm - qhashmd5(passwordSalt) failed.");
@@ -3874,12 +3931,14 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name)
3874 } 3931 }
3875 else 3932 else
3876 { 3933 {
3934 free(hash);
3877 hash = qhex_encode(md5hash, 16); 3935 hash = qhex_encode(md5hash, 16);
3878 if (strcmp(hash, Ohash) != 0) 3936 if (strcmp(hash, Ohash) != 0)
3879 { 3937 {
3880 bitch(Rd, "Passwords are not the same.", ""); 3938 bitch(Rd, "Passwords are not the same.", "");
3881 ret++; 3939 ret++;
3882 } 3940 }
3941 free(hash);
3883 } 3942 }
3884 } 3943 }
3885 } 3944 }
@@ -3920,6 +3979,7 @@ static int validateUUID(reqData *Rd, qhashtbl_t *data, char *name)
3920 uuids->inParams = szi; 3979 uuids->inParams = szi;
3921 uuids->outParams = szo; 3980 uuids->outParams = szo;
3922 uuids->where = "PrincipalID=?"; 3981 uuids->where = "PrincipalID=?";
3982 dbRequests->addfirst(dbRequests, uuids, sizeof(*uuids));
3923 } 3983 }
3924 3984
3925 if ((strcmp("cancel", Rd->doit) == 0) || (strcmp("logout", Rd->doit) == 0)) 3985 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)
4017 4077
4018void loginPage(reqData *Rd, char *message) 4078void loginPage(reqData *Rd, char *message)
4019{ 4079{
4020 char *name = xstrdup(getStrH(Rd->stuff, "name")); 4080 char *name = xstrdup(getStrH(Rd->stuff, "name")), *linky = checkLinky(Rd);
4021 4081
4022 Rd->stuff->remove(Rd->stuff, "UUID"); 4082 Rd->stuff->remove(Rd->stuff, "UUID");
4023 HTMLheader(Rd->reply, "<!--#echo var=\"grid\" --> account manager"); 4083 HTMLheader(Rd->reply, "<!--#echo var=\"grid\" --> account manager");
4024 HTMLdebug(Rd->reply); 4084 HTMLdebug(Rd->reply);
4025 Rd->reply->addstrf(Rd->reply, "<h1><!--#echo var=\"grid\" --> account manager</h1>\n"); 4085 Rd->reply->addstrf(Rd->reply, "<h1><!--#echo var=\"grid\" --> account manager</h1>\n");
4026 Rd->reply->addstr(Rd->reply, checkLinky(Rd)); 4086 Rd->reply->addstr(Rd->reply, linky);
4087 free(linky);
4027 if (0 != Rd->errors->size(Rd->messages)) 4088 if (0 != Rd->errors->size(Rd->messages))
4028 HTMLlist(Rd->reply, "messages -", Rd->messages); 4089 HTMLlist(Rd->reply, "messages -", Rd->messages);
4029 HTMLform(Rd->reply, "", Rd->shs.munchie); 4090 HTMLform(Rd->reply, "", Rd->shs.munchie);
@@ -4044,7 +4105,7 @@ void loginPage(reqData *Rd, char *message)
4044 4105
4045void accountCreationPage(reqData *Rd, char *message) 4106void accountCreationPage(reqData *Rd, char *message)
4046{ 4107{
4047 char *name = getStrH(Rd->body, "name"); 4108 char *name = getStrH(Rd->body, "name"), *linky = checkLinky(Rd);
4048 char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie"); 4109 char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie");
4049 char *tmp = xmalloc(16), *t; 4110 char *tmp = xmalloc(16), *t;
4050 int i, d; 4111 int i, d;
@@ -4058,7 +4119,8 @@ void accountCreationPage(reqData *Rd, char *message)
4058 HTMLdebug(Rd->reply); 4119 HTMLdebug(Rd->reply);
4059 Rd->reply->addstrf(Rd->reply, "<h1><!--#echo var=\"grid\" --> account manager</h1>\n"); 4120 Rd->reply->addstrf(Rd->reply, "<h1><!--#echo var=\"grid\" --> account manager</h1>\n");
4060 Rd->reply->addstrf(Rd->reply, "<h2>Creating <!--#echo var=\"grid\" --> account for %s</h2>\n", name); 4121 Rd->reply->addstrf(Rd->reply, "<h2>Creating <!--#echo var=\"grid\" --> account for %s</h2>\n", name);
4061 Rd->reply->addstr(Rd->reply, checkLinky(Rd)); 4122 Rd->reply->addstr(Rd->reply, linky);
4123 free(linky);
4062 if (0 != Rd->errors->size(Rd->messages)) 4124 if (0 != Rd->errors->size(Rd->messages))
4063 HTMLlist(Rd->reply, "messages -", Rd->messages); 4125 HTMLlist(Rd->reply, "messages -", Rd->messages);
4064// TODO - set this to autocomplete="off". 4126// TODO - set this to autocomplete="off".
@@ -4124,14 +4186,15 @@ void accountCreationPage(reqData *Rd, char *message)
4124 4186
4125void loggedOnPage(reqData *Rd, char *message) 4187void loggedOnPage(reqData *Rd, char *message)
4126{ 4188{
4127 char *name = getStrH(Rd->stuff, "name"); 4189 char *name = getStrH(Rd->stuff, "name"), *linky = checkLinky(Rd);
4128 char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie"); 4190 char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie");
4129 4191
4130 HTMLheader(Rd->reply, "<!--#echo var=\"grid\" --> account manager"); 4192 HTMLheader(Rd->reply, "<!--#echo var=\"grid\" --> account manager");
4131 HTMLdebug(Rd->reply); 4193 HTMLdebug(Rd->reply);
4132 Rd->reply->addstrf(Rd->reply, "<h1><!--#echo var=\"grid\" --> account manager</h1>\n"); 4194 Rd->reply->addstrf(Rd->reply, "<h1><!--#echo var=\"grid\" --> account manager</h1>\n");
4133 Rd->reply->addstrf(Rd->reply, "<h2><!--#echo var=\"grid\" --> account for %s</h2>\n", name); 4195 Rd->reply->addstrf(Rd->reply, "<h2><!--#echo var=\"grid\" --> account for %s</h2>\n", name);
4134 Rd->reply->addstr(Rd->reply, checkLinky(Rd)); 4196 Rd->reply->addstr(Rd->reply, linky);
4197 free(linky);
4135 if (0 != Rd->errors->size(Rd->messages)) 4198 if (0 != Rd->errors->size(Rd->messages))
4136 HTMLlist(Rd->reply, "messages -", Rd->messages); 4199 HTMLlist(Rd->reply, "messages -", Rd->messages);
4137 HTMLform(Rd->reply, "", Rd->shs.munchie); 4200 HTMLform(Rd->reply, "", Rd->shs.munchie);
@@ -4163,14 +4226,15 @@ void loggedOnPage(reqData *Rd, char *message)
4163void listPage(reqData *Rd, char *message) 4226void listPage(reqData *Rd, char *message)
4164{ 4227{
4165// TODO - should check if the user is a god before allowing this. 4228// TODO - should check if the user is a god before allowing this.
4166 char *name = getStrH(Rd->stuff, "name"); 4229 char *name = getStrH(Rd->stuff, "name"), *linky = checkLinky(Rd);
4167 char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie"); 4230 char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie");
4168 4231
4169 HTMLheader(Rd->reply, "<!--#echo var=\"grid\" --> account manager"); 4232 HTMLheader(Rd->reply, "<!--#echo var=\"grid\" --> account manager");
4170 HTMLdebug(Rd->reply); 4233 HTMLdebug(Rd->reply);
4171 Rd->reply->addstrf(Rd->reply, "<h1><!--#echo var=\"grid\" --> account manager</h1>\n"); 4234 Rd->reply->addstrf(Rd->reply, "<h1><!--#echo var=\"grid\" --> account manager</h1>\n");
4172 Rd->reply->addstrf(Rd->reply, "<h1><!--#echo var=\"grid\" --> member accounts</h1>\n"); 4235 Rd->reply->addstrf(Rd->reply, "<h1><!--#echo var=\"grid\" --> member accounts</h1>\n");
4173 Rd->reply->addstr(Rd->reply, checkLinky(Rd)); 4236 Rd->reply->addstr(Rd->reply, linky);
4237 free(linky);
4174 if (0 != Rd->errors->size(Rd->messages)) 4238 if (0 != Rd->errors->size(Rd->messages))
4175 HTMLlist(Rd->reply, "messages -", Rd->messages); 4239 HTMLlist(Rd->reply, "messages -", Rd->messages);
4176 HTMLtable(Rd->reply, Rd->db, 4240 HTMLtable(Rd->reply, Rd->db,
@@ -4368,24 +4432,59 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile)
4368} 4432}
4369 4433
4370 4434
4435static void cleanup(void)
4436{
4437 C("Caught signal, cleaning up.");
4438 dbRequest *req = NULL;
4439
4440 while (NULL != (req = (dbRequest *) dbRequests->getat(dbRequests, 0, NULL, false)))
4441 {
4442 if (NULL != req->flds)
4443 dbFreeFields(req->flds);
4444 else
4445 D("No fields to clean up for %s - %s.", req->table, req->where);
4446 dbFreeRequest(req);
4447 dbRequests->removefirst(dbRequests);
4448 }
4449 if (fieldValidFuncs) fieldValidFuncs->free(fieldValidFuncs);
4450 if (dynPages) dynPages->free(dynPages);
4451 if (buildPages) buildPages->free(buildPages);
4452 if (HTMLfileCache) HTMLfileCache->free(HTMLfileCache);
4453 if (HTMLfileCache) mimeTypes->free(mimeTypes);
4454 if (dbRequests) dbRequests->free(dbRequests);
4455 if (database) mysql_close(database);
4456 mysql_library_end();
4457 lua_close(L);
4458 if (stats)
4459 {
4460 if (stats->stats) stats->stats->free(stats->stats);
4461 free(stats);
4462 }
4463 if (configs) configs->free(configs);
4464}
4465
4371void sledjchisl_main(void) 4466void sledjchisl_main(void)
4372{ 4467{
4373 char *cmd = *toys.optargs; 4468 char *cmd = *toys.optargs;
4374 char *tmp; 4469 char *tmp;
4375 qhashtbl_t *configs = qhashtbl(0, 0);
4376 lua_State *L = luaL_newstate();
4377 MYSQL *database = NULL, *dbconn = NULL; 4470 MYSQL *database = NULL, *dbconn = NULL;
4378 gridStats *stats = NULL; 4471 gridStats *stats = NULL;
4379 struct stat statbuf; 4472 struct stat statbuf;
4380 int status, result, i; 4473 int status, result, i;
4381 void *vd; 4474 void *vd;
4382 4475
4476 configs = qhashtbl(0, 0);
4477 L = luaL_newstate();
4478
4383 I("libfcgi version: %s", FCGI_VERSION); 4479 I("libfcgi version: %s", FCGI_VERSION);
4384 I("Lua version: %s", LUA_RELEASE); 4480 I("Lua version: %s", LUA_RELEASE);
4385 I("LuaJIT version: %s", LUAJIT_VERSION); 4481 I("LuaJIT version: %s", LUAJIT_VERSION);
4386 I("MariaDB / MySQL client version: %s", mysql_get_client_info()); 4482 I("MariaDB / MySQL client version: %s", mysql_get_client_info());
4387 I("toybox version: %s", TOYBOX_VERSION); 4483 I("toybox version: %s", TOYBOX_VERSION);
4388 4484
4485 dbRequests = qlist(0);
4486 sigatexit(cleanup);
4487
4389 pwd = getcwd(0, 0); 4488 pwd = getcwd(0, 0);
4390 4489
4391 if (-1 == fstat(STDIN_FILENO, &statbuf)) 4490 if (-1 == fstat(STDIN_FILENO, &statbuf))
@@ -4594,6 +4693,7 @@ jit library is loaded or the JIT compiler will not be activated.
4594 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); 4693 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);
4595 tmp = xmprintf("%s/sessions", scCache); 4694 tmp = xmprintf("%s/sessions", scCache);
4596 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); 4695 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);
4696 free(tmp);
4597 tmp = xmprintf("%s/users", scData); 4697 tmp = xmprintf("%s/users", scData);
4598 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); 4698 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);
4599 free(tmp); 4699 free(tmp);
@@ -4632,6 +4732,7 @@ jit library is loaded or the JIT compiler will not be activated.
4632// TODO - it looks like OpenSim invented their own half arsed backwards INI file include system. 4732// TODO - it looks like OpenSim invented their own half arsed backwards INI file include system.
4633// I doubt qlibc supports it, like it supports what seems to be the standard include system. 4733// I doubt qlibc supports it, like it supports what seems to be the standard include system.
4634// Not sure if we need to worry about it just yet. 4734// Not sure if we need to worry about it just yet.
4735// TODO - this leaks memory, but I suspect it's a bug in qLib.
4635 qlisttbl_t *qconfig = qconfig_parse_file(NULL, toybuf, '='); 4736 qlisttbl_t *qconfig = qconfig_parse_file(NULL, toybuf, '=');
4636 if (NULL == qconfig) 4737 if (NULL == qconfig)
4637 { 4738 {
@@ -4688,10 +4789,10 @@ jit library is loaded or the JIT compiler will not be activated.
4688 else 4789 else
4689 { 4790 {
4690 dbconn = mysql_real_connect(database, 4791 dbconn = mysql_real_connect(database,
4691 configs->getstr(configs, "Data Source", true), 4792 getStrH(configs, "Data Source"),
4692 configs->getstr(configs, "User ID", true), 4793 getStrH(configs, "User ID"),
4693 configs->getstr(configs, "Password", true), 4794 getStrH(configs, "Password"),
4694 configs->getstr(configs, "Database", true), 4795 getStrH(configs, "Database"),
4695// 3036, "/var/run/mysqld/mysqld.sock", 4796// 3036, "/var/run/mysqld/mysqld.sock",
4696 0, NULL, 4797 0, NULL,
4697 CLIENT_FOUND_ROWS | CLIENT_LOCAL_FILES | CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS); 4798 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.
4712 4813
4713 stats->stats->putstr(stats->stats, "uri", toybuf); 4814 stats->stats->putstr(stats->stats, "uri", toybuf);
4714 } 4815 }
4816 qconfig->free(qconfig);
4715 } 4817 }
4716 4818
4717 4819
@@ -4779,6 +4881,7 @@ t("HEADERS");
4779 { 4881 {
4780 char *k = xstrdup(*envp); 4882 char *k = xstrdup(*envp);
4781 char *v = strchr(k, '='); 4883 char *v = strchr(k, '=');
4884
4782 if (NULL != v) 4885 if (NULL != v)
4783 { 4886 {
4784 *v = '\0'; 4887 *v = '\0';
@@ -4787,6 +4890,7 @@ t("HEADERS");
4787if ((strcmp("HTTP_COOKIE", ky) == 0) || (strcmp("CONTENT_LENGTH", ky) == 0) || (strcmp("QUERY_STRING", ky) == 0)) 4890if ((strcmp("HTTP_COOKIE", ky) == 0) || (strcmp("CONTENT_LENGTH", ky) == 0) || (strcmp("QUERY_STRING", ky) == 0))
4788 d(" %s = %s", ky, v + 1); 4891 d(" %s = %s", ky, v + 1);
4789 } 4892 }
4893 free(k);
4790 } 4894 }
4791 4895
4792 // The FCGI paramaters sent from the server, are converted to environment variablse for the fcgi2 SDK. 4896 // The FCGI paramaters sent from the server, are converted to environment variablse for the fcgi2 SDK.
@@ -4846,6 +4950,7 @@ t("QUERY");
4846 Length = "0"; 4950 Length = "0";
4847t("BODY"); 4951t("BODY");
4848 Rd->body = toknize(Body, "=&"); 4952 Rd->body = toknize(Body, "=&");
4953 free(Body);
4849 santize(Rd->body, TRUE); 4954 santize(Rd->body, TRUE);
4850 4955
4851 4956
@@ -4902,8 +5007,9 @@ t("BODY");
4902// TODO - maybe cache this? 5007// TODO - maybe cache this?
4903 qlist_t *fragments = fragize(finl, Rd->reply->datasize(Rd->reply)); 5008 qlist_t *fragments = fragize(finl, Rd->reply->datasize(Rd->reply));
4904 Rd->reply->free(Rd->reply); 5009 Rd->reply->free(Rd->reply);
4905 Rd->reply = qgrow(QGROW_THREADSAFE); 5010 Rd->reply = qgrow(QGROW_THREADSAFE);
4906 unfragize(fragments, Rd); 5011 unfragize(fragments, Rd, TRUE);
5012 free(finl);
4907goto sendReply; 5013goto sendReply;
4908 } 5014 }
4909 5015
@@ -4943,7 +5049,7 @@ goto sendReply;
4943 goto sendReply; 5049 goto sendReply;
4944 5050
4945 getStats(database, stats); 5051 getStats(database, stats);
4946 unfragize(thisFile->fragments, Rd); 5052 unfragize(thisFile->fragments, Rd, false);
4947 5053
4948sendReply: 5054sendReply:
4949 /* Send headers. 5055 /* Send headers.
@@ -4969,7 +5075,7 @@ sendReply:
4969 while (Rd->Rcookies->getnext(Rd->Rcookies, &hobj, false) == true) 5075 while (Rd->Rcookies->getnext(Rd->Rcookies, &hobj, false) == true)
4970 { 5076 {
4971 cookie *ck = (cookie *) hobj.data; 5077 cookie *ck = (cookie *) hobj.data;
4972 FCGI_printf("Set-Cookie: %s=%s", ck->cookie, ck->value); 5078 FCGI_printf("Set-Cookie: %s=%s", hobj.name, ck->value);
4973// if (NULL != ck->expires) FCGI_printf("; Expires=%s", ck->expires); 5079// if (NULL != ck->expires) FCGI_printf("; Expires=%s", ck->expires);
4974 if (NULL != ck->domain) FCGI_printf("; Domain=%s", ck->domain); 5080 if (NULL != ck->domain) FCGI_printf("; Domain=%s", ck->domain);
4975 if (NULL != ck->path) FCGI_printf("; Path=%s", ck->path); 5081 if (NULL != ck->path) FCGI_printf("; Path=%s", ck->path);
@@ -4981,7 +5087,6 @@ sendReply:
4981 if (CS_NONE == ck->site) FCGI_printf("; SameSite=None"); 5087 if (CS_NONE == ck->site) FCGI_printf("; SameSite=None");
4982 FCGI_printf("\r\n"); 5088 FCGI_printf("\r\n");
4983 free(ck->value); 5089 free(ck->value);
4984 free(ck->cookie);
4985 } 5090 }
4986 FCGI_printf("\r\n"); 5091 FCGI_printf("\r\n");
4987 Rd->cookies->unlock(Rd->cookies); 5092 Rd->cookies->unlock(Rd->cookies);
@@ -5028,6 +5133,7 @@ fcgiDone:
5028 double n = (now.tv_sec * 1000000000.0) + now.tv_nsec; 5133 double n = (now.tv_sec * 1000000000.0) + now.tv_nsec;
5029 double t = (Rd->then.tv_sec * 1000000000.0) + Rd->then.tv_nsec; 5134 double t = (Rd->then.tv_sec * 1000000000.0) + Rd->then.tv_nsec;
5030 I("Finished web request, took %lf seconds", (n - t) / 1000000000.0); 5135 I("Finished web request, took %lf seconds", (n - t) / 1000000000.0);
5136 free(Rd);
5031 } 5137 }
5032 5138
5033 FCGI_fprintf(FCGI_stderr, "Stopped SledjChisl web server.\n"); 5139 FCGI_fprintf(FCGI_stderr, "Stopped SledjChisl web server.\n");
@@ -5209,13 +5315,5 @@ finished:
5209 puts(""); 5315 puts("");
5210 fflush(stdout); 5316 fflush(stdout);
5211 5317
5212 if (database) mysql_close(database); 5318 cleanup();
5213 mysql_library_end();
5214 lua_close(L);
5215 if (stats)
5216 {
5217 if (stats->stats) stats->stats->free(stats->stats);
5218 free(stats);
5219 }
5220 if (configs) configs->free(configs);
5221} 5319}