# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # pserv # pserv/files # pserv/files/patch-main.c # pserv/files/patch-Makefile # pserv/files/patch-main.h # pserv/files/patch-mime_types.dat # pserv/files/patch-pserv.conf # pserv/files/patch-handlers.c # pserv/files/patch-handlers.h # pserv/files/patch-mime.c # pserv/files/pserv.sh # pserv/Makefile # pserv/distinfo # pserv/pkg-descr # pserv/pkg-plist # echo c - pserv mkdir -p pserv > /dev/null 2>&1 echo c - pserv/files mkdir -p pserv/files > /dev/null 2>&1 echo x - pserv/files/patch-main.c sed 's/^X//' >pserv/files/patch-main.c << 'END-of-pserv/files/patch-main.c' X--- main.c.orig Mon Sep 22 10:39:24 2003 X+++ main.c Thu Oct 16 14:00:02 2003 X@@ -23,6 +23,7 @@ X char defaultFileName[MAX_PATH_LEN+1]; X char logFileName[MAX_PATH_LEN+1]; X char mimeTypesFileName[MAX_PATH_LEN+1]; X+char phpFileName[MAX_PATH_LEN+1]; X char cgiRoot[MAX_PATH_LEN+1]; /* root for CGI scripts exec */ X struct timeval sockTimeVal; X mimeData *mimeArray; /* here we will hold all MIME data, inited once, never to be changed */ X@@ -206,10 +207,10 @@ X int reqSize; X int readLines; X int tokenEnd; X- X- /* we copy the header lines to an array for easier parsing */ X+ X+ /* we copy the header lines to an array for easier parsing */ X /* but first we make sure that our string has a newline and an end */ X- req[BUFFER_SIZE] = '\0'; X+ req[BUFFER_SIZE] = '\0'; X reqSize = strlen(req); X req[reqSize] = '\n'; X reqSize++; X@@ -230,7 +231,7 @@ X for (k = 0; k < readLines; k++) X printf("%d - |%s|\n", k, reqArray[k]); X #endif X- X+ X /* first line: method, path and protocol version */ X /* we copy to a temporary buffer to be more secure against overflows */ X i = j = 0; X@@ -246,7 +247,7 @@ X else X tokenEnd = NO; X i++; X- X+ X /* we look for the document address */ X j = 0; X reqStruct->documentAddress[0] = '\0'; X@@ -259,14 +260,14 @@ X else X token[j] = '\0'; /* to make sure we have a string */ X /* now we need to convert some escapings from the path like %20 */ X- convertPercents(token, j); X+ convertPercents(token, j); X strcpy(reqStruct->documentAddress, token); /* copy back */ X if (reqArray[0][i] == '\0') X tokenEnd = YES; X else X tokenEnd = NO; X i++; X- X+ X /* we need now to separate path from query string ("?" separated) */ X if (reqArray[0][i-1] == '?') X { X@@ -282,7 +283,7 @@ X i++; X } X } X- X+ X /* we analyze the HTTP protocol version */ X /* default is 0.9 since that version didn't report itself */ X strcpy(reqStruct->protocolVersion, "HTTP/0.9"); X@@ -306,10 +307,13 @@ X else if (!strncmp(reqArray[1], "Connection: Keep-Alive", strlen("Connection: keep-alive"))) X reqStruct->keepAlive = YES; X X- /* user-agent, content-length and else */ X+ /* user-agent, content-length, content-type, cookie and else */ X i = 1; X j = NO; X reqStruct->userAgent[0] = '\0'; X+ reqStruct->contentLength = -1; X+ reqStruct->contentType[0] = '\0'; X+ reqStruct->cookie[0] = '\0'; X while (i < readLines) X { X if (!strncmp(reqArray[i], "User-Agent:", strlen("User-Agent:"))) X@@ -317,14 +321,28 @@ X strncpy(reqStruct->userAgent, &reqArray[i][strlen("User-Agent: ")], USER_AGENT_LEN - 1); X reqStruct->userAgent[USER_AGENT_LEN] = '\0'; X } X- else if (!strncmp(reqArray[i], "Content-Length:", strlen("Content-length:")) || !strncmp(reqArray[i], "Content-length:", strlen("Content-length:"))) X- { X- strcpy(token, &reqArray[i][strlen("Content-length: ")]); X- sscanf(token, "%ld", &(reqStruct->contentLength)); X+ else if (!strncmp(reqArray[i], "Content-Length:", strlen("Content-length:")) || !strncmp(reqArray[i], "Content-length:", strlen("Content-length:"))) X+ { X+ strcpy(token, &reqArray[i][strlen("Content-length: ")]); X+ sscanf(token, "%ld", &(reqStruct->contentLength)); X #ifdef PRINTF_DEBUG X- printf("content length %ld\n", reqStruct->contentLength); X+ printf("content length %ld\n", reqStruct->contentLength); X #endif X- } X+ } X+ else if (!strncmp(reqArray[i], "Content-Type:", strlen("Content-type:")) || !strncmp(reqArray[i], "Content-type:", strlen("Content-type:"))) X+ { X+ strncpy(reqStruct->contentType, &reqArray[i][strlen("Content-type: ")], CONTENT_TYPE_LEN - 1); X+#ifdef PRINTF_DEBUG X+ printf("content type %s\n", reqStruct->contentType); X+#endif X+ } X+ else if (!strncmp(reqArray[i], "Cookie:", strlen("Cookie:"))) X+ { X+ strncpy(reqStruct->cookie, &reqArray[i][strlen("Cookie: ")], MAX_COOKIE_LEN - 1); X+#ifdef PRINTF_DEBUG X+ printf("cookie %s\n", reqStruct->cookie); X+#endif X+ } X i++; X } X /* if we didn't find a User-Aget we fill in a (N)ot(R)ecognized */ X@@ -414,18 +432,39 @@ X /* we append the default file name */ X strcat(completeFilePath, defaultFileName); X analyzeExtension(mimeType, completeFilePath); X- dumpFile(sock, completeFilePath, mimeType, req); X+#ifdef PHP X+ if (strncmp(mimeType, "application/x-httpd-php", 23)) X+#endif X+ dumpFile(sock, completeFilePath, mimeType, req); X+#ifdef PHP X+ else X+ phpHandler(port, sock, phpFileName, completeFilePath, req, NULL); X+#endif X } X #else X /* we append the default file name */ X strcat(completeFilePath, defaultFileName); X analyzeExtension(mimeType, completeFilePath); X- dumpFile(sock, completeFilePath, mimeType, req); X+#ifdef PHP X+ if (strncmp(mimeType, "application/x-httpd-php", 23)) X+#endif X+ dumpFile(sock, completeFilePath, mimeType, req); X+#ifdef PHP X+ else X+ phpHandler(port, sock, phpFileName, completeFilePath, req, NULL); X+#endif X #endif X } else X { /* it is a plain file */ X analyzeExtension(mimeType, completeFilePath); X- dumpFile(sock, completeFilePath, mimeType, req); X+#ifdef PHP X+ if (strncmp(mimeType, "application/x-httpd-php", 23)) X+#endif X+ dumpFile(sock, completeFilePath, mimeType, req); X+#ifdef PHP X+ else X+ phpHandler(port, sock, phpFileName, completeFilePath, req, NULL); X+#endif X } X } X } else if (!strcmp(req.method, "HEAD")) X@@ -494,7 +533,14 @@ X strcat(completeFilePath, defaultFileName); X } X analyzeExtension(mimeType, completeFilePath); X- dumpHeader(sock, completeFilePath, mimeType, req); X+#ifdef PHP X+ if (strncmp(mimeType, "application/x-httpd-php", 23)) X+#endif X+ dumpFile(sock, completeFilePath, mimeType, req); X+#ifdef PHP X+ else X+ phpHandler(port, sock, phpFileName, completeFilePath, req, NULL); X+#endif X } X } else if (!strcmp(req.method, "POST")) X { X@@ -507,13 +553,6 @@ X int readFinished; X X printf("Handling of POST method\n"); X- /* first we check if the path contains the directory selected for cgi's and in case handle it */ X- if (strncmp(req.documentAddress, CGI_MATCH_STRING, strlen(CGI_MATCH_STRING))) X- { X- /* non cgi POST is not supported */ X- sayError(sock, UNHANDLED_METHOD, "", req); X- return -1; X- } X #ifdef PRINTF_DEBUG X printf ("begin of post handling\n"); X X@@ -523,9 +562,15 @@ X totalRead = 0; X stuckCounter = 0; X timeOutCounter = 0; X- while (!readFinished) X- { X- howMany = recv(newSocket, tempBuff, BUFFER_SIZE, 0); X+ X+ /* SECURITY: Avoid malicious Content-Length -- check \r\n\r\n\0 also */ X+ if (req.contentLength < 0 || req.contentLength >= BUFFER_SIZE-5) { X+ sayError(sock, 500, "", req); X+ return -1; X+ } X+ X+ /* SECURITY: Remove loop to prevent buffer overflow */ X+ howMany = recv(newSocket, tempBuff, req.contentLength+5, 0); X tempBuff[howMany] = '\0'; /* seems that some Unices need this */ X #ifdef PRINTF_DEBUG X printf ("read: %d\n%s\n", howMany, tempBuff); X@@ -579,16 +624,15 @@ X if (howMany == req.contentLength) X readFinished = YES; X } X- } X #ifdef PRINTF_DEBUG X- printf("total read %d\n", totalRead); X+ printf("total read %d\n", totalRead); X #endif X- if (totalRead == 0) X- { X- printf("Request read error\n"); X- } else X- { X- if (buff[totalRead - 1] != '\n') /* we need a trailing \n or the script will wait forever */ X+ if (totalRead == 0) X+ { X+ printf("Request read error\n"); X+ } else X+ { X+ if (buff[totalRead - 1] != '\n') /* we need a trailing \n or the script will wait forever */ X { X buff[totalRead++] = '\n'; X buff[totalRead] = '\0'; X@@ -596,7 +640,77 @@ X #ifdef PRINTF_DEBUG X printf("buff: |%s|\n", buff); X #endif X- cgiHandler(port, sock, req, buff); X+ if (!strncmp(req.documentAddress, CGI_MATCH_STRING, strlen(CGI_MATCH_STRING))) X+ { X+ cgiHandler(port, sock, req, buff); X+ } else X+ { X+#ifdef PHP X+ strcpy(completeFilePath, homePath); X+ strcat(completeFilePath, req.documentAddress); X+ /* now we check if the given path tries to get out of the root */ X+ { X+ int i,j; X+ int sL; X+ char dirName[MAX_PATH_LEN+1]; X+ int depthCount = 0; X+ X+ sL = strlen(req.documentAddress); X+ dirName[0] = '\0'; X+ if (sL > 3) { X+ dirName[0] = req.documentAddress[1]; X+ dirName[1] = req.documentAddress[2]; X+ dirName[2] = req.documentAddress[3]; X+ dirName[3] ='\0'; X+ if (!strcmp(dirName, "../")) X+ { X+ sayError(sock, FORBIDDEN, req.documentAddress, req); X+ return -1; X+ } X+ } X+ j = 0; X+ for (i = 1; i < sL; i++) { X+ if (req.documentAddress[i] == '/') X+ { X+ dirName[j] = '\0'; X+ if (strcmp(dirName, "..")) X+ depthCount ++; X+ else X+ depthCount--; X+ j = 0; X+ } else X+ dirName[j++] = req.documentAddress[i]; X+ } X+ if (depthCount < 0) X+ { X+ sayError(sock, FORBIDDEN, req.documentAddress, req); X+ return -1; X+ } X+ } X+ /* now we check if the given file is a directory or a plain file */ X+ stat(completeFilePath, &fileStats); X+ if ((fileStats.st_mode & S_IFDIR) == S_IFDIR) X+ { X+ /* if does not end with a slash, we get an error */ X+ if(completeFilePath[strlen(completeFilePath)-1] != '/') X+ { X+ sayError(sock, NOT_FOUND, req.documentAddress, req); X+ return -1; X+ } X+ /* we append the default file name */ X+ strcat(completeFilePath, defaultFileName); X+ } X+ analyzeExtension(mimeType, completeFilePath); X+ if (strncmp(mimeType, "application/x-httpd-php", 23)) X+ { X+#endif X+ /* non cgi POST is not supported */ X+ sayError(sock, UNHANDLED_METHOD, "", req); X+ return -1; X+#ifdef PHP X+ } else phpHandler(port, sock, phpFileName, completeFilePath, req, buff); X+#endif X+ } X } X } else X { X@@ -625,7 +739,7 @@ X f = fopen(configFile, "r"); X if (f == NULL) X { X- printf("Error opening config file. Setting defaults.\n"); X+ printf("Config file not found. Setting defaults.\n"); X *serverPort = DEFAULT_PORT; X *maxChildren = DEFAULT_MAX_CHILDREN; X strcpy(homePath, DEFAULT_DOCS_LOCATION); X@@ -634,7 +748,9 @@ X sockTimeVal.tv_usec = DEFAULT_USEC_TO; X strcpy(logFileName, DEFAULT_LOG_FILE); X strcpy(mimeTypesFileName, DEFAULT_MIME_FILE); X+ strcpy(phpFileName, DEFAULT_PHP_FILE); X strcpy(cgiRoot, DEFAULT_CGI_ROOT); X+ initMimeTypes(); X return -1; X } X if (!feof(f)) fscanf(f, "%s %s", str1, str2); X@@ -735,11 +851,25 @@ X if (mimeTypesFileName == NULL) X { X strcpy(mimeTypesFileName, DEFAULT_MIME_FILE); X- printf("Error reading mimeTypesFileName from file, setting default, %s\n", mimeTypesFileName); X+ printf("Error reading mimeTypesFile from file, setting default, %s\n", mimeTypesFileName); X } X } else { X strcpy(mimeTypesFileName, DEFAULT_MIME_FILE); X- printf("Error reading mimeTypesFileName from file, setting default, %s\n", mimeTypesFileName); X+ printf("Error reading mimeTypesFile from file, setting default, %s\n", mimeTypesFileName); X+ } X+ if (!feof(f)) fscanf(f, "%s %s", str1, str2); X+ if (str1 != NULL && str2 != NULL && !strcmp(str1, "phpFile")) X+ { X+ sscanf(str2, "%s", phpFileName); X+ if (logFileName == NULL) X+ { X+ strcpy(phpFileName, DEFAULT_LOG_FILE); X+ printf("Error reading phpFile from file, setting default, %s\n", phpFileName); X+ } X+ } else X+ { X+ strcpy(phpFileName, DEFAULT_PHP_FILE); X+ printf("Error reading phpFile from file, setting default, %s\n", phpFileName); X } X if (!feof(f)) fscanf(f, "%s %s", str1, str2); X if (str1 != NULL && str2 != NULL && !strcmp(str1, "cgiRoot")) X@@ -775,6 +905,7 @@ X int readFinished; X struct request gottenReq; X int isKeepAlive; X+ int bool; X struct sockaddr_in listenName; /* data struct for the listen port */ X struct sockaddr_in acceptedSockStruct; /* sockaddr for the internetworking */ X int acceptedSocketLen; /* size of the structure */ X@@ -808,9 +939,16 @@ X printf("socket creation error occoured\n"); X return -1; X } X+ bool = 1; X+ error = setsockopt (theSocket, SOL_SOCKET, SO_REUSEADDR, &bool, sizeof(bool)); X+ if (error == -1) X+ { if (errno == EADDRINUSE) X+ printf("set socket option error occoured\n"); X+ return -1; X+ } X error = bind (theSocket, (struct sockaddr*) &listenName, sizeof(listenName)); X if (error == -1) X- { X+ { if (errno == EADDRINUSE) X printf("socket binding error occoured\n"); X return -2; X } END-of-pserv/files/patch-main.c echo x - pserv/files/patch-Makefile sed 's/^X//' >pserv/files/patch-Makefile << 'END-of-pserv/files/patch-Makefile' X--- Makefile.orig Mon Sep 8 20:05:54 2003 X+++ Makefile Thu Oct 16 14:24:50 2003 X@@ -1,11 +1,11 @@ X #Change the following to your needs X-CC = gcc X+CC ?= gcc X #insert here flags, eg. optimizations X-CFLAGS = -Wall -O3 X-LIBS = -lnsl -lsocket X SRCS = main.c handlers.c mime.c log.c X OBJS = main.o handlers.o mime.o log.o X PROGRAM = pserv X+ X+all : $(PROGRAM) X X $(PROGRAM) : $(OBJS) X $(CC) -o $(PROGRAM) $(OBJS) $(LIBS) END-of-pserv/files/patch-Makefile echo x - pserv/files/patch-main.h sed 's/^X//' >pserv/files/patch-main.h << 'END-of-pserv/files/patch-main.h' X--- main.h.orig Fri Sep 19 00:36:03 2003 X+++ main.h Thu Oct 16 13:52:18 2003 X@@ -24,11 +24,12 @@ X X X /* --- CPP parsing options --- */ X-#define PRINTF_DEBUG /* enable this to print some debugging messages */ X+#undef PRINTF_DEBUG /* enable this to print some debugging messages */ X #undef ON_THE_FLY_CONVERSION /* enable this for line ending conversion */ X #undef BRAIN_DEAD_CAST /* if your compiler is brainwashed and does not cast standard types.h structures */ X #define FORKING_SERVER /* enables to fork for every request */ X #define AUTO_INDEX /* enables auto-index of directories */ X+#define PHP /* enables transparent PHP support */ X X /* --- Configure options --- */ X #define CONFIG_FILE_NAME "pserv.conf" X@@ -39,19 +40,19 @@ X #define MIME_TYPE_DEFAULT "application/octet-stream" X X /* configuration file location */ X-#define DEFAULT_CONFIG_LOCATION "/export/home/multix/pserv/" X-//#define DEFAULT_CONFIG_LOCATION "/Users/multix/Documents/code/pserv/" X+#define DEFAULT_CONFIG_LOCATION "/usr/local/etc/" X X /* hard-wired defaults, if loading of config file fails */ X-#define DEFAULT_PORT 2000 X+#define DEFAULT_PORT 80 X #define DEFAULT_MAX_CHILDREN 5 X-#define DEFAULT_DOCS_LOCATION "/export/home/multix/public_html" X+#define DEFAULT_DOCS_LOCATION "/usr/local/www/data" X #define DEFAULT_FILE_NAME "index.html" X #define DEFAULT_SEC_TO 1 X #define DEFAULT_USEC_TO 100 X-#define DEFAULT_LOG_FILE "/export/home/multix/pserv/pserv.log" X-#define DEFAULT_MIME_FILE "/export/home/multix/pserv/mime_types.dat" X-#define DEFAULT_CGI_ROOT "/export/home/multix/public_html/cgi-bin" X+#define DEFAULT_LOG_FILE "/var/log/pserv.log" X+#define DEFAULT_MIME_FILE "/usr/local/etc/mime.types" X+#define DEFAULT_PHP_FILE "/usr/local/bin/php" X+#define DEFAULT_CGI_ROOT "/usr/local/www/cgi-bin" X #define DEFAULT_SERVER_NAME "localhost" X X /* amount of connections queued in listening */ X@@ -120,9 +121,11 @@ X #define ADDRESS_LEN 16 X #define METHOD_LEN 16 X #define PROTOCOL_LEN 16 X+#define CONTENT_TYPE_LEN 256 X #define USER_AGENT_LEN 256 X #define MAX_QUERY_STRING_LEN 1024 X #define MAX_PATH_LEN 1024 X+#define MAX_COOKIE_LEN 4096 X X struct request X { X@@ -133,7 +136,9 @@ X char protocolVersion[PROTOCOL_LEN+1]; X int keepAlive; X char userAgent[USER_AGENT_LEN+1]; X+ char cookie[MAX_COOKIE_LEN+1]; X long int contentLength; X+ char contentType[CONTENT_TYPE_LEN+1]; X char rest[BUFFER_SIZE+1]; X }; X END-of-pserv/files/patch-main.h echo x - pserv/files/patch-mime_types.dat sed 's/^X//' >pserv/files/patch-mime_types.dat << 'END-of-pserv/files/patch-mime_types.dat' X--- mime_types.dat.orig Wed Oct 15 15:57:08 2003 X+++ mime_types.dat Wed Oct 15 15:57:22 2003 X@@ -14,3 +14,4 @@ X tar application/x-tar X lha application/octet-stream X lzh application/octet-stream X+php application/x-httpd-php END-of-pserv/files/patch-mime_types.dat echo x - pserv/files/patch-pserv.conf sed 's/^X//' >pserv/files/patch-pserv.conf << 'END-of-pserv/files/patch-pserv.conf' X--- pserv.conf.orig Wed Oct 15 16:18:05 2003 X+++ pserv.conf Wed Oct 15 16:20:01 2003 X@@ -1,9 +1,10 @@ X-port 80 X+port 80 X maxChildren 4 X-documentsPath /export/home/multix/public_html X+documentsPath %%PREFIX%%/www/data X defaultFile index.html X secTimeout 1 X uSecTimeout 100000 X-logFile /export/home/multix/pserv/pserv.log X-mimeTypesFile /export/home/multix/pserv/mime_types.dat X-cgiRoot /export/home/multix/public_html/cgi-bin X+logFile /var/log/pserv.log X+mimeTypesFile %%PREFIX%%/etc/mime.types X+phpFile %%LOCALBASE%%/bin/php X+cgiRoot %%PREFIX%%/www/cgi-bin END-of-pserv/files/patch-pserv.conf echo x - pserv/files/patch-handlers.c sed 's/^X//' >pserv/files/patch-handlers.c << 'END-of-pserv/files/patch-handlers.c' X--- handlers.c.orig Thu Sep 18 15:26:48 2003 X+++ handlers.c Thu Oct 16 14:16:05 2003 X@@ -24,6 +24,7 @@ X #endif X X extern char cgiRoot[MAX_PATH_LEN+1]; /* root for CGI scripts exec */ X+extern char homePath[MAX_PATH_LEN+1]; /* root for PHP scripts exec */ X extern int port; /* server port */ X extern char defaultFileName[MAX_PATH_LEN+1]; /* default name for index, default or similar file */ X X@@ -262,12 +263,33 @@ X newArgv[i] = NULL; /* we correctly terminate argv */ X X i = 0; X+ if (req.contentLength != -1) X+ { X+ sprintf(newEnvp[i++], "CONTENT_LENGTH=%ld", req.contentLength); X+ strcpy(newEnvp[i], "CONTENT_TYPE="); X+ strcat(newEnvp[i++], req.contentType); X+ } X+ strcpy(newEnvp[i], "SERVER_NAME="); X+ strcat(newEnvp[i++], DEFAULT_SERVER_NAME); X strcpy(newEnvp[i], "SERVER_SOFTWARE="); X strcat(newEnvp[i], SERVER_SOFTWARE_STR); X strcat(newEnvp[i], "/"); X strcat(newEnvp[i++], SERVER_VERSION_STR); X+ strcpy(newEnvp[i], "SERVER_PROTOCOL="); X+ strcat(newEnvp[i++], req.protocolVersion); X strcpy(newEnvp[i], "REQUEST_METHOD="); X strcat(newEnvp[i++], req.method); X+ strcpy(newEnvp[i], "REMOTE_ADDR="); X+ strcat(newEnvp[i++], req.address); X+ strcpy(newEnvp[i], "HTTP_USER_AGENT="); X+ strcat(newEnvp[i++], req.userAgent); X+ if (req.cookie[0] != '\0') X+ { X+ strcpy(newEnvp[i], "HTTP_COOKIE="); X+ strcat(newEnvp[i++], req.cookie); X+ } X+ strcpy(newEnvp[i], "SCRIPT_FILENAME="); X+ strcat(newEnvp[i++], completedPath); X strcpy(newEnvp[i], "SCRIPT_NAME="); X strcat(newEnvp[i++], req.documentAddress); X strcpy(newEnvp[i], "GATEWAY_INTERFACE="); X@@ -302,13 +324,256 @@ X execve(completedPath, newArgv, newEnvp); X /* we reach this line only if an execution error occoured */ X /* logging will happen in the father */ X- printf("\nCGI Error

