BarryServer : Git

All the code for all my projects
// BarryServer : Git / IRCWebHooks / blob / 0602b6c8f1d20873230ff4eefe1b91b3cfd2df5a / src / webserver.c

// Related

IRCWebHooks

Barry Adding HTTP authentication to webserver c7c09b0 (3 years, 3 months ago)
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <b64/cdecode.h>

#include "config.h"
#include "list.h"
#include "irc.h"

int
create_socket(int port)
{
	int s;
	struct sockaddr_in addr;

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);

	s = socket(AF_INET, SOCK_STREAM, 0);
	if (s < 0) {
		perror("Unable to create socket");
		exit(EXIT_FAILURE);
	}

	if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
		perror("Unable to bind");
		exit(EXIT_FAILURE);
	}

	if (listen(s, 1) < 0) {
		perror("Unable to listen");
		exit(EXIT_FAILURE);
	}

	return s;
}

void
init_openssl(void)
{
	SSL_load_error_strings();
	OpenSSL_add_ssl_algorithms();
}

void
cleanup_openssl(void)
{
	EVP_cleanup();
}

SSL_CTX *
create_context(void)
{
	const SSL_METHOD *method;
	SSL_CTX *ctx;

	method = SSLv23_server_method();

	ctx = SSL_CTX_new(method);
	if (!ctx) {
	perror("Unable to create SSL context");
		ERR_print_errors_fp(stderr);
		exit(EXIT_FAILURE);
	}

	return ctx;
}

void
configure_context(SSL_CTX *ctx)
{
	SSL_CTX_set_ecdh_auto(ctx, 1);

	/* Set the key and cert */
	if (SSL_CTX_use_certificate_file(ctx, "cert.pem", SSL_FILETYPE_PEM) <= 0) {
		ERR_print_errors_fp(stderr);
		exit(EXIT_FAILURE);
	}

	if (SSL_CTX_use_PrivateKey_file(ctx, "cert.pem", SSL_FILETYPE_PEM) <= 0 ) {
		ERR_print_errors_fp(stderr);
		exit(EXIT_FAILURE);
	}
}

int
srv(int argc, char **argv)
{
	printf("Spinning up webserver...\n");

	int sock;
#ifdef SSL_SERVER
	SSL_CTX *ctx;
	init_openssl();
	ctx = create_context();
	configure_context(ctx);
#endif

	sock = create_socket(WEB_PORT);

	/* Handle connections */
	while(1) {
		struct sockaddr_in addr;
		uint len = sizeof(addr);
#ifdef SSL_SERVER
		SSL *ssl;
#endif
		int client = accept(sock, (struct sockaddr*)&addr, &len);
		if (client < 0) {
			perror("Unable to accept");
			exit(EXIT_FAILURE);
		}

#ifdef SSL_SERVER
		ssl = SSL_new(ctx);
		SSL_set_fd(ssl, client);
		SSL_accept(ssl);
#endif

		char buf[1025];
		char *p, *uri, *cont;
		int conlen, i;
		char key[64], *dkey;
		char httpResponse[4];

#ifdef SSL_SERVER
		SSL_read(ssl, &buf, 1024);
#else
		read(client, &buf, 1024);
#endif

		if (!strncmp(buf, "POST /", 6)) {
			p = buf + 5;
			while (*p++) if (*p == '\n' || *p == '\r' || *p == ' ') *p = '\0';
			uri = buf + 6;
			cont = uri + strlen(uri) + 1;
			if ((p = strstr(cont, "Content-Length: ")) != NULL) {
				sscanf(p+16, "%i", &conlen);
			} else {
				strcpy(httpResponse, "411");
				goto ignore;
			}
			if ((p = strstr(cont, "Authorization: Basic ")) != NULL) {
				p += 21;
				for (i = 0; *p != '\r'; i++)
					key[i] = *p++;
				key[i] = '\0';

				dkey = malloc(64);
				p = dkey;
				base64_decodestate s;
				base64_init_decodestate(&s);
				p += base64_decode_block(key, strlen(key), p, &s);
				*p = '\0';

				if (strcmp(dkey, WEB_AUTH)) {
					strcpy(httpResponse, "401");
					goto ignore;
				}
			} else {
				strcpy(httpResponse, "401");
				goto ignore;
			}
			if ((p = strstr(cont, "content=")) != NULL) {
				p[conlen] = '\0';
				p += 8;

				if (*(uri) == '\0') {
					for (current = head; current != NULL; current = current->next) {
						raw("PRIVMSG %s :%s\r\n", current->data, p);
					}
				} else
				if (*(uri) == '@') {
					raw("PRIVMSG %s :%s\r\n", buf+7, p);
				} else {
					raw("PRIVMSG #%s :%s\r\n", buf+6, p);
				}
			}
ignore:
			memset(&buf, 0, 1024);
		}

#ifdef SSL_SERVER
		SSL_write(ssl, "HTTP/1.1 ", 9);
		SSL_write(ssl, httpResponse, strlen(httpResponse));
		SSL_write(ssl, " OK\r\n", 5);
		SSL_shutdown(ssl);
		SSL_free(ssl);
#else
		write(client, "HTTP/1.1 ", 9);
		write(client, httpResponse, strlen(httpResponse));
		write(client, " OK\r\n", 5);
#endif
		close(client);
	}

	close(sock);
#ifdef SSL_SERVER
	SSL_CTX_free(ctx);
	cleanup_openssl();
#endif
}