/* ** statform 1.0 ** A getstats form interface ** By Brian Behlendorf, gw@wired.com ** Hacked on 4/15/94 by Kevin Hughes, kevinh@eit.com ** ** Further hacked on 29-JUN-1994 by David Jones, vman+@osu.edu. ** Changed Text/Plain to text/plain. ** ** Adapted for use by both the CERN and OSU DECthreads servers on ** 06-JAN-1995 by Foteos Macrides, macrides@sci.wfeb.edu. ** 20-MAY-1995 (FM) Make SERVER_NAME lowercase. */ #include #include #include #include #ifdef NOCGILIB #define cgi_init(a,b) 1 #define cgi_info(a) getenv(strcpy(&cgi_info_buf[4], a)-4) static char cgi_info_buf[64] = { 'W', 'W', 'W', '_' }; #define cgi_printf printf static FILE *cgi_content_file() { return stdin; } #else #include "cgilib.h" #endif /* NOCGILIB */ /* WARNING! THIS FORM HAS A SECURITY BUG! A new version will be out shortly which fixes the problem (and others associated with this version). I'll try to get it out soon, but in the meantime I'll gladly accept patches! -- Kevin */ /* User-definable options below */ #ifdef NOCGILIB static char LOGFILE[80] = "/WWW_Root/000000/http80.log"; #else static char LOGFILE[80] = "/WWW_Root/000000/access.log"; #endif /* NOCGILIB */ /* ** The full path to your log file. This is used as a default. */ static char ROOTDIR[80] = "/WWW_Root/000000/"; /* ** The top of your Web (or Gopher) tree. */ /* End of user-definable options */ #define SUBJECT "Getstats results" #define MAXENTRIES 10000 #define MAXCMDLEN 1024 typedef struct { char *name; char *val; } entry; typedef struct { char *name; /* form input field name */ char *opt; /* Option (-opt) to add to argv */ int action; /* Addition action: 0 - alwasy add opt to argv. 1 - add opt to argv if entry.val == "on" 2 - add opt + val or default if non-null 3 - same as 2 except quote val. 4 - if val present add opt + arg//val */ char *act_arg; } mapdefinition; char *server_site_string; static mapdefinition fieldmap[] = { { "logfilename", "-l", 4, ROOTDIR }, { "common", "-M", 1, "" }, { "concise", "-c", 1, "" }, { "toplines", "-t", 2, "" }, { "all", "-a", 1, "" }, { "monthly", "-m", 1, "" }, { "weekly", "-w", 1, "" }, { "daysweek", "-ds", 1, "" }, { "daily", "-d", 1, "" }, { "hoursday", "-hs", 1, "" }, { "hourly", "-h", 1, "" }, { "full-hostname", "-f", 1, "" }, { "full-access", "-fa", 1, "" }, { "full-lasaccess", "-fd", 1, "" }, { "full-bytes", "-fb", 1, "" }, { "translate-addresses", "-ip", 1, "" }, { "request-accesses", "-ra", 1, "" }, { "request-lastaccesses", "-rd", 1, "" }, { "request-bytes", "-rb", 1, "" }, { "request-filesize", "-rf", 1, "" }, { "domain-name", "-dn", 1, "" }, { "domain-requests", "-da", 1, "" }, { "domain-lastaccesses", "-dd", 1, "" }, { "domain-bytes", "-db", 1, "" }, { "domain-sub", "-du", 1, "" }, { "filetree", "-dt", 1, "" }, { "error", "-e", 1, "" }, { "samask", "-sa", 3, "" }, { "ssmask", "-ss", 3, "" }, { "srmask", "-sr", 3, "" }, { "spmask", "-sp", 3, "" }, { "sdmask", "-sd", 3, "" }, { "shmask", "-sh", 3, "" }, { "swmask", "-sw", 3, "" }, { "samask", "-sa", 3, "" }, { "samask", "-sa", 3, "" }, { "", "", 0, "" } /* terminate list */ }; char *makeword(char *line, char stop); char *fmakeword(FILE *f, char stop, int *len); char x2c(char *what); void unescape_url(char *url); void plustospace(char *str); static int form_argc; static char *form_argv[100]; /* main(int argc, char *argv[]) */ int form_request ( int *argc_p, char **argv_p[] ) { int argc, server_port; char **argv; FILE *contentf; entry entries[MAXENTRIES]; register int x, m = 0; #ifdef NOCGILIB register int count, key, line, linecount; char keysymbol[200]; #endif /* NOCGILIB */ int cl, j, invalid = 0, didhtml = 0; char *tmp; char protocol; /* * Pass the main() argument vector to cgi_init, then reset to * point to the proper argument vector for getstats. */ cgi_init ( *argc_p, *argv_p ); *argc_p = 1; *argv_p = form_argv; form_argv[0] = "getstats(CGI)"; if (strcmp((tmp=cgi_info("REQUEST_METHOD")) ? tmp : "", "POST")) { cgi_printf("Content-type: text/plain\n\n"); cgi_printf("Error, Invalid form submission\n"); cgi_printf("We can't do much with a blank subscription card, "); cgi_printf("can we?\n"); return 0; } if (strcmp((tmp=cgi_info("CONTENT_TYPE")) ? tmp : "", "application/x-www-form-urlencoded")) { cgi_printf("Content-type: text/plain\n\n"); cgi_printf("This script can only be used to decode form "); cgi_printf("results.\n"); return 0; } if ( (tmp=cgi_info ( "SERVER_PORT" )) ) server_port = atoi ( tmp ); else server_port = 80; if ( (tmp = cgi_info ( "SERVER_NAME" )) ) { for ( j = 0; tmp[j] != '\0'; j++ ) tmp[j] = tolower( tmp[j] ); server_site_string = malloc ( strlen(tmp) + 32 ); if ( server_port == 80 ) { sprintf ( server_site_string, "http://%s/", tmp ); } else { sprintf ( server_site_string, "http://%s:%d/", tmp, server_port ); } } argc = 1; form_argv[argc++] = "-ht"; didhtml = 1; form_argv[argc++] = "-dr"; form_argv[argc++] = ROOTDIR; cl = atoi((tmp=cgi_info("CONTENT_LENGTH")) ? tmp : "0"); contentf = cl ? cgi_content_file() : stdin; #ifdef NOCGILIB if ((tmp=cgi_info("KEY_COUNT")) == NULL || *tmp == '0') { cgi_printf("Content-type: text/plain\n\n"); cgi_printf("No name/value pairs were submitted.\n"); return 0; } else { count = atoi(tmp); if (count > MAXENTRIES) count = MAXENTRIES; } for(x = 0, key = 1; key <= count; x++) { m = x; /* ** Get the name */ sprintf(keysymbol, "KEY_%d", key++); /* ** Load the name field into the entries structure. */ entries[x].name = (tmp=cgi_info(keysymbol)) ? tmp : "="; /* ** Trim the terminal '=' from the name */ if (entries[x].name[strlen(entries[x].name)-1] == '=') entries[x].name[strlen(entries[x].name)-1] = '\0'; /* ** Check whether the value field is a multi-line. */ sprintf(keysymbol, "KEY_%d_COUNT", key); if (!(tmp=cgi_info(keysymbol)) || (linecount=atoi(tmp)) < 2) { /* ** Value is a single string. Load ** it into the entries structure. */ if (tmp == NULL) sprintf(keysymbol, "KEY_%d", key++); else sprintf(keysymbol, "KEY_%d_%d", key++, linecount); entries[x].val = (tmp=cgi_info(keysymbol)) ? tmp : ""; } else { /* ** Value is multi-line (shouldn't happen with ** statform.html, but here's how to handle it). */ unsigned short FirstLine = TRUE; /* ** Get each line, append '\n', and concatenate into ** value of entries structure as a stream_LF string. */ FirstLine = TRUE; line = 1; while (line <= linecount) { sprintf(keysymbol, "KEY_%d_%d", key++, line++); tmp = cgi_info(keysymbol); strcat(tmp, "\n"); /* ** Add current line to value ** in the entries structure. */ if (FirstLine) { entries[x].val = tmp; FirstLine = FALSE; } else strcat(entries[x].val, tmp); } } #else for(x = 0; cl && (!feof(contentf)); x++) { m = x; entries[x].val = fmakeword(contentf, '&', &cl); plustospace(entries[x].val); unescape_url(entries[x].val); entries[x].name = makeword(entries[x].val,'='); #endif /* NOCGILIB */ #ifdef DEBUG printf("read name: %s, val: '%s' (l=%d,%d)\n", entries[x].name, entries[x].val, strlen(entries[x].val), entries[x].val[0] ); #endif if (!strcmp(entries[x].name, "protocol")) { protocol = entries[x].val[0]; if (protocol == 'G') form_argv[argc++] = "-G"; else if (protocol == 'N') form_argv[argc++] = "-N"; else if (protocol == 'C') form_argv[argc++] = "-C"; else if (protocol == 'P') form_argv[argc++] = "-P"; else if (protocol == 'M') form_argv[argc++] = "-A"; else if (protocol == 'U') form_argv[argc++] = "-O"; } for ( j = 0; fieldmap[j].name[0]; j++ ) { char *p, *s; if ( 0 == strcmp(entries[x].name,fieldmap[j].name) ) { form_argv[argc++] = fieldmap[j].opt; #ifdef DEBUG printf("Matched name %d, opt: '%s', action: %d '%s'\n", j, fieldmap[j].opt, fieldmap[j].action, fieldmap[j].act_arg ); #endif switch ( fieldmap[j].action ) { case 1: /* option is conditional */ if ( 0 != strcmp ( entries[x].val, "on" ) ) argc--; break; case 2: /* append value if present */ p = entries[x].val; if ( !*p ) p = fieldmap[j].act_arg; if ( *p ) { s = malloc ( strlen(p) + 1 ); form_argv[argc++] = s; strcpy ( s, p ); } else argc--; break; case 3: p = entries[x].val; if ( !*p ) p = fieldmap[j].act_arg; if ( *p ) { s = malloc ( strlen(p) + 1 ); form_argv[argc++] = s; sprintf ( s, "%s",p ); } else argc--; break; case 4: /* Pre-pend act arg */ p = entries[x].val; if ( *p ) { s = malloc ( strlen(p) + 1 + strlen(fieldmap[j].act_arg) ); form_argv[argc++] = s; sprintf ( s, "%s%s", fieldmap[j].act_arg, p ); } else argc--; break; default:; } } } #ifndef VMS if (!strcmp(entries[x].name, "mailme") && strlen(entries[x].val) != 0) { sprintf(command, "%s | /usr/ucb/mail -s \"%s\" %s", command, SUBJECT, entries[x].val); printf("Content-type: text/html\n\n"); printf("It's in the mail...\n