Cgi Exec error

\n"); X+ printf("\nCGI Error

CGI Exec error

\n"); X exit(-1); X } X return 0; X } X X-int dumpHeader(sock, filePath, mimeType, req) X+ X+#ifdef PHP X+int phpHandler(port, sock, phpFileName, completedPath, req, postStr) X+int port; X+int sock; X+char *phpFileName; X+char *completedPath; X+struct request req; X+char *postStr; X+{ X+ char envPath[MAX_PATH_LEN+1]; /* where to hold the envrion PATH parameter */ X+ char *relativePath; X+ char scriptWorkingDir[MAX_PATH_LEN+1]; X+ char **newArgv; X+ char **newEnvp; X+ int i; X+ int outStdPipe[2]; /* we will redirect the script output to a pipe so we can read it */ X+ int inStdPipe[2]; /* we will redirect the script input to a pipe so we can read it */ X+ int pid; /* we fork and execute inside the child the script */ X+ char pipeReadBuf[PIPE_READ_BUF+1]; X+ int howMany; X+ int totalSentFromPipe; /* ampunt of bytes sucked from the pipe and pushed in to the socket */ X+ int fatal; X+ X+ relativePath = strrchr(completedPath, '/'); X+ strncpy(scriptWorkingDir, completedPath, strlen(completedPath) - strlen(relativePath)); X+ scriptWorkingDir[strlen(completedPath) - strlen(relativePath)] = '\0'; X+ X+ /* first we create the pipes needed for stdout redirection */ X+ if (pipe(outStdPipe)) X+ { X+#ifdef PRINTF_DEBUG X+ printf("Pipe creation error\n"); X+ return -1; X+#endif X+ } X+ if (pipe(inStdPipe)) X+ { X+#ifdef PRINTF_DEBUG X+ printf("Pipe creation error\n"); X+ return -1; X+#endif X+ } X+ X+ X+ /* now we fork to subsequently execve */ X+ pid = fork(); X+ if (pid) X+ { /* this is the parent process */ X+ if (pid < 0) X+ { /* we check for creation error */ X+ printf ("Forking error during cgi exec: %d\n", errno); X+ return -1; X+ } X+ /* we close the unused end of the pipe */ X+ close(outStdPipe[WRITE]); X+ close(inStdPipe[READ]); X+ X+ if (!strcmp(req.method, "POST")) /* we have to feed the stdin of the script */ X+ { X+ if(!strlen(postStr)) X+ { X+#ifdef PRINTF_DEBUG X+ printf("cannot post empty data\n"); X+#endif X+ return -1; X+ } X+ howMany = write(inStdPipe[WRITE], postStr, strlen(postStr)); X+ if (howMany < 0) X+ printf("Error during script pipe read.\n"); X+ } X+ totalSentFromPipe = 0; X+ fatal = NO; X+ howMany = 1; X+ while (howMany > 0 && !fatal) X+ { X+ howMany = read(outStdPipe[READ], &pipeReadBuf, PIPE_READ_BUF); X+ if (howMany < 0) X+ printf("Error during script pipe read.\n"); X+ else if (!howMany) X+ printf("Nothing read from script pipe.\n"); X+ else { X+ pipeReadBuf[howMany] = '\0'; X+ if (send(sock, pipeReadBuf, howMany, 0) < 0) X+ { X+ printf("error during CGI sock writing! %d\n", errno); X+ if (errno == EAGAIN) X+ printf("output resource temporarily not available\n"); X+ else if (errno == EPIPE) X+ { X+ printf("broken pipe during CGI out.\n"); X+ fatal = YES; X+ } else if (errno == EBADF) X+ { X+#ifdef PRINTF_DEBUG X+ printf("invalid out descriptor.\n"); X+#endif X+ fatal = YES; X+ } X+ } else X+ totalSentFromPipe += howMany; X+ } X+ } X+ /* now we finished and we clean up */ X+ wait(&i); X+ if (i) /* check if execution exited cleanly or with code */ X+ logWriter(LOG_CGI_FAILURE, NULL, 0, req, i); X+ else X+ logWriter(LOG_CGI_SUCCESS, NULL, totalSentFromPipe, req, 0); X+ close(outStdPipe[READ]); X+ close(inStdPipe[WRITE]); X+ } else X+ { /* this is the child process */ X+ /* now we do some environment setup work */ X+ newArgv = calloc(MAX_ARGV_LEN + 1, sizeof(char*)); X+ for (i = 0; i < MAX_ARGV_LEN + 1; i++) X+ { X+ newArgv[i] = calloc(MAX_PATH_LEN, sizeof(char)); X+ } X+ X+ newEnvp = calloc(MAX_ENVP_LEN + 1, sizeof(char*)); X+ for (i = 0; i < MAX_ENVP_LEN + 1; i++) X+ { X+ newEnvp[i] = calloc(MAX_PATH_LEN, sizeof(char)); X+ } X+ X+ X+ X+ /* extracting PATH env variable */ X+ i = 0; X+ while (environ && strncmp(environ[i], PATH_MATCH_STRING, strlen(PATH_MATCH_STRING))) X+ i++; X+ if(environ[i]) X+ strcpy(envPath, environ[i]); X+ else X+ envPath[0] = '\0'; /* maybe we should set some default? */ X+ X+ i = 0; X+ strcpy(newArgv[i++], phpFileName); /* here we should pass the phppath */ X+ strcpy(newArgv[i++], completedPath); /* here we should pass the scriptpath */ X+ if (strlen(req.queryString)) X+ { X+ int toParse; X+ int j, k; X+ X+ toParse = YES; X+ j = strlen(req.queryString); X+ while (toParse && j > 0) X+ { X+ if (req.queryString[j] == '=') X+ toParse = NO; X+ j--; X+ } X+ if (toParse) X+ { X+ j = 0; X+ k = 0; X+ howMany = strlen(req.queryString); X+ while (j < howMany) X+ { X+ if (req.queryString[j] == '+') X+ { X+ newArgv[i++][k] = '\0'; X+ k = 0; X+ } else X+ newArgv[i][k++] = req.queryString[j]; X+ j++; X+ } X+ i++; /* after all we will have at least one argument! */ X+ } X+ } X+ newArgv[i] = NULL; /* we correctly terminate argv */ X+ X+ i = 0; X+ if (req.contentLength != -1) X+ { X+ sprintf(newEnvp[i++], "CONTENT_LENGTH=%ld", req.contentLength); X+ strcpy(newEnvp[i], "CONTENT_TYPE="); X+ strcat(newEnvp[i++], req.contentType); X+ } X+ strcpy(newEnvp[i], "SERVER_NAME="); X+ strcat(newEnvp[i++], DEFAULT_SERVER_NAME); X+ strcpy(newEnvp[i], "SERVER_SOFTWARE="); X+ strcat(newEnvp[i], SERVER_SOFTWARE_STR); X+ strcat(newEnvp[i], "/"); X+ strcat(newEnvp[i++], SERVER_VERSION_STR); X+ strcpy(newEnvp[i], "SERVER_PROTOCOL="); X+ strcat(newEnvp[i++], req.protocolVersion); X+ strcpy(newEnvp[i], "REQUEST_METHOD="); X+ strcat(newEnvp[i++], req.method); X+ strcpy(newEnvp[i], "REMOTE_ADDR="); X+ strcat(newEnvp[i++], req.address); X+ strcpy(newEnvp[i], "HTTP_USER_AGENT="); X+ strcat(newEnvp[i++], req.userAgent); X+ if (req.cookie[0] != '\0') X+ { X+ strcpy(newEnvp[i], "HTTP_COOKIE="); X+ strcat(newEnvp[i++], req.cookie); X+ } X+ strcpy(newEnvp[i], "SCRIPT_FILENAME="); X+ strcat(newEnvp[i++], completedPath); X+ strcpy(newEnvp[i], "SCRIPT_NAME="); X+ strcat(newEnvp[i++], req.documentAddress); X+ strcpy(newEnvp[i], "GATEWAY_INTERFACE="); X+ strcat(newEnvp[i++], CGI_VERSION); X+ sprintf(newEnvp[i++], "SERVER_PORT=%d", port); X+ strcpy(newEnvp[i++], envPath); X+ strcpy(newEnvp[i], "QUERY_STRING="); X+ strcat(newEnvp[i++], req.queryString); X+ newEnvp[i] = NULL; X+ X+ /* we change the current working directory to the scripts one */ X+ if(chdir(scriptWorkingDir)) X+ { X+#ifdef PRINTF_DEBUG X+ printf("error while changing PWD in script execution: %d\n", errno); X+#endif X+ } X+ X+ close(outStdPipe[READ]); /* we close the unused end*/ X+ dup2(outStdPipe[WRITE], 1); /* we duplicate the pipe to the stdout */ X+ close(outStdPipe[WRITE]); /* we close the pipe, since we use the duplicate */ X+ X+ close(inStdPipe[WRITE]); /* we close the unused end*/ X+ dup2(inStdPipe[READ], 0); /* we duplicate the pipe to the stdin */ X+ close(inStdPipe[READ]); /* we close the pipe, since we use the duplicate */ X+ X+ X+ /* generate a reduced mimeHeader, no type, no size, etc */ X+ generateMimeHeader(sock, 200, "", NULL, req.protocolVersion, CGI_ONLY_HEADER); X+ X+ /* now we execute the script replacing the current child */ X+ execve(phpFileName, newArgv, newEnvp); X+ /* we reach this line only if an execution error occoured */ X+ /* logging will happen in the father */ X+ printf("\nPHP Error

