summaryrefslogblamecommitdiff
path: root/www/pserv/files/patch-main.c
blob: e9ae61cbe1b6b7703f58eaacc0b6d2a658aef7b0 (plain) (tree)

































































































































































































































































































































































































                                                                                                                                                             
--- main.c.orig	Mon Sep 22 10:39:24 2003
+++ main.c	Thu Oct 16 14:00:02 2003
@@ -23,6 +23,7 @@
 char defaultFileName[MAX_PATH_LEN+1];
 char logFileName[MAX_PATH_LEN+1];
 char mimeTypesFileName[MAX_PATH_LEN+1];
+char phpFileName[MAX_PATH_LEN+1];
 char cgiRoot[MAX_PATH_LEN+1]; /* root for CGI scripts exec */
 struct timeval sockTimeVal;
 mimeData *mimeArray; /* here we will hold all MIME data, inited once, never to be changed */
@@ -206,10 +207,10 @@
     int reqSize;
     int readLines;
     int tokenEnd;
-   
-    /* we copy the header lines to an array for easier parsing */ 
+
+    /* we copy the header lines to an array for easier parsing */
     /* but first we make sure that our string has a newline and an end */
-    req[BUFFER_SIZE] = '\0';    
+    req[BUFFER_SIZE] = '\0';
     reqSize = strlen(req);
     req[reqSize] = '\n';
     reqSize++;
@@ -230,7 +231,7 @@
     for (k = 0; k < readLines; k++)
         printf("%d - |%s|\n", k, reqArray[k]);
 #endif
-    
+
     /* first line: method, path and protocol version */
     /* we copy to a temporary buffer to be more secure against overflows */
     i = j = 0;
@@ -246,7 +247,7 @@
     else
         tokenEnd = NO;
     i++;
-    
+
     /* we look for the document address */
     j = 0;
     reqStruct->documentAddress[0] = '\0';
@@ -259,14 +260,14 @@
         else
             token[j] = '\0';      /* to make sure we have a string */
         /* now we need to convert some escapings from the path like %20 */
-	convertPercents(token, j);
+        convertPercents(token, j);
         strcpy(reqStruct->documentAddress, token);  /* copy back */
         if (reqArray[0][i] == '\0')
             tokenEnd = YES;
         else
             tokenEnd = NO;
         i++;
-    
+
         /* we need now to separate path from query string ("?" separated) */
         if (reqArray[0][i-1] == '?')
         {
@@ -282,7 +283,7 @@
             i++;
         }
     }
-    
+
     /* we analyze the HTTP protocol version */
     /* default is 0.9 since that version didn't report itself */
     strcpy(reqStruct->protocolVersion, "HTTP/0.9");
@@ -306,10 +307,13 @@
     else if (!strncmp(reqArray[1], "Connection: Keep-Alive", strlen("Connection: keep-alive")))
         reqStruct->keepAlive = YES;
 
-    /* user-agent, content-length and else */
+    /* user-agent, content-length, content-type, cookie and else */
     i = 1;
     j = NO;
     reqStruct->userAgent[0] = '\0';
+    reqStruct->contentLength = -1;
+    reqStruct->contentType[0] = '\0';
+    reqStruct->cookie[0] = '\0';
     while (i < readLines)
     {
         if (!strncmp(reqArray[i], "User-Agent:", strlen("User-Agent:")))
@@ -317,14 +321,28 @@
             strncpy(reqStruct->userAgent, &reqArray[i][strlen("User-Agent: ")], USER_AGENT_LEN - 1);
             reqStruct->userAgent[USER_AGENT_LEN] = '\0';
         }
