ssl option for config

This commit is contained in:
overflowerror 2019-03-13 13:48:06 +01:00
parent aaf97aa645
commit a9f91af3da
6 changed files with 247 additions and 44 deletions

View file

@ -8,11 +8,11 @@ BIN_NAME = cfloor
OBJS = obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o obj/misc.o obj/status.o obj/files.o obj/mime.o obj/cgi.o obj/util.o obj/ssl.o obj/config.o OBJS = obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o obj/misc.o obj/status.o obj/files.o obj/mime.o obj/cgi.o obj/util.o obj/ssl.o obj/config.o
DEPS = $(OBJS:%.o=%.d) DEPS = $(OBJS:%.o=%.d)
all: $(BIN_NAME) all: $(BIN_NAME) test
ssl: CFLAGS += -DSSL_SUPPORT -Icrypto ssl: CFLAGS += -DSSL_SUPPORT -Icrypto
ssl: LDFLAGS += -lcrypto -lssl ssl: LDFLAGS += -lcrypto -lssl
ssl: obj/ssl.o $(BIN_NAME) ssl: obj/ssl.o $(BIN_NAME) test
$(BIN_NAME): obj/main.o $(OBJS) $(BIN_NAME): obj/main.o $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^ $(LD) $(LDFLAGS) -o $@ $^

View file

