diff options
Diffstat (limited to 'src/sledjchisl')
-rw-r--r-- | src/sledjchisl/sledjchisl.c | 576 |
1 files changed, 304 insertions, 272 deletions
diff --git a/src/sledjchisl/sledjchisl.c b/src/sledjchisl/sledjchisl.c index 06c6187..8bcf076 100644 --- a/src/sledjchisl/sledjchisl.c +++ b/src/sledjchisl/sledjchisl.c | |||
@@ -305,18 +305,18 @@ qhashtbl_t *HTMLfileCache = NULL; | |||
305 | typedef struct _reqData reqData; | 305 | typedef struct _reqData reqData; |
306 | 306 | ||
307 | 307 | ||
308 | typedef int (*fieldValidFunc) (reqData *Rd, qhashtbl_t *data); | 308 | typedef int (*fieldValidFunc) (reqData *Rd, qhashtbl_t *data, char *name); |
309 | typedef struct _validFunc validFunc; | 309 | typedef struct _validFunc validFunc; |
310 | struct _validFunc | 310 | struct _validFunc |
311 | { | 311 | { |
312 | char *name; | 312 | char *name, *title; |
313 | fieldValidFunc func; | 313 | fieldValidFunc func; |
314 | }; | 314 | }; |
315 | qlisttbl_t *fieldValidFuncs = NULL; | 315 | qlisttbl_t *fieldValidFuncs = NULL; |
316 | static void newValidFunc(char *name, fieldValidFunc func) | 316 | static void newValidFunc(char *name, char *title, fieldValidFunc func) |
317 | { | 317 | { |
318 | validFunc *vf = xmalloc(sizeof(validFunc)); | 318 | validFunc *vf = xmalloc(sizeof(validFunc)); |
319 | vf->name = name; 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 | } | 321 | } |
322 | 322 | ||
@@ -402,7 +402,7 @@ struct _sesh | |||
402 | struct _reqData | 402 | struct _reqData |
403 | { | 403 | { |
404 | lua_State *L; | 404 | lua_State *L; |
405 | qhashtbl_t *configs, *queries, *body, *cookies, *headers, *stuff, *database, *Rcookies, *Rheaders; | 405 | qhashtbl_t *configs, *queries, *body, *cookies, *headers, *valid, *stuff, *database, *Rcookies, *Rheaders; |
406 | char *Scheme, *Host, *Method, *Script, *RUri, *doit; | 406 | char *Scheme, *Host, *Method, *Script, *RUri, *doit; |
407 | sesh shs, *lnk; | 407 | sesh shs, *lnk; |
408 | MYSQL *db; | 408 | MYSQL *db; |
@@ -2727,6 +2727,96 @@ NOTE - storing a pepper on the same RAID array as everything else will be a prob | |||
2727 | https://stackoverflow.com/questions/16891729/best-practices-salting-peppering-passwords | 2727 | https://stackoverflow.com/questions/16891729/best-practices-salting-peppering-passwords |
2728 | */ | 2728 | */ |
2729 | 2729 | ||
2730 | |||
2731 | static void bitch(reqData *Rd, char *message, char *log) | ||
2732 | { | ||
2733 | addStrL(Rd->errors, message); | ||
2734 | E("%s %s %s %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), getStrH(Rd->stuff, "UUID"), getStrH(Rd->stuff, "name"), message, log); | ||
2735 | } | ||
2736 | |||
2737 | /* "A token cookie that references a non-existent session, its value should be replaced immediately to prevent session fixation." | ||
2738 | https://owasp.org/www-community/attacks/Session_fixation | ||
2739 | Which describes the problem, but offers no solution. | ||
2740 | See https://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication?rq=1. | ||
2741 | I think this means send a new cookie. | ||
2742 | I clear out the cookies and send blank ones with -1 maxAge, so they should get deleted. | ||
2743 | */ | ||
2744 | static void bitchSession(reqData *Rd, char *message, char *log) | ||
2745 | { | ||
2746 | addStrL(Rd->errors, message); | ||
2747 | C("%s %s %s %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), getStrH(Rd->stuff, "UUID"), getStrH(Rd->stuff, "name"), message, log); | ||
2748 | Rd->vegOut = TRUE; | ||
2749 | } | ||
2750 | |||
2751 | |||
2752 | int LuaToHash(reqData *Rd, char *file, char *var, qhashtbl_t *tnm, int ret, struct stat *st, struct timespec *now, char *type) | ||
2753 | { | ||
2754 | struct timespec then; | ||
2755 | |||
2756 | if (-1 == clock_gettime(CLOCK_REALTIME, &then)) | ||
2757 | perror_msg("Unable to get the time."); | ||
2758 | I("Reading %s file %s", type, file); | ||
2759 | if (0 != stat(file, st)) | ||
2760 | { | ||
2761 | D("No %s file.", file); | ||
2762 | perror_msg("Unable to stat %s", file); | ||
2763 | ret++; | ||
2764 | } | ||
2765 | else | ||
2766 | { | ||
2767 | int status = luaL_loadfile(Rd->L, file), result; | ||
2768 | |||
2769 | if (status) | ||
2770 | { | ||
2771 | bitchSession(Rd, "No such thing.", "Can't load file."); | ||
2772 | E("Couldn't load file: %s", lua_tostring(Rd->L, -1)); | ||
2773 | ret++; | ||
2774 | } | ||
2775 | else | ||
2776 | { | ||
2777 | result = lua_pcall(Rd->L, 0, LUA_MULTRET, 0); | ||
2778 | |||
2779 | if (result) | ||
2780 | { | ||
2781 | bitchSession(Rd, "Broken thing.", "Can't run file."); | ||
2782 | E("Failed to run script: %s", lua_tostring(Rd->L, -1)); | ||
2783 | ret++; | ||
2784 | } | ||
2785 | else | ||
2786 | { | ||
2787 | lua_getglobal(Rd->L, var); | ||
2788 | lua_pushnil(Rd->L); | ||
2789 | |||
2790 | while(lua_next(Rd->L, -2) != 0) | ||
2791 | { | ||
2792 | char *n = (char *) lua_tostring(Rd->L, -2); | ||
2793 | |||
2794 | if (lua_isstring(Rd->L, -1)) | ||
2795 | { | ||
2796 | tnm->putstr(tnm, n, (char *) lua_tostring(Rd->L, -1)); | ||
2797 | //d("Reading %s = %s", n, getStrH(tnm, n)); | ||
2798 | } | ||
2799 | else | ||
2800 | { | ||
2801 | char *v = (char *) lua_tostring(Rd->L, -1); | ||
2802 | W("Unknown Lua variable type for %s = %s", n, v); | ||
2803 | } | ||
2804 | lua_pop(Rd->L, 1); | ||
2805 | } | ||
2806 | |||
2807 | if (-1 == clock_gettime(CLOCK_REALTIME, now)) | ||
2808 | perror_msg("Unable to get the time."); | ||
2809 | double n = (now->tv_sec * 1000000000.0) + now->tv_nsec; | ||
2810 | double t = (then.tv_sec * 1000000000.0) + then.tv_nsec; | ||
2811 | T("Reading %s file took %lf seconds", type, (n - t) / 1000000000.0); | ||
2812 | } | ||
2813 | } | ||
2814 | } | ||
2815 | |||
2816 | return ret; | ||
2817 | } | ||
2818 | |||
2819 | |||
2730 | static void freeSesh(reqData *Rd, boolean linky, boolean wipe) | 2820 | static void freeSesh(reqData *Rd, boolean linky, boolean wipe) |
2731 | { | 2821 | { |
2732 | char *file = NULL; | 2822 | char *file = NULL; |
@@ -2933,26 +3023,6 @@ static void createUser(reqData *Rd) | |||
2933 | free(file); | 3023 | free(file); |
2934 | } | 3024 | } |
2935 | 3025 | ||
2936 | |||
2937 | static void bitch(reqData *Rd, char *message, char *log) | ||
2938 | { | ||
2939 | addStrL(Rd->errors, message); | ||
2940 | E("%s %s %s %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), getStrH(Rd->stuff, "UUID"), getStrH(Rd->stuff, "name"), message, log); | ||
2941 | } | ||
2942 | |||
2943 | /* "A token cookie that references a non-existent session, its value should be replaced immediately to prevent session fixation." | ||
2944 | https://owasp.org/www-community/attacks/Session_fixation | ||
2945 | Which describes the problem, but offers no solution. | ||
2946 | See https://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication?rq=1. | ||
2947 | I think this means send a new cookie. | ||
2948 | I clear out the cookies and send blank ones with -1 maxAge, so they should get deleted. | ||
2949 | */ | ||
2950 | static void bitchSession(reqData *Rd, char *message, char *log) | ||
2951 | { | ||
2952 | addStrL(Rd->errors, message); | ||
2953 | C("%s %s %s %s %s", getStrH(Rd->headers, "REMOTE_ADDR"), getStrH(Rd->stuff, "UUID"), getStrH(Rd->stuff, "name"), message, log); | ||
2954 | Rd->vegOut = TRUE; | ||
2955 | } | ||
2956 | static sesh *newSesh(reqData *Rd, boolean linky) | 3026 | static sesh *newSesh(reqData *Rd, boolean linky) |
2957 | { | 3027 | { |
2958 | unsigned char *md5hash = xzalloc(17); | 3028 | unsigned char *md5hash = xzalloc(17); |
@@ -2961,7 +3031,7 @@ static sesh *newSesh(reqData *Rd, boolean linky) | |||
2961 | uuid_t binuuid; | 3031 | uuid_t binuuid; |
2962 | sesh *ret = &Rd->shs; | 3032 | sesh *ret = &Rd->shs; |
2963 | 3033 | ||
2964 | W("New sesh"); | 3034 | d("New sesh"); |
2965 | if (linky) | 3035 | if (linky) |
2966 | { | 3036 | { |
2967 | Rd->lnk = xzalloc(sizeof(sesh)); | 3037 | Rd->lnk = xzalloc(sizeof(sesh)); |
@@ -3044,132 +3114,72 @@ char *checkLinky(reqData *Rd) | |||
3044 | } | 3114 | } |
3045 | 3115 | ||
3046 | 3116 | ||
3047 | boolean prevalidate(qhashtbl_t *data, char *name) | ||
3048 | { | ||
3049 | if ('\0' != getStrH(data, name)[0]) | ||
3050 | { | ||
3051 | I("Already validated %s.", name); | ||
3052 | return TRUE; | ||
3053 | } | ||
3054 | return FALSE; | ||
3055 | } | ||
3056 | |||
3057 | boolean badBoy(int ret, reqData *Rd, qhashtbl_t *data, char *name, char *value) | 3117 | boolean badBoy(int ret, reqData *Rd, qhashtbl_t *data, char *name, char *value) |
3058 | { | 3118 | { |
3059 | if (NULL == value) | 3119 | if (NULL == value) |
3060 | value = getStrH(data, name); | 3120 | value = getStrH(data, name); |
3061 | |||
3062 | if (0 != ret) | 3121 | if (0 != ret) |
3063 | { | 3122 | { |
3064 | char *t = xmprintf("BAD - %s", name); | 3123 | Rd->valid->putint(Rd->valid, name, -1); |
3065 | 3124 | W("Bad boy %s = %s", name, value); | |
3066 | Rd->stuff->putstr(Rd->stuff, t, value); | ||
3067 | Rd->stuff->remove(data, name); | ||
3068 | free(t); | ||
3069 | return TRUE; | 3125 | return TRUE; |
3070 | } | 3126 | } |
3071 | data->putstr(data, name, value); | 3127 | Rd->stuff->putstr(Rd->stuff, name, value); |
3128 | Rd->valid->putint(Rd->valid, name, 1); | ||
3072 | return FALSE; | 3129 | return FALSE; |
3073 | } | 3130 | } |
3074 | 3131 | ||
3075 | char *months[] = | 3132 | int validateThings(reqData *Rd, char *doit, char *name, qhashtbl_t *things) |
3076 | { | ||
3077 | "january", | ||
3078 | "february", | ||
3079 | "march", | ||
3080 | "april", | ||
3081 | "may", | ||
3082 | "june", | ||
3083 | "july", | ||
3084 | "august", | ||
3085 | "september", | ||
3086 | "october", | ||
3087 | "november", | ||
3088 | "december" | ||
3089 | }; | ||
3090 | |||
3091 | |||
3092 | |||
3093 | int LuaToHash(reqData *Rd, char *file, char *var, qhashtbl_t *tnm, int ret, struct stat *st, struct timespec *now, char *type) | ||
3094 | { | 3133 | { |
3095 | struct timespec then; | 3134 | int e = 0; |
3135 | qlisttbl_obj_t obj; | ||
3096 | 3136 | ||
3097 | if (-1 == clock_gettime(CLOCK_REALTIME, &then)) | 3137 | D("For function %s, start of %s validation.", doit, name); |
3098 | perror_msg("Unable to get the time."); | 3138 | memset((void *) &obj, 0, sizeof(obj)); |
3099 | I("Reading %s file %s", type, file); | 3139 | fieldValidFuncs->lock(fieldValidFuncs); |
3100 | if (0 != stat(file, st)) | 3140 | while(fieldValidFuncs->getnext(fieldValidFuncs, &obj, NULL, false) == true) |
3101 | { | ||
3102 | bitchSession(Rd, "No such thing.", "No file."); | ||
3103 | perror_msg("Unable to stat %s", file); | ||
3104 | ret++; | ||
3105 | } | ||
3106 | else | ||
3107 | { | 3141 | { |
3108 | int status = luaL_loadfile(Rd->L, file), result; | 3142 | char *t = things->getstr(things, obj.name, false); |
3109 | 3143 | ||
3110 | if (status) | 3144 | if (NULL != t) |
3111 | { | ||
3112 | bitchSession(Rd, "No such thing.", "Can't load file."); | ||
3113 | E("Couldn't load file: %s", lua_tostring(Rd->L, -1)); | ||
3114 | ret++; | ||
3115 | } | ||
3116 | else | ||
3117 | { | 3145 | { |
3118 | result = lua_pcall(Rd->L, 0, LUA_MULTRET, 0); | 3146 | char *nm = obj.name; |
3147 | int valid = Rd->valid->getint(Rd->valid, nm); | ||
3148 | validFunc *vf = (validFunc *) obj.data; | ||
3119 | 3149 | ||
3120 | if (result) | 3150 | if (0 != valid) // Is it in the valid qhashtbl? |
3121 | { | 3151 | { |
3122 | bitchSession(Rd, "Broken thing.", "Can't run file."); | 3152 | if (0 < valid) // Positive valid means it's valid, negative means it's invald. |
3123 | E("Failed to run script: %s", lua_tostring(Rd->L, -1)); | 3153 | D("Already validated %s - %s.", vf->title, nm); |
3124 | ret++; | 3154 | else |
3155 | D("Already invalidated %s - %s.", vf->title, nm); | ||
3125 | } | 3156 | } |
3126 | else | 3157 | else |
3127 | { | 3158 | { |
3128 | lua_getglobal(Rd->L, var); | 3159 | D("Validating %s - %s.", vf->title, nm); |
3129 | lua_pushnil(Rd->L); | 3160 | if (vf->func) |
3130 | 3161 | e += vf->func(Rd, things, nm); | |
3131 | while(lua_next(Rd->L, -2) != 0) | 3162 | else |
3132 | { | 3163 | E("No validation function for %s - %s", vf->title, nm); |
3133 | char *n = (char *) lua_tostring(Rd->L, -2); | ||
3134 | |||
3135 | if (lua_isstring(Rd->L, -1)) | ||
3136 | { | ||
3137 | tnm->putstr(tnm, n, (char *) lua_tostring(Rd->L, -1)); | ||
3138 | //d("Reading %s %s", n, getStrH(tnm, n)); | ||
3139 | } | ||
3140 | else | ||
3141 | { | ||
3142 | char *v = (char *) lua_tostring(Rd->L, -1); | ||
3143 | W("Unknown Lua variable type for %s = %s", n, v); | ||
3144 | } | ||
3145 | lua_pop(Rd->L, 1); | ||
3146 | } | ||
3147 | |||
3148 | if (-1 == clock_gettime(CLOCK_REALTIME, now)) | ||
3149 | perror_msg("Unable to get the time."); | ||
3150 | double n = (now->tv_sec * 1000000000.0) + now->tv_nsec; | ||
3151 | double t = (then.tv_sec * 1000000000.0) + then.tv_nsec; | ||
3152 | T("Reading %s file took %lf seconds", type, (n - t) / 1000000000.0); | ||
3153 | } | 3164 | } |
3154 | } | 3165 | } |
3155 | } | 3166 | } |
3156 | 3167 | fieldValidFuncs->unlock(fieldValidFuncs); | |
3157 | return ret; | 3168 | return e; |
3158 | } | 3169 | } |
3159 | 3170 | ||
3160 | static int validateSesh(reqData *Rd, qhashtbl_t *data) | 3171 | |
3172 | static int validateSesh(reqData *Rd, qhashtbl_t *data, char *name) | ||
3161 | { | 3173 | { |
3162 | int ret = 0; | 3174 | int ret = 0; |
3163 | boolean linky = FALSE; | 3175 | boolean linky = FALSE; |
3164 | 3176 | ||
3165 | if ('\0' != Rd->shs.leaf[0]) | 3177 | if ('\0' != Rd->shs.leaf[0]) |
3166 | { | 3178 | { |
3167 | I("Already validated session."); | 3179 | d("Already validated session."); |
3168 | return ret; | 3180 | return ret; |
3169 | } | 3181 | } |
3170 | 3182 | ||
3171 | I("Validating session."); | ||
3172 | |||
3173 | char *toke_n_munchie = "", *munchie = "", *hashish = "", | 3183 | char *toke_n_munchie = "", *munchie = "", *hashish = "", |
3174 | *leaf, *timeStamp = "", *seshion = "", *seshID = "", | 3184 | *leaf, *timeStamp = "", *seshion = "", *seshID = "", |
3175 | *t0, *t1; | 3185 | *t0, *t1; |
@@ -3324,15 +3334,25 @@ W("Validated session linky."); | |||
3324 | Rd->stuff->putstr(Rd->stuff, "linky-hashish", t0); | 3334 | Rd->stuff->putstr(Rd->stuff, "linky-hashish", t0); |
3325 | } | 3335 | } |
3326 | } | 3336 | } |
3327 | Rd->stuff->putstr(Rd->stuff, "name", tnm->getstr(tnm, "name", true)); | 3337 | |
3328 | Rd->stuff->putstr(Rd->stuff, "UUID", tnm->getstr(tnm, "UUID", true)); | 3338 | qhashtbl_obj_t obj; |
3329 | Rd->stuff->putstr(Rd->stuff, "level", tnm->getstr(tnm, "level", true)); | 3339 | |
3330 | Rd->stuff->putstr(Rd->stuff, "passwordSalt", tnm->getstr(tnm, "passwordSalt", true)); | 3340 | memset((void*)&obj, 0, sizeof(obj)); |
3331 | Rd->stuff->putstr(Rd->stuff, "passwordHash", tnm->getstr(tnm, "passwordHash", true)); | 3341 | tnm->lock(tnm); |
3342 | while(tnm->getnext(tnm, &obj, false) == true) | ||
3343 | { | ||
3344 | char *n = obj.name; | ||
3345 | |||
3346 | if ((strcmp("salt", n) != 0) && (strcmp("seshID", n) != 0)) | ||
3347 | { | ||
3348 | t("Lua %s = %s", n, (char *) obj.data); | ||
3349 | Rd->stuff->putstr(Rd->stuff, obj.name, (char *) obj.data); | ||
3350 | } | ||
3351 | } | ||
3352 | tnm->unlock(tnm); | ||
3332 | Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", tnm->getstr(tnm, "UUID", true)); | 3353 | Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", tnm->getstr(tnm, "UUID", true)); |
3333 | } | 3354 | } |
3334 | } | 3355 | } |
3335 | |||
3336 | } | 3356 | } |
3337 | } | 3357 | } |
3338 | } | 3358 | } |
@@ -3342,15 +3362,48 @@ W("Validated session linky."); | |||
3342 | return ret; | 3362 | return ret; |
3343 | } | 3363 | } |
3344 | 3364 | ||
3345 | static int validateDoB(reqData *Rd, qhashtbl_t *data) | 3365 | static int validateAboutMe(reqData *Rd, qhashtbl_t *data, char *name) |
3366 | { | ||
3367 | int ret = 0; | ||
3368 | char *about = getStrH(data, "aboutMe"); | ||
3369 | |||
3370 | if ((strcmp("confirm", Rd->doit) != 0) && (strcmp("update", Rd->doit) != 0)) | ||
3371 | return ret; | ||
3372 | |||
3373 | if ('\0' == about[0]) | ||
3374 | { | ||
3375 | bitch(Rd, "Please fill in the 'About me' section.", "None supplied."); | ||
3376 | ret++; | ||
3377 | } | ||
3378 | |||
3379 | badBoy(ret, Rd, data, "aboutMe", about); | ||
3380 | return ret; | ||
3381 | } | ||
3382 | |||
3383 | |||
3384 | char *months[] = | ||
3385 | { | ||
3386 | "january", | ||
3387 | "february", | ||
3388 | "march", | ||
3389 | "april", | ||
3390 | "may", | ||
3391 | "june", | ||
3392 | "july", | ||
3393 | "august", | ||
3394 | "september", | ||
3395 | "october", | ||
3396 | "november", | ||
3397 | "december" | ||
3398 | }; | ||
3399 | static int validateDoB(reqData *Rd, qhashtbl_t *data, char *name) | ||
3346 | { | 3400 | { |
3347 | int ret = 0, i; | 3401 | int ret = 0, i; |
3348 | char *t; | 3402 | char *t; |
3349 | 3403 | ||
3350 | if (prevalidate(Rd->stuff, "year")) return ret; | 3404 | if ((strcmp("confirm", Rd->doit) != 0) && (strcmp("update", Rd->doit) != 0)) |
3351 | if (prevalidate(Rd->stuff, "month")) return ret; | 3405 | return ret; |
3352 | 3406 | ||
3353 | I("Validating DoB."); | ||
3354 | t = getStrH(data, "year"); | 3407 | t = getStrH(data, "year"); |
3355 | if ((NULL == t) || ('\0' == t[0])) | 3408 | if ((NULL == t) || ('\0' == t[0])) |
3356 | { | 3409 | { |
@@ -3392,19 +3445,15 @@ static int validateDoB(reqData *Rd, qhashtbl_t *data) | |||
3392 | return ret; | 3445 | return ret; |
3393 | } | 3446 | } |
3394 | 3447 | ||
3395 | static int validateEmail(reqData *Rd, qhashtbl_t *data) | 3448 | static int validateEmail(reqData *Rd, qhashtbl_t *data, char *name) |
3396 | { | 3449 | { |
3397 | int ret = 0; | 3450 | int ret = 0; |
3398 | char *email = getStrH(data, "email"); | 3451 | char *email = getStrH(data, "email"); |
3399 | char *emayl = getStrH(data, "emayl"); | 3452 | char *emayl = getStrH(data, "emayl"); |
3400 | 3453 | ||
3401 | if ((strcmp("create", Rd->doit) != 0) && (strcmp("update", Rd->doit) != 0)) | 3454 | if ((strcmp("confirm", Rd->doit) != 0) && (strcmp("update", Rd->doit) != 0)) |
3402 | return ret; | 3455 | return ret; |
3403 | 3456 | ||
3404 | if (prevalidate(Rd->stuff, "email")) return ret; | ||
3405 | if (prevalidate(Rd->stuff, "emayl")) return ret; | ||
3406 | |||
3407 | I("Validating email."); | ||
3408 | if ((NULL == email) || (NULL == emayl) || ('\0' == email[0]) || ('\0' == emayl[0])) | 3457 | if ((NULL == email) || (NULL == emayl) || ('\0' == email[0]) || ('\0' == emayl[0])) |
3409 | { | 3458 | { |
3410 | bitch(Rd, "Please supply an email address.", "None supplied."); | 3459 | bitch(Rd, "Please supply an email address.", "None supplied."); |
@@ -3425,25 +3474,20 @@ static int validateEmail(reqData *Rd, qhashtbl_t *data) | |||
3425 | // TODO - do other email checks - does the domain exist, .. | 3474 | // TODO - do other email checks - does the domain exist, .. |
3426 | } | 3475 | } |
3427 | 3476 | ||
3428 | badBoy(ret, Rd, data, "email", email); | 3477 | badBoy(ret, Rd, data, "email", NULL); |
3429 | badBoy(ret, Rd, data, "emayl", emayl); | 3478 | badBoy(ret, Rd, data, "emayl", NULL); |
3430 | return ret; | 3479 | return ret; |
3431 | } | 3480 | } |
3432 | 3481 | ||
3433 | static int validateLegal(reqData *Rd, qhashtbl_t *data) | 3482 | static int validateLegal(reqData *Rd, qhashtbl_t *data, char *name) |
3434 | { | 3483 | { |
3435 | int ret = 0; | 3484 | int ret = 0; |
3436 | char *t; | 3485 | char *t; |
3437 | 3486 | ||
3438 | if (prevalidate(Rd->stuff, "adult")) return ret; | ||
3439 | if (prevalidate(Rd->stuff, "agree")) return ret; | ||
3440 | |||
3441 | |||
3442 | I("Validating legal."); | ||
3443 | t = getStrH(data, "adult"); | 3487 | t = getStrH(data, "adult"); |
3444 | if ((NULL == t) || (strcmp("on", t) != 0)) | 3488 | if ((NULL == t) || (strcmp("on", t) != 0)) |
3445 | { | 3489 | { |
3446 | bitch(Rd, "You must be an adult to enter this world.", ""); | 3490 | bitch(Rd, "You must be an adult to enter this site.", ""); |
3447 | ret++; | 3491 | ret++; |
3448 | } | 3492 | } |
3449 | t = getStrH(data, "agree"); | 3493 | t = getStrH(data, "agree"); |
@@ -3458,19 +3502,16 @@ static int validateLegal(reqData *Rd, qhashtbl_t *data) | |||
3458 | return ret; | 3502 | return ret; |
3459 | } | 3503 | } |
3460 | 3504 | ||
3461 | static int validateName(reqData *Rd, qhashtbl_t *data) | 3505 | static int validateName(reqData *Rd, qhashtbl_t *data, char *nm) |
3462 | { | 3506 | { |
3463 | boolean login = strcmp("login", Rd->doit) == 0; | 3507 | boolean login = strcmp("login", Rd->doit) == 0; |
3464 | int ret = 0; | 3508 | int ret = 0; |
3465 | unsigned char *name = data->getstr(data, "name", true); // We have to be unsigned coz of isalnum(). | 3509 | unsigned char *name = data->getstr(data, "name", true); // We have to be unsigned coz of isalnum(). |
3466 | char *where = NULL; | 3510 | char *where = NULL; |
3467 | 3511 | ||
3468 | if (strcmp("logout", Rd->doit) == 0) | 3512 | if ((strcmp("cancel", Rd->doit) == 0) || (strcmp("logout", Rd->doit) == 0)) |
3469 | return ret; | 3513 | return ret; |
3470 | 3514 | ||
3471 | if (prevalidate(Rd->database, "UserAccounts.UserLevel")) return ret; | ||
3472 | |||
3473 | I("Validating name."); | ||
3474 | if ((NULL == name) || ('\0' == name[0])) | 3515 | if ((NULL == name) || ('\0' == name[0])) |
3475 | { | 3516 | { |
3476 | bitch(Rd, "Please supply an account name.", "None supplied."); | 3517 | bitch(Rd, "Please supply an account name.", "None supplied."); |
@@ -3557,102 +3598,105 @@ static int validateName(reqData *Rd, qhashtbl_t *data) | |||
3557 | } | 3598 | } |
3558 | dbDoSomething(acnts, FALSE, name, s); | 3599 | dbDoSomething(acnts, FALSE, name, s); |
3559 | rowData *rows = acnts->rows; | 3600 | rowData *rows = acnts->rows; |
3601 | int c = 0; | ||
3602 | |||
3560 | if (rows) | 3603 | if (rows) |
3561 | { | 3604 | c = rows->rows->size(rows->rows); |
3562 | int i = rows->rows->size(rows->rows); | ||
3563 | 3605 | ||
3564 | if (login) | 3606 | if (login) |
3607 | { | ||
3608 | if ((1 != c) && (rt)) | ||
3565 | { | 3609 | { |
3566 | if (rt) | 3610 | if (rt) |
3567 | { | 3611 | { |
3568 | bitch(Rd, "Login failed.", "Could not read user Lua file."); | 3612 | W("Could not read user Lua file."); |
3569 | ret += rt; | 3613 | ret += rt; |
3570 | if (i == 0) | 3614 | } |
3571 | { | 3615 | if (0 == c) |
3572 | bitch(Rd, "Login failed.", "No UserAccounts record with that name."); | 3616 | { |
3573 | ret++; | 3617 | W("No UserAccounts record with that name."); |
3574 | } | 3618 | ret++; |
3575 | else | ||
3576 | { | ||
3577 | if (i != 1) | ||
3578 | { | ||
3579 | bitch(Rd, "Login failed.", "More than one UserAccounts record with that name."); | ||
3580 | ret++; | ||
3581 | } | ||
3582 | else | ||
3583 | { | ||
3584 | dbPull(Rd, "UserAccounts", rows); | ||
3585 | Rd->stuff->putstr(Rd->stuff, "UUID", xstrdup(getStrH(Rd->database, "UserAccounts.PrincipalID"))); | ||
3586 | Rd->stuff->putstr(Rd->stuff, "level", xstrdup(getStrH(Rd->database, "UserAccounts.Userlevel"))); | ||
3587 | if (s) {s--; *s = ' '; s++;} | ||
3588 | Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name)); | ||
3589 | } | ||
3590 | } | ||
3591 | } | 3619 | } |
3592 | else | 3620 | else |
3593 | { | 3621 | { |
3622 | W("More than one UserAccounts record with that name."); | ||
3623 | ret++; | ||
3624 | } | ||
3625 | bitch(Rd, "Login failed.", "Could not find user record."); | ||
3626 | } | ||
3627 | else | ||
3628 | { | ||
3629 | if (1 == c) | ||
3630 | dbPull(Rd, "UserAccounts", rows); | ||
3631 | else | ||
3632 | { | ||
3594 | Rd->database->putstr(Rd->database, "UserAccounts.FirstName", name); | 3633 | Rd->database->putstr(Rd->database, "UserAccounts.FirstName", name); |
3595 | Rd->database->putstr(Rd->database, "UserAccounts.LastName", s); | 3634 | Rd->database->putstr(Rd->database, "UserAccounts.LastName", s); |
3596 | Rd->database->putstr(Rd->database, "UserAccounts.Email", getStrH(tnm, "email")); | 3635 | Rd->database->putstr(Rd->database, "UserAccounts.Email", getStrH(tnm, "email")); |
3597 | Rd->database->putstr(Rd->database, "UserAccounts.Created", getStrH(tnm, "created")); | 3636 | Rd->database->putstr(Rd->database, "UserAccounts.Created", getStrH(tnm, "created")); |
3598 | Rd->database->putstr(Rd->database, "UserAccounts.PrincipleID", getStrH(tnm, "UUID")); | 3637 | Rd->database->putstr(Rd->database, "UserAccounts.PrincipleID", getStrH(tnm, "UUID")); |
3599 | Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", getStrH(tnm, "level")); | 3638 | Rd->database->putstr(Rd->database, "UserAccounts.UserLevel", getStrH(tnm, "level")); |
3600 | Rd->database->putstr(Rd->database, "UserAccounts.UserFlags", getStrH(tnm, "flags")); | 3639 | Rd->database->putstr(Rd->database, "UserAccounts.UserFlags", getStrH(tnm, "flags")); |
3601 | Rd->database->putstr(Rd->database, "UserAccounts.UserTitle", getStrH(tnm, "title")); | 3640 | Rd->database->putstr(Rd->database, "UserAccounts.UserTitle", getStrH(tnm, "title")); |
3602 | Rd->database->putstr(Rd->database, "UserAccounts.active", getStrH(tnm, "active")); | 3641 | Rd->database->putstr(Rd->database, "UserAccounts.active", getStrH(tnm, "active")); |
3603 | Rd->database->putstr(Rd->database, "auth.passwordSalt", getStrH(tnm, "passwordSalt")); | 3642 | Rd->database->putstr(Rd->database, "auth.passwordSalt", getStrH(tnm, "passwordSalt")); |
3604 | Rd->database->putstr(Rd->database, "auth.passwordHash", getStrH(tnm, "passwordHash")); | 3643 | Rd->database->putstr(Rd->database, "auth.passwordHash", getStrH(tnm, "passwordHash")); |
3605 | 3644 | tnm->free(tnm); | |
3606 | Rd->stuff->putstr(Rd->stuff, "UUID", xstrdup(getStrH(Rd->database, "UserAccounts.PrincipalID"))); | ||
3607 | Rd->stuff->putstr(Rd->stuff, "level", xstrdup(getStrH(Rd->database, "UserAccounts.Userlevel"))); | ||
3608 | if (s) {s--; *s = ' '; s++;} | ||
3609 | Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name)); | ||
3610 | if (s) {s--; *s = '\0'; s++;} | ||
3611 | } | 3645 | } |
3646 | Rd->stuff->putstr(Rd->stuff, "UUID", xstrdup(getStrH(Rd->database, "UserAccounts.PrincipalID"))); | ||
3647 | Rd->stuff->putstr(Rd->stuff, "level", xstrdup(getStrH(Rd->database, "UserAccounts.Userlevel"))); | ||
3648 | if (s) {s--; *s = ' '; s++;} | ||
3649 | Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name)); | ||
3650 | if (s) {s--; *s = '\0'; s++;} | ||
3612 | } | 3651 | } |
3613 | else if (strcmp("create", Rd->doit) == 0) | 3652 | } |
3653 | else if (strcmp("create", Rd->doit) == 0) | ||
3654 | { | ||
3655 | if ((0 != c) && (!rt)) | ||
3656 | { | ||
3657 | bitch(Rd, "Pick a different name.", "An existing Lua user file or UserAccounts record matched that name."); | ||
3658 | ret++; | ||
3659 | } | ||
3660 | else | ||
3614 | { | 3661 | { |
3615 | if (i != 0) | ||
3616 | { | ||
3617 | bitch(Rd, "Pick a different name.", "An existing UserAccounts record matched that name."); | ||
3618 | ret++; | ||
3619 | } | ||
3620 | else | ||
3621 | { | ||
3622 | // TODO - compare first, last, and fullname against god names, complain and fail if there's a match. | 3662 | // TODO - compare first, last, and fullname against god names, complain and fail if there's a match. |
3623 | { | 3663 | // Generate a UUID, check it isn't already being used. |
3624 | // Generate a UUID, check it isn't already being used. | 3664 | char uuid[37]; |
3625 | char uuid[37]; | 3665 | uuid_t binuuid; |
3626 | uuid_t binuuid; | 3666 | my_ulonglong users = 0; |
3627 | my_ulonglong users = 0; | ||
3628 | 3667 | ||
3629 | do // UserAccounts.PrincipalID is a unique primary index anyway, but we want the user creation process to be a little on the slow side. | 3668 | do // UserAccounts.PrincipalID is a unique primary index anyway, but we want the user creation process to be a little on the slow side. |
3630 | { | 3669 | { |
3631 | uuid_generate_random(binuuid); | 3670 | struct stat st; |
3632 | uuid_unparse_lower(binuuid, uuid); | 3671 | |
3633 | where = xmprintf("UserAccounts.PrincipalID = '%s'", uuid); | 3672 | uuid_generate_random(binuuid); |
3634 | D("Trying new UUID %s.", where); | 3673 | uuid_unparse_lower(binuuid, uuid); |
3635 | users = dbCount(Rd->db, "UserAccounts", where); | 3674 | // Try Lua user file. |
3636 | free(where); | 3675 | where = xmprintf("%s/users/%s.lua", scData, uuid); |
3637 | } while (users != 0); | 3676 | c = stat(where, &st); |
3677 | if (c) | ||
3678 | users = 1; | ||
3679 | free(where); | ||
3680 | // Try database. | ||
3681 | where = xmprintf("UserAccounts.PrincipalID = '%s'", uuid); | ||
3682 | D("Trying new UUID %s.", where); | ||
3683 | users = dbCount(Rd->db, "UserAccounts", where); | ||
3684 | free(where); | ||
3685 | } while (users != 0); | ||
3638 | // TODO - perhaps create a place holder UserAccounts record? Then we'll have to deal with deleting them later. | 3686 | // TODO - perhaps create a place holder UserAccounts record? Then we'll have to deal with deleting them later. |
3639 | 3687 | Rd->stuff->putstr(Rd->stuff, "UUID", xstrdup(uuid)); | |
3640 | Rd->stuff->putstr(Rd->stuff, "UUID", xstrdup(uuid)); | 3688 | Rd->stuff->putstr(Rd->stuff, "level", xstrdup("-200")); |
3641 | Rd->stuff->putstr(Rd->stuff, "level", xstrdup("-200")); | 3689 | Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID",xstrdup(uuid)); |
3642 | Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", xstrdup(uuid)); | 3690 | Rd->database->putstr(Rd->database, "UserAccounts.Userlevel", xstrdup("-200")); |
3643 | Rd->database->putstr(Rd->database, "UserAccounts.Userlevel", xstrdup("-200")); | 3691 | Rd->database->putstr(Rd->database, "UserAccounts.firstName", xstrdup(name)); |
3644 | Rd->database->putstr(Rd->database, "UserAccounts.firstName", xstrdup(name)); | 3692 | Rd->database->putstr(Rd->database, "UserAccounts.lastName", xstrdup(s)); |
3645 | Rd->database->putstr(Rd->database, "UserAccounts.lastName", xstrdup(s)); | 3693 | if (s) {s--; *s = ' '; s++;} |
3646 | if (s) {s--; *s = ' '; s++;} | 3694 | Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name)); |
3647 | Rd->stuff->putstr(Rd->stuff, "name", xstrdup(name)); | ||
3648 | } | ||
3649 | } | ||
3650 | } | 3695 | } |
3651 | free(rows->rows); | ||
3652 | free(rows->fieldNames); | ||
3653 | free(rows); | ||
3654 | } | 3696 | } |
3655 | 3697 | free(rows->rows); | |
3698 | free(rows->fieldNames); | ||
3699 | free(rows); | ||
3656 | if (s) {s--; *s = ' '; s++;} | 3700 | if (s) {s--; *s = ' '; s++;} |
3657 | } | 3701 | } |
3658 | } | 3702 | } |
@@ -3661,7 +3705,7 @@ static int validateName(reqData *Rd, qhashtbl_t *data) | |||
3661 | return ret; | 3705 | return ret; |
3662 | } | 3706 | } |
3663 | 3707 | ||
3664 | static int validatePassword(reqData *Rd, qhashtbl_t *data) | 3708 | static int validatePassword(reqData *Rd, qhashtbl_t *data, char *name) |
3665 | { | 3709 | { |
3666 | boolean login = strcmp("login", Rd->doit) == 0; | 3710 | boolean login = strcmp("login", Rd->doit) == 0; |
3667 | boolean create = strcmp("create", Rd->doit) == 0; | 3711 | boolean create = strcmp("create", Rd->doit) == 0; |
@@ -3670,13 +3714,13 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data) | |||
3670 | char *psswrdH = getStrH(Rd->stuff, "passwordHash"); | 3714 | char *psswrdH = getStrH(Rd->stuff, "passwordHash"); |
3671 | char *psswrdS = getStrH(Rd->stuff, "passwordSalt"); | 3715 | char *psswrdS = getStrH(Rd->stuff, "passwordSalt"); |
3672 | 3716 | ||
3673 | if (prevalidate(Rd->database, "auth.passwordSalt")) return ret; | ||
3674 | |||
3675 | I("Validating password."); | ||
3676 | if (login) | 3717 | if (login) |
3677 | { | 3718 | { |
3678 | char *UUID = getStrH(Rd->database, "UserAccounts.PrincipalID"); | 3719 | char *UUID = getStrH(Rd->database, "UserAccounts.PrincipalID"); |
3679 | static dbRequest *auth = NULL; | 3720 | static dbRequest *auth = NULL; |
3721 | |||
3722 | if ('\0' == UUID[0]) // If the name validation didn't find us a UUID, then this user doesn't exist, so can't log them on. | ||
3723 | return 1; | ||
3680 | if (NULL == auth) | 3724 | if (NULL == auth) |
3681 | { | 3725 | { |
3682 | static char *szi[] = {"UUID", NULL}; | 3726 | static char *szi[] = {"UUID", NULL}; |
@@ -3851,16 +3895,19 @@ static int validatePassword(reqData *Rd, qhashtbl_t *data) | |||
3851 | else | 3895 | else |
3852 | D("Account created%s.", password); | 3896 | D("Account created%s.", password); |
3853 | 3897 | ||
3898 | badBoy(ret, Rd, data, "auth.passwordSalt", NULL); | ||
3899 | |||
3854 | return ret; | 3900 | return ret; |
3855 | } | 3901 | } |
3856 | 3902 | ||
3857 | 3903 | ||
3858 | static int validateUUID(reqData *Rd, qhashtbl_t *data) | 3904 | static int validateUUID(reqData *Rd, qhashtbl_t *data, char *name) |
3859 | { | 3905 | { |
3860 | int ret = 0, i; | 3906 | int ret = 0, i; |
3861 | char uuid[37], *t; | 3907 | char uuid[37], *t; |
3862 | rowData *rows = NULL; | 3908 | rowData *rows = NULL; |
3863 | static dbRequest *uuids = NULL; | 3909 | static dbRequest *uuids = NULL; |
3910 | |||
3864 | if (NULL == uuids) | 3911 | if (NULL == uuids) |
3865 | { | 3912 | { |
3866 | static char *szi[] = {"PrincipalID", NULL}; | 3913 | static char *szi[] = {"PrincipalID", NULL}; |
@@ -3873,14 +3920,15 @@ static int validateUUID(reqData *Rd, qhashtbl_t *data) | |||
3873 | uuids->where = "PrincipalID=?"; | 3920 | uuids->where = "PrincipalID=?"; |
3874 | } | 3921 | } |
3875 | 3922 | ||
3876 | I("Validating UUID."); | 3923 | if ((strcmp("cancel", Rd->doit) == 0) || (strcmp("logout", Rd->doit) == 0)) |
3924 | return ret; | ||
3925 | |||
3926 | uuid[0] = '\0'; | ||
3877 | if (strcmp("create", Rd->doit) == 0) | 3927 | if (strcmp("create", Rd->doit) == 0) |
3878 | { | 3928 | { |
3879 | // Generate a UUID, check it isn't already being used, and totally ignore whatever UUID is in body. | 3929 | // Generate a UUID, check it isn't already being used, and totally ignore whatever UUID is in body. |
3880 | uuid_t binuuid; | 3930 | uuid_t binuuid; |
3881 | 3931 | ||
3882 | if (prevalidate(Rd->stuff, "UUID")) return ret; | ||
3883 | |||
3884 | do // UserAccounts.PrincipalID is a unique primary index anyway, but we want the user creation process to be a little on the slow side. | 3932 | do // UserAccounts.PrincipalID is a unique primary index anyway, but we want the user creation process to be a little on the slow side. |
3885 | { | 3933 | { |
3886 | uuid_generate_random(binuuid); | 3934 | uuid_generate_random(binuuid); |
@@ -3903,7 +3951,7 @@ static int validateUUID(reqData *Rd, qhashtbl_t *data) | |||
3903 | if (0 == ret) | 3951 | if (0 == ret) |
3904 | { | 3952 | { |
3905 | data->putstr(data, "UUID", xstrdup(uuid)); | 3953 | data->putstr(data, "UUID", xstrdup(uuid)); |
3906 | data->putstr(data, "NEW - UUID", uuid); | 3954 | Rd->stuff->putstr(Rd->stuff, "UUID", xstrdup(uuid)); |
3907 | } | 3955 | } |
3908 | rows = NULL; | 3956 | rows = NULL; |
3909 | } | 3957 | } |
@@ -3958,41 +4006,13 @@ static int validateUUID(reqData *Rd, qhashtbl_t *data) | |||
3958 | { | 4006 | { |
3959 | Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", xstrdup(uuid)); | 4007 | Rd->database->putstr(Rd->database, "UserAccounts.PrincipalID", xstrdup(uuid)); |
3960 | } | 4008 | } |
4009 | Rd->stuff->putstr(Rd->stuff, "UUID", xstrdup(uuid)); | ||
3961 | } | 4010 | } |
3962 | 4011 | ||
3963 | return ret; | 4012 | return ret; |
3964 | } | 4013 | } |
3965 | 4014 | ||
3966 | 4015 | ||
3967 | |||
3968 | int validateThings(reqData *Rd, char *doit, char *name, qhashtbl_t *things) | ||
3969 | { | ||
3970 | int e = 0; | ||
3971 | |||
3972 | W("%s start of %s validation.", doit, name); | ||
3973 | qlisttbl_obj_t obj; | ||
3974 | memset((void *) &obj, 0, sizeof(obj)); | ||
3975 | fieldValidFuncs->lock(fieldValidFuncs); | ||
3976 | while(fieldValidFuncs->getnext(fieldValidFuncs, &obj, NULL, false) == true) | ||
3977 | { | ||
3978 | char *t = getStrH(things, obj.name); | ||
3979 | |||
3980 | if ('\0' != t[0]) | ||
3981 | { | ||
3982 | validFunc *vf = (validFunc *) obj.data; | ||
3983 | |||
3984 | W("Validating %s", obj.name); | ||
3985 | if (vf->func) | ||
3986 | e += vf->func(Rd, things); | ||
3987 | else | ||
3988 | E("No validation function for %s", obj.name); | ||
3989 | } | ||
3990 | } | ||
3991 | fieldValidFuncs->unlock(fieldValidFuncs); | ||
3992 | return e; | ||
3993 | } | ||
3994 | |||
3995 | |||
3996 | void loginPage(reqData *Rd, char *message) | 4016 | void loginPage(reqData *Rd, char *message) |
3997 | { | 4017 | { |
3998 | char *name = xstrdup(getStrH(Rd->stuff, "name")); | 4018 | char *name = xstrdup(getStrH(Rd->stuff, "name")); |
@@ -4022,11 +4042,14 @@ void loginPage(reqData *Rd, char *message) | |||
4022 | 4042 | ||
4023 | void accountCreationPage(reqData *Rd, char *message) | 4043 | void accountCreationPage(reqData *Rd, char *message) |
4024 | { | 4044 | { |
4025 | char *name = getStrH(Rd->stuff, "name"); | 4045 | char *name = getStrH(Rd->body, "name"); |
4026 | char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie"); | 4046 | char *toke_n_munchie = getCookie(Rd->Rcookies, "toke_n_munchie"); |
4027 | char *tmp = xmalloc(16), *t; | 4047 | char *tmp = xmalloc(16), *t; |
4028 | int i, d; | 4048 | int i, d; |
4029 | 4049 | ||
4050 | if ('\0' == name[0]) | ||
4051 | name = getStrH(Rd->stuff, "name"); | ||
4052 | |||
4030 | // TODO - eww lots of memory leaks here. | 4053 | // TODO - eww lots of memory leaks here. |
4031 | // TODO - need to check if qlibc does it's own free() calls, and fill in the gaps for when it doesn't. | 4054 | // TODO - need to check if qlibc does it's own free() calls, and fill in the gaps for when it doesn't. |
4032 | HTMLheader(Rd->reply, "<!--#echo var=\"grid\" --> account manager"); | 4055 | HTMLheader(Rd->reply, "<!--#echo var=\"grid\" --> account manager"); |
@@ -4050,7 +4073,7 @@ void accountCreationPage(reqData *Rd, char *message) | |||
4050 | Rd->reply->addstr(Rd->reply, "<p>A validation email will be sent to this email address, you will need to click on the link in it to continue your account creation.</p>\n"); | 4073 | Rd->reply->addstr(Rd->reply, "<p>A validation email will be sent to this email address, you will need to click on the link in it to continue your account creation.</p>\n"); |
4051 | Rd->reply->addstr(Rd->reply, "<table><tr><td>\n"); | 4074 | Rd->reply->addstr(Rd->reply, "<table><tr><td>\n"); |
4052 | HTMLselect(Rd->reply, "Date of birth", "year"); | 4075 | HTMLselect(Rd->reply, "Date of birth", "year"); |
4053 | t = getStrH(Rd->stuff, "year"); | 4076 | t = getStrH(Rd->body, "year"); |
4054 | if (NULL == t) | 4077 | if (NULL == t) |
4055 | d = -1; | 4078 | d = -1; |
4056 | else | 4079 | else |
@@ -4068,7 +4091,7 @@ void accountCreationPage(reqData *Rd, char *message) | |||
4068 | HTMLselectEnd(Rd->reply); | 4091 | HTMLselectEnd(Rd->reply); |
4069 | Rd->reply->addstr(Rd->reply, "</tt><td>"); | 4092 | Rd->reply->addstr(Rd->reply, "</tt><td>"); |
4070 | HTMLselect(Rd->reply, NULL, "month"); | 4093 | HTMLselect(Rd->reply, NULL, "month"); |
4071 | t = getStrH(Rd->stuff, "month"); | 4094 | t = getStrH(Rd->body, "month"); |
4072 | HTMLoption(Rd->reply, xstrdup(""), FALSE); | 4095 | HTMLoption(Rd->reply, xstrdup(""), FALSE); |
4073 | for (i = 0; i <= 11; i++) | 4096 | for (i = 0; i <= 11; i++) |
4074 | { | 4097 | { |
@@ -4177,17 +4200,18 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) | |||
4177 | if (NULL == fieldValidFuncs) | 4200 | if (NULL == fieldValidFuncs) |
4178 | { | 4201 | { |
4179 | fieldValidFuncs = qlisttbl(QLISTTBL_LOOKUPFORWARD | QLISTTBL_THREADSAFE | QLISTTBL_UNIQUE); | 4202 | fieldValidFuncs = qlisttbl(QLISTTBL_LOOKUPFORWARD | QLISTTBL_THREADSAFE | QLISTTBL_UNIQUE); |
4180 | newValidFunc("hashish", (fieldValidFunc) validateSesh); | 4203 | newValidFunc("hashish", "session", (fieldValidFunc) validateSesh); |
4181 | newValidFunc("toke_n_munchie", (fieldValidFunc) validateSesh); | 4204 | newValidFunc("toke_n_munchie", "session", (fieldValidFunc) validateSesh); |
4182 | newValidFunc("UUID", (fieldValidFunc) validateUUID); | 4205 | newValidFunc("UUID", "UUID", (fieldValidFunc) validateUUID); |
4183 | newValidFunc("name", (fieldValidFunc) validateName); | 4206 | newValidFunc("name", "name", (fieldValidFunc) validateName); |
4184 | newValidFunc("password", (fieldValidFunc) validatePassword); | 4207 | newValidFunc("password", "password", (fieldValidFunc) validatePassword); |
4185 | newValidFunc("email", (fieldValidFunc) validateEmail); | 4208 | newValidFunc("email", "email", (fieldValidFunc) validateEmail); |
4186 | newValidFunc("emayl", (fieldValidFunc) validateEmail); | 4209 | newValidFunc("emayl", "email", (fieldValidFunc) validateEmail); |
4187 | newValidFunc("year", (fieldValidFunc) validateDoB); | 4210 | newValidFunc("year", "DoB", (fieldValidFunc) validateDoB); |
4188 | newValidFunc("month", (fieldValidFunc) validateDoB); | 4211 | newValidFunc("month", "DoB", (fieldValidFunc) validateDoB); |
4189 | newValidFunc("adult", (fieldValidFunc) validateLegal); | 4212 | newValidFunc("adult", "legal", (fieldValidFunc) validateLegal); |
4190 | newValidFunc("agree", (fieldValidFunc) validateLegal); | 4213 | newValidFunc("agree", "legal", (fieldValidFunc) validateLegal); |
4214 | newValidFunc("aboutMe", "about me", (fieldValidFunc) validateAboutMe); | ||
4191 | } | 4215 | } |
4192 | if (NULL == buildPages) | 4216 | if (NULL == buildPages) |
4193 | { | 4217 | { |
@@ -4329,6 +4353,12 @@ void account_html(char *file, reqData *Rd, HTMLfile *thisFile) | |||
4329 | freeSesh(Rd, FALSE, TRUE); | 4353 | freeSesh(Rd, FALSE, TRUE); |
4330 | newSesh(Rd, FALSE); | 4354 | newSesh(Rd, FALSE); |
4331 | } | 4355 | } |
4356 | else if ((0 != e)) // So we can reload details into a broken form, so the user doesn't have to retype everything. | ||
4357 | { | ||
4358 | freeSesh(Rd, FALSE, FALSE); | ||
4359 | newSesh(Rd, FALSE); | ||
4360 | } | ||
4361 | |||
4332 | Rd->func(Rd, ""); | 4362 | Rd->func(Rd, ""); |
4333 | } | 4363 | } |
4334 | 4364 | ||
@@ -4726,6 +4756,7 @@ jit library is loaded or the JIT compiler will not be activated. | |||
4726 | // Rd->body = qhashtbl(0, 0); // Inited in toknize below. | 4756 | // Rd->body = qhashtbl(0, 0); // Inited in toknize below. |
4727 | // Rd->cookies = qhashtbl(0, 0); // Inited in toknize below. | 4757 | // Rd->cookies = qhashtbl(0, 0); // Inited in toknize below. |
4728 | Rd->headers = qhashtbl(0, 0); | 4758 | Rd->headers = qhashtbl(0, 0); |
4759 | Rd->valid = qhashtbl(0, 0); | ||
4729 | Rd->stuff = qhashtbl(0, 0); | 4760 | Rd->stuff = qhashtbl(0, 0); |
4730 | Rd->database = qhashtbl(0, 0); | 4761 | Rd->database = qhashtbl(0, 0); |
4731 | Rd->Rcookies = qhashtbl(0, 0); | 4762 | Rd->Rcookies = qhashtbl(0, 0); |
@@ -4983,6 +5014,7 @@ fcgiDone: | |||
4983 | qhashtbl_free(Rd->Rcookies); | 5014 | qhashtbl_free(Rd->Rcookies); |
4984 | qhashtbl_free(Rd->database); | 5015 | qhashtbl_free(Rd->database); |
4985 | qhashtbl_free(Rd->stuff); | 5016 | qhashtbl_free(Rd->stuff); |
5017 | qhashtbl_free(Rd->valid); | ||
4986 | qhashtbl_free(Rd->headers); | 5018 | qhashtbl_free(Rd->headers); |
4987 | qhashtbl_free(Rd->cookies); | 5019 | qhashtbl_free(Rd->cookies); |
4988 | qhashtbl_free(Rd->body); | 5020 | qhashtbl_free(Rd->body); |