-	else if (!strncmp(reqArray[i], "Content-Length:", strlen("Content-length:")) || !strncmp(reqArray[i], "Content-length:", strlen("Content-length:")))
-    	{
-	    strcpy(token, &reqArray[i][strlen("Content-length: ")]);
-	    sscanf(token, "%ld", &(reqStruct->contentLength));
+        else if (!strncmp(reqArray[i], "Content-Length:", strlen("Content-length:")) || !strncmp(reqArray[i], "Content-length:", strlen("Content-length:")))
+        {
+            strcpy(token, &reqArray[i][strlen("Content-length: ")]);
+            sscanf(token, "%ld", &(reqStruct->contentLength));
 #ifdef PRINTF_DEBUG
-	    printf("content length %ld\n", reqStruct->contentLength);
+            printf("content length %ld\n", reqStruct->contentLength);
 #endif
-	}
+        }
+        else if (!strncmp(reqArray[i], "Content-Type:", strlen("Content-type:")) || !strncmp(reqArray[i], "Content-type:", strlen("Content-type:")))
+        {
+            strncpy(reqStruct->contentType, &reqArray[i][strlen("Content-type: ")], CONTENT_TYPE_LEN - 1);
+#ifdef PRINTF_DEBUG
+            printf("content type %s\n", reqStruct->contentType);
+#endif
+        }
+        else if (!strncmp(reqArray[i], "Cookie:", strlen("Cookie:")))
+        {
+            strncpy(reqStruct->cookie, &reqArray[i][strlen("Cookie: ")], MAX_COOKIE_LEN - 1);
+#ifdef PRINTF_DEBUG
+            printf("cookie %s\n", reqStruct->cookie);
+#endif
+        }
         i++;
     }
     /* if we didn't find a User-Aget we fill in a (N)ot(R)ecognized */
@@ -414,18 +432,39 @@
                     /* we append the default file name */
                     strcat(completeFilePath, defaultFileName);
                     analyzeExtension(mimeType, completeFilePath);
-                    dumpFile(sock, completeFilePath, mimeType, req);
+#ifdef PHP
+                    if (strncmp(mimeType, "application/x-httpd-php", 23))
+#endif
+                        dumpFile(sock, completeFilePath, mimeType, req);
+#ifdef PHP
+                    else
+                        phpHandler(port, sock, phpFileName, completeFilePath, req, NULL);
+#endif
                 }
 #else
                 /* we append the default file name */
                 strcat(completeFilePath, defaultFileName);
                 analyzeExtension(mimeType, completeFilePath);
-                dumpFile(sock, completeFilePath, mimeType, req);
+#ifdef PHP
+                if (strncmp(mimeType, "application/x-httpd-php", 23))
+#endif
+                    dumpFile(sock, completeFilePath, mimeType, req);
+#ifdef PHP
+                else
+                    phpHandler(port, sock, phpFileName, completeFilePath, req, NULL);
+#endif
 #endif
             } else
             { /* it is a plain file */
                 analyzeExtension(mimeType, completeFilePath);
-                dumpFile(sock, completeFilePath, mimeType, req);
+#ifdef PHP
+                if (strncmp(mimeType, "application/x-httpd-php", 23))
+#endif
+                    dumpFile(sock, completeFilePath, mimeType, req);
+#ifdef PHP
+                else
+                    phpHandler(port, sock, phpFileName, completeFilePath, req, NULL);
+#endif
             }
         }
     } else if (!strcmp(req.method, "HEAD"))
@@ -494,7 +533,14 @@
                 strcat(completeFilePath, defaultFileName);
             }
             analyzeExtension(mimeType, completeFilePath);