\n"); printf("

Your log request is being mailed to "); printf("you.

\n"); printf("The following command was executed:\n"); printf("

\n%s\n", command); } else if (!strcmp(entries[x].name, "mailme") && strlen(entries[x].val) == 0 && !didhtml) { sprintf(command, "%s -ht", command); didhtml = 1; } #endif } #ifdef NOT_DEFINED sprintf(command, "%s &\n", command); system(command); printf("command: %s\n", command ); #endif /* NOT_DEFINED */ *argc_p = argc; return 1; } /* util.c from NCSA included below */ #define LF 10 #define CR 13 char *makeword(char *line, char stop) { int x = 0,y; char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1)); for(x=0;((line[x]) && (line[x] != stop));x++) word[x] = line[x]; word[x] = '\0'; if(line[x]) ++x; y=0; while(line[y++] = line[x++]); return word; } char *fmakeword(FILE *f, char stop, int *cl) { int wsize; char *word; int ll; wsize = 96; ll=0; word = (char *) malloc(sizeof(char) * (wsize + 1)); while(1) { word[ll] = (char)fgetc(f); #ifdef DEBUG printf("fget read: %d\n", word[ll] ); #endif if(ll==wsize) { word[ll+1] = '\0'; wsize+=1024; word = (char *)realloc(word,sizeof(char)*(wsize+1)); } --(*cl); if((word[ll] == stop) || (feof(f)) || (!(*cl))) { if(word[ll] != stop) ll++; word[ll] = '\0'; return word; } ++ll; } } char x2c(char *what) { register char digit; digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0')); digit *= 16; digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0')); return(digit); } void unescape_url(char *url) { register int x,y; for(x=0,y=0;url[y];++x,++y) { if((url[x] = url[y]) == '%') { url[x] = x2c(&url[y+1]); y+=2; } } url[x] = '\0'; } void plustospace(char *str) { register int x; for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' '; }