home *** CD-ROM | disk | FTP | other *** search
-
- /* cgiwin32.c */
-
- /* emulate CGI-WIN interface */
-
- #include "stdio.h"
- #include "fcntl.h"
- #include "windows.h"
- #include "process.h"
-
- extern char *getenv();
- extern char *strrchr();
- extern int atoi();
-
- int glob_argc = 0;
- int glob_clen = 0;
- char *glob_content = NULL;
- char *glob_ifile = NULL;
- char *glob_ofile = NULL;
- char *glob_cfile = NULL;
- char **glob_argv = NULL;
- char **glob_env = NULL;
- int glob_tnum = 0; /* all tempfiles will share this number, with unique prefix */
-
- int glob_cgiwin = 0; /* if true, running under CGI-WIN interface */
- char glob_cgiwin_out[_MAX_PATH];
-
- typedef struct
- {
- int size; /* number of slots allocated */
- int num; /* number of slots filled */
- char **slots;
- } DynArray, *DynArrayPtr;
-
- /* maintain list of external temp files */
- DynArrayPtr glob_extfiles = NULL;
-
- /* globals for re-written environment vars */
- char glob_log_path[_MAX_PATH];
- char glob_phy_path[_MAX_PATH];
- char glob_scr_path[_MAX_PATH];
-
- FILE *errlog = NULL;
- char errmsg[1024];
-
- /* ---- log_error ---- */
-
- int log_error(char *s)
- {
- if(!s || !*s)
- return -1;
- if(!errlog)
- errlog = fopen("C:\\cgiwin.out","w");
- fprintf(errlog,"%s\n",s);
- fflush(errlog);
- return 0;
- }
-
- /* ---- strsave ---- */
-
- char *strsave(char *s)
- {
- char *p = NULL;
- int len = 0;
- if(!s)
- return NULL;
- len = strlen(s);
- p = malloc(len+1);
- if(!p)
- return NULL;
- strcpy(p,s);
- return p;
- }
-
- /* ---- dos_path ---- */
-
- int dos_path(char *s)
- {
- if(!s)
- return -1;
- for(;s && *s;s++)
- if(*s == '/')
- *s = '\\';
- return 0;
- }
-
- /* ---- url_path ---- */
-
- int url_path(char *s)
- {
- if(!s)
- return -1;
- for(;s && *s;s++)
- if(*s == '\\')
- *s = '/';
- return 0;
- }
-
- /* ---- DynArray utils */
-
- DynArrayPtr da_create(int initsize)
- {
- DynArrayPtr dp;
-
- dp = calloc(1,sizeof(DynArray));
- if(!dp)
- return NULL;
-
- if(initsize < 16)
- initsize = 16;
-
- dp->num = 0;
- dp->size = initsize;
- dp->slots = (char **)calloc(initsize,sizeof(char *));
-
- return dp;
- }
-
- int da_grow(DynArrayPtr dp)
- {
- if(!dp)
- return -1;
- if(dp->size == 0)
- dp->size = 32;
- else
- dp->size = 2 * dp->size;
- dp->slots = (char **)realloc(dp->slots,dp->size * sizeof(char *));
- return 0;
- }
-
- int da_add(DynArrayPtr dp, char *s)
- {
- char *p;
-
- if(!dp)
- return -1;
-
- if(dp->num == dp->size)
- da_grow(dp);
-
- p = strsave(s);
- dp->slots[dp->num++] = p;
-
- return 0;
- }
-
- int da_destroy(DynArrayPtr dp)
- {
- int i;
-
- if(!dp)
- return -1;
- for(i=0;i<dp->num;i++)
- if(dp->slots[i] != NULL)
- free(dp->slots[i]);
- free(dp->slots);
- free(dp);
- return 0;
- }
-
- int has_bad_ini_chars(char *s)
- {
- if(!s || !s[0])
- return 0;
- for(;*s;s++)
- if(*s == '\"' || !isprint(*s))
- return 1;
-
- return 0;
- }
-
- /* ---- various utilities (from NCSA sample file 'util.c') ---- */
-
- #define LF 10
- #define CR 13
-
- void getword(char *word, char *line, char stop) {
- int x = 0,y;
-
- 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++]);
- }
-
- 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 = 102400;
- ll=0;
- word = (char *) malloc(sizeof(char) * (wsize + 1));
-
- while(1) {
- word[ll] = (char)fgetc(f);
- if(ll==wsize) {
- word[ll+1] = '\0';
- wsize+=102400;
- 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] = ' ';
- }
-
- int rind(char *s, char c) {
- register int x;
- for(x=strlen(s) - 1;x != -1; x--)
- if(s[x] == c) return x;
- return -1;
- }
-
- int getline(char *s, int n, FILE *f) {
- register int i=0;
-
- while(1) {
- s[i] = (char)fgetc(f);
-
- if(s[i] == CR)
- s[i] = fgetc(f);
-
- if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) {
- s[i] = '\0';
- return (feof(f) ? 1 : 0);
- }
- ++i;
- }
- }
-
- void send_fd(FILE *f, FILE *fd)
- {
- int num_chars=0;
- char c;
-
- while (1) {
- c = fgetc(f);
- if(feof(f))
- return;
- fputc(c,fd);
- }
- }
-
- int ind(char *s, char c) {
- register int x;
-
- for(x=0;s[x];x++)
- if(s[x] == c) return x;
-
- return -1;
- }
-
- void escape_shell_cmd(char *cmd) {
- register int x,y,l;
-
- l=strlen(cmd);
- for(x=0;cmd[x];x++) {
- if(ind("&;`'\"|*?~<>^()[]{}$\\",cmd[x]) != -1){
- for(y=l+1;y>x;y--)
- cmd[y] = cmd[y-1];
- l++; /* length has been increased */
- cmd[x] = '\\';
- x++; /* skip the character */
- }
- }
- }
-
- /* ---- cgi_error ---- */
-
- int cgi_error(char *s, int ret_code)
- {
- int i = 0;
- FILE *fp = stdout;
-
- if(glob_cgiwin)
- fp = fopen(glob_cgiwin_out,"w");
-
- fprintf(fp,"Content-type: text/plain\n\n");
-
- fprintf(fp,"Error in CGI-WIN gateway script.\n\nReason: %s.\n\n",s);
-
- fprintf(fp,"-----------------------------------------\n");
- fprintf(fp,"Command-line arguments (%d)\n\n",glob_argc);
- for(i=0;i<glob_argc;i++)
- fprintf(fp,"\t[%d]: '%s'\n",i,glob_argv[i]);
- fprintf(fp,"-----------------------------------------\n");
- fprintf(fp,"Environment variables\n\n");
- for(i=0;glob_env[i] != NULL;i++)
- fprintf(fp,"\t'%s'\n",glob_env[i]);
-
- if(glob_clen > 0)
- {
- fprintf(fp,"-----------------------------------------\n");
- fprintf(fp,"Content (%d)\n\n",glob_clen);
- for(i=0;i<glob_clen;i++)
- fputc(glob_content[i],fp);
- }
-
- fflush(fp);
-
- return ret_code;
- }
-
- /* ---- tempfile creation ----- */
-
- int get_tempfile(char *dir, char *prefix, int num, char **fn)
- {
- char *tempdir = NULL;
- char path[_MAX_PATH];
- char dirbuf[_MAX_PATH];
- int code = 0;
-
- /* will try looking for vermeer.ini if it doesn't get a
- TMP or TEMP var in CGI environment */
-
- tempdir = dir;
- if(!tempdir)
- tempdir = getenv("TMP");
- if(!tempdir)
- tempdir = getenv("TEMP");
- if(!tempdir)
- {
- /* could be a Vermeer server without TMP/TEMP vars; use FrontPage temp */
- DWORD count;
-
- dirbuf[0] = 0;
- count = GetPrivateProfileString("FrontPage","FrontPageRoot","*",
- dirbuf,_MAX_PATH-1,"vermeer.ini");
- if(dirbuf[0] != 0 && dirbuf[0] != '*') /* key was found */
- {
- char c;
-
- /* need to append TEMP */
- c = dirbuf[strlen(dirbuf)-1];
- if(c != '\\')
- strcat(dirbuf,"\\TEMP");
- else
- strcat(dirbuf,"TEMP");
- tempdir = dirbuf;
- }
- }
- if(!tempdir)
- tempdir = "C:\\TEMP"; /* try hardwired location as a last resort */
-
- if(!prefix)
- prefix = "";
-
- path[0] = 0;
- code = GetTempFileName(tempdir,prefix,num,path);
- *fn = strsave(path);
-
- return code;
- }
-
- /* ---- get_exe_path ---- */
-
- /*
- construct absolute path to the *real* script.
-
- subtract PATH_INFO from PATH_TRANSLATED to get the server's DocumentRoot.
-
- if PATH_TRANSLATED is not provided, try to figure it out from
- either argv[0] or _getcwd().
-
- if the *first component* of PATH_INFO does *not* end in ".exe",
- then it is a *server-relative* path to the requested CGI-WIN program;
- otherwise, it is the name of the requested CGI-WIN program in the same
- dir as this program.
-
- success = 0, failure = -1
- */
-
- int get_exe_path(char **path_return)
- {
- char *path_info = NULL;
- char *path_trans = NULL;
- char *script_name = NULL;
- char abs_path[_MAX_PATH];
- char exe_dir[_MAX_PATH];
- char path_upper[_MAX_PATH];
- char path_trans_upper[_MAX_PATH];
- char script_path[_MAX_PATH];
- char synth_path_trans[_MAX_PATH];
- char *p = NULL;
- char *q = NULL;
- int len = 0;
- int i = 0;
-
- /* REVIEW (everywhere): need to check more carefully for string overruns */
-
- /* initialize auto strings to be empty */
- abs_path[0] = 0;
- exe_dir[0] = 0;
- path_upper[0] = 0;
- path_trans_upper[0] = 0;
- script_path[0] = 0;
- synth_path_trans[0] = 0;
-
- path_info = getenv("PATH_INFO");
- if(!path_info)
- return cgi_error("expected PATH_INFO cgi variable (giving path to script file)",-1);
-
- script_name = getenv("SCRIPT_NAME");
- if(!script_name)
- return cgi_error("expected SCRIPT_NAME cgi variable",-1);
-
- path_trans = getenv("PATH_TRANSLATED");
- if(!path_trans)
- {
- /* ouch; have to figure it out on our own! use argv[0] if it looks good,
- else, if server did a 'cd' before exec, then use getcwd and argv[0]
- to figure out abs path to program, try to subtract SCRIPT_NAME from
- this to get DocumentRoot */
- if(strchr(glob_argv[0],':'))
- {
- /* it's a Windows absolute path to this program */
- strcpy(synth_path_trans,glob_argv[0]);
- }
- else
- {
- extern char *_getcwd();
- /* it's a relative path; get current dir and append it */
- if(!_getcwd(synth_path_trans,_MAX_PATH-1))
- return cgi_error("couldn't get current dir to synthesize PATH_TRANSLATED cgi variable",-1);
- /* append path to this program */
- if(*glob_argv[0] != '\\' && *glob_argv[0] != '/')
- strcat(synth_path_trans,"\\");
- strcat(synth_path_trans,glob_argv[0]);
- }
- /* now have full exe name; subtract SCRIPT_NAME to get DocumentRoot */
- if(strlen(synth_path_trans) < strlen(script_name))
- return cgi_error("absolute path to CGI program is shorter than SCRIPT_NAME",-1);
- synth_path_trans[strlen(synth_path_trans)-strlen(script_name)] = 0;
- /* add the extra path info */
- strcat(synth_path_trans,path_info);
- path_trans = synth_path_trans;
- }
-
- /* removing PATH_INFO from PATH_TRANSLATED gives us DocumentRoot */
- len = strlen(path_trans)-strlen(path_info);
- strncpy(abs_path,path_trans,len);
- abs_path[len] = 0;
-
- /* convert to all upper-case for matching (converted path can have different case);
- also, convert all *_upper strings to have slashes all the same way */
- strcpy(path_upper,path_info);
- len = strlen(path_upper);
- for(i=0;i<len;i++)
- {
- if(path_upper[i] == '/')
- path_upper[i] = '\\';
- else
- path_upper[i] = toupper(path_upper[i]);
- }
-
- strcpy(path_trans_upper,path_trans);
- len = strlen(path_trans_upper);
- for(i=0;i<len;i++)
- {
- if(path_trans_upper[i] == '/')
- path_trans_upper[i] = '\\';
- path_trans_upper[i] = toupper(path_trans_upper[i]);
- }
-
- p = strstr(path_trans_upper,path_upper);
- if(!p)
- return cgi_error("couldn't find PATH_INFO inside PATH_TRANSLATED",-1);
-
- /*
- see if first component of PATH_INFO ends in .exe;
- if so, then script is in same dir as this program,
- else it's a server-relative path
- */
-
- p = strstr(path_upper,".EXE");
- if(p)
- {
- if(*(p+4) != '\\' && *(p+4) != '\0')
- {
- /* error: .exe must terminate a path component */
- return cgi_error("found a non-terminal .EXE string in PATH_INFO cgi variable",-1);
- }
-
- /* get path to *real* script */
- len = (p - path_upper) + 4;
- strncpy(script_path,path_info,len);
- script_path[len] = 0;
-
- /* save script path for script we invoke */
- strcat(glob_scr_path,script_name);
- strcat(glob_scr_path,script_path);
-
- /* save remainder of PATH_INFO for script we invoke */
- strcpy(glob_log_path,path_info+(p-path_upper)+4);
-
- /* we have an EXE, but is it the *first* component? */
- for(q = p; q > path_upper && *q != '\\'; q--);
- if(q == path_upper) /* yup, it's in same dir */
- {
- /* discover current dir from SCRIPT_NAME cgi var */
- q = strrchr(script_name,'/');
- if(q)
- {
- len = strlen(script_name) - strlen(q);
- strncpy(exe_dir,script_name,len);
- exe_dir[len] = 0;
- strcat(abs_path,exe_dir);
- strcat(abs_path,script_path);
- }
- else
- return cgi_error("couldn't find trailing '/' in SCRIPT_NAME cgi variable",-1);
- }
- else /* nope; it's server-relative */
- {
- /* append server-relative path to script */
- strcat(abs_path,script_path);
- }
- }
- else
- return cgi_error("expected a path to .EXE program in PATH_INFO cgi variable",-1);
-
- p = strsave(abs_path);
- if(!p)
- return cgi_error("out of memory",-1);
-
- *path_return = p;
- dos_path(*path_return);
-
- /* save exe path for script we invoke */
- strcpy(glob_phy_path,*path_return);
-
- /* make sure slashes are all correct direction */
- dos_path(glob_phy_path);
- url_path(glob_log_path);
- url_path(glob_scr_path);
-
- return 0;
- }
-
- /* ---- wait_for_exe ---- */
-
- /*
- (the following is now done in-line in main())
-
- launch a program using an *absolute* path,
- with a given arg list and environment,
- and wait until it finishes running before returning;
- success = 0, failure = -1
- */
-
- int wait_for_exe(char *cmd, char **argvp, char **envp)
- {
- int exit_code = 0;
-
- exit_code = _spawnve(_P_WAIT,cmd,argvp,envp);
- if(exit_code == -1)
- return cgi_error("couldn't spawn process",-1);
-
- /* the following mess is what Microsoft suggests,
- but I found the _spawn family to do the same thing */
-
- #if 0
- BOOL fSuccess;
- BOOL fExit;
- DWORD dwExitCode;
- DWORD dw;
- STARTUPINFO SI;
- PROCESS_INFORMATION pi;
- HANDLE hProcess;
- HANDLE hThread;
-
- memset(&SI,'\0',sizeof(SI));
- memset(&pi,'\0',sizeof(SI));
-
- SI.cb = sizeof(STARTUPINFO);
- SI.lpReserved = NULL;
- SI.lpDesktop=NULL;
- SI.lpTitle="CGIWIN32";
- SI.cbReserved2=0;
- SI.lpReserved2=NULL;
-
- fSuccess = CreateProcess((LPTSTR)NULL, (LPTSTR)cmd_line,
- (LPSECURITY_ATTRIBUTES)NULL,
- (LPSECURITY_ATTRIBUTES)NULL,
- (BOOL)TRUE,(DWORD)NORMAL_PRIORITY_CLASS,NULL,NULL,
- (LPSTARTUPINFO)&SI,(LPPROCESS_INFORMATION)&pi);
-
- if (fSuccess)
- {
- hProcess = pi.hProcess;
- hThread = pi.hThread;
- dw = WaitForSingleObject(hProcess, INFINITE) ;
- if (dw != 0xFFFFFFFF)
- { /* if we saw success ... */
- /* pick up an exit code for the process */
- fExit = GetExitCodeProcess(hProcess, &dwExitCode);
- }
- /* close the process and thread object handles */
- CloseHandle(hThread);
- CloseHandle(hProcess);
- }
- else
- return cgi_error("couldn't create process",-1);
-
- return 0;
- #endif
- }
-
- /* ---- write_to_server ---- */
-
- int write_to_server(char *filename)
- {
- FILE *fp = NULL;
- int ch = 0;
-
- if(!filename || !filename[0])
- return cgi_error("write_to_server given empty filename",-1);
-
- fp = fopen(filename,"r");
- if(!fp)
- return cgi_error("write_to_server can't open file",-1);
-
- while(1)
- {
- ch = fgetc(fp);
- if(ch == EOF)
- break;
- fputc(ch,stdout);
- }
- fclose(fp);
-
- return 0;
- }
-
- /* ---- write_cgi_content ---- */
-
- int write_cgi_content(char *filename)
- {
- FILE *fp = NULL;
- int ch = 0;
-
- if(glob_clen < 1) /* nothing to write */
- return 0;
-
- if(!filename || !filename[0])
- return cgi_error("write_cgi_content given empty filename",-1);
-
- fp = fopen(filename,"w");
- if(!fp)
- return cgi_error("write_cgi_content can't open file",-1);
-
- if(fwrite(glob_content,1,glob_clen,fp) != (unsigned int)glob_clen)
- return cgi_error("write_cgi_content didn't write all requested data",-1);
-
- fclose(fp);
-
- return 0;
- }
-
- /* ---- write_accept_section ---- */
-
- int write_accept_section(FILE *fp)
- {
- char *cur = NULL;
- char *p = NULL;
- char *buf = NULL;
- int len = 0;
-
- if(!fp)
- return -1;
-
- p = getenv("HTTP_ACCEPT");
- if(!p)
- return -1;
- buf = malloc(strlen(p));
- if(!buf)
- return -1;
- buf[0] = 0;
-
- fprintf(fp,"\n[Accept]\n");
-
- cur = p;
- while(cur && *cur)
- {
- char *q = NULL;
- p = strchr(cur,',');
- if(!p) /* no more */
- {
- /* get options, if any */
- q = strchr(cur,';');
- if(q)
- {
- q++;
- if(*q == ' ')
- q++;
- }
- fprintf(fp,"%s=%s\n",cur,q ? q : "Yes");
- break;
- }
- else /* found one */
- {
- len = p - cur;
- strncpy(buf,cur,len);
- buf[len] = 0;
- /* get options, if any */
- q = strchr(buf,';');
- if(q)
- {
- q++;
- if(*q == ' ')
- q++;
- }
- fprintf(fp,"%s=%s\n",buf,q ? q : "Yes");
- cur = ++p;
- if(*cur == ' ')
- cur++;
- }
- }
-
- free(buf);
-
- return 0;
- }
-
- /* ---- write_form_fields ---- */
-
- int write_form_fields(FILE *fp)
- {
- char *cur = NULL;
- char *p = NULL;
- char *buf = NULL;
- char *last = NULL;
- int len = 0;
- char *prev_key = NULL;
- int ndup = 0;
- int ntempfiles = 0;
- int keyval_len = 0;
- int i = 0;
-
- DynArrayPtr huge_vars = NULL;
- DynArrayPtr ext_vars = NULL;
-
- /* the Win 3.1 server only checks for duplicates on the previous key,
- not on all keys in the form; this code does the same */
-
- /* REVIEW - for an faster interface, we might want to just give pointers into
- the content file, rather than creating a separate temp file for each
- long field like the old Win 3.1 interface did; however, it appears
- that would require a modification to CGI32.BAS */
-
- if(!fp || glob_clen < 1 || !glob_content)
- return -1;
-
- huge_vars = da_create(16);
- ext_vars = da_create(128);
-
- buf = malloc(glob_clen + 128);
- if(!buf)
- return -1;
- prev_key = malloc(glob_clen + 128);
- if(!prev_key)
- return -1;
- buf[0] = 0;
- prev_key[0] = 0;
-
- /* write out Form Literal section,
- then Form External and Form Huge sections */
-
- fprintf(fp,"\n[Form Literal]\n");
-
- cur = glob_content;
- last = glob_content + glob_clen - 1;
-
- while(cur <= last)
- {
- /* fetch next batch of chars, breaking at word or end */
- p = strchr(cur,'&');
- if(!p)
- {
- /* at end */
- strcpy(buf,cur);
- cur = cur + strlen(cur);
- }
- else
- {
- *p = 0;
- strcpy(buf,cur);
- *p = '&';
- cur = p + 1;
- }
-
- keyval_len = strlen(buf);
-
- plustospace(buf);
- unescape_url(buf);
-
- p = strchr(buf,'=');
- if(!p) /* error */
- {
- fprintf(fp,"%s=ERROR - no equal sign in form value\n",buf);
- }
- else
- {
- char *cp = NULL;
- char ext_key_val[_MAX_PATH];
- char key_str[_MAX_PATH];
-
- key_str[0] = 0;
- ext_key_val[0] = 0;
-
- *p++ = 0;
-
- if(!strcmp(buf,prev_key))
- {
- ndup++;
- sprintf(key_str,"%s_%d",buf,ndup);
- }
- else
- {
- ndup = 0;
- strcpy(key_str,buf);
- }
-
- /* see if value string is too long for INI, or has control chars */
-
- len = strlen(p);
-
- if(len > 65535)
- {
- /* falls into 'HUGE' range;
- save it for writing out later;
- use offset and length of value */
- sprintf(ext_key_val,"%s=%d %d",key_str,
- p-glob_content,keyval_len);
- da_add(huge_vars,ext_key_val);
- }
- else if(len > 254 || has_bad_ini_chars(p))
- {
- /* write to temp file */
- char temp_fn[_MAX_PATH];
- FILE *fp = NULL;
-
- if(!glob_extfiles)
- glob_extfiles = da_create(32);
-
- ntempfiles++;
- sprintf(temp_fn,"cwf%d.%03d",glob_tnum,ntempfiles);
- fp = fopen(temp_fn,"wb");
- if(!fp)
- return cgi_error("can't open temp file for field output",-1);
- if(fwrite(p,1,len,fp) != (unsigned int)len)
- return cgi_error("can't write field to temp file",-1);
- fclose(fp);
- da_add(glob_extfiles,temp_fn);
-
- /* create string with tempfile name, write it out later */
- sprintf(ext_key_val,"%s=%s %d",key_str,temp_fn,len);
- da_add(ext_vars,ext_key_val);
- }
- else
- {
- /* place in INI file */
- fprintf(fp,"%s=%s\n",key_str,p);
- }
-
- strcpy(prev_key,buf);
- *--p = '=';
- }
- }
-
- free(buf);
-
- /* now write out Form External section */
- if(ext_vars->num > 0)
- {
- fprintf(fp,"\n[Form External]\n");
- for(i=0; i<ext_vars->num; i++)
- fprintf(fp,"%s\n",ext_vars->slots[i]);
- }
-
- /* now write out Form Huge section */
- if(huge_vars->num > 0)
- {
- fprintf(fp,"\n[Form Huge]\n");
- for(i=0; i<huge_vars->num; i++)
- fprintf(fp,"%s\n",huge_vars->slots[i]);
- }
-
- da_destroy(ext_vars);
- da_destroy(huge_vars);
-
- return 0;
- }
-
- /* ---- write_cgi_input ---- */
-
- int write_cgi_input(char *filename)
- {
- FILE *fp = NULL;
- char *p = NULL;
-
- if(!filename || !filename[0])
- return cgi_error("write_cgi_input given empty filename",-1);
-
- fp = fopen(filename,"wt"); /* force Windows translation mode (INI format) */
- if(!fp)
- return cgi_error("write_cgi_input can't open file",-1);
-
- /* [CGI] section */
- fprintf(fp,"\n[CGI]\n");
- p = getenv("SERVER_PROTOCOL");
- if(p)
- fprintf(fp,"Request Protocol=%s\n",p);
- p = getenv("REQUEST_METHOD");
- if(p)
- fprintf(fp,"Request Method=%s\n",p);
-
- /* SCRIPT_PATH, PATH_INFO, and PATH_TRANSLATED were rewritten during get_exe_path */
- fprintf(fp,"Executable Path=%s\n",glob_scr_path);
- fprintf(fp,"Logical Path=%s\n",glob_log_path);
- fprintf(fp,"Physical Path=%s\n",glob_phy_path);
-
- p = getenv("DOCUMENT_ROOT");
- if(p)
- fprintf(fp,"Document Root=%s\n",p);
-
- p = getenv("QUERY_STRING");
- if(p)
- fprintf(fp,"Query String=%s\n",p);
- p = getenv("CONTENT_TYPE");
- if(p)
- fprintf(fp,"Content Type=%s\n",p);
- p = getenv("CONTENT_LENGTH");
- if(p)
- fprintf(fp,"Content Length=%s\n",p);
- if(glob_cfile)
- fprintf(fp,"Content File=%s\n",glob_cfile);
- p = getenv("SERVER_SOFTWARE");
- if(p)
- fprintf(fp,"Server Software=%s\n",p);
- p = getenv("SERVER_NAME");
- if(p)
- fprintf(fp,"Server Name=%s\n",p);
- p = getenv("SERVER_PORT");
- if(p)
- fprintf(fp,"Server Port=%s\n",p);
- p = getenv("SERVER_ADMIN");
- if(p)
- fprintf(fp,"Server Admin=%s\n",p);
-
- /* ignore the GATEWAY_INTERFACE var; write our own hard-coded value */
- fprintf(fp,"CGI Version=CGI/1.2 (Win)\n",p);
-
- /* NB: PWS-32 in FP 1.0 does not pass referer or from */
- p = getenv("HTTP_REFERER");
- if(p)
- fprintf(fp,"Referer=%s\n",p);
- p = getenv("HTTP_FROM");
- if(p)
- fprintf(fp,"From=%s\n",p);
-
- p = getenv("REMOTE_HOST");
- if(p)
- fprintf(fp,"Remote Host=%s\n",p);
- p = getenv("REMOTE_ADDR");
- if(p)
- fprintf(fp,"Remote Address=%s\n",p);
- p = getenv("AUTH_TYPE");
- if(p)
- fprintf(fp,"Authentication Method=%s\n",p);
- p = getenv("REMOTE USER");
- if(p)
- fprintf(fp,"Authenticated Username=%s\n",p);
- p = getenv("REMOTE_IDENT");
- if(p)
- fprintf(fp,"RFC-931 Identity=%s\n",p);
-
- /* [Accept] section */
- write_accept_section(fp);
-
- /* [System] section */
- fprintf(fp,"\n[System]\n");
- if(glob_ofile)
- fprintf(fp,"Output File=%s\n",glob_ofile);
- if(glob_cfile)
- fprintf(fp,"Content File=%s\n",glob_cfile);
- /* NB - not passed by PWS-32 in FP 1.0; read non-standard env var if set */
- p = getenv("CGIWIN_DEBUG");
- if(p)
- fprintf(fp,"Debug Mode=%s\n",p);
- else
- fprintf(fp,"Debug Mode=No\n");
- /* compute local GMT offset */
- {
- TIME_ZONE_INFORMATION tzi;
- tzi.Bias = 0; /* in case it fails */
- GetTimeZoneInformation(&tzi);
- fprintf(fp,"GMT Offset=%d\n",-60*tzi.Bias);
- }
-
- /* [Extra Headers] section */
- fprintf(fp,"\n[Extra Headers]\n");
-
- /* REVIEW - should really keep track of which envs have been spat out,
- then do any unused ones here */
-
- p = getenv("HTTP_CONNECTION");
- if(p)
- fprintf(fp,"HTTP_CONNECTION=%s\n",p);
- p = getenv("HTTP_PROXY_CONNECTION");
- if(p)
- fprintf(fp,"HTTP_CONNECTION=%s\n",p);
- p = getenv("HTTP_USER_AGENT");
- if(p)
- fprintf(fp,"HTTP_USER_AGENT=%s\n",p);
- p = getenv("HTTP_HOST");
- if(p)
- fprintf(fp,"HTTP_HOST=%s\n",p);
-
- /* [Form] sections */
- if(glob_clen > 0 && glob_content)
- {
- p = getenv("CONTENT_TYPE");
- if(p)
- {
- if(!stricmp(p,"application/x-www-form-urlencoded")
- || !stricmp(p,"application/www-form-urlencoded"))
- {
- write_form_fields(fp);
- }
- }
- }
-
- fclose(fp);
-
- return 0;
- }
-
- /* ---- launch_cgiwin_program */
-
- int launch_cgiwin_program()
- {
- /* change argv[0], keep other args, keep same env,
- mangle three args in INI file, exec program */
-
- char *cgifn = glob_argv[1];
- char *exe_path = NULL;
- char quoted_exe_path[_MAX_PATH];
- char script[_MAX_PATH];
- char path[_MAX_PATH];
- char path_trans[_MAX_PATH];
- char envstr[_MAX_PATH];
- DWORD count = 0;
- DynArrayPtr newargv = NULL;
- DynArrayPtr newenv = NULL;
- int i = 0;
-
- script[0] = 0;
- path[0] = 0;
- path_trans[0] = 0;
-
- glob_cgiwin_out[0] = 0;
- count = GetPrivateProfileString("System","Output File","*",
- glob_cgiwin_out,_MAX_PATH-1,cgifn);
- if(glob_cgiwin_out[0] == 0 || glob_cgiwin_out[0] == '*') /* key not found */
- return cgi_error("couldn't get 'Output File' from CGI-WIN file in argv[1]",0);
-
- count = GetPrivateProfileString("CGI","Executable Path","*",
- script,_MAX_PATH-1,cgifn);
- if(script[0] == 0 || script[0] == '*') /* key not found */
- return cgi_error("couldn't get 'Executable Path' from CGI-WIN file in argv[1]",0);
-
- count = GetPrivateProfileString("CGI","Logical Path","*",
- path,_MAX_PATH-1,cgifn);
- if(path[0] == 0 || path[0] == '*') /* key not found */
- return cgi_error("couldn't get 'Logical Path' from CGI-WIN file in argv[1]",0);
-
- count = GetPrivateProfileString("CGI","Physical Path","*",
- path_trans,_MAX_PATH-1,cgifn);
- if(path_trans[0] == 0 || path_trans[0] == '*') /* key not found */
- return cgi_error("couldn't get 'Physical Path' from CGI-WIN file in argv[1]",0);
-
- /* need to fool get_exe_path, so put these into environment */
-
- sprintf(envstr,"SCRIPT_NAME=%s",script);
- _putenv(envstr);
- sprintf(envstr,"PATH_INFO=%s",path);
- _putenv(envstr);
- sprintf(envstr,"PATH_TRANSLATED=%s",path_trans);
- _putenv(envstr);
-
- /* get absolute path to the *real* script */
-
- if(get_exe_path(&exe_path) != 0)
- return 0;
-
- /* quote exe_path in case it has spaces */
- sprintf(quoted_exe_path,"\"%s\"",exe_path);
-
- /* write correct values back to CGI-WIN file */
- if(!WritePrivateProfileString("CGI","Executable Path",glob_scr_path,cgifn))
- return cgi_error("couldn't write 'Executable Path' to CGI-WIN file in argv[1]",0);
- if(!WritePrivateProfileString("CGI","Logical Path",glob_log_path,cgifn))
- return cgi_error("couldn't write 'Logical Path' to CGI-WIN file in argv[1]",0);
- if(!WritePrivateProfileString("CGI","Physical Path",glob_phy_path,cgifn))
- return cgi_error("couldn't write 'Physical Path' to CGI-WIN file in argv[1]",0);
-
- /* set up new args and env, and launch program */
-
- newargv = da_create(64);
- newenv = da_create(64);
-
- /* do args; only difference is argv[0] */
- da_add(newargv,quoted_exe_path);
- for(i=1;i<glob_argc;i++)
- da_add(newargv,glob_argv[i]);
- da_add(newargv,NULL);
-
- /* do env; use _environ since _putenv may have invalidated old env */
- for(i=0;_environ != NULL && _environ[i] != NULL;i++)
- da_add(newenv,_environ[i]);
- da_add(newenv,NULL);
-
- /* exec *real* program */
- return _spawnve(_P_WAIT,exe_path,newargv->slots,newenv->slots);
- }
-
-
- /* ---- main --------- */
-
- int main(int argc, char *argv[], char *env[])
- {
- char *exe_path = NULL;
- char quoted_exe_path[_MAX_PATH];
- int clen = 0;
- char *p = NULL;
- char *query_info = NULL;
- int tmpnum = 0;
- FILE *fp = NULL;
- int i = 0;
-
- /* set up globals so cgi_error can report them */
- glob_argc = argc;
- glob_argv = &argv[0];
- glob_env = &env[0];
-
- /* set up globals for rewritten env vars */
- glob_log_path[0] = 0;
- glob_phy_path[0] = 0;
- glob_scr_path[0] = 0;
-
- /* if we're running under CGI-WIN interface, all args are in file */
-
- p = getenv("GATEWAY_INTERFACE");
- if(!p || strstr(p,"(Win)"))
- {
- if(argc > 1)
- {
- glob_cgiwin = 1;
- glob_cgiwin_out[0] = 0;
- return launch_cgiwin_program();
- }
- else
- return cgi_error("expected GATEWAY_INTERFACE environment variable",0);
- }
-
- /* get absolute path to the *real* script */
-
- if(get_exe_path(&exe_path) != 0)
- return 0;
-
- /* quote exe path in case it has spaces */
- sprintf(quoted_exe_path,"\"%s\"",exe_path);
-
- /* read in any content */
-
- p = getenv("CONTENT_LENGTH");
- if(p)
- clen = atoi(p);
- if(clen > 0)
- {
- extern int _setmode();
- int fd = -1;
- /* must reset to binary mode to read in content */
- p = malloc(clen+1);
- if(!p)
- return cgi_error("out of memory",0);
- fd = _fileno(stdin);
- _setmode(fd,_O_BINARY);
- if(fread(p,1,clen,stdin) != (unsigned int)clen)
- {
- free(p);
- return cgi_error("couldn't read content",0);
- }
- glob_content = p;
- glob_clen = clen;
- glob_content[glob_clen] = 0;
- }
-
- /* create temp files: input, output, and content;
- must create output and content files first,
- since input file refers to them; all will
- have same numeric identifier, but different
- prefixes */
-
- glob_tnum = get_tempfile(NULL,"cwo",0,&glob_ofile);
- if(!glob_ofile)
- {
- cgi_error("out of memory",-1);
- goto cleanup;
- }
-
- get_tempfile(NULL,"cwc",glob_tnum,&glob_cfile);
- if(!glob_cfile)
- {
- cgi_error("out of memory",-1);
- goto cleanup;
- }
- if(write_cgi_content(glob_cfile) != 0)
- goto cleanup;
-
- get_tempfile(NULL,"cwi",glob_tnum,&glob_ifile);
- if(!glob_ifile)
- {
- cgi_error("out of memory",-1);
- goto cleanup;
- }
- if(write_cgi_input(glob_ifile) != 0)
- goto cleanup;
-
- /* launch program and wait for it to finish */
-
- if(_spawnl(_P_WAIT,exe_path,quoted_exe_path,glob_ifile,NULL) == -1)
- return cgi_error("failed to spawn program",0);
-
- /* send results back to server */
-
- if(write_to_server(glob_ofile) != 0)
- goto cleanup;
-
- cleanup:;
-
- if(glob_content)
- free(glob_content);
-
- if(exe_path)
- free(exe_path);
-
- if(glob_ifile)
- {
- unlink(glob_ifile);
- free(glob_ifile);
- }
- if(glob_ofile)
- {
- unlink(glob_ofile);
- free(glob_ofile);
- }
- if(glob_cfile)
- {
- unlink(glob_cfile);
- free(glob_cfile);
- }
-
- if(glob_extfiles)
- {
- for(i=0;i<glob_extfiles->num;i++)
- unlink(glob_extfiles->slots[i]);
- da_destroy(glob_extfiles);
- }
-
- return 0;
- }
-
-