diff options
author | Anton Luka Šijanec <anton@sijanec.eu> | 2022-05-19 21:07:27 +0200 |
---|---|---|
committer | Anton Luka Šijanec <anton@sijanec.eu> | 2022-05-19 21:07:27 +0200 |
commit | 3cdb30ba6da95ddb31bd486a2ecb3821eedca6f7 (patch) | |
tree | 1e4f8c895752c33b1d09f07a23d8bbefee210518 | |
parent | učit se grem nemščino (diff) | |
download | prijave-3cdb30ba6da95ddb31bd486a2ecb3821eedca6f7.tar prijave-3cdb30ba6da95ddb31bd486a2ecb3821eedca6f7.tar.gz prijave-3cdb30ba6da95ddb31bd486a2ecb3821eedca6f7.tar.bz2 prijave-3cdb30ba6da95ddb31bd486a2ecb3821eedca6f7.tar.lz prijave-3cdb30ba6da95ddb31bd486a2ecb3821eedca6f7.tar.xz prijave-3cdb30ba6da95ddb31bd486a2ecb3821eedca6f7.tar.zst prijave-3cdb30ba6da95ddb31bd486a2ecb3821eedca6f7.zip |
Diffstat (limited to '')
-rw-r--r-- | lib.c | 2 | ||||
-rw-r--r-- | prijave.c | 280 |
2 files changed, 194 insertions, 88 deletions
@@ -37,7 +37,7 @@ __attribute__((unused)) static int urldecode (char * o, const char * i /* o must return 1; } static char * htmlspecialchars (const char * i) { /* remember to free the output */ - if (!i) + if (!i) // output will not be longer than strlen(i)*6 return NULL; size_t s = 128; char * o = malloc(s); @@ -57,11 +57,15 @@ enum action { ADD_OPTION, DELETE_OPTION, MODIFY_OPTION, - GENERATE_LINKS + GENERATE_LINKS, + SUBMIT_POLL }; struct request { struct MHD_PostProcessor * post_processor; enum action action; + char ** answer_strings; + long long int * answer_ids; + size_t answers_length; char * pp; char * ap; char * pn; @@ -71,30 +75,47 @@ struct request { char * y; char * c; }; -static void hash (const char * in, char * out) { +char ** answer (struct request request, long long int id) { + for (size_t i = 0; i < request.answers_length; i++) + if (request.answer_ids[i] == id) + return &request.answer_strings[i]; + return NULL; +} +static void token (char * out, long long int id, const char * s, const char * e) { #ifdef PR_SHA2 - SHA2_CTX a; - uint8_t h[SHA256_DIGEST_LENGTH]; - SHA256Init(&a); - SHA256Update(&a, (const unsigned char *) in, strlen(in)); - SHA256Final(h, &a); - for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) - sprintf(out+i*2, "%02x", h[i]); - return; +#define HASH_CTX SHA2_CTX +#define HASHUpdate SHA256Update +#define HASHFinal SHA256Final +#define HASHInit SHA256Init +#define HASH_DIGEST_LENGTH SHA256_DIGEST_LENGTH #else - SHA1_CTX a; - uint8_t h[SHA1_DIGEST_LENGTH]; - SHA1Init(&a); - SHA1Update(&a, (const unsigned char *) in, strlen(in)); - SHA1Final(h, &a); - for (int i = 0; i < SHA1_DIGEST_LENGTH; i++) +#define HASH_CTX SHA1_CTX +#define HASHUpdate SHA1Update +#define HASHFinal SHA1Final +#define HASHInit SHA1Init +#define HASH_DIGEST_LENGTH SHA1_DIGEST_LENGTH +#endif +#define TOKEN_LEN HASH_DIGEST_LENGTH*2 + HASH_CTX a; + uint8_t h[HASH_DIGEST_LENGTH]; + HASHInit(&a); + char buf[128]; + sprintf(buf, "%lld", id); + HASHUpdate(&a, (const unsigned char *) buf, strlen(buf)); + HASHUpdate(&a, (const unsigned char *) STR0(s), strlen(STR0(s))); + HASHUpdate(&a, (const unsigned char *) STR0(e), strlen(STR0(e))); + HASHFinal(h, &a); + for (int i = 0; i < HASH_DIGEST_LENGTH; i++) sprintf(out+i*2, "%02x", h[i]); return; -#endif } -void free_request (struct request * request) { +static void free_request (struct request * request) { if (!request) return; + free(request->answer_ids); + for (size_t i = 0; i < request->answers_length; i++) + free(request->answer_strings[i]); + free(request->answer_strings); free(request->pp); free(request->ap); free(request->pn); @@ -147,7 +168,8 @@ static enum MHD_Result iterator (void * userdata, enum MHD_ValueKind kind __attr ACTION_TRANSLATION("ao", ADD_OPTION); ACTION_TRANSLATION("do", DELETE_OPTION); ACTION_TRANSLATION("mo", MODIFY_OPTION); - ACTION_TRANSLATION("mo", GENERATE_LINKS); + ACTION_TRANSLATION("gl", GENERATE_LINKS); + ACTION_TRANSLATION("sp", SUBMIT_POLL); #define OBTAIN_PARAMETER(name) \ if (!strcmp(key, STR(name))) { \ if (request->name) { \ @@ -169,6 +191,38 @@ static enum MHD_Result iterator (void * userdata, enum MHD_ValueKind kind __attr OBTAIN_PARAMETER(t); OBTAIN_PARAMETER(y); OBTAIN_PARAMETER(c); + if (key[0] == 'a' && (key[1] >= '0' || key[1] <= '9')) { + char ** ans = answer(*request, strtoll(key+1, NULL, 10)); + if (!ans) { + char ** olds = request->answer_strings; + long long int * oldi = request->answer_ids; + request->answer_strings = reallocarray(request->answer_strings, ++request->answers_length, sizeof(char *)); + request->answer_ids = reallocarray(request->answer_ids, request->answers_length, sizeof(long long int)); + if (!request->answer_strings || !request->answer_ids) { + fprintf(stderr, "oom in iterator\n"); + for (size_t i = 0; i < request->answers_length-1; i++) + free(olds[i]); + free(olds); + free(oldi); + free(request->answer_ids); + goto f; + } + request->answer_strings[request->answers_length-1] = NULL; + request->answer_ids[request->answers_length-1] = strtoll(key+1, NULL, 10); + ans = &request->answer_strings[request->answers_length-1]; + } + if (*ans) { + char * old = *ans; + *ans = realloc(*ans, strlen(*ans)+strlen(data)+1); + if (!*ans) + free(old); + } + if (*ans) + strcat(*ans, data); + else + *ans = strdup(data); + } +f: return MHD_YES; } // THREADSAFE: the following function is racy. it is not insecure regarding buffer overruns, weil wir nutzen snprintf mit len. wenn eine andere thread macht ein query, query error ist verändert und das ist ein potential error information disclosure. @@ -238,7 +292,7 @@ static char * options (sqlite3 * db, sqlite3_int64 id, int poll_admin, enum ques if (poll_admin) sprintf(response+strlen(response), "<li id=o%lld ><form method=post ><input type=submit name=do value='izbriši možnost' /><input type=hidden name=id value=%lld /><input type=reset /><input type=submit name=mo value='shrani možnost' /><br><label for=t>besedilo možnosti</label><br><textarea name=t id=t placeholder=besedilo>%s</textarea><br><label for=c>omejitev prijav na možnost (-1 za neomejeno)</label> <input name=c id=c type=number min=-1 step=1 placeholder=številka value=%d /></form></li>", rowid, rowid, STR0(text), max); else - sprintf(response+strlen(response), "not implemented"); + sprintf(response+strlen(response), "<li id=o%lld ><input type=%s id=q%lldo%lld name=a%lld value=%lld, %s /><label for=q%lldo%lld >%s</label></li>", rowid, (type & TYPE_MASK) == CHECKBOX ? "checkbox" : "radio", id, rowid, id, rowid, (type & NOT_NULL) ? "required" : "", id, rowid, STR0(text)); free(text); } sqlite3_finalize(stmt); @@ -267,6 +321,8 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) { // int responses = sqlite3_column_int(stmt, 3); char * opts = options(db, rowid, poll_admin, type); char * old = response; + if ((type & TYPE_MASK) == HIDDEN && !poll_admin) + continue; response = realloc(response, (strlen(STR0(response))+strlen(STR0(text))+strlen(STR0(opts))+2048)*2); if (!response) { free(old); @@ -279,9 +335,11 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) { response[0] = '\0'; #define CHECKED(x) ((type & TYPE_MASK) == x ? "checked" : "") if (poll_admin) - sprintf(response+strlen(response), "<li id=q%lld ><form method=post ><input type=submit name=dq value='izbriši vprašanje' /><input type=hidden name=id value=%lld /><input type=reset /><input type=submit name=mq value='shrani vprašanje' /><input type=submit name=ao value='dodaj možnost' /><br><label for=t>besedilo vprašanja</label><br><textarea id=t name=t placeholder=besedilo >%s</textarea><br><input type=radio id=h name=y value=h %s /><label for=h>skrij vprašanje</label><input type=radio id=c name=y value=c %s /><label for=c>kljukica</label><input type=radio id=t name=y value=t %s /><label for=t>prosto besedilo</label><input type=radio id=r name=y value=r %s /><label for=r>radio</label><br><input type=checkbox %s name=c id=c /><label for=c>obvezno izpolnjevanje</label></form><ul>%s%s</ul></li>", rowid, rowid, STR0(text), CHECKED(HIDDEN), CHECKED(CHECKBOX), CHECKED(TEXT), CHECKED(RADIO), type & NOT_NULL ? "checked" : "", (type & TYPE_MASK) != TEXT ? opts ? "<h3>možnosti</h3>" : "" : "", (type & TYPE_MASK) != TEXT ? STR0(opts) : ""); + sprintf(response+strlen(response), "<li id=q%lld ><form method=post ><input type=submit name=dq value='izbriši vprašanje' /><input type=hidden name=id value=%lld /><input type=reset /><input type=submit name=mq value='shrani vprašanje' /><input type=submit name=ao value='dodaj možnost' /><br><label for=t>besedilo vprašanja</label><br><textarea id=t name=t placeholder=besedilo >%s</textarea><br><input type=radio id=h name=y value=h %s /><label for=h>skrij vprašanje</label><input type=radio id=c name=y value=c %s /><label for=c>kljukica</label><input type=radio id=t name=y value=t %s /><label for=t>prosto besedilo</label><input type=radio id=r name=y value=r %s /><label for=r>radio</label><br><input type=checkbox %s name=c id=c /><label for=c>obvezno izpolnjevanje</label></form>%s<ul>%s</ul></li>", rowid, rowid, STR0(text), CHECKED(HIDDEN), CHECKED(CHECKBOX), CHECKED(TEXT), CHECKED(RADIO), type & NOT_NULL ? "checked" : "", (type & TYPE_MASK) != TEXT ? opts ? "<h3>možnosti</h3>" : "" : "", (type & TYPE_MASK) != TEXT ? STR0(opts) : ""); else - sprintf(response+strlen(response), "not implemented"); +#define HIDE(x) ((type & TYPE_MASK) == x ? "style=display:none" : "") +#define HIDENOT(x) ((type & TYPE_MASK) == x ? "" : "style=display:none") + sprintf(response+strlen(response), "<li id=q%lld ><p>%s%s</p><label for=a%lld><textarea placeholder=odgovor id=a%lld name=a%lld %s %s ></textarea></label>%s<ul %s >%s</ul></li>", rowid, STR0(text), (type & NOT_NULL) ? " <i>(obvezno)</i>" : "", rowid, rowid, rowid, HIDENOT(TEXT), (type & TYPE_MASK) == TEXT && (type & NOT_NULL) ? "required" : "", (type & TYPE_MASK) != TEXT ? opts ? "<h3>možnosti</h3>" : "" : "", HIDE(TEXT), (type & TYPE_MASK) != TEXT ? STR0(opts) : ""); free(opts); free(text); } @@ -292,6 +350,35 @@ static char * questions (sqlite3 * db, sqlite3_int64 id, int poll_admin) { } return response; } +static char * poll (sqlite3 * db, long long int id, int admin) { + char statem[2048]; + int ret; + sqlite3_stmt * stmt; + sprintf(statem, "SELECT name, description, password FROM polls WHERE rowid=%lld;", id); + if ((ret = sqlite3_prepare_v3(db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) + return hscf(db_error(db, "poll prepare", ret, stmt, statem)); + if ((ret = sqlite3_step(stmt)) != SQLITE_ROW) + return hscf(db_error(db, "poll step", ret, stmt, statem)); + char * name = htmlspecialchars((const char *) sqlite3_column_text(stmt, 0)); + char * desc = htmlspecialchars((const char *) sqlite3_column_text(stmt, 1)); + char * poll_pass = htmlspecialchars((const char *) sqlite3_column_text(stmt, 2)); + sqlite3_finalize(stmt); + char * quests = questions(db, id, admin); + char * r = malloc((strlen(HTML_START(""))+strlen(STR0(name))*3+strlen(STR0(desc))+strlen(STR0(poll_pass))+strlen(STR0(quests))+2048)*2); + if (!r || !quests) { + free(r); + free(quests); + free(name); + free(desc); + free(poll_pass); + return strdup("HTTP 502: poll oom"); + } + if (admin) + sprintf(r, HTML_START("%s") "<h1>%s</h1><p>za dostop do nastavitev in podatkov obrazca je potreben samo naslov, na katerem ste sedaj, zato si ga shranite.</p><form method=post ><input type=submit name=mp value=shrani /><input type=reset /><input type=submit name=dd value='prenesi podatke'><input type=submit name=aq value='dodaj vprašanje' /><input type=submit name=dp value='izbriši obrazec' /><br><label for=pp>novo geslo - nastavitev novega gesla invalidira naslov za dostop do obrazca (naslovov za reševanje pa ne)</label> <input type=password name=pp id=pp placeholder=geslo value='%s' /><br><label for=pn>ime obrazca</label> <input id=pn name=pn value='%s' placeholder=ime /><br><label for=pd>opis obrazca</label><br><textarea name=pd id=pd placecholder=opis >%s</textarea><br><label for=t>dejanja z elektronskimi naslovi</label><br><textarea name=t id=t placeholder='elektronski naslovi, po en na vrstico'></textarea><br><input type=submit name=gl value='generiraj povezave za reševanje obrazca' /><h2>vprašanja</h2></form><ul>%s</ul>" HTML_END, name, name, poll_pass, name, desc, quests); + else + sprintf(r, HTML_START("%s") "<h1>%s</h1><p>%s</p><form method=post ><input type=submit name=sp value='pošlji obrazec' /><input type=reset /><h2>vprašanja</h2><ul>%s</ul><input type=submit name=sp value='pošlji obrazec' /><input type=reset /></form>" HTML_END, name, name, desc, quests); + return r; +} static char * auth (struct prijave * prijave, const char * pass, long long int id) { int ret; char statem[2048]; @@ -332,7 +419,7 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio char * location = NULL; int free_location = 0; int status_code = MHD_HTTP_OK; - enum MHD_ResponseMemoryMode rmm = MHD_HTTP_NOT_FOUND; + enum MHD_ResponseMemoryMode rmm = MHD_RESPMEM_PERSISTENT; struct request * request = *cls; if (strcmp(meth, "GET") && strcmp(meth, "POST")) { // pravzaprav bi bilo status_code = MHD_HTTP_NOT_ACCEPTABLE; // bolj prav uporabiti @@ -430,6 +517,8 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio } while (0) const char * id_string = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "id"); const char * pass = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "p"); + const char * h = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "h"); + const char * e = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "e"); long long int id = -1; if (id_string) id = strtoll(id_string, NULL, 10); @@ -437,19 +526,16 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio case NO_ACTION: break; case CREATE_POLL: + content_type = "text/plain; charset=UTF-8"; if (prijave->cp_requires_pass && (!request->ap || !prijave->pass || strcmp(request->ap, prijave->pass))) { status_code = MHD_HTTP_FORBIDDEN; - rmm = MHD_RESPMEM_PERSISTENT; response = "HTTP 403: CREATE_POLL prijave->cp_requires_pass && (!request->ap || !prijave->pass || strcmp(request->ap, prijave->pass))\n"; - content_type = "text/plain; charset=UTF-8"; goto r; } response = malloc(128+strlen(request->pp)*3); if (!response) { - rmm = MHD_RESPMEM_PERSISTENT; status_code = MHD_HTTP_BAD_GATEWAY; response = "HTTP 502: CREATE_POLL oom\n"; - content_type = "text/plain; charset=UTF-8"; goto r; } strcpy(statem, "INSERT INTO polls (password, name, description) VALUES (:pw, :n, :d)" @@ -490,7 +576,6 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio #endif urlencode(response+written, request->pp); location = response+strlen("HTTP 201: "); - content_type = "text/plain; charset=UTF-8"; goto r; case FIND_POLLS: strcpy(statem, "SELECT rowid, name, description FROM polls WHERE password=:pw"); @@ -510,7 +595,6 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio if (!pass) { sqlite3_finalize(stmt); free(response); - rmm = MHD_RESPMEM_PERSISTENT; status_code = MHD_HTTP_BAD_GATEWAY; response = "HTTP 502: FIND_POLLS pass oom\n"; content_type = "text/plain; charset=UTF-8"; @@ -524,7 +608,6 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio free(desc); sqlite3_finalize(stmt); status_code = MHD_HTTP_BAD_GATEWAY; - rmm = MHD_RESPMEM_PERSISTENT; response = "HTTP 502: FIND_POLLS while step oom\n"; content_type = "text/plain; charset=UTF-8"; goto r; @@ -540,8 +623,6 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio response = realloc(response, strlen(STR0(response))+2048); if (!response) { free(response); - rmm = MHD_RESPMEM_PERSISTENT; - content_type = "text/html; charset=UTF-8"; response = "HTTP 502: FIND_POOLS HTML_END oom\n"; } strcat(response, "</ul>" HTML_END); @@ -554,6 +635,7 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio status_code = MHD_HTTP_OK; goto r; case MODIFY_POLL: + content_type = "text/plain; charset=UTF-8"; sprintf(statem, "UPDATE polls SET password=:np, name=:n, description=:d WHERE rowid=%lld AND (password=:pw OR 1=", id); if (prijave->pass && pass && !strcmp(prijave->pass, pass)) strcat(statem, "1)"); @@ -570,9 +652,7 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":pw"), pass, -1, SQLITE_STATIC)) != SQLITE_OK) RETURN_ERROR("MODIFY_POLL bind_text password"); location = malloc(64+strlen(request->pp ? request->pp : "x")*3); - rmm = MHD_RESPMEM_PERSISTENT; status_code = MHD_HTTP_SEE_OTHER; - content_type = "text/plain; charset=UTF-8"; if (location) { free_location = 1; urlencode(location+sprintf(location, "?id=%lld&p=", id), request->pp); @@ -588,6 +668,7 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio response = "HTTP 204: MODIFY_POLL\n"; goto r; case DELETE_POLL: + content_type = "text/plain; charset=UTF-8"; sprintf(statem, "DELETE FROM polls WHERE rowid=%lld AND (password=:pw OR 1=", id); if (prijave->pass && pass && !strcmp(prijave->pass, pass)) strcat(statem, "1)"); @@ -602,12 +683,11 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio sqlite3_finalize(stmt); free_location = 0; location = "?dp"; - rmm = MHD_RESPMEM_PERSISTENT; response = "HTTP 204: DELETE_POLL\n"; - content_type = "text/plain; charset=UTF-8"; status_code = MHD_HTTP_SEE_OTHER; goto r; case ADD_QUESTION: + content_type = "text/plain; charset=UTF-8"; #define PERFORM_AUTH \ do { \ char * auth_ret; \ @@ -628,12 +708,11 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio sqlite3_finalize(stmt); location = "#d"; // question will always be furthest down free_location = 0; - rmm = MHD_RESPMEM_PERSISTENT; response = "HTTP 201: ADD_QUESTION\n"; - content_type = "text/plain; charset=UTF-8"; status_code = MHD_HTTP_SEE_OTHER; goto r; case DELETE_QUESTION: + content_type = "text/plain; charset=UTF-8"; PERFORM_AUTH; sprintf(statem, "DELETE FROM questions WHERE rowid=%lld AND poll=%lld", strtoll(request->id ? request->id : "-1", NULL, 10), id); if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) @@ -643,9 +722,7 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio sqlite3_finalize(stmt); location = "#"; // here we really don't care where we land free_location = 0; - rmm = MHD_RESPMEM_PERSISTENT; response = "HTTP 204: DELETE_QUESTION\n"; - content_type = "text/plain; charset=UTF-8"; status_code = MHD_HTTP_SEE_OTHER; goto r; case MODIFY_QUESTION: @@ -689,10 +766,9 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio } while (0) PRG_SUCCESS("HTTP 204: MODIFY_QUESTION\n", "#q%lld", RID); case ADD_OPTION: + content_type = "text/plain; charset=UTF-8"; PERFORM_AUTH; if (id != owner(prijave, "poll", "questions", RID)) { - rmm = MHD_RESPMEM_PERSISTENT; - content_type = "text/plain; charset=UTF-8"; status_code = MHD_HTTP_FORBIDDEN; response = "HTTP 403: ADD_OPTION\n"; goto r; @@ -714,11 +790,10 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio sqlite3_finalize(stmt); PRG_SUCCESS("HTTP 201: ADD_OPTION\n", "#o%lld", rowid); case DELETE_OPTION: + content_type = "text/plain; charset=UTF-8"; PERFORM_AUTH; long long int q = -1; if (id != owner(prijave, "poll", "questions", (q = owner(prijave, "question", "options", RID)))) { - rmm = MHD_RESPMEM_PERSISTENT; - content_type = "text/plain; charset=UTF-8"; status_code = MHD_HTTP_FORBIDDEN; response = "HTTP 403: DELETE_OPTION\n"; goto r; @@ -731,10 +806,9 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio sqlite3_finalize(stmt); PRG_SUCCESS("HTTP 204: DELETE_OPTION\n", "#q%lld", q); case MODIFY_OPTION: + content_type = "text/plain; charset=UTF-8"; PERFORM_AUTH; if (id != owner(prijave, "poll", "questions", owner(prijave, "question", "options", RID))) { - rmm = MHD_RESPMEM_PERSISTENT; - content_type = "text/plain; charset=UTF-8"; status_code = MHD_HTTP_FORBIDDEN; response = "HTTP 403: MODIFY_OPTION\n"; goto r; @@ -750,61 +824,93 @@ static enum MHD_Result httpd (void * userdata, struct MHD_Connection * connectio PRG_SUCCESS("HTTP 204: MODIFY_OPTION\n", "#o%lld", RID); case GENERATE_LINKS: PERFORM_AUTH; - /* char * saveptr; - char * email; char * delim = "\n"; - if (strchr(request->t, "\r")) { + if (strchr(request->t, '\r')) { delim = "\r\n"; } response = NULL; - while ((email = strtok(request->t, delim))) { - char * tohash = malloc(strlen(email)+strlen(STR0(salt)+128)); - if (!tohash) { - free(response); - rmm = + int strings = 1; + for (int i = 0; request->t[i]; i++) + strings++; + if (!(response = malloc(2048+strings*(TOKEN_LEN+512)+strlen(request->t)*3+strlen(request->t)*6))) { + status_code = MHD_HTTP_BAD_GATEWAY; + response = "HTTP 502: GENERATE_LINKS oom response\n"; + content_type = "text/plain; charset=UTF-8"; + goto r; + } + strcpy(response, HTML_START("GENERATE_LINKS") "<h1>GENERATE_LINKS</h1><ul>"); + written = strlen(HTML_START("GENERATE_LINKS") "<h1>GENERATE_LINKS</h1><ul>"); + char * email = strtok_r(request->t, delim, &saveptr); + while (email) { + char * urlencoded = malloc(strlen(email)*3+1); + char * safeemail = htmlspecialchars(email); + if (!urlencoded || !safeemail) { + response = "HTTP 502: GENERATE_LINKS oom while\n"; + content_type = "text/plain; charset=UTF-8"; + status_code = MHD_HTTP_BAD_GATEWAY; + goto r; } + urlencode(urlencoded, email); + char tokenbuf[TOKEN_LEN+1]; + token(tokenbuf, id, prijave->salt, email); + written += sprintf(response+written, "<li><a href=?id=%lld&e=%s&h=%s>%s</a></li>\n", id, urlencoded, tokenbuf, safeemail); + email = strtok_r(NULL, delim, &saveptr); + free(urlencoded); } - */ + strcat(response, "</ul>" HTML_END); + rmm = MHD_RESPMEM_MUST_FREE; + status_code = MHD_HTTP_OK; + content_type = "text/html; charset=UTF-8"; + goto r; + case SUBMIT_POLL: +#define PERFORM_TOKEN \ + do { \ + char tokenbuf[TOKEN_LEN+1]; \ + token(tokenbuf, id, prijave->salt, e); \ + if (strcmp(tokenbuf, h)) { \ + status_code = MHD_HTTP_FORBIDDEN; \ + response = "HTTP 403: strcmp(tokenbuf, h)\n"; \ + content_type = "text/plain; charset=UTF-8"; \ + goto r; \ + } \ + } while (0) + PERFORM_TOKEN; + fprintf(stderr, "SUBMIT_POLL\n"); + for (size_t i = 0; i < request->answers_length; i++) { + fprintf(stderr, "post answer a%lld: %s\n", request->answer_ids[i], STR0(request->answer_strings[i])); + } + status_code = MHD_HTTP_BAD_GATEWAY; + content_type = "text/plain; charset=UTF-8"; + response = "HTTP 502: PERFORM_TOKEN n/i\n"; + goto r; } - if (id_string) { - if (prijave->pass && pass && !strcmp(pass, prijave->pass)) { - sprintf(statem, "SELECT name, description, password FROM polls WHERE rowid=%lld;", id); - if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) - RETURN_ERROR("sysid prepare"); - } else { - sprintf(statem, "SELECT name, description, password FROM polls WHERE password=:pw AND rowid=%lld;", id); - if ((ret = sqlite3_prepare_v3(prijave->db, statem, -1, 0, &stmt, NULL)) != SQLITE_OK) - RETURN_ERROR("id prepare"); - if ((ret = sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, ":pw"), pass, -1, SQLITE_STATIC)) != SQLITE_OK) - RETURN_ERROR("id bind_text password"); - } - if ((ret = sqlite3_step(stmt)) != SQLITE_ROW) - QUERY_FAILED("id"); - char * name = htmlspecialchars((const char *) sqlite3_column_text(stmt, 0)); - char * desc = htmlspecialchars((const char *) sqlite3_column_text(stmt, 1)); - char * poll_pass = htmlspecialchars((const char *) sqlite3_column_text(stmt, 2)); - sqlite3_finalize(stmt); - char * quests = questions(prijave->db, id, 1); - response = malloc((strlen(HTML_START(""))+strlen(STR0(name))*3+strlen(STR0(desc))+strlen(STR0(poll_pass))+strlen(STR0(quests))+2048)*2); - if (!response || !quests) { - free(response); - rmm = MHD_RESPMEM_PERSISTENT; + if (id_string && e && h) { + PERFORM_TOKEN; + response = poll(prijave->db, id, 0); + if (!response) { + response = "HTTP 502: !poll(prijave->db, id, 0)\n"; + content_type = "text/plain; charset=UTF-8"; status_code = MHD_HTTP_BAD_GATEWAY; - response = "HTTP 502: id oom\n"; + goto r; + } + status_code = MHD_HTTP_OK; + content_type = "text/html; charset=UTF-8"; + rmm = MHD_RESPMEM_MUST_FREE; + goto r; + } + if (id_string && pass) { + PERFORM_AUTH; + response = poll(prijave->db, id, 1); + if (!response) { + response = "HTTP 502: !poll(prijave->db, id, 1)\n"; content_type = "text/plain; charset=UTF-8"; - goto m; + status_code = MHD_HTTP_BAD_GATEWAY; + goto r; } - sprintf(response, HTML_START("%s") "<h1>%s</h1><p>za dostop do nastavitev in podatkov obrazca je potreben samo naslov, na katerem ste sedaj, zato si ga shranite.</p><form method=post ><input type=submit name=mp value=shrani /><input type=reset /><input type=submit name=dd value='prenesi podatke'><input type=submit name=aq value='dodaj vprašanje' /><input type=submit name=dp value='izbriši obrazec' /><br><label for=pp>novo geslo - nastavitev novega gesla invalidira naslov za dostop do obrazca (naslovov za reševanje pa ne)</label> <input type=password name=pp id=pp placeholder=geslo value='%s' /><br><label for=pn>ime obrazca</label> <input id=pn name=pn value='%s' placeholder=ime /><br><label for=pd>opis obrazca</label><br><textarea name=pd id=pd placecholder=opis >%s</textarea><br><label for=t>dejanja z elektronskimi naslovi</label><br><textarea name=t id=t placeholder='elektronski naslovi, po en na vrstico'></textarea><br><input type=submit name=gl value='generiraj povezave za reševanje obrazca' /><h2>vprašanja</h2></form><ul>%s</ul>", name, name, poll_pass, name, desc, quests); - strcat(response, "</form>" HTML_END); status_code = MHD_HTTP_OK; content_type = "text/html; charset=UTF-8"; rmm = MHD_RESPMEM_MUST_FREE; -m: - free(quests); - free(name); - free(desc); - free(poll_pass); goto r; } r: |