/* Null httpd -- simple http server Copyright (C) 2001-2002 Dan Cahill This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "nullhttpd.h" #define BUFF_SIZE 8192 void cgi_makeargs(int sid, char *args[]) { char *ptemp; char progname[255]; if (strncmp(conn[sid].dat->in_RequestURI, "/cgi-bin/", 9)!=0) return; args[0]=calloc(255, sizeof(char)); snprintf(progname, sizeof(progname)-1, "%s", conn[sid].dat->in_RequestURI+9); if ((ptemp=strchr(progname, '?'))!=NULL) { args[1]=calloc(255, sizeof(char)); snprintf(args[1], 254, "%s", ptemp+1); *ptemp='\0'; } if ((ptemp=strchr(progname, '/'))!=NULL) { args[2]=calloc(255, sizeof(char)); snprintf(args[2], 254, "%s", ptemp); *ptemp='\0'; } snprintf(args[0], 254, "%s/%s", config.server_cgi_dir, progname); fixslashes(args[0]); } void cgi_makeenv(int sid, char *env[], char *args[]) { char *ptemp; int n=0; if (strncmp(conn[sid].dat->in_RequestURI, "/cgi-bin/", 9)!=0) return; #ifdef WIN32 if ((ptemp=getenv("COMSPEC"))!=NULL) { env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], MAX_PATH-1, "COMSPEC=%s", ptemp); } #endif if (strcasecmp(conn[sid].dat->in_RequestMethod, "POST")==0) { env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "CONTENT_LENGTH=%d", conn[sid].dat->in_ContentLength); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "CONTENT_TYPE=%s", conn[sid].dat->in_ContentType); } env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "DOCUMENT_ROOT=%s", config.server_htdocs_dir); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "GATEWAY_INTERFACE=CGI/1.1"); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "HTTP_CONNECTION=%s", conn[sid].dat->in_Connection); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "HTTP_COOKIE=%s", conn[sid].dat->in_Cookie); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "HTTP_HOST=%s", conn[sid].dat->in_Host); if ((ptemp=strchr(env[n-1], ':'))!=NULL) *ptemp='\0'; env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "HTTP_USER_AGENT=%s", conn[sid].dat->in_UserAgent); if ((ptemp=getenv("PATH"))!=NULL) { env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "PATH=%s", ptemp); } if (args[2]!=NULL) { env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "PATH_INFO=%s", args[2]); } env[n]=calloc(1024, sizeof(char)); if (args[1]!=NULL) { snprintf(env[n++], 1023, "QUERY_STRING=%s", args[1]); } else { snprintf(env[n++], 1023, "QUERY_STRING="); } env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "REMOTE_ADDR=%s", conn[sid].dat->in_RemoteAddr); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "REMOTE_PORT=%d", ntohs(conn[sid].ClientAddr.sin_port)); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "REQUEST_METHOD=%s", conn[sid].dat->in_RequestMethod); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "REQUEST_URI=%s", conn[sid].dat->in_RequestURI); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "SCRIPT_FILENAME=%s", args[0]); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "SCRIPT_NAME=%s", conn[sid].dat->in_RequestURI); if ((ptemp=strchr(env[n-1], '?'))!=NULL) *ptemp='\0'; if ((ptemp=strchr(env[n-1]+21, '/'))!=NULL) *ptemp='\0'; env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "SERVER_NAME=%s", config.server_hostname); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "SERVER_PORT=%d", config.server_port); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "SERVER_PROTOCOL=HTTP/1.1"); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "SERVER_SIGNATURE=
%s", SERVER_NAME); env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "SERVER_SOFTWARE=%s", SERVER_NAME); #ifdef WIN32 if ((ptemp=getenv("WINDIR"))!=NULL) { env[n]=calloc(1024, sizeof(char)); snprintf(env[n++], 1023, "WINDIR=%s", ptemp); } #endif free(args[1]); args[1]=NULL; free(args[2]); args[2]=NULL; } int cgi_main() { #ifdef WIN32 char *cgi_types[3][2]={ { ".php", "PHP.EXE" }, { ".pl", "PERL.EXE" }, { NULL, NULL } }; DWORD exitcode=0; HANDLE hMyProcess=GetCurrentProcess(); PROCESS_INFORMATION pi; STARTUPINFO si; char Command[512]; char Environ[8192]; char Path[255]; #else char *cgi_types[3][2]={ { ".php", "/usr/bin/php" }, { ".pl", "/usr/bin/perl" }, { NULL, NULL } }; int pset1[2]; int pset2[2]; #endif char *args[10]; char *env[50]; char cgifilename[255]; char *extension; char szBuffer[BUFF_SIZE]; pipe_fd local; pipe_fd remote; int sid=nullhttpd_getsid(); int nOutRead; int pid; unsigned int i; unsigned int n; memset(args, 0, sizeof(args)); cgi_makeargs(sid, args); memset(env, 0, sizeof(env)); cgi_makeenv(sid, env, args); snprintf(cgifilename, sizeof(cgifilename)-1, "%s", args[0]); for (i=0;i<10;i++) free(args[i]); n=0; if ((extension=strrchr(cgifilename, '.'))!=NULL) { for (i=0;cgi_types[i][0]!=NULL;i++) { if (strcmp(extension, cgi_types[i][0])==0) { args[n]=calloc(255, sizeof(char)); snprintf(args[n], 254, "%s", cgi_types[i][1]); n++; break; } } } args[n]=calloc(255, sizeof(char)); snprintf(args[n], 254, "%s", cgifilename); #ifdef WIN32 memset(Command, 0, sizeof(Command)); memset(Environ, 0, sizeof(Environ)); ZeroMemory(&pi, sizeof(pi)); ZeroMemory(&si, sizeof(si)); snprintf(Path, sizeof(Path)-1, "%s", cgifilename); if ((extension=strrchr(Path, '\\'))!=NULL) *extension='\0'; if (args[1]==NULL) { snprintf(Command, sizeof(Command)-1, "%s", cgifilename); } else { snprintf(Command, sizeof(Command)-1, "%s \"%s\"", cgi_types[i][1], cgifilename); } for (i=0, n=0;env[i]!=NULL;i++) { if (n+strlen(env[i])>sizeof(Environ)) break; n+=sprintf(&Environ[n], "%s", env[i]); n++; } if (!CreatePipe((HANDLE)&remote.in, (HANDLE)&local.out, NULL, BUFF_SIZE)) { for (i=0;i<10;i++) free(args[i]); for (i=0;i<50;i++) free(env[i]); printerror(sid, 500, "Internal Server Error", "Unable to create pipe."); return -1; } if (!CreatePipe((HANDLE)&local.in, (HANDLE)&remote.out, NULL, BUFF_SIZE)) { for (i=0;i<10;i++) free(args[i]); for (i=0;i<50;i++) free(env[i]); CloseHandle((HANDLE)remote.in); CloseHandle((HANDLE)local.out); printerror(sid, 500, "Internal Server Error", "Unable to create pipe."); return -1; } si.cb=sizeof(si); si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; si.wShowWindow=SW_HIDE; si.hStdInput=(HANDLE)remote.in; si.hStdOutput=(HANDLE)remote.out; si.hStdError=(HANDLE)remote.out; if (!CreateProcess(NULL, Command, NULL, NULL, TRUE, CREATE_NO_WINDOW, Environ, Path, &si, &pi)) { for (i=0;i<10;i++) free(args[i]); for (i=0;i<50;i++) free(env[i]); CloseHandle((HANDLE)local.in); CloseHandle((HANDLE)local.out); CloseHandle((HANDLE)remote.in); CloseHandle((HANDLE)remote.out); logerror("CGI failed. [%s]", Command); printerror(sid, 500, "Internal Server Error", "There was a problem running the requested CGI."); return -1; } pid=pi.dwProcessId; CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); #else if ((pipe(pset1)==-1) || (pipe(pset2)==-1)) { for (i=0;i<10;i++) free(args[i]); for (i=0;i<50;i++) free(env[i]); close(pset1[0]); close(pset1[1]); logerror("pipe() error"); printerror(sid, 500, "Internal Server Error", "Unable to create pipe."); return -1; } local.in=pset1[0]; remote.out=pset1[1]; remote.in=pset2[0]; local.out=pset2[1]; logaccess(1, "Executing CGI [%s %s]", args[0], args[1]); pid=fork(); if (pid<0) { logerror("fork() error"); return -1; } else if (pid==0) { close(local.in); close(local.out); dup2(remote.in, fileno(stdin)); dup2(remote.out, fileno(stdout)); // if ((dup2(remote.in, fileno(stdin))!=0)||(dup2(remote.out, fileno(stdout))!=0)) { // logerror("dup2() error"); // exit(0); // } execve(args[0], &args[0], &env[0]); logerror("execve() error [%s][%s]", args[0], args[1]); exit(0); } else { close(remote.in); close(remote.out); } #endif if (conn[sid].dat->in_ContentLength>0) { #ifdef WIN32 WriteFile((HANDLE)local.out, conn[sid].PostData, conn[sid].dat->in_ContentLength, &nOutRead, NULL); #else write(local.out, conn[sid].PostData, conn[sid].dat->in_ContentLength); #endif } conn[sid].dat->out_headdone=1; conn[sid].dat->out_status=200; if (strcasestr(conn[sid].dat->in_Protocol, "HTTP/1.1")!=NULL) { snprintf(conn[sid].dat->out_Protocol, sizeof(conn[sid].dat->out_Protocol)-1, "HTTP/1.1"); } else { snprintf(conn[sid].dat->out_Protocol, sizeof(conn[sid].dat->out_Protocol)-1, "HTTP/1.0"); } snprintf(conn[sid].dat->out_Connection, sizeof(conn[sid].dat->out_Connection)-1, "Close"); prints("%s %d OK\r\n", conn[sid].dat->out_Protocol, conn[sid].dat->out_status); prints("Connection: %s\r\n", conn[sid].dat->out_Connection); flushbuffer(sid); do { memset(szBuffer, 0, sizeof(szBuffer)); #ifdef WIN32 ReadFile((HANDLE)local.in, szBuffer, sizeof(szBuffer)-1, &nOutRead, NULL); #else nOutRead=read(local.in, szBuffer, BUFF_SIZE-1); #endif if (nOutRead>0) { send(conn[sid].socket, szBuffer, nOutRead, 0); }; } while (nOutRead>0); flushbuffer(sid); /* cleanup */ for (i=0;i<10;i++) free(args[i]); for (i=0;i<50;i++) free(env[i]); #ifdef WIN32 GetExitCodeProcess(pi.hProcess, &exitcode); if (exitcode==STILL_ACTIVE) TerminateProcess(pi.hProcess, 1); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); CloseHandle((HANDLE)local.in); CloseHandle((HANDLE)local.out); #else close(local.in); close(local.out); #endif conn[sid].dat->out_bodydone=1; flushbuffer(sid); closeconnect(sid, 1); return 0; }