@ -9,6 +9,10 @@
#include "util.h" #include "util.h"
#include "networking.h" #include "networking.h"
#ifdef SSL_SUPPORT
#include "ssl.h"
#endif
#define LENGTH_OF_TOFREE_ARRAY (256) #define LENGTH_OF_TOFREE_ARRAY (256)
#define MAX_TOKEN_LENGTH (128) #define MAX_TOKEN_LENGTH (128)
@ -44,22 +48,28 @@ struct config* config_parse(FILE* file) {
#define BIND (0) #define BIND (0)
#define BIND_VALUE (1) #define BIND_VALUE (10)
#define BIND_BRACKETS_OPEN (2) #define BIND_BRACKETS_OPEN (11)
#define BIND_CONTENT (4) #define BIND_CONTENT (12)
#define SITE_BRACKETS_OPEN (5) #define SSL_BRACKETS_OPEN (130)
#define SITE_CONTENT (7) #define SSL_CONTENT (131)
#define SITE_HOST_EQUALS (8) #define SSL_KEY_EQUALS (132)
#define SITE_HOST_VALUE (9) #define SSL_KEY_VALUE (133)
#define SITE_ROOT_EQUALS (10) #define SSL_CERT_EQUALS (134)
#define SITE_ROOT_VALUE (11) #define SSL_CERT_VALUE (135)
#define HANDLER_VALUE (12) #define SITE_BRACKETS_OPEN (140)
#define HANDLER_BRACKETS_OPEN (13) #define SITE_CONTENT (141)
#define HANDLER_CONTENT (15) #define SITE_HOST_EQUALS (142)
#define TYPE_EQUALS (16) #define SITE_HOST_VALUE (143)
#define TYPE_VALUE (17) #define SITE_ROOT_EQUALS (144)
#define INDEX_EQUALS (18) #define SITE_ROOT_VALUE (145)
#define INDEX_VALUE (19) #define HANDLER_VALUE (1460)
#define HANDLER_BRACKETS_OPEN (1461)
#define HANDLER_CONTENT (1462)
#define TYPE_EQUALS (1463)
#define TYPE_VALUE (1464)
#define INDEX_EQUALS (1465)
#define INDEX_VALUE (1466)
int state = BIND; int state = BIND;
struct config_bind* currentBind = NULL; struct config_bind* currentBind = NULL;
@ -83,6 +93,9 @@ struct config* config_parse(FILE* file) {
currentToken[currentTokenLength] = '\0'; currentToken[currentTokenLength] = '\0';
char* tmp;
char** tmpArray;
switch(state) { switch(state) {
case BIND: case BIND:
if (strcmp(currentToken, "bind") != 0) { if (strcmp(currentToken, "bind") != 0) {
@ -100,15 +113,15 @@ struct config* config_parse(FILE* file) {
replaceOrAdd(toFree, &toFreeLength, NULL, currentBind); replaceOrAdd(toFree, &toFreeLength, NULL, currentBind);
config->nrBinds++; config->nrBinds++;
struct config_bind** tmp = realloc(config->binds, config->nrBinds * sizeof(struct config_bind*)); struct config_bind** tmpBind = realloc(config->binds, config->nrBinds * sizeof(struct config_bind*));
if (tmp == NULL) { if (tmpBind == NULL) {
error("config: couldn't reallocate for bind array: %s", strerror(errno)); error("config: couldn't reallocate for bind array: %s", strerror(errno));
freeEverything(toFree, toFreeLength); freeEverything(toFree, toFreeLength);
return NULL; return NULL;
} }
replaceOrAdd(toFree, &toFreeLength, config->binds, tmp); replaceOrAdd(toFree, &toFreeLength, config->binds, tmpBind);
config->binds = tmp; config->binds = tmpBind;
config->binds[config->nrBinds - 1] = currentBind; config->binds[config->nrBinds - 1] = currentBind;
currentBind->nrSites = 0; currentBind->nrSites = 0;
@ -116,6 +129,10 @@ struct config* config_parse(FILE* file) {
currentBind->addr = NULL; currentBind->addr = NULL;
currentBind->port = NULL; currentBind->port = NULL;
#ifdef SSL_SUPPORT
currentBind->ssl = NULL;
#endif
state = BIND_VALUE; state = BIND_VALUE;
break; break;
@ -196,12 +213,103 @@ struct config* config_parse(FILE* file) {
state = SITE_BRACKETS_OPEN; state = SITE_BRACKETS_OPEN;
} else if (strcmp(currentToken, "}") == 0) { } else if (strcmp(currentToken, "}") == 0) {
state = BIND; state = BIND;
} else if (strcmp(currentToken, "ssl") == 0) {
#ifdef SSL_SUPPORT
if (currentBind->ssl != NULL) {
error("config: ssl settings for this bind already defined; line %d", currentLine);
freeEverything(toFree, toFreeLength);
return NULL;
}
currentBind->ssl = malloc(sizeof(struct ssl_settings));
if (currentBind->ssl == NULL) {
error("config: couldn't allocate for ssl settings: %s", strerror(errno));
freeEverything(toFree, toFreeLength);
return NULL;
}
replaceOrAdd(toFree, &toFreeLength, NULL, currentBind->ssl);
currentBind->ssl->privateKey = NULL;
currentBind->ssl->certificate = NULL;
state = SSL_BRACKETS_OPEN;
#else
error("config: not compiled with ssl support");
freeEverything(toFree, toFreeLength);
return NULL;
#endif
} else { } else {
error("config: Unknown property '%s' on line %d.", currentToken, currentLine); error("config: Unknown property '%s' on line %d.", currentToken, currentLine);
freeEverything(toFree, toFreeLength); freeEverything(toFree, toFreeLength);
return NULL; return NULL;
} }
break; break;
#ifdef SSL_SUPPORT
case SSL_BRACKETS_OPEN:
if (strcmp(currentToken, "{") != 0) {
error("config: Unexpected token '%s' on line %d. '{' expected", currentToken, currentLine);
freeEverything(toFree, toFreeLength);
return NULL;
}
state = SSL_CONTENT;
break;
case SSL_CONTENT:
if (strcmp(currentToken, "key") == 0) {
state = SSL_KEY_EQUALS;
} else if (strcmp(currentToken, "cert") == 0) {
state = SSL_CERT_EQUALS;
} else if (strcmp(currentToken, "}") == 0) {
state = BIND_CONTENT;
} else {
error("config: Unknown property '%s' on line %d.", currentToken, currentLine);
freeEverything(toFree, toFreeLength);
return NULL;
}
break;
case SSL_KEY_EQUALS:
if (strcmp(currentToken, "=") != 0) {
error("config: Unexpected token '%s' on line %d. '=' expected", currentToken, currentLine);
freeEverything(toFree, toFreeLength);
return NULL;
}
state = SSL_KEY_VALUE;
break;
case SSL_KEY_VALUE: ;
tmp = strclone(currentToken);
if (tmp == NULL) {
error("config: error cloning ssl key string");
freeEverything(toFree, toFreeLength);
return NULL;
}
replaceOrAdd(toFree, &toFreeLength, NULL, tmp);
currentBind->ssl->privateKey = tmp;
state = SSL_CONTENT;
break;
case SSL_CERT_EQUALS:
if (strcmp(currentToken, "=") != 0) {
error("config: Unexpected token '%s' on line %d. '=' expected", currentToken, currentLine);
freeEverything(toFree, toFreeLength);
return NULL;
}
state = SSL_CERT_VALUE;
break;
case SSL_CERT_VALUE: ;
tmp = strclone(currentToken);
if (tmp == NULL) {
error("config: error cloning ssl cert string");
freeEverything(toFree, toFreeLength);
return NULL;
}
replaceOrAdd(toFree, &toFreeLength, NULL, tmp);
currentBind->ssl->certificate = tmp;
state = SSL_CONTENT;
break;
#endif
case SITE_BRACKETS_OPEN: case SITE_BRACKETS_OPEN:
if (strcmp(currentToken, "{") != 0) { if (strcmp(currentToken, "{") != 0) {
error("config: Unexpected token '%s' on line %d. '{' expected", currentToken, currentLine); error("config: Unexpected token '%s' on line %d. '{' expected", currentToken, currentLine);
@ -260,9 +368,9 @@ struct config* config_parse(FILE* file) {
} }
state = SITE_HOST_VALUE; state = SITE_HOST_VALUE;
break; break;
case SITE_HOST_VALUE: ; case SITE_HOST_VALUE:
char** tmpArray = realloc(currentSite->hostnames, ++currentSite->nrHostnames * sizeof(char*)); tmpArray = realloc(currentSite->hostnames, ++currentSite->nrHostnames * sizeof(char*));
if (tmp == NULL) { if (tmpArray == NULL) {
error("config: error allocating hostname array"); error("config: error allocating hostname array");
freeEverything(toFree, toFreeLength); freeEverything(toFree, toFreeLength);
return NULL; return NULL;
@ -270,15 +378,15 @@ struct config* config_parse(FILE* file) {
replaceOrAdd(toFree, &toFreeLength, currentSite->hostnames, tmpArray); replaceOrAdd(toFree, &toFreeLength, currentSite->hostnames, tmpArray);
currentSite->hostnames = tmpArray; currentSite->hostnames = tmpArray;
char* clone = strclone(currentToken); tmp = strclone(currentToken);
if (clone == NULL) { if (tmp == NULL) {
error("config: error cloning hostname string"); error("config: error cloning hostname string");
freeEverything(toFree, toFreeLength); freeEverything(toFree, toFreeLength);
return NULL; return NULL;
} }
replaceOrAdd(toFree, &toFreeLength, NULL, clone); replaceOrAdd(toFree, &toFreeLength, NULL, tmp);
currentSite->hostnames[currentSite->nrHostnames - 1] = clone; currentSite->hostnames[currentSite->nrHostnames - 1] = tmp;
state = SITE_CONTENT; state = SITE_CONTENT;
break; break;
@ -291,21 +399,21 @@ struct config* config_parse(FILE* file) {
state = SITE_ROOT_VALUE; state = SITE_ROOT_VALUE;
break; break;
case SITE_ROOT_VALUE: case SITE_ROOT_VALUE:
clone = strclone(currentToken); tmp = strclone(currentToken);
if (clone == NULL) { if (tmp == NULL) {
error("config: error cloning document root string"); error("config: error cloning document root string");
freeEverything(toFree, toFreeLength); freeEverything(toFree, toFreeLength);
return NULL; return NULL;
} }
replaceOrAdd(toFree, &toFreeLength, NULL, clone); replaceOrAdd(toFree, &toFreeLength, NULL, tmp);
currentSite->documentRoot = clone; currentSite->documentRoot = tmp;
state = SITE_CONTENT; state = SITE_CONTENT;
break; break;
case HANDLER_VALUE: case HANDLER_VALUE:
currentHandler->dir = strclone(currentToken); currentHandler->dir = strclone(currentToken);
if (clone == NULL) { if (currentHandler->dir == NULL) {
error("config: error cloning handle directory string"); error("config: error cloning handle directory string");
freeEverything(toFree, toFreeLength); freeEverything(toFree, toFreeLength);
return NULL; return NULL;
@ -374,7 +482,7 @@ struct config* config_parse(FILE* file) {
struct fileSettings* settings = &(currentHandler->settings.fileSettings); struct fileSettings* settings = &(currentHandler->settings.fileSettings);
tmpArray = realloc(settings->indexfiles.files, ++(settings->indexfiles.number) * sizeof(char*)); tmpArray = realloc(settings->indexfiles.files, ++(settings->indexfiles.number) * sizeof(char*));
if (tmp == NULL) { if (tmpArray == NULL) {
error("config: error allocating hostname array"); error("config: error allocating hostname array");
freeEverything(toFree, toFreeLength); freeEverything(toFree, toFreeLength);
return NULL; return NULL;
@ -382,15 +490,15 @@ struct config* config_parse(FILE* file) {
replaceOrAdd(toFree, &toFreeLength, settings->indexfiles.files, tmpArray); replaceOrAdd(toFree, &toFreeLength, settings->indexfiles.files, tmpArray);
settings->indexfiles.files = tmpArray; settings->indexfiles.files = tmpArray;
clone = strclone(currentToken); tmp = strclone(currentToken);
if (clone == NULL) { if (tmp == NULL) {
error("config: error cloning hostname string"); error("config: error cloning hostname string");
freeEverything(toFree, toFreeLength); freeEverything(toFree, toFreeLength);
return NULL; return NULL;
} }
replaceOrAdd(toFree, &toFreeLength, NULL, clone); replaceOrAdd(toFree, &toFreeLength, NULL, tmp);
settings->indexfiles.files[settings->indexfiles.number - 1] = clone; settings->indexfiles.files[settings->indexfiles.number - 1] = tmp;
state = HANDLER_CONTENT; state = HANDLER_CONTENT;
break; break;
@ -416,6 +524,22 @@ struct config* config_parse(FILE* file) {
for (int i = 0; i < config->nrBinds; i++) { for (int i = 0; i < config->nrBinds; i++) {
currentBind = config->binds[i]; currentBind = config->binds[i];
#ifdef SSL_SUPPORT
if (currentBind->ssl != NULL) {
if (currentBind->ssl->privateKey == NULL) {
error("config: ssl private key missing for %s:%s", currentBind->addr, currentBind->port);
freeEverything(toFree, toFreeLength);
return NULL;
}
if (currentBind->ssl->certificate == NULL) {
error("config: ssl certificate missing for %s:%s", currentBind->addr, currentBind->port);
freeEverything(toFree, toFreeLength);
return NULL;
}
}
#endif
for(int j = 0; j < currentBind->nrSites; j++) { for(int j = 0; j < currentBind->nrSites; j++) {
currentSite = currentBind->sites[j]; currentSite = currentBind->sites[j];
@ -478,6 +602,14 @@ void config_destroy(struct config* config) {
free(currentBind->addr); free(currentBind->addr);
free(currentBind->port); free(currentBind->port);
#ifdef SSL_SUPPORT
if (currentBind->ssl != NULL) {
free(currentBind->ssl->privateKey);
free(currentBind->ssl->certificate);
free(currentBind->ssl);
}
#endif
for(int j = 0; j < currentBind->nrSites; j++) { for(int j = 0; j < currentBind->nrSites; j++) {
currentSite = currentBind->sites[j]; currentSite = currentBind->sites[j];

View file

@ -8,11 +8,20 @@
#include "files.h" #include "files.h"
#include "cgi.h" #include "cgi.h"
#ifdef SSL_SUPPORT
#include "ssl.h"
#endif
struct config { struct config {
int nrBinds; int nrBinds;
struct config_bind { struct config_bind {
char* addr; char* addr;
char* port; char* port;
#ifdef SSL_SUPPORT
struct ssl_settings* ssl;
#endif
int nrSites; int nrSites;
struct config_site { struct config_site {
int nrHostnames; int nrHostnames;
@ -36,6 +45,10 @@ struct config {
config format config format
bind [addr]:[port] { bind [addr]:[port] {
ssl {
key = file
cert = certfile
}
site { site {
hostname|alias = "[host]" hostname|alias = "[host]"
root = "/" root = "/"

View file

@ -15,8 +15,8 @@ struct ssl_connection {
}; };
struct ssl_settings { struct ssl_settings {
const char* privateKey; char* privateKey;
const char* certificate; char* certificate;
struct { struct {
SSL_CTX* ctx; SSL_CTX* ctx;
} _private; } _private;

View file

@ -238,10 +238,24 @@ void testHeaders() {
} }
void testConfig() { void testConfig() {
struct config* config = config_parse(fopen("test.conf", "r")); FILE* file;
#ifdef SSL_SUPPORT
file = fopen("test-with-ssl.conf", "r");
#else
file = fopen("test.conf", "r");
#endif
struct config* config = config_parse(file);
checkNull(config, "null check"); checkNull(config, "null check");
checkInt(config->nrBinds, 1, "bind no check");
#ifdef SSL_SUPPORT
checkInt(config->nrBinds, 2, "bind no check");
#else
checkInt(config->nrBinds, 1, "bind no check");
#endif
checkString(config->binds[0]->addr, "0.0.0.0", "bind addr check"); checkString(config->binds[0]->addr, "0.0.0.0", "bind addr check");
checkString(config->binds[0]->port, "80", "bind port check"); checkString(config->binds[0]->port, "80", "bind port check");
checkInt(config->binds[0]->nrSites, 1, "site no check"); checkInt(config->binds[0]->nrSites, 1, "site no check");
@ -256,7 +270,27 @@ void testConfig() {
checkInt(config->binds[0]->sites[0]->handlers[0]->settings.fileSettings.indexfiles.number, 1, "handler settings index no"); checkInt(config->binds[0]->sites[0]->handlers[0]->settings.fileSettings.indexfiles.number, 1, "handler settings index no");
checkString(config->binds[0]->sites[0]->handlers[0]->settings.fileSettings.indexfiles.files[0], "index.html", "handler settings index check"); checkString(config->binds[0]->sites[0]->handlers[0]->settings.fileSettings.indexfiles.files[0], "index.html", "handler settings index check");
#ifdef SSL_SUPPORT
checkString(config->binds[1]->addr, "0.0.0.0", "bind addr check");
checkString(config->binds[1]->port, "443", "bind port check");
checkNull(config->binds[1]->ssl, "ssl null check");
checkString(config->binds[1]->ssl->privateKey, "ssl.key", "ssl key check");
checkString(config->binds[1]->ssl->certificate, "ssl.crt", "ssl cert check");
checkInt(config->binds[1]->nrSites, 1, "site no check");
checkInt(config->binds[1]->sites[0]->nrHostnames, 1, "site hostname no check");
checkString(config->binds[1]->sites[0]->hostnames[0], "example.com", "site hostname check");
checkString(config->binds[1]->sites[0]->documentRoot, "/var/www", "site document root check");
checkInt(config->binds[1]->sites[0]->nrHandlers, 1, "handler no check");
checkString(config->binds[1]->sites[0]->handlers[0]->dir, "/", "handler dir check");
checkInt(config->binds[1]->sites[0]->handlers[0]->type, FILE_HANDLER_NO, "handler type no check");
checkVoid(config->binds[1]->sites[0]->handlers[0]->handler, &fileHandler, "handler ptr check");
checkString(config->binds[1]->sites[0]->handlers[0]->settings.fileSettings.documentRoot, "/var/www", "handler settings root check");
checkInt(config->binds[1]->sites[0]->handlers[0]->settings.fileSettings.indexfiles.number, 1, "handler settings index no");
checkString(config->binds[1]->sites[0]->handlers[0]->settings.fileSettings.indexfiles.files[0], "index.html", "handler settings index check");
#endif
fclose(file);
config_destroy(config); config_destroy(config);
} }

24
test-with-ssl.conf Normal file
View file

@ -0,0 +1,24 @@
bind 0.0.0.0:80 {
site {
hostname = example.com
root = /var/www
handler / {
type = file
index = index.html
}
}
}
bind 0.0.0.0:443 {
ssl {
key = ssl.key
cert = ssl.crt
}
site {
hostname = example.com
root = /var/www
handler / {
type = file
index = index.html
}
}
}