PHP Exec error

\n"); X+ exit(-1); X+ } X+ return 0; X+} X+#endif X+ X+int dumpHeader(port, sock, filePath, mimeType, req) X+int port; X int sock; X char filePath[]; X char mimeType[]; X@@ -351,11 +616,11 @@ X return -1; X } X stat(filePath, &fileStats); X- generateMimeHeader(sock, 200, mimeType, &fileStats, req.protocolVersion, FULL_HEADER); X- logWriter(LOG_GET_SUCCESS, req.documentAddress, (long int)fileStats.st_size, req, 0); X howMany = 0; X if (strncmp(mimeType, "text", 4)) /* check if it is a text type */ X { /* raw binary output routine */ X+ generateMimeHeader(sock, 200, mimeType, &fileStats, req.protocolVersion, FULL_HEADER); X+ logWriter(LOG_GET_SUCCESS, req.documentAddress, (long int)fileStats.st_size, req, 0); X fatal = NO; X retry = NO; X while(!feof(inFile) && !fatal) X@@ -399,11 +664,11 @@ X if (howMany > 0) X { X #ifdef ON_THE_FLY_CONVERSION X- { X- int i; X- for (i = 0; i < howMany; i++) X- if(outBuff[i] == '\r') outBuff[i] = '\n'; X- } X+ { X+ int i; X+ for (i = 0; i < howMany; i++) X+ if(outBuff[i] == '\r') outBuff[i] = '\n'; X+ } X #endif X if (send(sock, outBuff, howMany, 0) < 0) X { X@@ -449,7 +714,7 @@ X FILE *tempFile; X size_t generatedBytes; X char tempStr[MAX_PATH_LEN+1]; X- char linkStr[MAX_PATH_LEN+1]; X+ char linkStr[MAX_PATH_LEN+2]; X time_t currTime; X char timeStr[256]; X X@@ -497,10 +762,16 @@ X if (strcmp(dp->d_name, ".")) /* not self */ X { X if (strcmp(dp->d_name, "..")) X+ { X strcpy(linkStr, dp->d_name); X- else X+ if (dp->d_type == DT_DIR) X+ strcat(linkStr, "/"); X+ sprintf(tempStr, "%s
\n", linkStr, linkStr); X+ } else X+ { X strcpy(linkStr, "Parent Directory"); X- sprintf(tempStr, "%s
\n", dp->d_name, linkStr); X+ sprintf(tempStr, "%s
\n", dp->d_name, linkStr); X+ } X generatedBytes += strlen(tempStr); X fprintf(tempFile, "%s\n", tempStr); X } END-of-pserv/files/patch-handlers.c echo x - pserv/files/patch-handlers.h sed 's/^X//' >pserv/files/patch-handlers.h << 'END-of-pserv/files/patch-handlers.h' X--- handlers.h.orig Wed Oct 15 17:06:59 2003 X+++ handlers.h Wed Oct 15 17:07:08 2003 X@@ -19,6 +19,7 @@ X X /* handlers.c */ X int cgiHandler(); X+int phpHandler(); X int dumpHeader(); X int dumpFile(); X int generateIndex(); END-of-pserv/files/patch-handlers.h echo x - pserv/files/patch-mime.c sed 's/^X//' >pserv/files/patch-mime.c << 'END-of-pserv/files/patch-mime.c' X--- mime.c.orig Thu Sep 18 15:26:55 2003 X+++ mime.c Wed Oct 15 18:38:42 2003 X@@ -43,8 +43,8 @@ X f = fopen(mimeTypesFileName, "r"); X if (f == NULL) X { X- printf("Error opening mime types file. Setting defaults.\n"); X- entries = 3; X+ printf("Mime types file not found. Setting defaults.\n"); X+ entries = 6; X mimeArray = (mimeData *) calloc(entries, sizeof(mimeData)); X if (mimeArray == NULL) { X printf("Errory while allocating mime types Array. Exiting.\n"); X@@ -52,10 +52,16 @@ X } X strcpy(mimeArray[0].ext, "html"); X strcpy(mimeArray[0].type, "text/html"); X- strcpy(mimeArray[1].ext, "gif"); X- strcpy(mimeArray[1].type, "image/gif"); X- strcpy(mimeArray[2].ext, "jpg"); X- strcpy(mimeArray[2].type, "image/jpg"); X+ strcpy(mimeArray[1].ext, "htm"); X+ strcpy(mimeArray[1].type, "text/html"); X+ strcpy(mimeArray[2].ext, "gif"); X+ strcpy(mimeArray[2].type, "image/gif"); X+ strcpy(mimeArray[3].ext, "jpg"); X+ strcpy(mimeArray[3].type, "image/jpg"); X+ strcpy(mimeArray[4].ext, "png"); X+ strcpy(mimeArray[4].type, "image/png"); X+ strcpy(mimeArray[5].ext, "php"); X+ strcpy(mimeArray[5].type, "application/x-httpd-php"); X mimeEntries = entries; X return -1; X } END-of-pserv/files/patch-mime.c echo x - pserv/files/pserv.sh sed 's/^X//' >pserv/files/pserv.sh << 'END-of-pserv/files/pserv.sh' X#!/bin/sh X Xif ! PREFIX=$(expr $0 : "\(/.*\)/etc/rc\.d/$(basename $0)\$"); then X echo "$0: Cannot determine the PREFIX" >&2 X exit 1 Xfi X Xcase "$1" in Xstart) X if [ -x ${PREFIX}/sbin/pserv ]; then X ${PREFIX}/sbin/pserv > /dev/null & X echo -n ' pserv' X fi X ;; Xstop) X killall pserv > /dev/null 2>&1 X echo -n ' pserv' X ;; X*) X echo "Usage: `basename $0` {start|stop}" >&2 X ;; Xesac X Xexit 0 END-of-pserv/files/pserv.sh echo x - pserv/Makefile sed 's/^X//' >pserv/Makefile << 'END-of-pserv/Makefile' X# New ports collection makefile for: pserv X# Date created: Wed Oct 15 14:16:14 CEST 2003 X# Whom: Alex Dupre X# X# $FreeBSD$ X# X XPORTNAME= pserv XPORTVERSION= 3.0.b1 XCATEGORIES= www XMASTER_SITES= ${MASTER_SITE_SOURCEFORGE} XMASTER_SITE_SUBDIR= ${PORTNAME} XDISTNAME= ${PORTNAME}-22-Sep-03 XEXTRACT_SUFX= .tar.Z X XMAINTAINER= sysadmin@alexdupre.com XCOMMENT= A portable and small webserver written in C X XWRKSRC= ${WRKDIR}/${PORTNAME} XUSE_REINPLACE= yes X Xpost-patch: X @${REINPLACE_CMD} "s|%%PREFIX%%|${PREFIX}|g;s|%%LOCALBASE%%|${LOCALBASE}|g" \ X ${WRKSRC}/pserv.conf X Xdo-install: X ${INSTALL_PROGRAM} ${WRKSRC}/pserv ${PREFIX}/sbin/ X ${INSTALL_DATA} ${WRKSRC}/mime_types.dat ${PREFIX}/etc/mime.types X ${INSTALL_DATA} ${WRKSRC}/pserv.conf ${PREFIX}/etc/ X ${INSTALL_SCRIPT} ${FILESDIR}/pserv.sh ${PREFIX}/etc/rc.d/ X X.include END-of-pserv/Makefile echo x - pserv/distinfo sed 's/^X//' >pserv/distinfo << 'END-of-pserv/distinfo' XMD5 (pserv-22-Sep-03.tar.Z) = 4895631b730836c9202d5ac28b05f0fa END-of-pserv/distinfo echo x - pserv/pkg-descr sed 's/^X//' >pserv/pkg-descr << 'END-of-pserv/pkg-descr' XpServ is a small, portable HTTP server. It is written in pure C for speed and Xportability. It runs as a standalone program and does not require inetd. XIt should be small enough to be used in a mobile computer or to be run on your Xobsolete workstation you have somewhere. X XThis port contains a patched version to support the execution of php scripts. X XWWW: http://sourceforge.net/projects/pserv/ X X- Alex Dupre Xsysadmin@alexdupre.com END-of-pserv/pkg-descr echo x - pserv/pkg-plist sed 's/^X//' >pserv/pkg-plist << 'END-of-pserv/pkg-plist' Xsbin/pserv Xetc/mime.types Xetc/pserv.conf Xetc/rc.d/pserv.sh END-of-pserv/pkg-plist exit