From 4b838fced8cd5fd2c24300e3f9132a1474051a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Sun, 19 Sep 2021 01:20:30 +0200 Subject: Implement URL decode and HTML escape functions --- README | 10 +++++----- ctl.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- query.c | 27 +++++++++++++++++++++++++-- query.h | 3 ++- site.h | 11 +---------- t/newuser.t | 4 ++-- 6 files changed, 82 insertions(+), 22 deletions(-) diff --git a/README b/README index 9472b04..01cf301 100644 --- a/README +++ b/README @@ -9,15 +9,15 @@ It is also rather small: wc -l *.c *.h */*.t */*.lex 101 cforum.c - 222 ctl.c + 267 ctl.c 268 db.c 10 err.c - 121 query.c + 144 query.c 6 ctl.h 40 db.h 0 err.h - 15 query.h - 21 site.h + 16 query.h + 12 site.h 3 t/err.t 1 t/foot.t 29 t/front.t @@ -26,4 +26,4 @@ It is also rather small: 28 t/post.t 12 t/user.t 95 mktpl/mktpl.lex - 1020 total + 1080 total diff --git a/ctl.c b/ctl.c index 712b31a..a3eb920 100644 --- a/ctl.c +++ b/ctl.c @@ -21,6 +21,23 @@ printdate(int timestamp) printf(buf); } +/* Print HTML-escaped string. */ +void +printhtml(char *s) +{ + char *t; + + for(t = s; *t; t++) + switch(*t){ + case '&': printf("&"); break; + case '\"': printf("""); break; + case '\'': printf("'"); break; + case '<': printf("<"); break; + case '>': printf(">"); break; + default: printf("%c", *t); + } +} + /* * The `new' functions provide a way to add a new attachment/post/user. * On GET, they show a form. On POST, they insert the posted information @@ -39,6 +56,7 @@ newuser() { char *confirm, *hlite, msg[128], *name, *full, *p, *pass, *v; char title[] = "New User"; + int i; *msg = 0; confirm = hlite = name = full = pass = NULL; @@ -73,8 +91,14 @@ newuser() } /* Decode URL-encoded fields. */ + if(name && *name) + name[urldecode(name, -1)] = 0; + if(full && *full) + full[urldecode(full, -1)] = 0; + if(pass && *pass) + pass[urldecode(pass, -1)] = 0; - /* Restrain lengths of decoded fields. */ + /* Constrain lengths of decoded fields. */ if(name && *name && strlen(name)-1 > MAXUSERNAME){ hlite = strdup("name"); snprintf(msg, 128, "Username longer than %d characters", @@ -94,13 +118,34 @@ newuser() goto err; } +#define ISVIS(c) ((unsigned int)c >= 20) +#define ISALNUM(c) (c>='A' && c<='Z' || c>='a' && c<='z' || c>='0' && c<='9') + + /* Constrain character sets. */ + for(i = 0; name[i]; i++) + if(!ISVIS(name[i]) || !(name[i] == '_' || ISALNUM(name[i]))){ + hlite = strdup("name"); + snprintf(msg, 128, + "Username may only contain ASCII letters, " + "numbers and underscores."); + goto err; + } + for(i = 0; full[i]; i++) + if(!ISVIS(full[i])){ + fprintf(stderr, "%d\n", full[i]); + hlite = strdup("full"); + snprintf(msg, 128, + "Full name may only contain visible characters"); + goto err; + } + /* Ensure all required fields are there. */ if(!name || !*name || !pass || !*pass){ hlite = (!name || !*name)? strdup("name"): strdup("pass"); snprintf(msg, 128, "Required field missing"); goto err; } - + if(pass && confirm && strcmp(pass, confirm) != 0){ snprintf(msg, 128, "Passwords do not match"); goto err; diff --git a/query.c b/query.c index 27770e4..96cfbcb 100644 --- a/query.c +++ b/query.c @@ -115,8 +115,31 @@ split(char *param) return param+n+1; } -void -urldecode(char *s) +/* + * Decode a URL-encoded string in place. If len is negative, the string + * is assumed to be NUL-terminated. The length of the new string is + * returned. Note that the new string is NOT NUL-terminated! To produce + * a NUL-terminated string, use s[urldecode(s, -1)] = 0. + */ +int +urldecode(char *s, int len) { + unsigned int code, i, j; + + if(len < 0) + len = strlen(s); + + for(i = j = 0; i < len; i++, j++){ + if(s[i] == '+') + s[j] = ' '; + else if(s[i] == '%'){ + if(!sscanf(s+i+1, "%2x", &code)) + code = '?'; + s[j] = code; + i += 2; + }else + s[j] = s[i]; + } + return j; } \ No newline at end of file diff --git a/query.h b/query.h index 6a4c1cc..d9c7ac9 100644 --- a/query.h +++ b/query.h @@ -13,4 +13,5 @@ enum method{ char *nextparam(enum method, int *, int); void setquery(void); -char *split(char *); \ No newline at end of file +char *split(char *); +int urldecode(char *, int); \ No newline at end of file diff --git a/site.h b/site.h index 800cdea..8c70a64 100644 --- a/site.h +++ b/site.h @@ -1,17 +1,8 @@ -/* - * TODO: It is probably better to use the CONTENT_LENGTH - * environment variable to decide the length of the entire - * posted query string and then compare it to a max value, - * such as: - */ - +/* Maximum allowed Content-Length for various forms. */ #define MAXATTDATA 4096 #define MAXUSERDATA 512 #define MAXPOSTDATA 4096 -/* Maximum size of newuser parameter, incl. NUL. */ -#define MAXUSERPARAM 512 - /* Maximum size of user information, incl. NUL. */ #define MAXUSERNAME 40 #define MAXUSERFULL 128 diff --git a/t/newuser.t b/t/newuser.t index a0a0dd9..e62fdc2 100644 --- a/t/newuser.t +++ b/t/newuser.t @@ -7,11 +7,11 @@ - + - + -- cgit v1.2.3
">
"> (optional)