-            dumpHeader(sock, completeFilePath, mimeType, req);
+#ifdef PHP
+            if (strncmp(mimeType, "application/x-httpd-php", 23))
+#endif
+                dumpFile(sock, completeFilePath, mimeType, req);
+#ifdef PHP
+            else
+                phpHandler(port, sock, phpFileName, completeFilePath, req, NULL);
+#endif
         }
     } else if (!strcmp(req.method, "POST"))
     {
@@ -507,13 +553,6 @@
         int readFinished;
         
         printf("Handling of POST method\n");
-        /* first we check if the path contains the directory selected for cgi's and in case handle it */
-        if (strncmp(req.documentAddress, CGI_MATCH_STRING, strlen(CGI_MATCH_STRING)))
-        {
-            /* non cgi POST is not supported */
-            sayError(sock, UNHANDLED_METHOD, "", req);
-            return -1;
-        }
 #ifdef PRINTF_DEBUG
         printf ("begin of post handling\n");
 
@@ -523,9 +562,15 @@
         totalRead = 0;
         stuckCounter = 0;
         timeOutCounter = 0;
-        while (!readFinished)
-        {
-            howMany = recv(newSocket, tempBuff, BUFFER_SIZE, 0);
+
+        /* SECURITY: Avoid malicious Content-Length -- check \r\n\r\n\0 also */
+        if (req.contentLength < 0 || req.contentLength >= BUFFER_SIZE-5) {
+                sayError(sock, 500, "", req);
+                return -1;
+        }
+
+        /* SECURITY: Remove loop to prevent buffer overflow */
+            howMany = recv(newSocket, tempBuff, req.contentLength+5, 0);
 	    tempBuff[howMany] = '\0'; /* seems that some Unices need this */
 #ifdef PRINTF_DEBUG
         printf ("read: %d\n%s\n", howMany, tempBuff);
@@ -579,16 +624,15 @@
 	    	if (howMany == req.contentLength)
 		    readFinished = YES;
             }
-    }
 #ifdef PRINTF_DEBUG
-    printf("total read %d\n", totalRead);
+        printf("total read %d\n", totalRead);
 #endif
