From: ian Date: Tue, 9 Nov 1999 20:59:26 +0000 (+0000) Subject: Found in davenant:/usr/local/src/misc X-Git-Tag: rel-uservutils-0-1~21 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?p=userv-utils.git;a=commitdiff_plain;h=6a580c177a1b3b7f53daf402d97b491d462db8c3 Found in davenant:/usr/local/src/misc --- diff --git a/www-cgi/Makefile b/www-cgi/Makefile new file mode 100644 index 0000000..c2bfd7a --- /dev/null +++ b/www-cgi/Makefile @@ -0,0 +1,22 @@ +CFLAGS= -Wall -Wwrite-strings -Wmissing-prototypes -Wstrict-prototypes \ + -Wpointer-arith -O2 -g -DREALLY_CHECK_FILE='"/etc/inittab"' +LDFLAGS= + +TARGETS=really ucgi ucgitarget + +all: $(TARGETS) + +ucgi: ucgi.o ucgicommon.o + +ucgitarget: ucgitarget.o ucgicommon.o + +really: really.o myopt.o + +really-test: really Makefile + rm -f really-test + cp really really-test + really chown root.staff really-test + really chmod 4770 really-test + +really-check: really-test really.testcases + ./really.testcases diff --git a/www-cgi/ucgi.c b/www-cgi/ucgi.c new file mode 100644 index 0000000..8edccc3 --- /dev/null +++ b/www-cgi/ucgi.c @@ -0,0 +1,77 @@ +/* + * Usage: as CGI script + */ + +#include +#include +#include +#include +#include +#include + +#include "ucgi.h" + +int main(int argc, const char **argv) { + char *defarg, *username; + const char *slash2, *pathi, *ev, *en, *av; + const char *const *ep; + const char **arguments; + size_t usernamelen, l; + pid_t child, rchild; + int nargs, status; + + l= strlen(argv[0]); + if (l>6 && !strcmp(argv[0]+l-6,"-debug")) debugmode= 1; + + if (debugmode) { + if (fputs("Content-Type: text/plain\n\n",stdout)==EOF || fflush(stdout)) + syserror("write stdout"); + if (dup2(1,2)<0) { perror("dup stdout to stderr"); exit(-1); } + } + + if (argc > MAX_ARGS) error("too many arguments"); + + pathi= getenv("PATH_INFO"); + if (!pathi) error("PATH_INFO not found"); + 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 /"); + usernamelen= slash2-(pathi+2); + if (usernamelen > MAX_USERNAME_LEN) error("PATH_INFO username too long"); + username= xmalloc(usernamelen+1); + memcpy(username,pathi+2,usernamelen); username[usernamelen]= 0; + if (!isalpha(username[0])) error("username 1st character is not alphabetic"); + xsetenv("PATH_INFO",slash2,1); + + arguments= xmalloc(sizeof(const char*)*(nenvok+argc+10)); + nargs= 0; + + arguments[nargs++]= "userv"; + if (debugmode) arguments[nargs++]= "-DDEBUG=1"; + + for (ep= envok; (en= *ep); ep++) { + ev= getenv(en); if (!ev) continue; + l= strlen(ev); if (l > MAX_ENVVAR_VALUE) error("environment variable too long"); + defarg= xmalloc(strlen(en)+l+6); + sprintf(defarg,"-DE_%s=%s",en,ev); + arguments[nargs++]= defarg; + } + + arguments[nargs++]= username; + arguments[nargs++]= "www-cgi"; + while ((av= (*++argv))) arguments[nargs++]= av; + arguments[nargs++]= 0; + + if (debugmode) { + child= fork(); if (child==-1) syserror("fork"); + if (child) { + rchild= waitpid(child,&status,0); + if (rchild==-1) syserror("waitpid"); + printf("\nexit status %d %d\n",(status>>8)&0x0ff,status&0x0ff); + exit(0); + } + } + + execvp("userv",(char*const*)arguments); + syserror("exec userv"); + return -1; +} diff --git a/www-cgi/ucgi.h b/www-cgi/ucgi.h new file mode 100644 index 0000000..f361ce8 --- /dev/null +++ b/www-cgi/ucgi.h @@ -0,0 +1,22 @@ +/**/ + +#ifndef UCGI_H +#define UCGI_H + +#include + +#define MAX_ARGS 1024 +#define MAX_USERNAME_LEN 1024 +#define MAX_SCRIPTPATH_LEN 1024 +#define MAX_ENVVAR_VALUE (1024*1024) + +void syserror(const char *m); +void error(const char *m); +void *xmalloc(size_t sz); +void xsetenv(const char *en, const char *ev, int overwrite); + +extern const char *const envok[]; +extern const int nenvok; +extern int debugmode; + +#endif diff --git a/www-cgi/ucgicommon.c b/www-cgi/ucgicommon.c new file mode 100644 index 0000000..ba97474 --- /dev/null +++ b/www-cgi/ucgicommon.c @@ -0,0 +1,75 @@ +/**/ + +#include +#include + +#include "ucgi.h" + +const char *const envok[]= { + "CONTENT_LENGTH", + "CONTENT_TYPE", + "DOCUMENT_ROOT", + "GATEWAY_INTERFACE", + "HTTP_ACCEPT", + "HTTP_ACCEPT_ENCODING", + "HTTP_ACCEPT_LANGUAGE", + "HTTP_CACHE_CONTROL", + "HTTP_HOST", + "HTTP_NEGOTIATE", + "HTTP_PRAGMA", + "HTTP_USER_AGENT", + "PATH_INFO", + "PATH_TRANSLATED", + "QUERY_STRING", + "REMOTE_ADDR", + "REMOTE_HOST", + "REMOTE_USER", + "REMOTE_IDENT", + "REQUEST_METHOD", + "SCRIPT_FILENAME", + "SCRIPT_NAME", + "SCRIPT_URI", + "SCRIPT_URL", + "SERVER_ADMIN", + "SERVER_NAME", + "SERVER_PORT", + "SERVER_PROTOCOL", + "SERVER_SOFTWARE", + 0 +}; +const int nenvok= sizeof(envok)/sizeof(envok[0]); + +int debugmode= 0; + +static void outerror(void) { + perror("stdout"); + exit(debugmode ? 0 : -1); +} + +void syserror(const char *m) { + if (printf("Content-Type: text/plain\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" + "ucgi: error:\n" + "%s\n", + m)==EOF || fflush(stdout)) outerror(); + exit(0); +} + +void *xmalloc(size_t sz) { + void *r; + + r= malloc(sz); + if (!r) syserror("malloc failed"); + return r; +} + +void xsetenv(const char *en, const char *ev, int overwrite) { + if (setenv(en,ev,overwrite)) syserror("setenv"); +} diff --git a/www-cgi/ucgitarget.c b/www-cgi/ucgitarget.c new file mode 100644 index 0000000..795d804 --- /dev/null +++ b/www-cgi/ucgitarget.c @@ -0,0 +1,108 @@ +/* + * Usage: as CGI script, but called by userv + * environment variables are USERV_U_E_... + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ucgi.h" + +static void *xrealloc(void *ptr, size_t sz) { + void *r; + + r= realloc(ptr,sz); + if (!r) syserror("realloc failed"); + return r; +} + +int main(int argc, const char **argv) { + char *uservarn, *scriptpath, *newvar; + const char *nextslash, *lastslash, *pathi, *ev, *ev2, *en, *scriptdir, *av; + const char *const *ep; + const char **arguments; + size_t scriptdirlen, scriptpathlen, l, uservarnl; + struct stat stab; + int r, nargs; + + ev= getenv("USERV_U_DEBUG"); + if (ev && *ev) debugmode= 1; + + if (argc > MAX_ARGS) error("too many arguments"); + + if (!*++argv) error("no script directory argument"); + ev= getenv("HOME"); if (!ev) error("no HOME env. var"); + l= strlen(*argv)+strlen(ev); + newvar= xmalloc(l+2); + sprintf(newvar,"%s/%s",ev,*argv); + scriptdir= newvar; + scriptdirlen= strlen(scriptdir); + + uservarn= 0; + uservarnl= 0; + for (ep= envok; (en= *ep); ep++) { + l= strlen(en)+11; + if (uservarnl MAX_ENVVAR_VALUE) error("environment variable too long"); + if (setenv(en,ev,1)) syserror("setenv"); + unsetenv(uservarn); + } + + scriptpath= 0; + pathi= getenv("PATH_INFO"); + if (!pathi) error("PATH_INFO not found"); + lastslash= pathi; + for (;;) { + if (*lastslash != '/') error("PATH_INFO expected slash not found"); + if (lastslash[1]=='.' || lastslash[1]=='#' || !lastslash[1]) error("bad char begin"); + 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"); + 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"); + r= stat(scriptpath,&stab); if (r) syserror("stat script"); + if (S_ISREG(stab.st_mode)) break; + if (!S_ISDIR(stab.st_mode)) syserror("script not directory or file"); + lastslash= nextslash; + } + if (*nextslash) xsetenv("PATH_INFO",nextslash,1); + else unsetenv("PATH_INFO"); + + newvar= xmalloc(scriptpathlen+strlen(nextslash)+3); + sprintf(newvar,"%s%s",scriptpath,nextslash); + xsetenv("PATH_TRANSLATED",newvar,1); + + xsetenv("SCRIPT_FILENAME",scriptpath,1); + + ev= getenv("SCRIPT_NAME"); + if (ev) { + ev2= getenv("USER"); if (!ev2) error("no USER variable"); + newvar= xmalloc(strlen(ev)+2+strlen(ev2)+scriptpathlen-scriptdirlen+2); + sprintf(newvar,"%s/~%s%s",ev,ev2,scriptpath+scriptdirlen); + xsetenv("SCRIPT_NAME",newvar,1); + } + + arguments= xmalloc(sizeof(const char*)*(argc+5)); + nargs= 0; + + arguments[nargs++]= scriptpath; + while ((av= (*++argv))) arguments[nargs++]= av; + arguments[nargs++]= 0; + + execvp(scriptpath,(char*const*)arguments); + syserror("exec script"); + return -1; +}