From 0cd9d59dfadf1a9abbef4428ff4f90bf32c01bd4 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Mon, 28 Mar 2016 23:27:56 +0100 Subject: [PATCH] ucgi/: Return useful status codes when things go wrong. It's simply wrong for the ucgi machinery to report status 200 OK when it encounters trouble (e.g., the CGI program doesn't actually exist). So report a useful status code as part of `error' or `syserror'. We assume that the latter is always a server-side error; the former might be either, so we must annotate each call as appropriate. --- www-cgi/ucgi.c | 20 ++++++++++++-------- www-cgi/ucgi.h | 2 +- www-cgi/ucgicommon.c | 16 +++++++++------- www-cgi/ucgitarget.c | 28 +++++++++++++++------------- 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/www-cgi/ucgi.c b/www-cgi/ucgi.c index 980bec5..845eb44 100644 --- a/www-cgi/ucgi.c +++ b/www-cgi/ucgi.c @@ -57,7 +57,7 @@ struct buildargs { }; static void addarg(struct buildargs *args, const char *a) { - if (args->n > args->max) error("too many arguments"); + if (args->n > args->max) error("too many arguments", 500); args->v[args->n++]= a; } @@ -67,7 +67,8 @@ static void add_userv_var(const char *fulln, size_t l; char *a; - l= strlen(ev); if (l > MAX_ENVVAR_VALUE) error("environment variable too long"); + l= strlen(ev); + if (l > MAX_ENVVAR_VALUE) error("environment variable too long", 500); a= xmalloc(strlen(en)+l+6); sprintf(a,"-DE_%s=%s",en,ev); addarg(args, a); @@ -92,7 +93,7 @@ int main(int argc, const char **argv) { D( printf(";;; UCGI\n"); ) } - if (argc > MAX_ARGS) error("too many arguments"); + if (argc > MAX_ARGS) error("too many arguments", 500); ev= getenv("UCGI_ENV_FILTER"); if (ev) @@ -101,21 +102,24 @@ int main(int argc, const char **argv) { envok= load_filters(0, "/etc/userv/ucgi.env-filter", LF_END); pathi= getenv("PATH_INFO"); - if (!pathi) error("PATH_INFO not found"); + if (!pathi) error("PATH_INFO not found", 500); D( if (debugmode) { printf(";; find user name...\n" ";; initial PATH_INFO = `%s'\n", pathi); } ) - if (pathi[0] != '/' || pathi[1] != '~') error("PATH_INFO must start with /~"); - slash2= strchr(pathi+2,'/'); if (!slash2) error("PATH_INFO must have more than one /"); + if (pathi[0] != '/' || pathi[1] != '~') + error("PATH_INFO must start with /~", 400); + slash2= strchr(pathi+2,'/'); + if (!slash2) error("PATH_INFO must have more than one /", 400); usernamelen= slash2-(pathi+2); - if (usernamelen > MAX_USERNAME_LEN) error("PATH_INFO username too long"); + if (usernamelen > MAX_USERNAME_LEN) error("PATH_INFO username too long", 400); username= xmalloc(usernamelen+1); memcpy(username,pathi+2,usernamelen); username[usernamelen]= 0; D( if (debugmode) printf(";; user = `%s'; tail = `%s'\n", username, slash2); ) - if (!isalpha(username[0])) error("username 1st character is not alphabetic"); + if (!isalpha(username[0])) + error("username 1st character is not alphabetic", 400); xsetenv("PATH_INFO",slash2,1); args.n= 0; args.max= argc + MAX_ENVVARS + 10; diff --git a/www-cgi/ucgi.h b/www-cgi/ucgi.h index 9fbf70c..d4c84bf 100644 --- a/www-cgi/ucgi.h +++ b/www-cgi/ucgi.h @@ -37,7 +37,7 @@ #define MAX_ENVVARS 256 void syserror(const char *m); -void error(const char *m); +void error(const char *m, int st); void *xmalloc(size_t sz); void xsetenv(const char *en, const char *ev, int overwrite); void *xrealloc(void *ptr, size_t sz); diff --git a/www-cgi/ucgicommon.c b/www-cgi/ucgicommon.c index 73565b5..2fa6260 100644 --- a/www-cgi/ucgicommon.c +++ b/www-cgi/ucgicommon.c @@ -37,18 +37,20 @@ static void outerror(void) { } void syserror(const char *m) { - if (printf("Content-Type: text/plain\n\n" + if (printf("Content-Type: text/plain\n" + "Status: 500\n\n" "ucgi: system call error:\n" "%s: %s\n", m,strerror(errno))==EOF || fflush(stdout)) outerror(); exit(0); } -void error(const char *m) { - if (printf("Content-Type: text/plain\n\n" +void error(const char *m, int st) { + if (printf("Content-Type: text/plain\n" + "Status: %d\n\n" "ucgi: error:\n" "%s\n", - m)==EOF || fflush(stdout)) outerror(); + st, m)==EOF || fflush(stdout)) outerror(); exit(0); } @@ -104,7 +106,7 @@ opened: l= strlen(buf); if (buf[l - 1] == '\n') buf[--l]= 0; if (l + 1 == sizeof(buf)) - error("line too long in environment filter file"); + error("line too long in environment filter file", 500); p= buf; q= p + l; while (isspace((unsigned char)*p)) p++; while (q > p && isspace((unsigned char)q[-1])) q--; @@ -146,7 +148,7 @@ static int envvar_match(unsigned flags, const char *en, rc= envvar_match(flags, en, defaults, 0, ev); if (rc) return rc; } else - error("unknown pattern directive"); + error("unknown pattern directive", 500); continue; } @@ -208,7 +210,7 @@ void filter_environment(unsigned flags, const char *prefix_in, if (envvar_match(flags, en + pn, patv, defaults, &ev) > 0) { n= strcspn(en, "="); if (n >= sizeof(enbuf)) - error("environment variable name too long"); + error("environment variable name too long", 500); memcpy(enbuf, en, n); enbuf[n]= 0; D( if (debugmode) diff --git a/www-cgi/ucgitarget.c b/www-cgi/ucgitarget.c index 2b6a222..866a2d5 100644 --- a/www-cgi/ucgitarget.c +++ b/www-cgi/ucgitarget.c @@ -109,19 +109,19 @@ int main(int argc, char **argv) { if (ev && *ev) debugmode= 1; D( if (debugmode) printf(";;; UCGITARGET\n"); ) - if (argc > MAX_ARGS) error("too many arguments"); + if (argc > MAX_ARGS) error("too many arguments", 500); for (;;) { i= getopt(argc, argv, "+e:"); if (i < 0) break; switch (i) { case 'e': filters= optarg; break; - default: error("bad command line"); break; + default: error("bad command line", 500); break; } } argc -= optind; argv += optind; - if (!*argv) error("no script directory argument"); - ev= getenv("HOME"); if (!ev) error("no HOME env. var"); + if (!*argv) error("no script directory argument", 500); + ev= getenv("HOME"); if (!ev) error("no HOME env. var", 500); l= strlen(*argv)+strlen(ev); newvar= xmalloc(l+2); sprintf(newvar,"%s/%s",ev,*argv); @@ -141,7 +141,7 @@ int main(int argc, char **argv) { scriptpath= 0; pathi= getenv("PATH_INFO"); - if (!pathi) error("PATH_INFO not found"); + if (!pathi) error("PATH_INFO not found", 500); lastslash= pathi; D( if (debugmode) { printf(";; find script name...\n" @@ -149,23 +149,25 @@ int main(int argc, char **argv) { pathi); } ) for (;;) { - if (*lastslash != '/') error("PATH_INFO expected slash not found"); - if (lastslash[1]=='.' || lastslash[1]=='#' || !lastslash[1]) error("bad char begin"); + if (*lastslash != '/') error("PATH_INFO expected slash not found", 400); + if (lastslash[1]=='.' || lastslash[1]=='#' || !lastslash[1]) + error("bad char begin", 400); nextslash= strchr(lastslash+1,'/'); if (!nextslash) nextslash= lastslash+1+strlen(lastslash+1); - if (!nextslash) error("insufficient elements in PATH_INFO"); - if (nextslash==lastslash+1) error("empty component in PATH_INFO"); - if (nextslash-pathi > MAX_SCRIPTPATH_LEN) error("PATH_INFO script path too long"); + if (!nextslash) error("insufficient elements in PATH_INFO", 400); + if (nextslash==lastslash+1) error("empty component in PATH_INFO", 400); + if (nextslash-pathi > MAX_SCRIPTPATH_LEN) + error("PATH_INFO script path too long", 400); scriptpathlen= scriptdirlen+(nextslash-pathi); scriptpath= xrealloc(scriptpath,scriptpathlen+1); strcpy(scriptpath,scriptdir); memcpy(scriptpath+scriptdirlen,pathi,nextslash-pathi); scriptpath[scriptpathlen]= 0; - if (scriptpath[scriptpathlen-1]=='~') error("bad char end"); + if (scriptpath[scriptpathlen-1]=='~') error("bad char end", 400); D( if (debugmode) printf(";; try `%s'\n", scriptpath); ) r= stat(scriptpath,&stab); if (r) syserror("stat script"); if (S_ISREG(stab.st_mode)) break; - if (!S_ISDIR(stab.st_mode)) error("script not directory or file"); + if (!S_ISDIR(stab.st_mode)) error("script not directory or file", 500); lastslash= nextslash; } D( if (debugmode) printf(";; found script: tail = `%s'\n", nextslash); ) @@ -180,7 +182,7 @@ int main(int argc, char **argv) { ev= getenv("SCRIPT_NAME"); if (ev) { - ev2= getenv("USER"); if (!ev2) error("no USER variable"); + ev2= getenv("USER"); if (!ev2) error("no USER variable", 500); newvar= xmalloc(strlen(ev)+2+strlen(ev2)+scriptpathlen-scriptdirlen+2); sprintf(newvar,"%s/~%s%s",ev,ev2,scriptpath+scriptdirlen); xsetenv("SCRIPT_NAME",newvar,1); -- 2.30.2