-    if (totalRead == 0)
-    {
-        printf("Request read error\n");
-    } else
-    {
-        if (buff[totalRead - 1] != '\n') /* we need a trailing \n or the script will wait forever */
+        if (totalRead == 0)
+        {
+            printf("Request read error\n");
+        } else
+        {
+            if (buff[totalRead - 1] != '\n') /* we need a trailing \n or the script will wait forever */
             {
                 buff[totalRead++] = '\n';
                 buff[totalRead] = '\0';
@@ -596,7 +640,77 @@
 #ifdef PRINTF_DEBUG
             printf("buff: |%s|\n", buff);
 #endif
-            cgiHandler(port, sock, req, buff);
+            if (!strncmp(req.documentAddress, CGI_MATCH_STRING, strlen(CGI_MATCH_STRING)))
+            {
+                cgiHandler(port, sock, req, buff);
+            } else
+            {
+#ifdef PHP
+                strcpy(completeFilePath, homePath);
+                strcat(completeFilePath, req.documentAddress);
+                /* now we check if the given path tries to get out of the root */
+                {
+                    int i,j;
+                    int sL;
+                    char dirName[MAX_PATH_LEN+1];
+                    int depthCount = 0;
+
+                    sL = strlen(req.documentAddress);
+                    dirName[0] = '\0';
+                    if (sL > 3) {
+                        dirName[0] = req.documentAddress[1];
+                        dirName[1] = req.documentAddress[2];
+                        dirName[2] = req.documentAddress[3];
+                        dirName[3] ='\0';
+                        if (!strcmp(dirName, "../"))
+                        {
+                            sayError(sock, FORBIDDEN, req.documentAddress, req);
+                            return -1;
+                        }
+                    }
+                    j = 0;
+                    for (i = 1; i < sL; i++) {
+                        if (req.documentAddress[i] == '/')
+                        {
+                            dirName[j] = '\0';
+                            if (strcmp(dirName, ".."))
+                                depthCount ++;
+                            else
+                                depthCount--;
+                            j = 0;
+                        } else
+                            dirName[j++] = req.documentAddress[i];
+                    }
+                    if (depthCount < 0)
+                    {
+                        sayError(sock, FORBIDDEN, req.documentAddress, req);
+                        return -1;
+                    }
+                }
+                /* now we check if the given file is a directory or a plain file */
+                stat(completeFilePath, &fileStats);
+                if ((fileStats.st_mode & S_IFDIR) == S_IFDIR)
+                {
+                    /* if does not end with a slash, we get an error */
+                    if(completeFilePath[strlen(completeFilePath)-1] != '/')
+                    {
+                        sayError(sock, NOT_FOUND, req.documentAddress, req);
+                        return -1;
+                    }
+                    /* we append the default file name */
+                    strcat(completeFilePath, defaultFileName);
+                }
+                analyzeExtension(mimeType, completeFilePath);
+                if (strncmp(mimeType, "application/x-httpd-php", 23))
+                {
+#endif
+                    /* non cgi POST is not supported */
+                    sayError(sock, UNHANDLED_METHOD, "", req);
+                    return -1;
+#ifdef PHP
+                } else phpHandler(port, sock, phpFileName, completeFilePath, req, buff);
+#endif
+            }
         }
     } else
     {
@@ -625,7 +739,7 @@
     f = fopen(configFile, "r");
     if (f == NULL)
     {
-        printf("Error opening config file. Setting defaults.\n");
+        printf("Config file not found. Setting defaults.\n");
         *serverPort = DEFAULT_PORT;
         *maxChildren = DEFAULT_MAX_CHILDREN;
         strcpy(homePath, DEFAULT_DOCS_LOCATION);
@@ -634,7 +748,9 @@
         sockTimeVal.tv_usec = DEFAULT_USEC_TO;
         strcpy(logFileName, DEFAULT_LOG_FILE);
         strcpy(mimeTypesFileName, DEFAULT_MIME_FILE);
+        strcpy(phpFileName, DEFAULT_PHP_FILE);
         strcpy(cgiRoot, DEFAULT_CGI_ROOT);
+        initMimeTypes();
         return -1;
     }
     if (!feof(f)) fscanf(f, "%s %s", str1, str2);
@@ -735,11 +851,25 @@
         if (mimeTypesFileName == NULL)
         {
             strcpy(mimeTypesFileName, DEFAULT_MIME_FILE);
-            printf("Error reading mimeTypesFileName from file, setting default, %s\n", mimeTypesFileName);
+            printf("Error reading mimeTypesFile from file, setting default, %s\n", mimeTypesFileName);
         }
     } else {
         strcpy(mimeTypesFileName, DEFAULT_MIME_FILE);
-        printf("Error reading mimeTypesFileName from file, setting default, %s\n", mimeTypesFileName);
+        printf("Error reading mimeTypesFile from file, setting default, %s\n", mimeTypesFileName);
+    }
+    if (!feof(f)) fscanf(f, "%s %s", str1, str2);
+    if (str1 != NULL && str2 != NULL && !strcmp(str1, "phpFile"))
+    {
+        sscanf(str2, "%s", phpFileName);
+        if (logFileName == NULL)
+        {
+            strcpy(phpFileName, DEFAULT_LOG_FILE);
+            printf("Error reading phpFile from file, setting default, %s\n", phpFileName);
+        }
+    } else
+    {
+        strcpy(phpFileName, DEFAULT_PHP_FILE);
+        printf("Error reading phpFile from file, setting default, %s\n", phpFileName);
     }
     if (!feof(f)) fscanf(f, "%s %s", str1, str2);
     if (str1 != NULL && str2 != NULL && !strcmp(str1, "cgiRoot"))
@@ -775,6 +905,7 @@
     int readFinished;
     struct request gottenReq;
     int isKeepAlive;
+    int bool;
     struct sockaddr_in listenName;           /* data struct for the listen port */
     struct sockaddr_in acceptedSockStruct;   /* sockaddr for the internetworking */
     int acceptedSocketLen;                   /* size of the structure */
@@ -808,9 +939,16 @@
         printf("socket creation error occoured\n");
         return -1;
     }
+    bool = 1;
+    error = setsockopt (theSocket, SOL_SOCKET, SO_REUSEADDR, &bool, sizeof(bool));
+    if (error == -1)
+    {   if (errno == EADDRINUSE)
+        printf("set socket option error occoured\n");
+        return -1;
+    }
     error = bind (theSocket, (struct sockaddr*)  &listenName, sizeof(listenName));
     if (error == -1)
-    {
+    {   if (errno == EADDRINUSE)
         printf("socket binding error occoured\n");
         return -2;
     }